diff --git a/compiler/cbuilderexprs.nim b/compiler/cbuilderexprs.nim index b9083a3075c6..5609df0c61fc 100644 --- a/compiler/cbuilderexprs.nim +++ b/compiler/cbuilderexprs.nim @@ -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 & ")" diff --git a/compiler/cbuilderstmts.nim b/compiler/cbuilderstmts.nim index 98d655ce87a2..ac74dbfa37f7 100644 --- a/compiler/cbuilderstmts.nim +++ b/compiler/cbuilderstmts.nim @@ -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") diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index 97a7a53e1591..371a7363a344 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -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.. 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.. 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..$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..$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) diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 04b740aa92d9..80a09a814f7f 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -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: