diff options
author | Andreas Rumpf <rumpf_a@web.de> | 2017-04-19 08:33:19 +0200 |
---|---|---|
committer | Andreas Rumpf <rumpf_a@web.de> | 2017-04-19 08:33:19 +0200 |
commit | 02bbfa116403adeaf29c5446a971228053e11d0d (patch) | |
tree | 92795e6c3aa8a8e84bf79a54904f7729889270ef /compiler | |
parent | 55b5401dc6ac0b42db1cca9f9dd50f3e19e3dbc0 (diff) | |
download | Nim-02bbfa116403adeaf29c5446a971228053e11d0d.tar.gz |
precise stack scanning for Nim's GCs; work in progress
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/ast.nim | 3 | ||||
-rw-r--r-- | compiler/ccgexprs.nim | 43 | ||||
-rw-r--r-- | compiler/ccgstmts.nim | 5 | ||||
-rw-r--r-- | compiler/ccgtypes.nim | 8 | ||||
-rw-r--r-- | compiler/cgen.nim | 23 | ||||
-rw-r--r-- | compiler/cgendata.nim | 2 | ||||
-rw-r--r-- | compiler/options.nim | 3 |
7 files changed, 49 insertions, 38 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index 49ca1c5e0..a064ac72b 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -739,6 +739,8 @@ type OnUnknown, # location is unknown (stack, heap or static) OnStatic, # in a static section OnStack, # location is on hardware stack + OnStackShadowDup, # location is on the stack but also replicated + # on the shadow stack OnHeap # location is on heap or global # (reference counting needed) TLocFlags* = set[TLocFlag] @@ -748,6 +750,7 @@ type flags*: TLocFlags # location's flags t*: PType # type of location r*: Rope # rope value of location (code generators) + dup*: Rope # duplicated location for precise stack scans # ---------------- end of backend information ------------------------------ diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index b03f7c5aa..71845ddfc 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -132,32 +132,12 @@ proc genSetNode(p: BProc, n: PNode): Rope = else: result = genRawSetData(cs, size) -proc getStorageLoc(n: PNode): TStorageLoc = - case n.kind - of nkSym: - case n.sym.kind - of skParam, skTemp: - result = OnStack - of skVar, skForVar, skResult, skLet: - if sfGlobal in n.sym.flags: result = OnHeap - else: result = OnStack - of skConst: - if sfGlobal in n.sym.flags: result = OnHeap - else: result = OnUnknown - else: result = OnUnknown - of nkDerefExpr, nkHiddenDeref: - case n.sons[0].typ.kind - of tyVar: result = OnUnknown - of tyPtr: result = OnStack - of tyRef: result = OnHeap - else: internalError(n.info, "getStorageLoc") - of nkBracketExpr, nkDotExpr, nkObjDownConv, nkObjUpConv: - result = getStorageLoc(n.sons[0]) - else: result = OnUnknown - proc genRefAssign(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = if dest.s == OnStack or not usesNativeGC(): linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src)) + elif dest.s == OnStackShadowDup: + linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src)) + linefmt(p, cpsStmts, "$1 = $2;$n", dupLoc(dest), rdLoc(src)) elif dest.s == OnHeap: # location is on heap # now the writer barrier is inlined for performance: @@ -184,6 +164,8 @@ proc genRefAssign(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = else: linefmt(p, cpsStmts, "#unsureAsgnRef((void**) $1, $2);$n", addrLoc(dest), rdLoc(src)) + if preciseStack(): + linefmt(p, cpsStmts, "$1 = $2;$n", dupLoc(dest), rdLoc(src)) proc asgnComplexity(n: PNode): int = if n != nil: @@ -241,7 +223,7 @@ proc genOptAsgnObject(p: BProc, dest, src: TLoc, flags: TAssignmentFlags, proc genGenericAsgn(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = # Consider: - # type TMyFastString {.shallow.} = string + # type MyFastString {.shallow.} = string # Due to the implementation of pragmas this would end up to set the # tfShallow flag for the built-in string type too! So we check only # here for this flag, where it is reasonably safe to do so @@ -259,6 +241,9 @@ proc genGenericAsgn(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = else: linefmt(p, cpsStmts, "#genericAssign((void*)$1, (void*)$2, $3);$n", addrLoc(dest), addrLoc(src), genTypeInfo(p.module, dest.t)) + if dest.s == OnStackShadowDup: + linefmt(p, cpsStmts, "#genericAssignDup((void*)&$1, (void*)$2, $3);$n", + dupLoc(dest), addrLoc(src), genTypeInfo(p.module, dest.t)) proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = # This function replaces all other methods for generating @@ -277,12 +262,17 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = else: linefmt(p, cpsStmts, "#genericSeqAssign($1, $2, $3);$n", addrLoc(dest), rdLoc(src), genTypeInfo(p.module, dest.t)) + if dest.s == OnStackShadowDup: + linefmt(p, cpsStmts, "$1 = $2;$n", dest.dupLoc, dest.rdLoc) of tyString: if needToCopy notin flags and src.s != OnStatic: genRefAssign(p, dest, src, flags) else: if dest.s == OnStack or not usesNativeGC(): linefmt(p, cpsStmts, "$1 = #copyString($2);$n", dest.rdLoc, src.rdLoc) + elif dest.s == OnStackShadowDup: + linefmt(p, cpsStmts, "$1 = #copyString($2);$n", dest.rdLoc, src.rdLoc) + linefmt(p, cpsStmts, "$1 = $2;$n", dest.dupLoc, dest.rdLoc) elif dest.s == OnHeap: # we use a temporary to care for the dreaded self assignment: var tmp: TLoc @@ -293,6 +283,8 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = else: linefmt(p, cpsStmts, "#unsureAsgnRef((void**) $1, #copyString($2));$n", addrLoc(dest), rdLoc(src)) + if preciseStack(): + linefmt(p, cpsStmts, "$1 = $2;$n", dest.dupLoc, dest.rdLoc) of tyProc: if needsComplexAssignment(dest.t): # optimize closure assignment: @@ -1170,6 +1162,7 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) = var t = e.typ.skipTypes(abstractInst) getTemp(p, t, tmp) let isRef = t.kind == tyRef + let stck = stackPlacement(t) var r = rdLoc(tmp) if isRef: rawGenNew(p, tmp, nil) @@ -1193,7 +1186,7 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) = add(tmp2.r, field.loc.r) tmp2.k = locTemp tmp2.t = field.loc.t - tmp2.s = if isRef: OnHeap else: OnStack + tmp2.s = if isRef: OnHeap else: stck expr(p, it.sons[1], tmp2) if d.k == locNone: diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index cc925b150..80500f508 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -803,6 +803,8 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) = endBlock(p, ropecg(p.module, "} catch (NimException& $1) {$n", [exc])) if optStackTrace in p.options: linefmt(p, cpsStmts, "#setFrame((TFrame*)&FR_);$n") + if p.gcFrameLen > 0: + linefmt(p, cpsStmts, "#setGcFrame((#GcFrameBase*)&GCF_);$n") inc p.inExceptBlock var i = 1 var catchAllPresent = false @@ -911,6 +913,9 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) = linefmt(p, cpsStmts, "#popSafePoint();$n") if optStackTrace in p.options: linefmt(p, cpsStmts, "#setFrame((TFrame*)&FR_);$n") + if p.gcFrameLen > 0: + linefmt(p, cpsStmts, "#setGcFrame((#GcFrameBase*)&GCF_);$n") + inc p.inExceptBlock var i = 1 while (i < length) and (t.sons[i].kind == nkExceptBranch): diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 2b7cfaea1..0a4a85c6f 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -282,7 +282,7 @@ proc ccgIntroducedPtr(s: PSym): bool = proc fillResult(param: PSym) = fillLoc(param.loc, locParam, param.typ, ~"Result", - OnStack) + stackPlacement(param.typ)) if mapReturnType(param.typ) != ctArray and isInvalidReturnType(param.typ): incl(param.loc.flags, lfIndirect) param.loc.s = OnUnknown @@ -376,9 +376,9 @@ proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet): Rope = result = getTypeDescAux(m, t, check) proc paramStorageLoc(param: PSym): TStorageLoc = - if param.typ.skipTypes({tyVar, tyTypeDesc}).kind notin { - tyArray, tyOpenArray, tyVarargs}: - result = OnStack + let t = param.typ.skipTypes({tyVar, tyTypeDesc}) + if t.kind notin {tyArray, tyOpenArray, tyVarargs}: + result = stackPlacement(t) else: result = OnUnknown diff --git a/compiler/cgen.nim b/compiler/cgen.nim index fd15d0793..dc021d17e 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -244,6 +244,10 @@ proc addrLoc(a: TLoc): Rope = if lfIndirect notin a.flags and mapType(a.t) != ctArray: result = "(&" & result & ")" +proc dupLoc(a: TLoc): Rope = + result = a.dup + assert result != nil + proc rdCharLoc(a: TLoc): Rope = # read a location that may need a char-cast: result = rdLoc(a) @@ -288,12 +292,13 @@ proc resetLoc(p: BProc, loc: var TLoc) = if not isComplexValueType(typ): if containsGcRef: var nilLoc: TLoc - initLoc(nilLoc, locTemp, loc.t, OnStack) + initLoc(nilLoc, locTemp, loc.t, stackPlacement(typ)) nilLoc.r = rope("NIM_NIL") genRefAssign(p, loc, nilLoc, {afSrcIsNil}) else: linefmt(p, cpsStmts, "$1 = 0;$n", rdLoc(loc)) else: + XXX use stackPlacement here? if optNilCheck in p.options: linefmt(p, cpsStmts, "#chckNil((void*)$1);$n", addrLoc(loc)) if loc.s != OnStack: @@ -343,17 +348,21 @@ proc getTemp(p: BProc, t: PType, result: var TLoc; needsInit=false) = linefmt(p, cpsLocals, "$1 $2;$n", getTypeDesc(p.module, t), result.r) result.k = locTemp result.t = t - result.s = OnStack + result.s = stackPlacement(t) result.flags = {} constructLoc(p, result, not needsInit) proc initGCFrame(p: BProc): Rope = - if p.gcFrameId > 0: result = "struct {$1} GCFRAME_;$n" % [p.gcFrameType] + if p.gcFrameLen > 0: + result = ropegc(p.module, """ + struct {#GcFrameBase b_; $1} GCF_;$n + GCF_.b_.L=$2;$n + #pushGcFrame((GcFrameBase*)&GCF_);$n""" % [ + p.gcFrameType, rope(p.gcFrameLen)]) proc deinitGCFrame(p: BProc): Rope = - if p.gcFrameId > 0: - result = ropecg(p.module, - "if (((NU)&GCFRAME_) < 4096) #nimGCFrame(&GCFRAME_);$n") + if p.gcFrameLen > 0: + result = ropecg(p.module, "#popGcFrame();$n") proc localDebugInfo(p: BProc, s: PSym) = if {optStackTrace, optEndb} * p.options != {optStackTrace, optEndb}: return @@ -370,7 +379,7 @@ proc localDebugInfo(p: BProc, s: PSym) = proc localVarDecl(p: BProc; s: PSym): Rope = if s.loc.k == locNone: - fillLoc(s.loc, locLocalVar, s.typ, mangleLocalName(p, s), OnStack) + fillLoc(s.loc, locLocalVar, s.typ, mangleLocalName(p, s), stackPlacement(s.typ)) if s.kind == skLet: incl(s.loc.flags, lfNoDeepCopy) result = getTypeDesc(p.module, s.typ) if s.constraint.isNil: diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim index be087095f..2f927c83e 100644 --- a/compiler/cgendata.nim +++ b/compiler/cgendata.nim @@ -90,7 +90,7 @@ type splitDecls*: int # > 0 if we are in some context for C++ that # requires 'T x = T()' to become 'T x; x = T()' # (yes, C++ is weird like that) - gcFrameId*: Natural # for the GC stack marking + gcFrameLen*: int # the number of slots in the GC-Frame gcFrameType*: Rope # the struct {} we put the GC markers into sigConflicts*: CountTable[string] diff --git a/compiler/options.nim b/compiler/options.nim index c4a57f41c..3e681c8d1 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -140,12 +140,13 @@ var gEvalExpr* = "" # expression for idetools --eval gLastCmdTime*: float # when caas is enabled, we measure each command gListFullPaths*: bool - isServing*: bool = false + gPreciseStack*: bool = false gNoNimblePath* = false gExperimentalMode*: bool proc importantComments*(): bool {.inline.} = gCmd in {cmdDoc, cmdIdeTools} proc usesNativeGC*(): bool {.inline.} = gSelectedGC >= gcRefc +template preciseStack*(): bool = gPreciseStack template compilationCachePresent*: untyped = {optCaasEnabled, optSymbolFiles} * gGlobalOptions != {} |