no ropes WIP (#20433)

* refactorings in preparation for ropes elimination of the C code generator; mostly the usual ': Rope' -> 'result: var Rope' rewrite
* rewrote ccgcalls.nim
* refactored ccgexprs.nim
* ccgliterals: refactoring
* refactoring: code dealing with name mangling
* refactoring: getRecordFieldsAux
* ropes are strings (insert obscene joke here)
* optimize JS code gen
* optimizations and code improvements
* more optimizations
* final cleanups
This commit is contained in:
Andreas Rumpf 2022-09-27 10:57:47 +02:00 • committed by GitHub
commit ca1f3f36b9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 1058 additions and 1002 deletions

View file

@ -35,7 +35,8 @@ import
cgmeth, lowerings, sighashes, modulegraphs, lineinfos, rodutils,
transf, injectdestructors, sourcemap, astmsgs
import json, sets, math, tables, intsets, strutils
import json, sets, math, tables, intsets
import strutils except addf
when defined(nimPreviewSlimSystem):
import std/[assertions, syncio]
@ -110,21 +111,18 @@ type
template config*(p: PProc): ConfigRef = p.module.config
proc indentLine(p: PProc, r: Rope): Rope =
result = r
var p = p
var ind = 0
while true:
for i in 0..<p.blocks.len + p.extraIndent:
prepend(result, rope" ")
inc ind, p.blocks.len + p.extraIndent
if p.up == nil or p.up.prc != p.prc.owner:
break
p = p.up
result = repeat(' ', ind*2) & r
template line(p: PProc, added: string) =
p.body.add(indentLine(p, rope(added)))
template line(p: PProc, added: Rope) =
p.body.add(indentLine(p, added))
template lineF(p: PProc, frmt: FormatStr, args: varargs[Rope]) =
p.body.add(indentLine(p, ropes.`%`(frmt, args)))
@ -140,9 +138,9 @@ proc newGlobals(): PGlobals =
result.typeInfoGenerated = initIntSet()
proc initCompRes(r: var TCompRes) =
r.address = nil
r.res = nil
r.tmpLoc = nil
r.address = ""
r.res = ""
r.tmpLoc = ""
r.typ = etyNone
r.kind = resNone
@ -241,7 +239,7 @@ proc mangleName(m: BModule, s: PSym): Rope =
if chr notin {'A'..'Z','a'..'z','_','$','0'..'9'}:
return false
result = s.loc.r
if result == nil:
if result == "":
if s.kind == skField and s.name.s.validJsName:
result = rope(s.name.s)
elif s.kind == skTemp:
@ -464,7 +462,7 @@ proc maybeMakeTemp(p: PProc, n: PNode; x: TCompRes): tuple[a, tmp: Rope] =
b = a
if needsTemp(p, n):
# if we have tmp just use it
if x.tmpLoc != nil and (mapType(n.typ) == etyBaseIndex or n.kind in {nkHiddenDeref, nkDerefExpr}):
if x.tmpLoc != "" and (mapType(n.typ) == etyBaseIndex or n.kind in {nkHiddenDeref, nkDerefExpr}):
b = "$1[0][$1[1]]" % [x.tmpLoc]
(a: a, tmp: b)
else:
@ -481,10 +479,10 @@ proc maybeMakeTempAssignable(p: PProc, n: PNode; x: TCompRes): tuple[a, tmp: Rop
b = a
if needsTemp(p, n):
# if we have tmp just use it
if x.tmpLoc != nil and (mapType(n.typ) == etyBaseIndex or n.kind in {nkHiddenDeref, nkDerefExpr}):
if x.tmpLoc != "" and (mapType(n.typ) == etyBaseIndex or n.kind in {nkHiddenDeref, nkDerefExpr}):
b = "$1[0][$1[1]]" % [x.tmpLoc]
result = (a: a, tmp: b)
elif x.tmpLoc != nil and n.kind == nkBracketExpr:
elif x.tmpLoc != "" and n.kind == nkBracketExpr:
# genArrayAddr
var
address, index: TCompRes
@ -745,7 +743,7 @@ proc moveInto(p: PProc, src: var TCompRes, dest: TCompRes) =
else:
lineF(p, "$1;$n", [src.rdLoc])
src.kind = resNone
src.res = nil
src.res = ""
proc genTry(p: PProc, n: PNode, r: var TCompRes) =
# code to generate:
@ -800,7 +798,7 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
moveInto(p, a, r)
if i > 1: lineF(p, "}$n", [])
else:
var orExpr: Rope = nil
var orExpr: Rope = ""
var excAlias: PNode = nil
useMagic(p, "isObj")
@ -813,13 +811,13 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
excAlias = it[2]
# If this is a ``except exc as sym`` branch there must be no following
# nodes
doAssert orExpr == nil
doAssert orExpr == ""
elif it.kind == nkType:
throwObj = it
else:
internalError(p.config, n.info, "genTryStmt")
if orExpr != nil: orExpr.add("||")
if orExpr != "": orExpr.add("||")
# Generate the correct type checking code depending on whether this is a
# NIM-native or a JS-native exception
# if isJsObject(throwObj.typ):
@ -907,7 +905,7 @@ proc genCaseJS(p: PProc, n: PNode, r: var TCompRes) =
gen(p, e[1], b)
if j != itLen - 2:
lineF(p, "$1 >= $2 && $1 <= $3 || $n", [cond.rdLoc, a.rdLoc, b.rdLoc])
else:
else:
lineF(p, "$1 >= $2 && $1 <= $3", [cond.rdLoc, a.rdLoc, b.rdLoc])
else:
var v = copyNode(e[0])
@ -998,7 +996,7 @@ proc genBreakStmt(p: PProc, n: PNode) =
proc genAsmOrEmitStmt(p: PProc, n: PNode) =
genLineDir(p, n)
p.body.add p.indentLine(nil)
p.body.add p.indentLine("")
for i in 0..<n.len:
let it = n[i]
case it.kind
@ -1016,12 +1014,12 @@ proc genAsmOrEmitStmt(p: PProc, n: PNode) =
if it.typ.kind == tyPointer:
# A fat pointer is disguised as an array
r.res = r.address
r.address = nil
r.address = ""
r.typ = etyNone
elif r.typ == etyBaseIndex:
# Deference first
r.res = "$1[$2]" % [r.address, r.res]
r.address = nil
r.address = ""
r.typ = etyNone
p.body.add(r.rdLoc)
@ -1055,12 +1053,12 @@ proc genIf(p: PProc, n: PNode, r: var TCompRes) =
line(p, repeat('}', toClose) & "\L")
proc generateHeader(p: PProc, typ: PType): Rope =
result = nil
result = ""
for i in 1..<typ.n.len:
assert(typ.n[i].kind == nkSym)
var param = typ.n[i].sym
if isCompileTimeOnly(param.typ): continue
if result != nil: result.add(", ")
if result != "": result.add(", ")
var name = mangleName(p.module, param)
result.add(name)
if mapType(param.typ) == etyBaseIndex:
@ -1135,7 +1133,7 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
elif b.typ == etyBaseIndex:
lineF(p, "$# = [$#, $#];$n", [a.res, b.address, b.res])
elif b.typ == etyNone:
internalAssert p.config, b.address == nil
internalAssert p.config, b.address == ""
lineF(p, "$# = [$#, 0];$n", [a.address, b.res])
elif x.typ.kind == tyVar and y.typ.kind == tyPtr:
lineF(p, "$# = [$#, $#];$n", [a.res, b.address, b.res])
@ -1143,13 +1141,13 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
lineF(p, "$1 = $2;$n", [a.rdLoc, b.rdLoc])
elif a.typ == etyBaseIndex:
# array indexing may not map to var type
if b.address != nil:
if b.address != "":
lineF(p, "$1 = $2; $3 = $4;$n", [a.address, b.address, a.res, b.res])
else:
lineF(p, "$1 = $2;$n", [a.address, b.res])
else:
internalError(p.config, x.info, $("genAsgn", b.typ, a.typ))
elif b.address != nil:
elif b.address != "":
lineF(p, "$1 = $2; $3 = $4;$n", [a.address, b.address, a.res, b.res])
else:
lineF(p, "$1 = $2;$n", [a.address, b.res])
@ -1201,7 +1199,7 @@ proc genFieldAddr(p: PProc, n: PNode, r: var TCompRes) =
else:
if b[1].kind != nkSym: internalError(p.config, b[1].info, "genFieldAddr")
var f = b[1].sym
if f.loc.r == nil: f.loc.r = mangleName(p.module, f)
if f.loc.r == "": f.loc.r = mangleName(p.module, f)
r.res = makeJSString($f.loc.r)
internalAssert p.config, a.typ != etyBaseIndex
r.address = a.res
@ -1229,7 +1227,7 @@ proc genFieldAccess(p: PProc, n: PNode, r: var TCompRes) =
else:
if n[1].kind != nkSym: internalError(p.config, n[1].info, "genFieldAccess")
var f = n[1].sym
if f.loc.r == nil: f.loc.r = mangleName(p.module, f)
if f.loc.r == "": f.loc.r = mangleName(p.module, f)
r.res = "$1.$2" % [r.res, f.loc.r]
mkTemp(1)
r.kind = resExpr
@ -1250,11 +1248,11 @@ proc genCheckedFieldOp(p: PProc, n: PNode, addrTyp: PType, r: var TCompRes) =
# Field symbol
var field = accessExpr[1].sym
internalAssert p.config, field.kind == skField
if field.loc.r == nil: field.loc.r = mangleName(p.module, field)
if field.loc.r == "": field.loc.r = mangleName(p.module, field)
# Discriminant symbol
let disc = checkExpr[2].sym
internalAssert p.config, disc.kind == skField
if disc.loc.r == nil: disc.loc.r = mangleName(p.module, disc)
if disc.loc.r == "": disc.loc.r = mangleName(p.module, disc)
var setx: TCompRes
gen(p, checkExpr[1], setx)
@ -1271,7 +1269,7 @@ proc genCheckedFieldOp(p: PProc, n: PNode, addrTyp: PType, r: var TCompRes) =
useMagic(p, "reprDiscriminant") # no need to offset by firstOrd unlike for cgen
let msg = genFieldDefect(p.config, field.name.s, disc)
lineF(p, "if ($1[$2.$3]$4undefined) { raiseFieldError2(makeNimstrLit($5), reprDiscriminant($2.$3, $6)); }$n",
setx.res, tmp, disc.loc.r, if negCheck: ~"!==" else: ~"===",
setx.res, tmp, disc.loc.r, if negCheck: "!==" else: "===",
makeJSString(msg), genTypeInfo(p, disc.typ))
if addrTyp != nil and mapType(p, addrTyp) == etyBaseIndex:
@ -1320,7 +1318,7 @@ proc genArrayAccess(p: PProc, n: PNode, r: var TCompRes) =
genFieldAddr(p, n, r)
else: internalError(p.config, n.info, "expr(nkBracketExpr, " & $ty.kind & ')')
r.typ = mapType(n.typ)
if r.res == nil: internalError(p.config, n.info, "genArrayAccess")
if r.res == "": internalError(p.config, n.info, "genArrayAccess")
if ty.kind == tyCstring:
r.res = "$1.charCodeAt($2)" % [r.address, r.res]
elif r.typ == etyBaseIndex:
@ -1347,11 +1345,11 @@ template isIndirect(x: PSym): bool =
proc genSymAddr(p: PProc, n: PNode, typ: PType, r: var TCompRes) =
let s = n.sym
if s.loc.r == nil: internalError(p.config, n.info, "genAddr: 3")
if s.loc.r == "": internalError(p.config, n.info, "genAddr: 3")
case s.kind
of skParam:
r.res = s.loc.r
r.address = nil
r.address = ""
r.typ = etyNone
of skVar, skLet, skResult:
r.kind = resExpr
@ -1367,7 +1365,7 @@ proc genSymAddr(p: PProc, n: PNode, typ: PType, r: var TCompRes) =
r.res = s.loc.r & "[0]"
else:
r.res = s.loc.r
r.address = nil
r.address = ""
elif {sfGlobal, sfAddrTaken} * s.flags != {} or jsType == etyBaseIndex:
# for ease of code generation, we do not distinguish between
# sfAddrTaken and sfGlobal.
@ -1466,7 +1464,7 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) =
var s = n.sym
case s.kind
of skVar, skLet, skParam, skTemp, skResult, skForVar:
if s.loc.r == nil:
if s.loc.r == "":
internalError(p.config, n.info, "symbol has no generated name: " & s.name.s)
if sfCompileTime in s.flags:
genVarInit(p, s, if s.ast != nil: s.ast else: newNodeI(nkEmpty, s.info))
@ -1491,7 +1489,7 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) =
r.res = s.loc.r
of skConst:
genConstant(p, s)
if s.loc.r == nil:
if s.loc.r == "":
internalError(p.config, n.info, "symbol has no generated name: " & s.name.s)
r.res = s.loc.r
of skProc, skFunc, skConverter, skMethod:
@ -1511,7 +1509,7 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) =
else:
genProcForSymIfNeeded(p, s)
else:
if s.loc.r == nil:
if s.loc.r == "":
internalError(p.config, n.info, "symbol has no generated name: " & s.name.s)
if mapType(p, s.typ) == etyBaseIndex:
r.address = s.loc.r
@ -1536,7 +1534,7 @@ proc genDeref(p: PProc, n: PNode, r: var TCompRes) =
r.res = "$1[1]" % [tmp]
r.tmpLoc = tmp
elif a.typ == etyBaseIndex:
if a.tmpLoc != nil:
if a.tmpLoc != "":
r.tmpLoc = a.tmpLoc
r.res = a.rdLoc
else:
@ -1659,9 +1657,9 @@ proc genPatternCall(p: PProc; n: PNode; pat: string; typ: PType;
proc genInfixCall(p: PProc, n: PNode, r: var TCompRes) =
# don't call '$' here for efficiency:
let f = n[0].sym
if f.loc.r == nil: f.loc.r = mangleName(p.module, f)
if f.loc.r == "": f.loc.r = mangleName(p.module, f)
if sfInfixCall in f.flags:
let pat = n[0].sym.loc.r.data
let pat = $n[0].sym.loc.r
internalAssert p.config, pat.len > 0
if pat.contains({'#', '(', '@'}):
var typ = skipTypes(n[0].typ, abstractInst)
@ -1671,10 +1669,10 @@ proc genInfixCall(p: PProc, n: PNode, r: var TCompRes) =
if n.len != 1:
gen(p, n[1], r)
if r.typ == etyBaseIndex:
if r.address == nil:
if r.address == "":
globalError(p.config, n.info, "cannot invoke with infix syntax")
r.res = "$1[$2]" % [r.address, r.res]
r.address = nil
r.address = ""
r.typ = etyNone
r.res.add(".")
var op: TCompRes
@ -1826,12 +1824,12 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope =
result = createVar(p, lastSon t, indirect)
else:
internalError(p.config, "createVar: " & $t.kind)
result = nil
result = ""
else:
internalError(p.config, "createVar: " & $t.kind)
result = nil
result = ""
template returnType: untyped = ~""
template returnType: untyped = ""
proc genVarInit(p: PProc, v: PSym, n: PNode) =
var
@ -1929,8 +1927,7 @@ proc genVarStmt(p: PProc, n: PNode) =
proc genConstant(p: PProc, c: PSym) =
if lfNoDecl notin c.loc.flags and not p.g.generatedSyms.containsOrIncl(c.id):
let oldBody = p.body
p.body = nil
let oldBody = move p.body
#genLineDir(p, c.ast)
genVarInit(p, c, c.ast)
p.g.constants.add(p.body)
@ -1984,7 +1981,7 @@ proc genConStrStr(p: PProc, n: PNode, r: var TCompRes) =
else:
r.res.add("$1 || [])" % [a.res])
proc genReprAux(p: PProc, n: PNode, r: var TCompRes, magic: string, typ: Rope = nil) =
proc genReprAux(p: PProc, n: PNode, r: var TCompRes, magic: string, typ: Rope = "") =
useMagic(p, magic)
r.res.add(magic & "(")
var a: TCompRes
@ -1993,7 +1990,7 @@ proc genReprAux(p: PProc, n: PNode, r: var TCompRes, magic: string, typ: Rope =
if magic == "reprAny":
# the pointer argument in reprAny is expandend to
# (pointedto, pointer), so we need to fill it
if a.address.isNil:
if a.address.len == 0:
r.res.add(a.res)
r.res.add(", null")
else:
@ -2001,14 +1998,14 @@ proc genReprAux(p: PProc, n: PNode, r: var TCompRes, magic: string, typ: Rope =
else:
r.res.add(a.res)
if not typ.isNil:
if typ != "":
r.res.add(", ")
r.res.add(typ)
r.res.add(")")
proc genRepr(p: PProc, n: PNode, r: var TCompRes) =
let t = skipTypes(n[1].typ, abstractVarRange)
case t.kind:
case t.kind
of tyInt..tyInt64, tyUInt..tyUInt64:
genReprAux(p, n, r, "reprInt")
of tyChar:
@ -2327,7 +2324,7 @@ proc genObjConstr(p: PProc, n: PNode, r: var TCompRes) =
let val = it[1]
gen(p, val, a)
var f = it[0].sym
if f.loc.r == nil: f.loc.r = mangleName(p.module, f)
if f.loc.r == "": f.loc.r = mangleName(p.module, f)
fieldIDs.incl(lookupFieldAgain(nTyp, f).id)
let typ = val.typ.skipTypes(abstractInst)
@ -2388,7 +2385,7 @@ proc convStrToCStr(p: PProc, n: PNode, r: var TCompRes) =
gen(p, n[0][0], r)
else:
gen(p, n[0], r)
if r.res == nil: internalError(p.config, n.info, "convStrToCStr")
if r.res == "": internalError(p.config, n.info, "convStrToCStr")
useMagic(p, "toJSStr")
r.res = "toJSStr($1)" % [r.res]
r.kind = resExpr
@ -2400,7 +2397,7 @@ proc convCStrToStr(p: PProc, n: PNode, r: var TCompRes) =
gen(p, n[0][0], r)
else:
gen(p, n[0], r)
if r.res == nil: internalError(p.config, n.info, "convCStrToStr")
if r.res == "": internalError(p.config, n.info, "convCStrToStr")
useMagic(p, "cstrToNimstr")
r.res = "cstrToNimstr($1)" % [r.res]
r.kind = resExpr
@ -2430,11 +2427,11 @@ proc genProcBody(p: PProc, prc: PSym): Rope =
makeJSString(prc.owner.name.s & '.' & prc.name.s),
makeJSString(toFilenameOption(p.config, prc.info.fileIndex, foStacktrace)))
else:
result = nil
result = ""
if p.beforeRetNeeded:
result.add p.indentLine(~"BeforeRet: {$n")
result.add p.indentLine("BeforeRet: {\n")
result.add p.body
result.add p.indentLine(~"};$n")
result.add p.indentLine("};\n")
else:
result.add(p.body)
if prc.typ.callConv == ccSysCall:
@ -2444,8 +2441,8 @@ proc genProcBody(p: PProc, prc: PSym): Rope =
result.add(frameDestroy(p))
proc optionalLine(p: Rope): Rope =
if p == nil:
return nil
if p == "":
return ""
else:
return p & "\L"
@ -2458,8 +2455,8 @@ proc genProc(oldProc: PProc, prc: PSym): Rope =
# echo "BEGIN generating code for: " & prc.name.s
var p = newProc(oldProc.g, oldProc.module, prc.ast, prc.options)
p.up = oldProc
var returnStmt: Rope = nil
var resultAsgn: Rope = nil
var returnStmt: Rope = ""
var resultAsgn: Rope = ""
var name = mangleName(p.module, prc)
let header = generateHeader(p, prc.typ)
if prc.typ[0] != nil and sfPure notin prc.flags:
@ -2503,7 +2500,7 @@ proc genProc(oldProc: PProc, prc: PSym): Rope =
optionalLine(p.indentLine(returnStmt))])
else:
# if optLineDir in p.config.options:
# result.add(~"\L")
# result.add("\L")
if p.config.hcrOn:
# Here, we introduce thunks that create the equivalent of a jump table
@ -2526,7 +2523,7 @@ proc genProc(oldProc: PProc, prc: PSym): Rope =
dec p.extraIndent
result.add p.indentLine(def)
result.add p.indentLine(~"}$n")
result.add p.indentLine("}\n")
#if gVerbosity >= 3:
# echo "END generated code for: " & prc.name.s
@ -2534,7 +2531,7 @@ proc genProc(oldProc: PProc, prc: PSym): Rope =
proc genStmt(p: PProc, n: PNode) =
var r: TCompRes
gen(p, n, r)
if r.res != nil: lineF(p, "$#;$n", [r.res])
if r.res != "": lineF(p, "$#;$n", [r.res])
proc genPragma(p: PProc, n: PNode) =
for it in n.sons:
@ -2574,7 +2571,7 @@ proc genCast(p: PProc, n: PNode, r: var TCompRes) =
r.res = "($1 - ($2 $3))" % [rope minuend, r.res, trimmer]
elif (src.kind == tyPtr and mapType(p, src) == etyObject) and dest.kind == tyPointer:
r.address = r.res
r.res = ~"null"
r.res = "null"
r.typ = etyBaseIndex
elif (dest.kind == tyPtr and mapType(p, dest) == etyObject) and src.kind == tyPointer:
r.res = r.address
@ -2583,8 +2580,8 @@ proc genCast(p: PProc, n: PNode, r: var TCompRes) =
proc gen(p: PProc, n: PNode, r: var TCompRes) =
r.typ = etyNone
if r.kind != resCallee: r.kind = resNone
#r.address = nil
r.res = nil
#r.address = ""
r.res = ""
case n.kind
of nkSym:
@ -2723,7 +2720,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
var s = n[namePos].sym
if {sfExportc, sfCompilerProc} * s.flags == {sfExportc}:
genSym(p, n[namePos], r)
r.res = nil
r.res = ""
of nkGotoState, nkState:
globalError(p.config, n.info, "First class iterators not implemented")
of nkPragmaBlock: gen(p, n.lastSon, r)
@ -2840,7 +2837,7 @@ proc getClassName(t: PType): Rope =
s = skipTypes(t, abstractPtrs).sym
if s.isNil or sfAnon in s.flags:
doAssert(false, "cannot retrieve class name")
if s.loc.r != nil: result = s.loc.r
if s.loc.r != "": result = s.loc.r
else: result = rope(s.name.s)
proc myClose(graph: ModuleGraph; b: PPassContext, n: PNode): PNode =