This commit is contained in:
Araq
2011-03-12 12:38:42 +01:00
parent 0fee9f9924
commit 6850fb73c1
8 changed files with 132 additions and 75 deletions

View File

@@ -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 {.

View File

@@ -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

View File

@@ -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:

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -7,5 +7,5 @@ proc MakeObj(): TTestObj =
while true:
var obj = MakeObj()
# echo GC_getstatistics()

20
tests/gc/gcleak2.nim Normal file
View 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()