mirror of
https://github.com/nim-lang/Nim.git
synced 2026-04-19 14:00:35 +00:00
cbuilder: most of ccgstmts (#24420)
This adapts most of ccgstmts to cbuilder, missing C++ exceptions and `genCaseGeneric`/`genIfForCaseUntil`. Rebased version of #24399 which was split into some other PRs and since has had conflicts with #24416.
This commit is contained in:
@@ -55,6 +55,9 @@ template addCast(builder: var Builder, typ: Snippet, valueBody: typed) =
|
||||
proc cAddr(value: Snippet): Snippet =
|
||||
"&" & value
|
||||
|
||||
proc cLabelAddr(value: TLabel): Snippet =
|
||||
"&&" & value
|
||||
|
||||
proc cDeref(value: Snippet): Snippet =
|
||||
"(*" & value & ")"
|
||||
|
||||
|
||||
@@ -257,21 +257,26 @@ proc addLabel(builder: var Builder, name: TLabel) =
|
||||
proc addReturn(builder: var Builder) =
|
||||
builder.add("return;\n")
|
||||
|
||||
proc addReturn(builder: var Builder, value: string) =
|
||||
proc addReturn(builder: var Builder, value: Snippet) =
|
||||
builder.add("return ")
|
||||
builder.add(value)
|
||||
builder.add(";\n")
|
||||
|
||||
template addGoto(builder: var Builder, label: TLabel) =
|
||||
proc addGoto(builder: var Builder, label: TLabel) =
|
||||
builder.add("goto ")
|
||||
builder.add(label)
|
||||
builder.add(";\n")
|
||||
|
||||
template addIncr(builder: var Builder, val: Snippet) =
|
||||
proc addComputedGoto(builder: var Builder, value: Snippet) =
|
||||
builder.add("goto *")
|
||||
builder.add(value)
|
||||
builder.add(";\n")
|
||||
|
||||
proc addIncr(builder: var Builder, val: Snippet) =
|
||||
builder.add(val)
|
||||
builder.add("++;\n")
|
||||
|
||||
template addDecr(builder: var Builder, val: Snippet) =
|
||||
proc addDecr(builder: var Builder, val: Snippet) =
|
||||
builder.add(val)
|
||||
builder.add("--;\n")
|
||||
|
||||
|
||||
@@ -24,12 +24,12 @@ proc registerTraverseProc(p: BProc, v: PSym) =
|
||||
traverseProc = genTraverseProcForGlobal(p.module, v, v.info)
|
||||
|
||||
if traverseProc.len != 0 and not p.hcrOn:
|
||||
if sfThread in v.flags:
|
||||
appcg(p.module, p.module.preInitProc.procSec(cpsInit),
|
||||
"$n\t#nimRegisterThreadLocalMarker($1);$n$n", [traverseProc])
|
||||
else:
|
||||
appcg(p.module, p.module.preInitProc.procSec(cpsInit),
|
||||
"$n\t#nimRegisterGlobalMarker($1);$n$n", [traverseProc])
|
||||
p.module.preInitProc.procSec(cpsInit).add("\n\t")
|
||||
let fnName = cgsymValue(p.module,
|
||||
if sfThread in v.flags: "nimRegisterThreadLocalMarker"
|
||||
else: "nimRegisterGlobalMarker")
|
||||
p.module.preInitProc.procSec(cpsInit).addCallStmt(fnName, traverseProc)
|
||||
p.module.preInitProc.procSec(cpsInit).add("\n")
|
||||
|
||||
proc isAssignedImmediately(conf: ConfigRef; n: PNode): bool {.inline.} =
|
||||
if n.kind == nkEmpty:
|
||||
@@ -134,11 +134,14 @@ proc genVarTuple(p: BProc, n: PNode) =
|
||||
assignLocalVar(p, vn)
|
||||
initLocalVar(p, v, immediateAsgn=isAssignedImmediately(p.config, n[^1]))
|
||||
var field = initLoc(locExpr, vn, tup.storage)
|
||||
if t.kind == tyTuple:
|
||||
field.snippet = "$1.Field$2" % [rdLoc(tup), rope(i)]
|
||||
else:
|
||||
if t.n[i].kind != nkSym: internalError(p.config, n.info, "genVarTuple")
|
||||
field.snippet = "$1.$2" % [rdLoc(tup), mangleRecFieldName(p.module, t.n[i].sym)]
|
||||
let rtup = rdLoc(tup)
|
||||
let fieldName =
|
||||
if t.kind == tyTuple:
|
||||
"Field" & $i
|
||||
else:
|
||||
if t.n[i].kind != nkSym: internalError(p.config, n.info, "genVarTuple")
|
||||
mangleRecFieldName(p.module, t.n[i].sym)
|
||||
field.snippet = dotField(rtup, fieldName)
|
||||
putLocIntoDest(p, v.loc, field)
|
||||
if forHcr or isGlobalInBlock:
|
||||
hcrGlobals.add((loc: v.loc, tp: "NULL"))
|
||||
@@ -153,10 +156,20 @@ proc genVarTuple(p: BProc, n: PNode) =
|
||||
# insert the registration of the globals for the different parts of the tuple at the
|
||||
# start of the current scope (after they have been iterated) and init a boolean to
|
||||
# check if any of them is newly introduced and the initializing code has to be ran
|
||||
lineCg(p, cpsLocals, "NIM_BOOL $1 = NIM_FALSE;$n", [hcrCond])
|
||||
p.s(cpsLocals).addVar(kind = Local,
|
||||
name = hcrCond,
|
||||
typ = "NIM_BOOL",
|
||||
initializer = "NIM_FALSE")
|
||||
for curr in hcrGlobals:
|
||||
lineCg(p, cpsLocals, "$1 |= hcrRegisterGlobal($4, \"$2\", sizeof($3), $5, (void**)&$2);$N",
|
||||
[hcrCond, curr.loc.snippet, rdLoc(curr.loc), getModuleDllPath(p.module, n[0].sym), curr.tp])
|
||||
let rc = rdLoc(curr.loc)
|
||||
p.s(cpsLocals).addInPlaceOp(BitOr, "NIM_BOOL",
|
||||
hcrCond,
|
||||
cCall("hcrRegisterGlobal",
|
||||
getModuleDllPath(p.module, n[0].sym),
|
||||
'"' & curr.loc.snippet & '"',
|
||||
cSizeof(rc),
|
||||
curr.tp,
|
||||
cCast("void**", cAddr(curr.loc.snippet))))
|
||||
|
||||
|
||||
proc loadInto(p: BProc, le, ri: PNode, a: var TLoc) {.inline.} =
|
||||
@@ -174,9 +187,9 @@ proc loadInto(p: BProc, le, ri: PNode, a: var TLoc) {.inline.} =
|
||||
a.flags.incl(lfEnforceDeref)
|
||||
expr(p, ri, a)
|
||||
|
||||
proc assignLabel(b: var TBlock; result: var Builder) {.inline.} =
|
||||
proc assignLabel(b: var TBlock; result: var TLabel) {.inline.} =
|
||||
b.label = "LA" & b.id.rope
|
||||
result.add b.label
|
||||
result = b.label
|
||||
|
||||
proc startSimpleBlock(p: BProc, scope: out ScopeBuilder): int {.discardable, inline.} =
|
||||
startBlockWith(p):
|
||||
@@ -208,9 +221,9 @@ proc genState(p: BProc, n: PNode) =
|
||||
let n0 = n[0]
|
||||
if n0.kind == nkIntLit:
|
||||
let idx = n[0].intVal
|
||||
linefmt(p, cpsStmts, "STATE$1: ;$n", [idx])
|
||||
p.s(cpsStmts).addLabel("STATE" & $idx)
|
||||
elif n0.kind == nkStrLit:
|
||||
linefmt(p, cpsStmts, "$1: ;$n", [n0.strVal])
|
||||
p.s(cpsStmts).addLabel(n0.strVal)
|
||||
|
||||
proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int) =
|
||||
# Called by return and break stmts.
|
||||
@@ -224,7 +237,7 @@ proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int) =
|
||||
if p.config.exc == excSetjmp:
|
||||
# Pop safe points generated by try
|
||||
if not tryStmt.inExcept:
|
||||
linefmt(p, cpsStmts, "#popSafePoint();$n", [])
|
||||
p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "popSafePoint"))
|
||||
|
||||
# Pop this try-stmt of the list of nested trys
|
||||
# so we don't infinite recurse on it in the next step.
|
||||
@@ -246,7 +259,7 @@ proc blockLeaveActions(p: BProc, howManyTrys, howManyExcepts: int) =
|
||||
# except-blocks we are in
|
||||
if noSafePoints notin p.flags:
|
||||
for i in countdown(howManyExcepts-1, 0):
|
||||
linefmt(p, cpsStmts, "#popCurrentException();$n", [])
|
||||
p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "popCurrentException"))
|
||||
|
||||
proc genGotoState(p: BProc, n: PNode) =
|
||||
# we resist the temptation to translate it into duff's device as it later
|
||||
@@ -255,21 +268,22 @@ proc genGotoState(p: BProc, n: PNode) =
|
||||
# case 0: goto STATE0;
|
||||
# ...
|
||||
var a: TLoc = initLocExpr(p, n[0])
|
||||
lineF(p, cpsStmts, "switch ($1) {$n", [rdLoc(a)])
|
||||
p.flags.incl beforeRetNeeded
|
||||
lineF(p, cpsStmts, "case -1:$n", [])
|
||||
blockLeaveActions(p,
|
||||
howManyTrys = p.nestedTryStmts.len,
|
||||
howManyExcepts = p.inExceptBlockLen)
|
||||
lineF(p, cpsStmts, " goto BeforeRet_;$n", [])
|
||||
var statesCounter = lastOrd(p.config, n[0].typ)
|
||||
if n.len >= 2 and n[1].kind == nkIntLit:
|
||||
statesCounter = getInt(n[1])
|
||||
let prefix = if n.len == 3 and n[2].kind == nkStrLit: n[2].strVal.rope
|
||||
else: rope"STATE"
|
||||
for i in 0i64..toInt64(statesCounter):
|
||||
lineF(p, cpsStmts, "case $2: goto $1$2;$n", [prefix, rope(i)])
|
||||
lineF(p, cpsStmts, "}$n", [])
|
||||
let ra = rdLoc(a)
|
||||
p.s(cpsStmts).addSwitchStmt(ra):
|
||||
p.flags.incl beforeRetNeeded
|
||||
p.s(cpsStmts).addSingleSwitchCase(cIntValue(-1)):
|
||||
blockLeaveActions(p,
|
||||
howManyTrys = p.nestedTryStmts.len,
|
||||
howManyExcepts = p.inExceptBlockLen)
|
||||
p.s(cpsStmts).addGoto("BeforeRet_")
|
||||
var statesCounter = lastOrd(p.config, n[0].typ)
|
||||
if n.len >= 2 and n[1].kind == nkIntLit:
|
||||
statesCounter = getInt(n[1])
|
||||
let prefix = if n.len == 3 and n[2].kind == nkStrLit: n[2].strVal.rope
|
||||
else: rope"STATE"
|
||||
for i in 0i64..toInt64(statesCounter):
|
||||
p.s(cpsStmts).addSingleSwitchCase(cIntValue(i)):
|
||||
p.s(cpsStmts).addGoto(prefix & $i)
|
||||
|
||||
proc genBreakState(p: BProc, n: PNode, d: var TLoc) =
|
||||
var a: TLoc
|
||||
@@ -277,17 +291,27 @@ proc genBreakState(p: BProc, n: PNode, d: var TLoc) =
|
||||
|
||||
if n[0].kind == nkClosure:
|
||||
a = initLocExpr(p, n[0][1])
|
||||
d.snippet = "(((NI*) $1)[1] < 0)" % [rdLoc(a)]
|
||||
let ra = a.rdLoc
|
||||
d.snippet = cOp(LessThan,
|
||||
subscript(
|
||||
cCast(ptrType("NI"), ra),
|
||||
cIntValue(1)),
|
||||
cIntValue(0))
|
||||
else:
|
||||
a = initLocExpr(p, n[0])
|
||||
let ra = a.rdLoc
|
||||
# the environment is guaranteed to contain the 'state' field at offset 1:
|
||||
d.snippet = "((((NI*) $1.ClE_0)[1]) < 0)" % [rdLoc(a)]
|
||||
d.snippet = cOp(LessThan,
|
||||
subscript(
|
||||
cCast(ptrType("NI"), dotField(ra, "ClE_0")),
|
||||
cIntValue(1)),
|
||||
cIntValue(0))
|
||||
|
||||
proc genGotoVar(p: BProc; value: PNode) =
|
||||
if value.kind notin {nkCharLit..nkUInt64Lit}:
|
||||
localError(p.config, value.info, "'goto' target must be a literal value")
|
||||
else:
|
||||
lineF(p, cpsStmts, "goto NIMSTATE_$#;$n", [value.intVal.rope])
|
||||
p.s(cpsStmts).addGoto("NIMSTATE_" & $value.intVal)
|
||||
|
||||
proc genBracedInit(p: BProc, n: PNode; isConst: bool; optionalType: PType; result: var Builder)
|
||||
|
||||
@@ -416,8 +440,13 @@ proc genSingleVar(p: BProc, v: PSym; vn, value: PNode) =
|
||||
if forHcr and targetProc.blocks.len > 3 and v.owner.kind == skModule:
|
||||
# put it in the locals section - mainly because of loops which
|
||||
# use the var in a call to resetLoc() in the statements section
|
||||
lineCg(targetProc, cpsLocals, "hcrRegisterGlobal($3, \"$1\", sizeof($2), $4, (void**)&$1);$n",
|
||||
[v.loc.snippet, rdLoc(v.loc), getModuleDllPath(p.module, v), traverseProc])
|
||||
let rv = rdLoc(v.loc)
|
||||
p.s(cpsLocals).addCallStmt("hcrRegisterGlobal",
|
||||
getModuleDllPath(p.module, v),
|
||||
'"' & v.loc.snippet & '"',
|
||||
cSizeof(rv),
|
||||
traverseProc,
|
||||
cCast("void**", cAddr(v.loc.snippet)))
|
||||
# nothing special left to do later on - let's avoid closing and reopening blocks
|
||||
forHcr = false
|
||||
|
||||
@@ -503,18 +532,18 @@ proc genIf(p: BProc, n: PNode, d: var TLoc) =
|
||||
a = initLocExprSingleUse(p, it[0])
|
||||
lelse = getLabel(p)
|
||||
inc(p.labels)
|
||||
lineF(p, cpsStmts, "if (!$1) goto $2;$n",
|
||||
[rdLoc(a), lelse])
|
||||
let ra = rdLoc(a)
|
||||
p.s(cpsStmts).addSingleIfStmt(cOp(Not, ra)):
|
||||
p.s(cpsStmts).addGoto(lelse)
|
||||
if p.module.compileToCpp:
|
||||
# avoid "jump to label crosses initialization" error:
|
||||
p.s(cpsStmts).add "{"
|
||||
expr(p, it[1], d)
|
||||
p.s(cpsStmts).add "}"
|
||||
p.s(cpsStmts).addScope():
|
||||
expr(p, it[1], d)
|
||||
else:
|
||||
expr(p, it[1], d)
|
||||
endSimpleBlock(p, scope)
|
||||
if n.len > 1:
|
||||
lineF(p, cpsStmts, "goto $1;$n", [lend])
|
||||
p.s(cpsStmts).addGoto(lend)
|
||||
fixLabel(p, lelse)
|
||||
elif it.len == 1:
|
||||
var scope: ScopeBuilder
|
||||
@@ -536,8 +565,12 @@ proc genReturnStmt(p: BProc, t: PNode) =
|
||||
# If we're in a finally block, and we came here by exception
|
||||
# consume it before we return.
|
||||
var safePoint = p.finallySafePoints[^1]
|
||||
linefmt(p, cpsStmts, "if ($1.status != 0) #popCurrentException();$n", [safePoint])
|
||||
lineF(p, cpsStmts, "goto BeforeRet_;$n", [])
|
||||
p.s(cpsStmts).addSingleIfStmt(
|
||||
cOp(NotEqual,
|
||||
dotField(safePoint, "status"),
|
||||
cIntValue(0))):
|
||||
p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "popCurrentException"))
|
||||
p.s(cpsStmts).addGoto("BeforeRet_")
|
||||
|
||||
proc genGotoForCase(p: BProc; caseStmt: PNode) =
|
||||
for i in 1..<caseStmt.len:
|
||||
@@ -549,7 +582,7 @@ proc genGotoForCase(p: BProc; caseStmt: PNode) =
|
||||
localError(p.config, it.info, "range notation not available for computed goto")
|
||||
return
|
||||
let val = getOrdValue(it[j])
|
||||
lineF(p, cpsStmts, "NIMSTATE_$#:$n", [val.rope])
|
||||
p.s(cpsStmts).addLabel("NIMSTATE_" & $val)
|
||||
genStmts(p, it.lastSon)
|
||||
endSimpleBlock(p, scope)
|
||||
|
||||
@@ -594,19 +627,24 @@ proc genComputedGoto(p: BProc; n: PNode) =
|
||||
var id = p.labels+1
|
||||
inc p.labels, arraySize+1
|
||||
let tmp = "TMP$1_" % [id.rope]
|
||||
var gotoArray = "static void* $#[$#] = {" % [tmp, arraySize.rope]
|
||||
for i in 1..arraySize-1:
|
||||
gotoArray.addf("&&TMP$#_, ", [rope(id+i)])
|
||||
gotoArray.addf("&&TMP$#_};$n", [rope(id+arraySize)])
|
||||
line(p, cpsLocals, gotoArray)
|
||||
p.s(cpsStmts).addArrayVarWithInitializer(kind = Global,
|
||||
name = tmp,
|
||||
elementType = "void*",
|
||||
len = arraySize):
|
||||
var labelsInit: StructInitializer
|
||||
p.s(cpsStmts).addStructInitializer(labelsInit, kind = siArray):
|
||||
for i in 1..arraySize:
|
||||
p.s(cpsStmts).addField(labelsInit, ""):
|
||||
p.s(cpsStmts).add(cLabelAddr("TMP" & $(id+i) & "_"))
|
||||
|
||||
for j in 0..<casePos:
|
||||
genStmts(p, n[j])
|
||||
|
||||
let caseStmt = n[casePos]
|
||||
var a: TLoc = initLocExpr(p, caseStmt[0])
|
||||
let ra = a.rdLoc
|
||||
# first goto:
|
||||
lineF(p, cpsStmts, "goto *$#[$#];$n", [tmp, a.rdLoc])
|
||||
p.s(cpsStmts).addComputedGoto(subscript(tmp, ra))
|
||||
|
||||
for i in 1..<caseStmt.len:
|
||||
var scope: ScopeBuilder
|
||||
@@ -619,7 +657,7 @@ proc genComputedGoto(p: BProc; n: PNode) =
|
||||
|
||||
let val = getOrdValue(it[j])
|
||||
let lit = cIntLiteral(toInt64(val)+id+1)
|
||||
lineF(p, cpsStmts, "TMP$#_:$n", [lit])
|
||||
p.s(cpsStmts).addLabel("TMP" & lit & "_")
|
||||
|
||||
genStmts(p, it.lastSon)
|
||||
|
||||
@@ -643,7 +681,8 @@ proc genComputedGoto(p: BProc; n: PNode) =
|
||||
genStmts(p, it)
|
||||
|
||||
var a: TLoc = initLocExpr(p, caseStmt[0])
|
||||
lineF(p, cpsStmts, "goto *$#[$#];$n", [tmp, a.rdLoc])
|
||||
let ra = a.rdLoc
|
||||
p.s(cpsStmts).addComputedGoto(subscript(tmp, ra))
|
||||
endSimpleBlock(p, scope)
|
||||
|
||||
for j in casePos+1..<n.len:
|
||||
@@ -674,14 +713,16 @@ proc genWhileStmt(p: BProc, t: PNode) =
|
||||
p.blocks[p.breakIdx].isLoop = true
|
||||
a = initLocExpr(p, t[0])
|
||||
if (t[0].kind != nkIntLit) or (t[0].intVal == 0):
|
||||
lineF(p, cpsStmts, "if (!$1) goto ", [rdLoc(a)])
|
||||
assignLabel(p.blocks[p.breakIdx], p.s(cpsStmts))
|
||||
appcg(p, cpsStmts, ";$n", [])
|
||||
let ra = a.rdLoc
|
||||
var label: TLabel = ""
|
||||
assignLabel(p.blocks[p.breakIdx], label)
|
||||
p.s(cpsStmts).addSingleIfStmt(cOp(Not, ra)):
|
||||
p.s(cpsStmts).addGoto(label)
|
||||
genStmts(p, loopBody)
|
||||
|
||||
if optProfiler in p.options:
|
||||
# invoke at loop body exit:
|
||||
linefmt(p, cpsStmts, "#nimProfile();$n", [])
|
||||
p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "nimProfile"))
|
||||
endBlockWith(p):
|
||||
finishWhileStmt(p.s(cpsStmts), stmt)
|
||||
|
||||
@@ -763,31 +804,33 @@ proc genBreakStmt(p: BProc, t: PNode) =
|
||||
p.nestedTryStmts.len - p.blocks[idx].nestedTryStmts,
|
||||
p.inExceptBlockLen - p.blocks[idx].nestedExceptStmts)
|
||||
genLineDir(p, t)
|
||||
lineF(p, cpsStmts, "goto $1;$n", [p.blocks[idx].label])
|
||||
p.s(cpsStmts).addGoto(p.blocks[idx].label)
|
||||
|
||||
proc raiseExit(p: BProc) =
|
||||
assert p.config.exc == excGoto
|
||||
if nimErrorFlagDisabled notin p.flags:
|
||||
p.flags.incl nimErrorFlagAccessed
|
||||
if p.nestedTryStmts.len == 0:
|
||||
p.flags.incl beforeRetNeeded
|
||||
# easy case, simply goto 'ret':
|
||||
lineCg(p, cpsStmts, "if (NIM_UNLIKELY(*nimErr_)) goto BeforeRet_;$n", [])
|
||||
else:
|
||||
lineCg(p, cpsStmts, "if (NIM_UNLIKELY(*nimErr_)) goto LA$1_;$n",
|
||||
[p.nestedTryStmts[^1].label])
|
||||
p.s(cpsStmts).addSingleIfStmt(cUnlikely(cDeref("nimErr_"))):
|
||||
if p.nestedTryStmts.len == 0:
|
||||
p.flags.incl beforeRetNeeded
|
||||
# easy case, simply goto 'ret':
|
||||
p.s(cpsStmts).addGoto("BeforeRet_")
|
||||
else:
|
||||
p.s(cpsStmts).addGoto("LA" & $p.nestedTryStmts[^1].label & "_")
|
||||
|
||||
proc raiseExitCleanup(p: BProc, destroy: string) =
|
||||
assert p.config.exc == excGoto
|
||||
if nimErrorFlagDisabled notin p.flags:
|
||||
p.flags.incl nimErrorFlagAccessed
|
||||
if p.nestedTryStmts.len == 0:
|
||||
p.flags.incl beforeRetNeeded
|
||||
# easy case, simply goto 'ret':
|
||||
lineCg(p, cpsStmts, "if (NIM_UNLIKELY(*nimErr_)) {$1; goto BeforeRet_;}$n", [destroy])
|
||||
else:
|
||||
lineCg(p, cpsStmts, "if (NIM_UNLIKELY(*nimErr_)) {$2; goto LA$1_;}$n",
|
||||
[p.nestedTryStmts[^1].label, destroy])
|
||||
p.s(cpsStmts).addSingleIfStmt(cUnlikely(cDeref("nimErr_"))):
|
||||
p.s(cpsStmts).addStmt():
|
||||
p.s(cpsStmts).add(destroy)
|
||||
if p.nestedTryStmts.len == 0:
|
||||
p.flags.incl beforeRetNeeded
|
||||
# easy case, simply goto 'ret':
|
||||
p.s(cpsStmts).addGoto("BeforeRet_")
|
||||
else:
|
||||
p.s(cpsStmts).addGoto("LA" & $p.nestedTryStmts[^1].label & "_")
|
||||
|
||||
proc finallyActions(p: BProc) =
|
||||
if p.config.exc != excGoto and p.nestedTryStmts.len > 0 and p.nestedTryStmts[^1].inExcept:
|
||||
@@ -803,12 +846,11 @@ proc raiseInstr(p: BProc; result: var Builder) =
|
||||
if L == 0:
|
||||
p.flags.incl beforeRetNeeded
|
||||
# easy case, simply goto 'ret':
|
||||
result.add ropecg(p.module, "goto BeforeRet_;$n", [])
|
||||
result.addGoto("BeforeRet_")
|
||||
else:
|
||||
# raise inside an 'except' must go to the finally block,
|
||||
# raise outside an 'except' block must go to the 'except' list.
|
||||
result.add ropecg(p.module, "goto LA$1_;$n",
|
||||
[p.nestedTryStmts[L-1].label])
|
||||
result.addGoto("LA" & $p.nestedTryStmts[L-1].label & "_")
|
||||
# + ord(p.nestedTryStmts[L-1].inExcept)])
|
||||
|
||||
proc genRaiseStmt(p: BProc, t: PNode) =
|
||||
@@ -830,16 +872,22 @@ proc genRaiseStmt(p: BProc, t: PNode) =
|
||||
if isImportedException(typ, p.config):
|
||||
lineF(p, cpsStmts, "throw $1;$n", [e])
|
||||
else:
|
||||
lineCg(p, cpsStmts, "#raiseExceptionEx((#Exception*)$1, $2, $3, $4, $5);$n",
|
||||
[e, makeCString(typ.sym.name.s),
|
||||
makeCString(if p.prc != nil: p.prc.name.s else: p.module.module.name.s),
|
||||
quotedFilename(p.config, t.info), toLinenumber(t.info)])
|
||||
let eName = makeCString(typ.sym.name.s)
|
||||
let pName = makeCString(if p.prc != nil: p.prc.name.s else: p.module.module.name.s)
|
||||
let fName = quotedFilename(p.config, t.info)
|
||||
let ln = toLinenumber(t.info)
|
||||
p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "raiseExceptionEx"),
|
||||
cCast(ptrType(cgsymValue(p.module, "Exception")), e),
|
||||
eName,
|
||||
pName,
|
||||
fName,
|
||||
cIntValue(ln))
|
||||
if optOwnedRefs in p.config.globalOptions:
|
||||
lineCg(p, cpsStmts, "$1 = NIM_NIL;$n", [e])
|
||||
p.s(cpsStmts).addAssignment(e, "NIM_NIL")
|
||||
else:
|
||||
finallyActions(p)
|
||||
genLineDir(p, t)
|
||||
linefmt(p, cpsStmts, "#reraiseException();$n", [])
|
||||
p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "reraiseException"))
|
||||
raiseInstr(p, p.s(cpsStmts))
|
||||
|
||||
template genCaseGenericBranch(p: BProc, b: PNode, e: TLoc,
|
||||
@@ -861,10 +909,10 @@ proc genCaseSecondPass(p: BProc, t: PNode, d: var TLoc,
|
||||
for i in 1..until:
|
||||
# bug #4230: avoid false sharing between branches:
|
||||
if d.k == locTemp and isEmptyType(t.typ): d.k = locNone
|
||||
lineF(p, cpsStmts, "LA$1_: ;$n", [rope(labId + i)])
|
||||
p.s(cpsStmts).addLabel("LA" & $(labId + i) & "_")
|
||||
if t[i].kind == nkOfBranch:
|
||||
exprBlock(p, t[i][^1], d)
|
||||
lineF(p, cpsStmts, "goto $1;$n", [lend])
|
||||
p.s(cpsStmts).addGoto(lend)
|
||||
else:
|
||||
exprBlock(p, t[i][0], d)
|
||||
result = lend
|
||||
@@ -872,35 +920,37 @@ proc genCaseSecondPass(p: BProc, t: PNode, d: var TLoc,
|
||||
template genIfForCaseUntil(p: BProc, t: PNode, d: var TLoc,
|
||||
rangeFormat, eqFormat: FormatStr,
|
||||
until: int, a: TLoc): TLabel =
|
||||
# XXX doesn't work with cbuilder
|
||||
# generate a C-if statement for a Nim case statement
|
||||
var res: TLabel
|
||||
var labId = p.labels
|
||||
for i in 1..until:
|
||||
inc(p.labels)
|
||||
let lab = "LA" & $p.labels & "_"
|
||||
if t[i].kind == nkOfBranch: # else statement
|
||||
genCaseGenericBranch(p, t[i], a, rangeFormat, eqFormat,
|
||||
"LA" & rope(p.labels) & "_")
|
||||
genCaseGenericBranch(p, t[i], a, rangeFormat, eqFormat, lab)
|
||||
else:
|
||||
lineF(p, cpsStmts, "goto LA$1_;$n", [rope(p.labels)])
|
||||
p.s(cpsStmts).addGoto(lab)
|
||||
if until < t.len-1:
|
||||
inc(p.labels)
|
||||
var gotoTarget = p.labels
|
||||
lineF(p, cpsStmts, "goto LA$1_;$n", [rope(gotoTarget)])
|
||||
var gotoTarget = "LA" & $p.labels & "_"
|
||||
p.s(cpsStmts).addGoto(gotoTarget)
|
||||
res = genCaseSecondPass(p, t, d, labId, until)
|
||||
lineF(p, cpsStmts, "LA$1_: ;$n", [rope(gotoTarget)])
|
||||
p.s(cpsStmts).addLabel(gotoTarget)
|
||||
else:
|
||||
res = genCaseSecondPass(p, t, d, labId, until)
|
||||
res
|
||||
|
||||
template genCaseGeneric(p: BProc, t: PNode, d: var TLoc,
|
||||
rangeFormat, eqFormat: FormatStr) =
|
||||
# XXX doesn't work with cbuilder
|
||||
var a: TLoc = initLocExpr(p, t[0])
|
||||
var lend = genIfForCaseUntil(p, t, d, rangeFormat, eqFormat, t.len-1, a)
|
||||
fixLabel(p, lend)
|
||||
|
||||
proc genCaseStringBranch(p: BProc, b: PNode, e: TLoc, labl: TLabel,
|
||||
stringKind: TTypeKind,
|
||||
branches: var openArray[Rope]) =
|
||||
branches: var openArray[Builder]) =
|
||||
var x: TLoc
|
||||
for i in 0..<b.len - 1:
|
||||
assert(b[i].kind != nkRange)
|
||||
@@ -912,12 +962,13 @@ proc genCaseStringBranch(p: BProc, b: PNode, e: TLoc, labl: TLabel,
|
||||
of nkNilLit: j = 0
|
||||
else:
|
||||
assert false, "invalid string case branch node kind"
|
||||
if stringKind == tyCstring:
|
||||
appcg(p.module, branches[j], "if (#eqCstrings($1, $2)) goto $3;$n",
|
||||
[rdLoc(e), rdLoc(x), labl])
|
||||
else:
|
||||
appcg(p.module, branches[j], "if (#eqStrings($1, $2)) goto $3;$n",
|
||||
[rdLoc(e), rdLoc(x), labl])
|
||||
let re = rdLoc(e)
|
||||
let rx = rdLoc(x)
|
||||
branches[j].addSingleIfStmtWithCond():
|
||||
let eqName = if stringKind == tyCstring: "eqCstrings" else: "eqStrings"
|
||||
branches[j].addCall(cgsymValue(p.module, eqName), re, rx)
|
||||
do:
|
||||
branches[j].addGoto(labl)
|
||||
|
||||
proc genStringCase(p: BProc, t: PNode, stringKind: TTypeKind, d: var TLoc) =
|
||||
# count how many constant strings there are in the case:
|
||||
@@ -926,7 +977,7 @@ proc genStringCase(p: BProc, t: PNode, stringKind: TTypeKind, d: var TLoc) =
|
||||
if t[i].kind == nkOfBranch: inc(strings, t[i].len - 1)
|
||||
if strings > stringCaseThreshold:
|
||||
var bitMask = math.nextPowerOfTwo(strings) - 1
|
||||
var branches: seq[Rope]
|
||||
var branches: seq[Builder]
|
||||
newSeq(branches, bitMask + 1)
|
||||
var a: TLoc = initLocExpr(p, t[0]) # first pass: generate ifs+goto:
|
||||
var labId = p.labels
|
||||
@@ -939,20 +990,21 @@ proc genStringCase(p: BProc, t: PNode, stringKind: TTypeKind, d: var TLoc) =
|
||||
# else statement: nothing to do yet
|
||||
# but we reserved a label, which we use later
|
||||
discard
|
||||
if stringKind == tyCstring:
|
||||
linefmt(p, cpsStmts, "switch (#hashCstring($1) & $2) {$n",
|
||||
[rdLoc(a), bitMask])
|
||||
else:
|
||||
linefmt(p, cpsStmts, "switch (#hashString($1) & $2) {$n",
|
||||
[rdLoc(a), bitMask])
|
||||
for j in 0..high(branches):
|
||||
if branches[j] != "":
|
||||
let lit = cIntLiteral(j)
|
||||
lineF(p, cpsStmts, "case $1: $n$2break;$n",
|
||||
[lit, branches[j]])
|
||||
lineF(p, cpsStmts, "}$n", []) # else statement:
|
||||
let fnName = if stringKind == tyCstring: "hashCstring" else: "hashString"
|
||||
let ra = rdLoc(a)
|
||||
p.s(cpsStmts).addSwitchStmt(
|
||||
cOp(BitAnd, "NI",
|
||||
cCall(cgsymValue(p.module, fnName), ra),
|
||||
cIntValue(bitMask))):
|
||||
for j in 0..high(branches):
|
||||
if branches[j].buf.len != 0:
|
||||
let lit = cIntLiteral(j)
|
||||
p.s(cpsStmts).addSingleSwitchCase(lit):
|
||||
p.s(cpsStmts).add(extract(branches[j]))
|
||||
p.s(cpsStmts).addBreak()
|
||||
# else statement:
|
||||
if t[^1].kind != nkOfBranch:
|
||||
lineF(p, cpsStmts, "goto LA$1_;$n", [rope(p.labels)])
|
||||
p.s(cpsStmts).addGoto("LA" & rope(p.labels) & "_")
|
||||
# third pass: generate statements
|
||||
var lend = genCaseSecondPass(p, t, d, labId, t.len-1)
|
||||
fixLabel(p, lend)
|
||||
@@ -1064,9 +1116,12 @@ proc genRestoreFrameAfterException(p: BProc) =
|
||||
if optStackTrace in p.module.config.options:
|
||||
if hasCurFramePointer notin p.flags:
|
||||
p.flags.incl hasCurFramePointer
|
||||
p.procSec(cpsLocals).add(ropecg(p.module, "\tTFrame* _nimCurFrame;$n", []))
|
||||
p.procSec(cpsInit).add(ropecg(p.module, "\t_nimCurFrame = #getFrame();$n", []))
|
||||
linefmt(p, cpsStmts, "#setFrame(_nimCurFrame);$n", [])
|
||||
p.procSec(cpsLocals).add('\t')
|
||||
p.procSec(cpsLocals).addVar(kind = Local, name = "_nimCurFrame", typ = ptrType("TFrame"))
|
||||
p.procSec(cpsInit).add('\t')
|
||||
p.procSec(cpsInit).addAssignmentWithValue("_nimCurFrame"):
|
||||
p.procSec(cpsInit).addCall(cgsymValue(p.module, "getFrame"))
|
||||
p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "setFrame"), "_nimCurFrame")
|
||||
|
||||
proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
|
||||
#[ code to generate:
|
||||
@@ -1387,7 +1442,7 @@ proc genTryGoto(p: BProc; t: PNode; d: var TLoc) =
|
||||
else:
|
||||
startBlockWith(p):
|
||||
scope = initScope(p.s(cpsStmts))
|
||||
linefmt(p, cpsStmts, "LA$1_:;$n", [lab])
|
||||
p.s(cpsStmts).addLabel("LA" & $lab & "_")
|
||||
|
||||
p.nestedTryStmts[^1].inExcept = true
|
||||
var i = 1
|
||||
@@ -1412,33 +1467,46 @@ proc genTryGoto(p: BProc; t: PNode; d: var TLoc) =
|
||||
isScope = true
|
||||
innerScope = initScope(p.s(cpsStmts))
|
||||
# we handled the exception, remember this:
|
||||
linefmt(p, cpsStmts, "*nimErr_ = NIM_FALSE;$n", [])
|
||||
p.s(cpsStmts).addAssignment(cDeref("nimErr_"), "NIM_FALSE")
|
||||
expr(p, t[i][0], d)
|
||||
else:
|
||||
if not innerIsIf:
|
||||
innerIsIf = true
|
||||
innerIfStmt = initIfStmt(p.s(cpsStmts))
|
||||
var orExpr = newRopeAppender()
|
||||
var orExpr: Snippet = ""
|
||||
for j in 0..<t[i].len - 1:
|
||||
assert(t[i][j].kind == nkType)
|
||||
if orExpr.len != 0: orExpr.add("||")
|
||||
let memberName = if p.module.compileToCpp: "m_type" else: "Sup.m_type"
|
||||
var excVal = cCall(cgsymValue(p.module, "nimBorrowCurrentException"))
|
||||
let member =
|
||||
if p.module.compileToCpp:
|
||||
derefField(excVal, "m_type")
|
||||
else:
|
||||
dotField(derefField(excVal, "Sup"), "m_type")
|
||||
var branch: Snippet = ""
|
||||
if optTinyRtti in p.config.globalOptions:
|
||||
let checkFor = $getObjDepth(t[i][j].typ)
|
||||
appcg(p.module, orExpr, "#isObjDisplayCheck(#nimBorrowCurrentException()->$1, $2, $3)",
|
||||
[memberName, checkFor, $genDisplayElem(MD5Digest(hashType(t[i][j].typ, p.config)))])
|
||||
branch = cCall(cgsymValue(p.module, "isObjDisplayCheck"),
|
||||
member,
|
||||
checkFor,
|
||||
$genDisplayElem(MD5Digest(hashType(t[i][j].typ, p.config))))
|
||||
else:
|
||||
let checkFor = genTypeInfoV1(p.module, t[i][j].typ, t[i][j].info)
|
||||
appcg(p.module, orExpr, "#isObj(#nimBorrowCurrentException()->$1, $2)", [memberName, checkFor])
|
||||
branch = cCall(cgsymValue(p.module, "isObj"),
|
||||
member,
|
||||
checkFor)
|
||||
if orExpr.len == 0:
|
||||
orExpr = branch
|
||||
else:
|
||||
orExpr = cOp(Or, orExpr, branch)
|
||||
|
||||
startBlockWith(p):
|
||||
initElifBranch(p.s(cpsStmts), innerIfStmt, orExpr)
|
||||
# we handled the exception, remember this:
|
||||
linefmt(p, cpsStmts, "*nimErr_ = NIM_FALSE;$n", [])
|
||||
p.s(cpsStmts).addAssignment(cDeref("nimErr_"), "NIM_FALSE")
|
||||
expr(p, t[i][^1], d)
|
||||
|
||||
linefmt(p, cpsStmts, "#popCurrentException();$n", [])
|
||||
linefmt(p, cpsStmts, "LA$1_:;$n", [nextExcept])
|
||||
p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "popCurrentException"))
|
||||
p.s(cpsStmts).addLabel("LA" & $nextExcept & "_")
|
||||
endBlockWith(p):
|
||||
if isScope:
|
||||
finishScope(p.s(cpsStmts), innerScope)
|
||||
@@ -1465,8 +1533,9 @@ proc genTryGoto(p: BProc; t: PNode; d: var TLoc) =
|
||||
genStmts(p, t[i][0])
|
||||
else:
|
||||
# pretend we did handle the error for the safe execution of the 'finally' section:
|
||||
p.procSec(cpsLocals).add(ropecg(p.module, "NIM_BOOL oldNimErrFin$1_;$n", [lab]))
|
||||
linefmt(p, cpsStmts, "oldNimErrFin$1_ = *nimErr_; *nimErr_ = NIM_FALSE;$n", [lab])
|
||||
p.procSec(cpsLocals).addVar(kind = Local, name = "oldNimErrFin" & $lab & "_", typ = "NIM_BOOL")
|
||||
p.s(cpsStmts).addAssignment("oldNimErrFin" & $lab & "_", cDeref("nimErr_"))
|
||||
p.s(cpsStmts).addAssignment(cDeref("nimErr_"), "NIM_FALSE")
|
||||
genStmts(p, t[i][0])
|
||||
# this is correct for all these cases:
|
||||
# 1. finally is run during ordinary control flow
|
||||
@@ -1474,7 +1543,7 @@ proc genTryGoto(p: BProc; t: PNode; d: var TLoc) =
|
||||
# error back to nil.
|
||||
# 3. finally is run for exception handling code without any 'except'
|
||||
# handler present or only handlers that did not match.
|
||||
linefmt(p, cpsStmts, "*nimErr_ = oldNimErrFin$1_;$n", [lab])
|
||||
p.s(cpsStmts).addAssignment(cDeref("nimErr_"), "oldNimErrFin" & $lab & "_")
|
||||
endSimpleBlock(p, finallyScope)
|
||||
raiseExit(p)
|
||||
if hasExcept: inc p.withinTryWithExcept
|
||||
@@ -1522,20 +1591,24 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) =
|
||||
var nonQuirkyIf = default(IfBuilder)
|
||||
if not quirkyExceptions:
|
||||
safePoint = getTempName(p.module)
|
||||
linefmt(p, cpsLocals, "#TSafePoint $1;$n", [safePoint])
|
||||
linefmt(p, cpsStmts, "#pushSafePoint(&$1);$n", [safePoint])
|
||||
p.s(cpsLocals).addVar(name = safePoint, typ = cgsymValue(p.module, "TSafePoint"))
|
||||
p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "pushSafePoint"), cAddr(safePoint))
|
||||
if isDefined(p.config, "nimStdSetjmp"):
|
||||
linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", [safePoint])
|
||||
p.s(cpsStmts).addFieldAssignmentWithValue(safePoint, "status"):
|
||||
p.s(cpsStmts).addCall("setjmp", dotField(safePoint, "context"))
|
||||
elif isDefined(p.config, "nimSigSetjmp"):
|
||||
linefmt(p, cpsStmts, "$1.status = sigsetjmp($1.context, 0);$n", [safePoint])
|
||||
p.s(cpsStmts).addFieldAssignmentWithValue(safePoint, "status"):
|
||||
p.s(cpsStmts).addCall("sigsetjmp", dotField(safePoint, "context"), cIntValue(0))
|
||||
elif isDefined(p.config, "nimBuiltinSetjmp"):
|
||||
linefmt(p, cpsStmts, "$1.status = __builtin_setjmp($1.context);$n", [safePoint])
|
||||
p.s(cpsStmts).addFieldAssignmentWithValue(safePoint, "status"):
|
||||
p.s(cpsStmts).addCall("__builtin_setjmp", dotField(safePoint, "context"))
|
||||
elif isDefined(p.config, "nimRawSetjmp"):
|
||||
if isDefined(p.config, "mswindows"):
|
||||
if isDefined(p.config, "vcc") or isDefined(p.config, "clangcl"):
|
||||
# For the vcc compiler, use `setjmp()` with one argument.
|
||||
# See https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/setjmp?view=msvc-170
|
||||
linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", [safePoint])
|
||||
p.s(cpsStmts).addFieldAssignmentWithValue(safePoint, "status"):
|
||||
p.s(cpsStmts).addCall("setjmp", dotField(safePoint, "context"))
|
||||
else:
|
||||
# The Windows `_setjmp()` takes two arguments, with the second being an
|
||||
# undocumented buffer used by the SEH mechanism for stack unwinding.
|
||||
@@ -1543,11 +1616,14 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) =
|
||||
# prone to stack corruption during unwinding, so we disable that by setting
|
||||
# it to NULL.
|
||||
# More details: https://github.com/status-im/nimbus-eth2/issues/3121
|
||||
linefmt(p, cpsStmts, "$1.status = _setjmp($1.context, 0);$n", [safePoint])
|
||||
p.s(cpsStmts).addFieldAssignmentWithValue(safePoint, "status"):
|
||||
p.s(cpsStmts).addCall("_setjmp", dotField(safePoint, "context"), cIntValue(0))
|
||||
else:
|
||||
linefmt(p, cpsStmts, "$1.status = _setjmp($1.context);$n", [safePoint])
|
||||
p.s(cpsStmts).addFieldAssignmentWithValue(safePoint, "status"):
|
||||
p.s(cpsStmts).addCall("_setjmp", dotField(safePoint, "context"))
|
||||
else:
|
||||
linefmt(p, cpsStmts, "$1.status = setjmp($1.context);$n", [safePoint])
|
||||
p.s(cpsStmts).addFieldAssignmentWithValue(safePoint, "status"):
|
||||
p.s(cpsStmts).addCall("setjmp", dotField(safePoint, "context"))
|
||||
nonQuirkyIf = initIfStmt(p.s(cpsStmts))
|
||||
initElifBranch(p.s(cpsStmts), nonQuirkyIf, removeSinglePar(
|
||||
cOp(Equal, dotField(safePoint, "status"), cIntValue(0))))
|
||||
@@ -1558,11 +1634,11 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) =
|
||||
var quirkyScope = default(ScopeBuilder)
|
||||
var isScope = false
|
||||
if not quirkyExceptions:
|
||||
linefmt(p, cpsStmts, "#popSafePoint();$n", [])
|
||||
p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "popSafePoint"))
|
||||
finishBranch(p.s(cpsStmts), nonQuirkyIf)
|
||||
startBlockWith(p):
|
||||
initElseBranch(p.s(cpsStmts), nonQuirkyIf)
|
||||
linefmt(p, cpsStmts, "#popSafePoint();$n", [])
|
||||
p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "popSafePoint"))
|
||||
genRestoreFrameAfterException(p)
|
||||
elif 1 < t.len and t[1].kind == nkExceptBranch:
|
||||
startBlockWith(p):
|
||||
@@ -1589,27 +1665,40 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) =
|
||||
else:
|
||||
scope = initScope(p.s(cpsStmts))
|
||||
if not quirkyExceptions:
|
||||
linefmt(p, cpsStmts, "$1.status = 0;$n", [safePoint])
|
||||
p.s(cpsStmts).addFieldAssignment(safePoint, "status", cIntValue(0))
|
||||
expr(p, t[i][0], d)
|
||||
linefmt(p, cpsStmts, "#popCurrentException();$n", [])
|
||||
p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "popCurrentException"))
|
||||
endBlockWith(p):
|
||||
if exceptIfInited:
|
||||
finishBranch(p.s(cpsStmts), exceptIf)
|
||||
else:
|
||||
finishScope(p.s(cpsStmts), scope)
|
||||
else:
|
||||
var orExpr = newRopeAppender()
|
||||
var orExpr: Snippet = ""
|
||||
for j in 0..<t[i].len - 1:
|
||||
assert(t[i][j].kind == nkType)
|
||||
if orExpr.len != 0: orExpr.add("||")
|
||||
let memberName = if p.module.compileToCpp: "m_type" else: "Sup.m_type"
|
||||
var excVal = cCall(cgsymValue(p.module, "nimBorrowCurrentException"))
|
||||
let member =
|
||||
if p.module.compileToCpp:
|
||||
derefField(excVal, "m_type")
|
||||
else:
|
||||
dotField(derefField(excVal, "Sup"), "m_type")
|
||||
var branch: Snippet = ""
|
||||
if optTinyRtti in p.config.globalOptions:
|
||||
let checkFor = $getObjDepth(t[i][j].typ)
|
||||
appcg(p.module, orExpr, "#isObjDisplayCheck(#nimBorrowCurrentException()->$1, $2, $3)",
|
||||
[memberName, checkFor, $genDisplayElem(MD5Digest(hashType(t[i][j].typ, p.config)))])
|
||||
branch = cCall(cgsymValue(p.module, "isObjDisplayCheck"),
|
||||
member,
|
||||
checkFor,
|
||||
$genDisplayElem(MD5Digest(hashType(t[i][j].typ, p.config))))
|
||||
else:
|
||||
let checkFor = genTypeInfoV1(p.module, t[i][j].typ, t[i][j].info)
|
||||
appcg(p.module, orExpr, "#isObj(#nimBorrowCurrentException()->$1, $2)", [memberName, checkFor])
|
||||
branch = cCall(cgsymValue(p.module, "isObj"),
|
||||
member,
|
||||
checkFor)
|
||||
if orExpr.len == 0:
|
||||
orExpr = branch
|
||||
else:
|
||||
orExpr = cOp(Or, orExpr, branch)
|
||||
|
||||
if not exceptIfInited:
|
||||
exceptIf = initIfStmt(p.s(cpsStmts))
|
||||
@@ -1617,9 +1706,9 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) =
|
||||
startBlockWith(p):
|
||||
initElifBranch(p.s(cpsStmts), exceptIf, orExpr)
|
||||
if not quirkyExceptions:
|
||||
linefmt(p, cpsStmts, "$1.status = 0;$n", [safePoint])
|
||||
p.s(cpsStmts).addFieldAssignment(safePoint, "status", cIntValue(0))
|
||||
expr(p, t[i][^1], d)
|
||||
linefmt(p, cpsStmts, "#popCurrentException();$n", [])
|
||||
p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "popCurrentException"))
|
||||
endBlockWith(p):
|
||||
finishBranch(p.s(cpsStmts), exceptIf)
|
||||
inc(i)
|
||||
@@ -1645,11 +1734,19 @@ proc genTrySetjmp(p: BProc, t: PNode, d: var TLoc) =
|
||||
# re-raise the unhandled one but instead keep the old one (it was
|
||||
# not popped either):
|
||||
if not quirkyExceptions and getCompilerProc(p.module.g.graph, "nimLeaveFinally") != nil:
|
||||
linefmt(p, cpsStmts, "if ($1.status != 0) #nimLeaveFinally();$n", [safePoint])
|
||||
p.s(cpsStmts).addSingleIfStmt(
|
||||
cOp(NotEqual,
|
||||
dotField(safePoint, "status"),
|
||||
cIntValue(0))):
|
||||
p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "nimLeaveFinally"))
|
||||
endSimpleBlock(p, finallyScope)
|
||||
discard pop(p.finallySafePoints)
|
||||
if not quirkyExceptions:
|
||||
linefmt(p, cpsStmts, "if ($1.status != 0) #reraiseException();$n", [safePoint])
|
||||
p.s(cpsStmts).addSingleIfStmt(
|
||||
cOp(NotEqual,
|
||||
dotField(safePoint, "status"),
|
||||
cIntValue(0))):
|
||||
p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "reraiseException"))
|
||||
|
||||
proc genAsmOrEmitStmt(p: BProc, t: PNode, isAsmStmt=false; result: var Rope) =
|
||||
var res = ""
|
||||
@@ -1766,13 +1863,17 @@ proc genDiscriminantCheck(p: BProc, a, tmp: TLoc, objtype: PType,
|
||||
assert t.kind == tyObject
|
||||
discard genTypeInfoV1(p.module, t, a.lode.info)
|
||||
if not containsOrIncl(p.module.declaredThings, field.id):
|
||||
appcg(p.module, cfsVars, "extern $1",
|
||||
[discriminatorTableDecl(p.module, t, field)])
|
||||
p.module.s[cfsVars].addDeclWithVisibility(Extern):
|
||||
discriminatorTableDecl(p.module, t, field, p.module.s[cfsVars])
|
||||
let lit = cIntLiteral(toInt64(lengthOrd(p.config, field.typ))+1)
|
||||
lineCg(p, cpsStmts,
|
||||
"#FieldDiscriminantCheck((NI)(NU)($1), (NI)(NU)($2), $3, $4);$n",
|
||||
[rdLoc(a), rdLoc(tmp), discriminatorTableName(p.module, t, field),
|
||||
lit])
|
||||
let ra = rdLoc(a)
|
||||
let rtmp = rdLoc(tmp)
|
||||
let dn = discriminatorTableName(p.module, t, field)
|
||||
p.s(cpsStmts).addCallStmt(cgsymValue(p.module, "FieldDiscriminantCheck"),
|
||||
cCast("NI", cCast("NU", ra)),
|
||||
cCast("NI", cCast("NU", rtmp)),
|
||||
dn,
|
||||
lit)
|
||||
if p.config.exc == excGoto:
|
||||
raiseExit(p)
|
||||
|
||||
|
||||
@@ -1329,10 +1329,13 @@ proc discriminatorTableName(m: BModule; objtype: PType, d: PSym): Rope =
|
||||
|
||||
proc rope(arg: Int128): Rope = rope($arg)
|
||||
|
||||
proc discriminatorTableDecl(m: BModule; objtype: PType, d: PSym): Rope =
|
||||
proc discriminatorTableDecl(m: BModule; objtype: PType, d: PSym, result: var Builder) =
|
||||
cgsym(m, "TNimNode")
|
||||
var tmp = discriminatorTableName(m, objtype, d)
|
||||
result = "TNimNode* $1[$2];$n" % [tmp, rope(lengthOrd(m.config, d.typ)+1)]
|
||||
result.addArrayVar(kind = Local,
|
||||
name = tmp,
|
||||
elementType = ptrType("TNimNode"),
|
||||
len = toInt(lengthOrd(m.config, d.typ)) + 1)
|
||||
|
||||
proc genTNimNodeArray(m: BModule; name: Rope, size: int) =
|
||||
if m.hcrOn:
|
||||
|
||||
Reference in New Issue
Block a user