code gen can generate code to keep alive stack roots
This commit is contained in:
parent
f19c1c0f6e
commit
cd83cc81aa
12 changed files with 125 additions and 44 deletions
|
|
@ -273,6 +273,7 @@ type
|
|||
|
||||
const
|
||||
tyPureObject* = tyTuple
|
||||
GcTypeKinds* = {tyRef, tySequence, tyString}
|
||||
|
||||
type
|
||||
TTypeKinds* = set[TTypeKind]
|
||||
|
|
|
|||
|
|
@ -252,7 +252,8 @@ proc genCall(p: BProc, e: PNode, d: var TLoc) =
|
|||
genNamedParamCall(p, e, d)
|
||||
else:
|
||||
genPrefixCall(p, nil, e, d)
|
||||
if d.s == onStack and containsGarbageCollectedRef(d.t): keepAlive(p, d)
|
||||
when false:
|
||||
if d.s == onStack and containsGarbageCollectedRef(d.t): keepAlive(p, d)
|
||||
|
||||
proc genAsgnCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
||||
if ri.sons[0].kind == nkSym and sfInfixCall in ri.sons[0].sym.flags and
|
||||
|
|
@ -262,5 +263,6 @@ proc genAsgnCall(p: BProc, le, ri: PNode, d: var TLoc) =
|
|||
genNamedParamCall(p, ri, d)
|
||||
else:
|
||||
genPrefixCall(p, le, ri, d)
|
||||
if d.s == onStack and containsGarbageCollectedRef(d.t): keepAlive(p, d)
|
||||
when false:
|
||||
if d.s == onStack and containsGarbageCollectedRef(d.t): keepAlive(p, d)
|
||||
|
||||
|
|
|
|||
|
|
@ -297,23 +297,36 @@ proc getTemp(p: BProc, t: PType, result: var TLoc) =
|
|||
initTemp(p, result)
|
||||
|
||||
proc keepAlive(p: BProc, toKeepAlive: TLoc) =
|
||||
if optRefcGC notin gGlobalOptions: return
|
||||
var result: TLoc
|
||||
inc(p.labels)
|
||||
result.r = con("LOC", toRope(p.labels))
|
||||
appf(p.s[cpsLocals], "volatile $1 $2;$n",
|
||||
[getTypeDesc(p.module, toKeepAlive.t), result.r])
|
||||
result.k = locTemp
|
||||
result.a = -1
|
||||
result.t = toKeepAlive.t
|
||||
result.s = OnStack
|
||||
result.flags = {}
|
||||
if skipTypes(toKeepAlive.t, abstractVarRange).Kind notin complexValueType:
|
||||
appf(p.s[cpsStmts], "$1 = $2;$n", [rdLoc(result), rdLoc(toKeepAlive)])
|
||||
else:
|
||||
appcg(p, cpsStmts,
|
||||
"memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($3));$n",
|
||||
[addrLoc(result), addrLoc(toKeepAlive), rdLoc(result)])
|
||||
when false:
|
||||
# deactivated because of the huge slowdown this causes; GC will take care
|
||||
# of interior pointers instead
|
||||
if optRefcGC notin gGlobalOptions: return
|
||||
var result: TLoc
|
||||
var fid = toRope(p.gcFrameId)
|
||||
result.r = con("GCFRAME.F", fid)
|
||||
appf(p.gcFrameType, " $1 F$2;$n",
|
||||
[getTypeDesc(p.module, toKeepAlive.t), fid])
|
||||
inc(p.gcFrameId)
|
||||
result.k = locTemp
|
||||
result.a = -1
|
||||
result.t = toKeepAlive.t
|
||||
result.s = OnStack
|
||||
result.flags = {}
|
||||
|
||||
if skipTypes(toKeepAlive.t, abstractVarRange).Kind notin complexValueType:
|
||||
appf(p.s[cpsStmts], "$1 = $2;$n", [rdLoc(result), rdLoc(toKeepAlive)])
|
||||
else:
|
||||
appcg(p, cpsStmts,
|
||||
"memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($3));$n",
|
||||
[addrLoc(result), addrLoc(toKeepAlive), rdLoc(result)])
|
||||
|
||||
proc initGCFrame(p: BProc): PRope =
|
||||
if p.gcFrameId > 0: result = ropef("struct {$1} GCFRAME;$n", p.gcFrameType)
|
||||
|
||||
proc deinitGCFrame(p: BProc): PRope =
|
||||
if p.gcFrameId > 0:
|
||||
result = ropecg(p.module,
|
||||
"if (((NU)&GCFRAME) < 4096) #nimGCFrame(&GCFRAME);$n")
|
||||
|
||||
proc cstringLit(p: BProc, r: var PRope, s: string): PRope =
|
||||
if gCmd == cmdCompileToLLVM:
|
||||
|
|
@ -370,6 +383,8 @@ proc assignLocalVar(p: BProc, s: PSym) =
|
|||
if s.kind == skLet: incl(s.loc.flags, lfNoDeepCopy)
|
||||
app(p.s[cpsLocals], getTypeDesc(p.module, s.loc.t))
|
||||
if sfRegister in s.flags: app(p.s[cpsLocals], " register")
|
||||
elif skipTypes(s.typ, abstractInst).kind in GcTypeKinds:
|
||||
app(p.s[cpsLocals], " GC_GUARD")
|
||||
if (sfVolatile in s.flags) or (p.nestedTryStmts.len > 0):
|
||||
app(p.s[cpsLocals], " volatile")
|
||||
appf(p.s[cpsLocals], " $1;$n", [s.loc.r])
|
||||
|
|
@ -428,7 +443,7 @@ include "ccgexprs.nim", "ccgstmts.nim"
|
|||
proc libCandidates(s: string, dest: var TStringSeq) =
|
||||
var le = strutils.find(s, '(')
|
||||
var ri = strutils.find(s, ')', le+1)
|
||||
if le >= 0 and ri > le:
|
||||
if le >= 0 and ri > le:
|
||||
var prefix = substr(s, 0, le - 1)
|
||||
var suffix = substr(s, ri + 1)
|
||||
for middle in split(substr(s, le + 1, ri - 1), '|'):
|
||||
|
|
@ -583,8 +598,9 @@ proc genProcAux(m: BModule, prc: PSym) =
|
|||
if sfPure in prc.flags:
|
||||
generatedProc = ropeff("$1 {$n$2$3$4}$n", "define $1 {$n$2$3$4}$n",
|
||||
[header, p.s[cpsLocals], p.s[cpsInit], p.s[cpsStmts]])
|
||||
else:
|
||||
else:
|
||||
generatedProc = ropeff("$1 {$n", "define $1 {$n", [header])
|
||||
app(generatedProc, initGCFrame(p))
|
||||
if optStackTrace in prc.options:
|
||||
getFrameDecl(p)
|
||||
app(generatedProc, p.s[cpsLocals])
|
||||
|
|
@ -608,6 +624,7 @@ proc genProcAux(m: BModule, prc: PSym) =
|
|||
app(generatedProc, p.s[cpsInit])
|
||||
app(generatedProc, p.s[cpsStmts])
|
||||
if p.beforeRetNeeded: appf(generatedProc, "BeforeRet: $n;")
|
||||
app(generatedProc, deinitGCFrame(p))
|
||||
if optStackTrace in prc.options: app(generatedProc, deinitFrame(p))
|
||||
if (optProfiler in prc.options) and (gCmd != cmdCompileToLLVM):
|
||||
appf(generatedProc,
|
||||
|
|
@ -816,6 +833,8 @@ proc genInitCode(m: BModule) =
|
|||
m.FrameDeclared = true
|
||||
getFrameDecl(m.initProc)
|
||||
|
||||
app(prc, initGCFrame(m.initProc))
|
||||
|
||||
app(prc, genSectionStart(cpsLocals))
|
||||
app(prc, m.initProc.s[cpsLocals])
|
||||
app(prc, genSectionEnd(cpsLocals))
|
||||
|
|
@ -842,6 +861,7 @@ proc genInitCode(m: BModule) =
|
|||
if optStackTrace in m.initProc.options and not m.PreventStackTrace:
|
||||
app(prc, deinitFrame(m.initProc))
|
||||
app(prc, genSectionEnd(cpsStmts))
|
||||
app(prc, deinitGCFrame(m.initProc))
|
||||
appf(prc, "}$n$n")
|
||||
# we cannot simply add the init proc to ``m.s[cfsProcs]`` anymore because
|
||||
# that would lead to a *nesting* of merge sections which the merger does
|
||||
|
|
|
|||
|
|
@ -72,6 +72,8 @@ type
|
|||
receiveClosure*: PType # closure record type that we get
|
||||
module*: BModule # used to prevent excessive parameter passing
|
||||
withinLoop*: int # > 0 if we are within a loop
|
||||
gcFrameId*: natural # for the GC stack marking
|
||||
gcFrameType*: PRope # the struct {} we put the GC markers into
|
||||
|
||||
TTypeSeq* = seq[PType]
|
||||
TCGen = object of TPassContext # represents a C source file
|
||||
|
|
|
|||
|
|
@ -207,7 +207,7 @@ proc addPathRec(dir: string, info: TLineInfo) =
|
|||
|
||||
proc track(arg: string, info: TLineInfo) =
|
||||
var a = arg.split(',')
|
||||
if a.len != 3: LocalError(info, errTokenExpected, "FILE,LINE,COLMUN")
|
||||
if a.len != 3: LocalError(info, errTokenExpected, "FILE,LINE,COLUMN")
|
||||
var line, column: int
|
||||
if parseUtils.parseInt(a[1], line) <= 0:
|
||||
LocalError(info, errInvalidNumber, a[1])
|
||||
|
|
|
|||
|
|
@ -21,7 +21,8 @@ type
|
|||
hasSwitchRange, # CC allows ranges in switch statements (GNU C)
|
||||
hasComputedGoto, # CC has computed goto (GNU C extension)
|
||||
hasCpp, # CC is/contains a C++ compiler
|
||||
hasAssume # CC has __assume (Visual C extension)
|
||||
hasAssume, # CC has __assume (Visual C extension)
|
||||
hasGcGuard # CC supports GC_GUARD to keep stack roots
|
||||
TInfoCCProps* = set[TInfoCCProp]
|
||||
TInfoCC* = tuple[
|
||||
name: string, # the short name of the compiler
|
||||
|
|
@ -71,7 +72,7 @@ compiler gcc:
|
|||
debug: "",
|
||||
pic: "-fPIC",
|
||||
asmStmtFrmt: "asm($1);$n",
|
||||
props: {hasSwitchRange, hasComputedGoto, hasCpp})
|
||||
props: {hasSwitchRange, hasComputedGoto, hasCpp, hasGcGuard})
|
||||
|
||||
compiler gpp:
|
||||
result = gcc()
|
||||
|
|
@ -79,11 +80,10 @@ compiler gpp:
|
|||
result.name = "gpp"
|
||||
result.compilerExe = "g++"
|
||||
result.linkerExe = "g++"
|
||||
|
||||
result.debug.add " -g " # XXX: Why is this default for g++, but not for gcc?
|
||||
|
||||
result.buildDll = " -mdll" # XXX: Hmm, I'm keeping this from the previos version,
|
||||
# but my gcc doesn't even have such an option (is this mingw?)
|
||||
result.buildDll = " -mdll"
|
||||
# XXX: Hmm, I'm keeping this from the previos version,
|
||||
# but my gcc doesn't even have such an option (is this mingw?)
|
||||
|
||||
compiler llvmGcc:
|
||||
result = gcc()
|
||||
|
|
|
|||
|
|
@ -277,7 +277,7 @@ proc analyseObjectWithTypeField(t: PType): TTypeFieldResult =
|
|||
result = analyseObjectWithTypeFieldAux(t, marker)
|
||||
|
||||
proc isGBCRef(t: PType): bool =
|
||||
result = t.kind in {tyRef, tySequence, tyString}
|
||||
result = t.kind in GcTypeKinds
|
||||
|
||||
proc containsGarbageCollectedRef(typ: PType): bool =
|
||||
# returns true if typ contains a reference, sequence or string (all the
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue