mirror of
https://github.com/nim-lang/Nim.git
synced 2026-06-09 21:28:13 +00:00
fixes #20
This commit is contained in:
@@ -662,7 +662,6 @@ proc newString*(len: int): string {.
|
||||
## optimization purposes; the same effect can be achieved with the
|
||||
## ``&`` operator.
|
||||
|
||||
# concat operator:
|
||||
proc `&` * (x: string, y: char): string {.
|
||||
magic: "ConStrStr", noSideEffect, merge.}
|
||||
proc `&` * (x: char, y: char): string {.
|
||||
|
||||
@@ -118,3 +118,34 @@ proc objectInit(dest: Pointer, typ: PNimType) =
|
||||
for i in 0..(typ.size div typ.base.size)-1:
|
||||
objectInit(cast[pointer](d +% i * typ.base.size), typ.base)
|
||||
else: nil # nothing to do
|
||||
|
||||
# ---------------------- assign zero -----------------------------------------
|
||||
|
||||
proc genericReset(dest: Pointer, mt: PNimType) {.compilerProc.}
|
||||
proc genericResetAux(dest: Pointer, n: ptr TNimNode) =
|
||||
var d = cast[TAddress](dest)
|
||||
case n.kind
|
||||
of nkNone: assert(false)
|
||||
of nkSlot: genericReset(cast[pointer](d +% n.offset), n.typ)
|
||||
of nkList:
|
||||
for i in 0..n.len-1: genericResetAux(dest, n.sons[i])
|
||||
of nkCase:
|
||||
zeroMem(cast[pointer](d +% n.offset), n.typ.size)
|
||||
var m = selectBranch(dest, n)
|
||||
if m != nil: genericResetAux(dest, m)
|
||||
|
||||
proc genericReset(dest: Pointer, mt: PNimType) =
|
||||
var d = cast[TAddress](dest)
|
||||
assert(mt != nil)
|
||||
case mt.Kind
|
||||
of tyString, tyRef, tySequence:
|
||||
unsureAsgnRef(cast[ppointer](dest), nil)
|
||||
of tyObject, tyTuple, tyPureObject:
|
||||
# we don't need to reset m_type field for tyObject
|
||||
genericResetAux(dest, mt.node)
|
||||
of tyArray, tyArrayConstr:
|
||||
for i in 0..(mt.size div mt.base.size)-1:
|
||||
genericReset(cast[pointer](d +% i*% mt.base.size), mt.base)
|
||||
else:
|
||||
zeroMem(dest, mt.size) # set raw bits to zero
|
||||
|
||||
|
||||
@@ -74,8 +74,9 @@ var
|
||||
# we use a lock to prevent the garbage collector to be triggered in a
|
||||
# finalizer; the collector should not call itself this way! Thus every
|
||||
# object allocated by a finalizer will not trigger a garbage collection.
|
||||
# This is wasteful but safe. This is a lock against recursive garbage
|
||||
# collection, not a lock for threads!
|
||||
# This is wasteful but safe and won't ever be a problem for sane
|
||||
# finalizers. This is a lock against recursive garbage collection, not a
|
||||
# lock for threads!
|
||||
|
||||
proc aquire(gch: var TGcHeap) {.inline.} =
|
||||
when hasThreadSupport:
|
||||
|
||||
@@ -150,12 +150,6 @@ proc getStorageLoc(n: PNode): TStorageLoc =
|
||||
result = getStorageLoc(n.sons[0])
|
||||
else: result = OnUnknown
|
||||
|
||||
type
|
||||
TAssignmentFlag = enum
|
||||
needToCopy, needForSubtypeCheck, afDestIsNil, afDestIsNotNil, afSrcIsNil,
|
||||
afSrcIsNotNil
|
||||
TAssignmentFlags = set[TAssignmentFlag]
|
||||
|
||||
proc genRefAssign(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
|
||||
if (dest.s == OnStack) or not (optRefcGC in gGlobalOptions):
|
||||
appf(p.s[cpsStmts], "$1 = $2;$n", [rdLoc(dest), rdLoc(src)])
|
||||
@@ -902,27 +896,6 @@ proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) =
|
||||
dest.r = ropef("$1->data[$1->Sup.len-1]", [rdLoc(a)])
|
||||
genAssignment(p, dest, b, {needToCopy, afDestIsNil})
|
||||
|
||||
proc genObjectInit(p: BProc, t: PType, a: TLoc, takeAddr: bool) =
|
||||
var
|
||||
r: PRope
|
||||
s: PType
|
||||
case analyseObjectWithTypeField(t)
|
||||
of frNone:
|
||||
nil
|
||||
of frHeader:
|
||||
r = rdLoc(a)
|
||||
if not takeAddr: r = ropef("(*$1)", [r])
|
||||
s = t
|
||||
while (s.kind == tyObject) and (s.sons[0] != nil):
|
||||
app(r, ".Sup")
|
||||
s = skipTypes(s.sons[0], abstractInst)
|
||||
appf(p.s[cpsStmts], "$1.m_type = $2;$n", [r, genTypeInfo(p.module, t)])
|
||||
of frEmbedded:
|
||||
# worst case for performance:
|
||||
if takeAddr: r = addrLoc(a)
|
||||
else: r = rdLoc(a)
|
||||
appcg(p, cpsStmts, "#objectInit($1, $2);$n", [r, genTypeInfo(p.module, t)])
|
||||
|
||||
proc genNew(p: BProc, e: PNode) =
|
||||
var
|
||||
a, b: TLoc
|
||||
@@ -936,7 +909,7 @@ proc genNew(p: BProc, e: PNode) =
|
||||
getTypeDesc(p.module, skipTypes(reftype.sons[0], abstractRange))])
|
||||
genAssignment(p, a, b, {}) # set the object type:
|
||||
bt = skipTypes(refType.sons[0], abstractRange)
|
||||
genObjectInit(p, bt, a, false)
|
||||
genObjectInit(p, cpsStmts, bt, a, false)
|
||||
|
||||
proc genNewSeq(p: BProc, e: PNode) =
|
||||
var
|
||||
@@ -1001,7 +974,7 @@ proc genNewFinalize(p: BProc, e: PNode) =
|
||||
ti, getTypeDesc(p.module, skipTypes(reftype.sons[0], abstractRange))])
|
||||
genAssignment(p, a, b, {}) # set the object type:
|
||||
bt = skipTypes(refType.sons[0], abstractRange)
|
||||
genObjectInit(p, bt, a, false)
|
||||
genObjectInit(p, cpsStmts, bt, a, false)
|
||||
|
||||
proc genRepr(p: BProc, e: PNode, d: var TLoc) =
|
||||
var a: TLoc
|
||||
|
||||
@@ -42,6 +42,7 @@ proc genVarTuple(p: BProc, n: PNode) =
|
||||
v = n.sons[i].sym
|
||||
if sfGlobal in v.flags:
|
||||
assignGlobalVar(p, v)
|
||||
genObjectInit(p, cpsInit, v.typ, v.loc, true)
|
||||
else:
|
||||
assignLocalVar(p, v)
|
||||
initVariable(p, v)
|
||||
@@ -53,7 +54,6 @@ proc genVarTuple(p: BProc, n: PNode) =
|
||||
field.r = ropef("$1.$2",
|
||||
[rdLoc(tup), mangleRecFieldName(t.n.sons[i].sym, t)])
|
||||
putLocIntoDest(p, v.loc, field)
|
||||
genObjectInit(p, v.typ, v.loc, true)
|
||||
|
||||
proc genVarStmt(p: BProc, n: PNode) =
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
@@ -64,14 +64,13 @@ proc genVarStmt(p: BProc, n: PNode) =
|
||||
var v = a.sons[0].sym
|
||||
if sfGlobal in v.flags:
|
||||
assignGlobalVar(p, v)
|
||||
genObjectInit(p, cpsInit, v.typ, v.loc, true)
|
||||
else:
|
||||
assignLocalVar(p, v)
|
||||
initVariable(p, v) # XXX: this is not required if a.sons[2] != nil,
|
||||
# unless it is a GC'ed pointer
|
||||
initVariable(p, v)
|
||||
if a.sons[2].kind != nkEmpty:
|
||||
genLineDir(p, a)
|
||||
expr(p, a.sons[2], v.loc)
|
||||
genObjectInit(p, v.typ, v.loc, true) # correct position
|
||||
else:
|
||||
genVarTuple(p, a)
|
||||
|
||||
|
||||
110
rod/cgen.nim
110
rod/cgen.nim
@@ -256,35 +256,75 @@ proc rdCharLoc(a: TLoc): PRope =
|
||||
if skipTypes(a.t, abstractRange).kind == tyChar:
|
||||
result = ropef("((NU8)($1))", [result])
|
||||
|
||||
proc zeroLoc(p: BProc, loc: TLoc) =
|
||||
if not (skipTypes(loc.t, abstractVarRange).Kind in
|
||||
{tyArray, tyArrayConstr, tySet, tyTuple, tyObject}):
|
||||
if gCmd == cmdCompileToLLVM:
|
||||
appf(p.s[cpsStmts], "store $2 0, $2* $1$n",
|
||||
[addrLoc(loc), getTypeDesc(p.module, loc.t)])
|
||||
else:
|
||||
proc genObjectInit(p: BProc, section: TCProcSection, t: PType, a: TLoc,
|
||||
takeAddr: bool) =
|
||||
case analyseObjectWithTypeField(t)
|
||||
of frNone:
|
||||
nil
|
||||
of frHeader:
|
||||
var r = rdLoc(a)
|
||||
if not takeAddr: r = ropef("(*$1)", [r])
|
||||
var s = t
|
||||
while (s.kind == tyObject) and (s.sons[0] != nil):
|
||||
app(r, ".Sup")
|
||||
s = skipTypes(s.sons[0], abstractInst)
|
||||
appcg(p, section, "$1.m_type = $2;$n", [r, genTypeInfo(p.module, t)])
|
||||
of frEmbedded:
|
||||
# worst case for performance:
|
||||
var r = if takeAddr: addrLoc(a) else: rdLoc(a)
|
||||
appcg(p, section, "#objectInit($1, $2);$n", [r, genTypeInfo(p.module, t)])
|
||||
|
||||
type
|
||||
TAssignmentFlag = enum
|
||||
needToCopy, needForSubtypeCheck, afDestIsNil, afDestIsNotNil, afSrcIsNil,
|
||||
afSrcIsNotNil
|
||||
TAssignmentFlags = set[TAssignmentFlag]
|
||||
|
||||
proc genRefAssign(p: BProc, dest, src: TLoc, flags: TAssignmentFlags)
|
||||
|
||||
proc zeroVar(p: BProc, loc: TLoc, containsGCref: bool) =
|
||||
if skipTypes(loc.t, abstractVarRange).Kind notin
|
||||
{tyArray, tyArrayConstr, tySet, tyTuple, tyObject}:
|
||||
if containsGcref:
|
||||
appf(p.s[cpsInit], "$1 = 0;$n", [rdLoc(loc)])
|
||||
var nilLoc: TLoc
|
||||
initLoc(nilLoc, locTemp, loc.t, onStack)
|
||||
nilLoc.r = toRope("NIM_NIL")
|
||||
# puts ``unsureAsgnRef`` etc to ``p.s[cpsStmts]``:
|
||||
genRefAssign(p, loc, nilLoc, {afSrcIsNil})
|
||||
else:
|
||||
appf(p.s[cpsStmts], "$1 = 0;$n", [rdLoc(loc)])
|
||||
else:
|
||||
if gCmd == cmdCompileToLLVM:
|
||||
app(p.module.s[cfsProcHeaders],
|
||||
"declare void @llvm.memset.i32(i8*, i8, i32, i32)" & tnl)
|
||||
inc(p.labels, 2)
|
||||
appf(p.s[cpsStmts], "%LOC$3 = getelementptr $2* null, %NI 1$n" &
|
||||
"%LOC$4 = cast $2* %LOC$3 to i32$n" &
|
||||
"call void @llvm.memset.i32(i8* $1, i8 0, i32 %LOC$4, i32 0)$n", [
|
||||
addrLoc(loc), getTypeDesc(p.module, loc.t), toRope(p.labels),
|
||||
toRope(p.labels - 1)])
|
||||
else:
|
||||
if containsGcref:
|
||||
appf(p.s[cpsInit], "memset((void*)$1, 0, sizeof($2));$n",
|
||||
[addrLoc(loc), rdLoc(loc)])
|
||||
appcg(p, cpsStmts, "#genericReset((void*)$1, $2);$n",
|
||||
[addrLoc(loc), genTypeInfo(p.module, loc.t)])
|
||||
else:
|
||||
appf(p.s[cpsStmts], "memset((void*)$1, 0, sizeof($2));$n",
|
||||
[addrLoc(loc), rdLoc(loc)])
|
||||
genObjectInit(p, cpsInit, loc.t, loc, true)
|
||||
|
||||
proc zeroTemp(p: BProc, loc: TLoc) =
|
||||
if skipTypes(loc.t, abstractVarRange).Kind notin
|
||||
{tyArray, tyArrayConstr, tySet, tyTuple, tyObject}:
|
||||
var nilLoc: TLoc
|
||||
initLoc(nilLoc, locTemp, loc.t, onStack)
|
||||
nilLoc.r = toRope("NIM_NIL")
|
||||
# puts ``unsureAsgnRef`` etc to ``p.s[cpsStmts]``:
|
||||
genRefAssign(p, loc, nilLoc, {afSrcIsNil})
|
||||
else:
|
||||
appcg(p, cpsStmts, "#genericReset((void*)$1, $2);$n",
|
||||
[addrLoc(loc), genTypeInfo(p.module, loc.t)])
|
||||
|
||||
proc initVariable(p: BProc, v: PSym) =
|
||||
if containsGarbageCollectedRef(v.typ) or (v.ast == nil):
|
||||
zeroLoc(p, v.loc)
|
||||
var b = containsGarbageCollectedRef(v.typ)
|
||||
if b or v.ast == nil:
|
||||
zeroVar(p, v.loc, b)
|
||||
|
||||
proc initTemp(p: BProc, tmp: var TLoc) =
|
||||
if containsGarbageCollectedRef(tmp.t):
|
||||
zeroLoc(p, tmp)
|
||||
zeroTemp(p, tmp)
|
||||
|
||||
proc getTemp(p: BProc, t: PType, result: var TLoc) =
|
||||
inc(p.labels)
|
||||
@@ -324,11 +364,10 @@ proc cstringLit(m: BModule, r: var PRope, s: string): PRope =
|
||||
result = makeCString(s)
|
||||
|
||||
proc allocParam(p: BProc, s: PSym) =
|
||||
var tmp: PRope
|
||||
assert(s.kind == skParam)
|
||||
if not (lfParamCopy in s.loc.flags):
|
||||
inc(p.labels)
|
||||
tmp = con("%LOC", toRope(p.labels))
|
||||
var tmp = con("%LOC", toRope(p.labels))
|
||||
incl(s.loc.flags, lfParamCopy)
|
||||
incl(s.loc.flags, lfIndirect)
|
||||
appf(p.s[cpsInit], "$1 = alloca $3$n" & "store $3 $2, $3* $1$n",
|
||||
@@ -520,11 +559,7 @@ proc cgsym(m: BModule, name: string): PRope =
|
||||
# we used to exclude the system module from this check, but for DLL
|
||||
# generation support this sloppyness leads to hard to detect bugs, so
|
||||
# we're picky here for the system module too:
|
||||
when false:
|
||||
if not (sfSystemModule in m.module.flags):
|
||||
rawMessage(errSystemNeeds, name)
|
||||
else:
|
||||
rawMessage(errSystemNeeds, name)
|
||||
rawMessage(errSystemNeeds, name)
|
||||
result = sym.loc.r
|
||||
|
||||
proc generateHeaders(m: BModule) =
|
||||
@@ -593,14 +628,13 @@ proc genProcAux(m: BModule, prc: PSym) =
|
||||
assignLocalVar(p, res)
|
||||
assert(res.loc.r != nil)
|
||||
returnStmt = ropeff("return $1;$n", "ret $1$n", [rdLoc(res.loc)])
|
||||
initVariable(p, res)
|
||||
else:
|
||||
fillResult(res)
|
||||
assignParam(p, res)
|
||||
if skipTypes(res.typ, abstractInst).kind == tyArray:
|
||||
incl(res.loc.flags, lfIndirect)
|
||||
res.loc.s = OnUnknown
|
||||
initVariable(p, res)
|
||||
genObjectInit(p, res.typ, res.loc, true)
|
||||
for i in countup(1, sonsLen(prc.typ.n) - 1):
|
||||
param = prc.typ.n.sons[i].sym
|
||||
assignParam(p, param)
|
||||
@@ -644,23 +678,22 @@ proc genProcAux(m: BModule, prc: PSym) =
|
||||
|
||||
proc genProcPrototype(m: BModule, sym: PSym) =
|
||||
useHeader(m, sym)
|
||||
if (lfNoDecl in sym.loc.Flags): return
|
||||
if lfNoDecl in sym.loc.Flags: return
|
||||
if lfDynamicLib in sym.loc.Flags:
|
||||
if (sym.owner.id != m.module.id) and
|
||||
if sym.owner.id != m.module.id and
|
||||
not intSetContainsOrIncl(m.declaredThings, sym.id):
|
||||
appff(m.s[cfsVars], "extern $1 $2;$n",
|
||||
"@$2 = linkonce global $1 zeroinitializer$n",
|
||||
[getTypeDesc(m, sym.loc.t), mangleDynLibProc(sym)])
|
||||
if gCmd == cmdCompileToLLVM: incl(sym.loc.flags, lfIndirect)
|
||||
else:
|
||||
if not IntSetContainsOrIncl(m.declaredProtos, sym.id):
|
||||
appf(m.s[cfsProcHeaders], "$1;$n", [genProcHeader(m, sym)])
|
||||
elif not IntSetContainsOrIncl(m.declaredProtos, sym.id):
|
||||
appf(m.s[cfsProcHeaders], "$1;$n", [genProcHeader(m, sym)])
|
||||
|
||||
proc genProcNoForward(m: BModule, prc: PSym) =
|
||||
fillProcLoc(prc)
|
||||
useHeader(m, prc)
|
||||
genProcPrototype(m, prc)
|
||||
if (lfNoDecl in prc.loc.Flags): return
|
||||
if lfNoDecl in prc.loc.Flags: return
|
||||
if prc.typ.callConv == ccInline:
|
||||
# We add inline procs to the calling module to enable C based inlining.
|
||||
# This also means that a check with ``gGeneratedSyms`` is wrong, we need
|
||||
@@ -771,7 +804,8 @@ proc genMainProc(m: BModule) =
|
||||
" NimMain();$n" & " return 0;$n" & "}$n"
|
||||
WinNimDllMain = "N_LIB_EXPORT N_CDECL(void, NimMain)(void) {$n" &
|
||||
CommonMainBody & "}$n"
|
||||
WinCDllMain = "BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fwdreason, $n" &
|
||||
WinCDllMain =
|
||||
"BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fwdreason, $n" &
|
||||
" LPVOID lpvReserved) {$n" & " NimMain();$n" &
|
||||
" return 1;$n" & "}$n"
|
||||
PosixNimDllMain = WinNimDllMain
|
||||
@@ -779,8 +813,8 @@ proc genMainProc(m: BModule) =
|
||||
"void NIM_POSIX_INIT NimMainInit(void) {$n" &
|
||||
" NimMain();$n}$n"
|
||||
var nimMain, otherMain: TFormatStr
|
||||
if (platform.targetOS == osWindows) and
|
||||
(gGlobalOptions * {optGenGuiApp, optGenDynLib} != {}):
|
||||
if platform.targetOS == osWindows and
|
||||
gGlobalOptions * {optGenGuiApp, optGenDynLib} != {}:
|
||||
if optGenGuiApp in gGlobalOptions:
|
||||
nimMain = WinNimMain
|
||||
otherMain = WinCMain
|
||||
|
||||
@@ -7,5 +7,5 @@ proc MakeObj(): TTestObj =
|
||||
|
||||
while true:
|
||||
var obj = MakeObj()
|
||||
|
||||
# echo GC_getstatistics()
|
||||
|
||||
|
||||
20
tests/gc/gcleak2.nim
Normal file
20
tests/gc/gcleak2.nim
Normal file
@@ -0,0 +1,20 @@
|
||||
type
|
||||
TTestObj = object of TObject
|
||||
x: string
|
||||
s: seq[int]
|
||||
|
||||
proc MakeObj(): TTestObj =
|
||||
result.x = "Hello"
|
||||
result.s = @[1,2,3]
|
||||
|
||||
#while true:
|
||||
# var obj = MakeObj()
|
||||
# echo GC_getstatistics()
|
||||
|
||||
proc inProc() =
|
||||
while true:
|
||||
var obj: TTestObj
|
||||
obj = MakeObj()
|
||||
|
||||
inProc()
|
||||
|
||||
Reference in New Issue
Block a user