diff options
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/ast.nim | 9 | ||||
-rw-r--r-- | compiler/ccgcalls.nim | 10 | ||||
-rw-r--r-- | compiler/ccgexprs.nim | 179 | ||||
-rw-r--r-- | compiler/ccgliterals.nim | 24 | ||||
-rw-r--r-- | compiler/ccgstmts.nim | 2 | ||||
-rw-r--r-- | compiler/ccgtrav.nim | 23 | ||||
-rw-r--r-- | compiler/ccgtypes.nim | 53 | ||||
-rw-r--r-- | compiler/cgen.nim | 25 | ||||
-rw-r--r-- | compiler/commands.nim | 9 | ||||
-rw-r--r-- | compiler/condsyms.nim | 1 | ||||
-rw-r--r-- | compiler/destroyer.nim | 31 | ||||
-rw-r--r-- | compiler/options.nim | 6 | ||||
-rw-r--r-- | compiler/semasgn.nim | 28 | ||||
-rw-r--r-- | compiler/semstmts.nim | 15 | ||||
-rw-r--r-- | compiler/semtypes.nim | 35 | ||||
-rw-r--r-- | compiler/transf.nim | 8 | ||||
-rw-r--r-- | compiler/types.nim | 15 |
17 files changed, 330 insertions, 143 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index 01e70ce75..a722f63f6 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -627,6 +627,7 @@ type mIsPartOf, mAstToStr, mParallel, mSwap, mIsNil, mArrToSeq, mCopyStr, mCopyStrLast, mNewString, mNewStringOfCap, mParseBiggestFloat, + mMove, mWasMoved, mReset, mArray, mOpenArray, mRange, mSet, mSeq, mOpt, mVarargs, mRef, mPtr, mVar, mDistinct, mVoid, mTuple, @@ -1087,9 +1088,9 @@ proc newSym*(symKind: TSymKind, name: PIdent, owner: PSym, result.id = getID() when debugIds: registerId(result) - #if result.id == 93289: + #if result.id == 77131: # writeStacktrace() - # MessageOut(name.s & " has id: " & toString(result.id)) + # echo name.s proc isMetaType*(t: PType): bool = return t.kind in tyMetaTypes or @@ -1267,14 +1268,14 @@ proc newType*(kind: TTypeKind, owner: PSym): PType = new(result) result.kind = kind result.owner = owner - result.size = - 1 + result.size = -1 result.align = 2 # default alignment result.id = getID() result.lockLevel = UnspecifiedLockLevel when debugIds: registerId(result) when false: - if result.id == 205734: + if result.id == 76426: echo "KNID ", kind writeStackTrace() diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim index 2621574a6..83461350b 100644 --- a/compiler/ccgcalls.nim +++ b/compiler/ccgcalls.nim @@ -124,15 +124,19 @@ proc openArrayLoc(p: BProc, n: PNode): Rope = of tyString, tySequence: if skipTypes(n.typ, abstractInst).kind == tyVar and not compileToCpp(p.module): - result = "(*$1)$3, (*$1 ? (*$1)->$2 : 0)" % [a.rdLoc, lenField(p), dataField(p)] + var t: TLoc + t.r = "(*$1)" % [a.rdLoc] + result = "(*$1)$3, $2" % [a.rdLoc, lenExpr(p, t), dataField(p)] else: - result = "$1$3, ($1 ? $1->$2 : 0)" % [a.rdLoc, lenField(p), dataField(p)] + result = "$1$3, $2" % [a.rdLoc, lenExpr(p, a), dataField(p)] of tyArray: result = "$1, $2" % [rdLoc(a), rope(lengthOrd(p.config, a.t))] of tyPtr, tyRef: case lastSon(a.t).kind of tyString, tySequence: - result = "(*$1)$3, (*$1 ? (*$1)->$2 : 0)" % [a.rdLoc, lenField(p), dataField(p)] + var t: TLoc + t.r = "(*$1)" % [a.rdLoc] + result = "(*$1)$3, (*$1 ? (*$1)->$2 : 0)" % [a.rdLoc, lenExpr(p, t), dataField(p)] of tyArray: result = "$1, $2" % [rdLoc(a), rope(lengthOrd(p.config, lastSon(a.t)))] else: diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index b30d216f2..65cae8866 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -165,7 +165,7 @@ proc canMove(n: PNode): bool = # result = false proc genRefAssign(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = - if dest.storage == OnStack or not usesNativeGC(p.config): + if dest.storage == OnStack or not usesWriteBarrier(p.config): linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src)) elif dest.storage == OnHeap: # location is on heap @@ -255,9 +255,13 @@ proc genGenericAsgn(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = # tfShallow flag for the built-in string type too! So we check only # here for this flag, where it is reasonably safe to do so # (for objects, etc.): - if needToCopy notin flags or + if p.config.selectedGC == gcDestructors: + linefmt(p, cpsStmts, + "$1.len = $2.len; $1.p = $2.p;$n", + rdLoc(dest), rdLoc(src)) + elif needToCopy notin flags or tfShallow in skipTypes(dest.t, abstractVarRange).flags: - if dest.storage == OnStack or not usesNativeGC(p.config): + if dest.storage == OnStack or not usesWriteBarrier(p.config): linefmt(p, cpsStmts, "#nimCopyMem((void*)$1, (NIM_CONST void*)$2, sizeof($3));$n", addrLoc(p.config, dest), addrLoc(p.config, src), rdLoc(dest)) @@ -280,17 +284,21 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) = of tyRef: genRefAssign(p, dest, src, flags) of tySequence: - if (needToCopy notin flags and src.storage != OnStatic) or canMove(src.lode): + if p.config.selectedGC == gcDestructors: + genGenericAsgn(p, dest, src, flags) + elif (needToCopy notin flags and src.storage != OnStatic) or canMove(src.lode): genRefAssign(p, dest, src, flags) else: linefmt(p, cpsStmts, "#genericSeqAssign($1, $2, $3);$n", addrLoc(p.config, dest), rdLoc(src), genTypeInfo(p.module, dest.t, dest.lode.info)) of tyString: - if (needToCopy notin flags and src.storage != OnStatic) or canMove(src.lode): + if p.config.selectedGC == gcDestructors: + genGenericAsgn(p, dest, src, flags) + elif (needToCopy notin flags and src.storage != OnStatic) or canMove(src.lode): genRefAssign(p, dest, src, flags) else: - if dest.storage == OnStack or not usesNativeGC(p.config): + if dest.storage == OnStack or not usesWriteBarrier(p.config): linefmt(p, cpsStmts, "$1 = #copyString($2);$n", dest.rdLoc, src.rdLoc) elif dest.storage == OnHeap: # we use a temporary to care for the dreaded self assignment: @@ -453,6 +461,13 @@ proc binaryStmt(p: BProc, e: PNode, d: var TLoc, frmt: string) = initLocExpr(p, e.sons[2], b) lineCg(p, cpsStmts, frmt, rdLoc(a), rdLoc(b)) +proc binaryStmtAddr(p: BProc, e: PNode, d: var TLoc, frmt: string) = + var a, b: TLoc + if d.k != locNone: internalError(p.config, e.info, "binaryStmtAddr") + initLocExpr(p, e.sons[1], a) + initLocExpr(p, e.sons[2], b) + lineCg(p, cpsStmts, frmt, addrLoc(p.config, a), rdLoc(b)) + proc unaryStmt(p: BProc, e: PNode, d: var TLoc, frmt: string) = var a: TLoc if d.k != locNone: internalError(p.config, e.info, "unaryStmt") @@ -889,8 +904,8 @@ proc genBoundsCheck(p: BProc; arr, a, b: TLoc) = of tySequence, tyString: linefmt(p, cpsStmts, "if ($2-$1 != -1 && " & - "(!$3 || (NU)($1) >= (NU)($3->$4) || (NU)($2) >= (NU)($3->$4))) #raiseIndexError();$n", - rdLoc(a), rdLoc(b), rdLoc(arr), lenField(p)) + "((NU)($1) >= (NU)$3 || (NU)($2) >= (NU)$3)) #raiseIndexError();$n", + rdLoc(a), rdLoc(b), lenExpr(p, arr)) else: discard proc genOpenArrayElem(p: BProc, n, x, y: PNode, d: var TLoc) = @@ -914,12 +929,12 @@ proc genSeqElem(p: BProc, n, x, y: PNode, d: var TLoc) = if optBoundsCheck in p.options: if ty.kind == tyString and (not defined(nimNoZeroTerminator) or optLaxStrings in p.options): linefmt(p, cpsStmts, - "if (!$2 || (NU)($1) > (NU)($2->$3)) #raiseIndexError();$n", - rdLoc(b), rdLoc(a), lenField(p)) + "if ((NU)($1) > (NU)$2) #raiseIndexError();$n", + rdLoc(b), lenExpr(p, a)) else: linefmt(p, cpsStmts, - "if (!$2 || (NU)($1) >= (NU)($2->$3)) #raiseIndexError();$n", - rdLoc(b), rdLoc(a), lenField(p)) + "if ((NU)($1) >= (NU)$2) #raiseIndexError();$n", + rdLoc(b), lenExpr(p, a)) if d.k == locNone: d.storage = OnHeap if skipTypes(a.t, abstractVar).kind in {tyRef, tyPtr}: a.r = ropecg(p.module, "(*$1)", a.r) @@ -1010,6 +1025,12 @@ proc genEcho(p: BProc, n: PNode) = proc gcUsage(conf: ConfigRef; n: PNode) = if conf.selectedGC == gcNone: message(conf, n.info, warnGcMem, n.renderTree) +proc strLoc(p: BProc; d: TLoc): Rope = + if p.config.selectedGc == gcDestructors: + result = addrLoc(p.config, d) + else: + result = rdLoc(d) + proc genStrConcat(p: BProc, e: PNode, d: var TLoc) = # <Nim code> # s = 'Hello ' & name & ', how do you feel?' & 'z' @@ -1037,13 +1058,14 @@ proc genStrConcat(p: BProc, e: PNode, d: var TLoc) = initLocExpr(p, e.sons[i + 1], a) if skipTypes(e.sons[i + 1].typ, abstractVarRange).kind == tyChar: inc(L) - add(appends, ropecg(p.module, "#appendChar($1, $2);$n", tmp.r, rdLoc(a))) + add(appends, ropecg(p.module, "#appendChar($1, $2);$n", strLoc(p, tmp), rdLoc(a))) else: if e.sons[i + 1].kind in {nkStrLit..nkTripleStrLit}: inc(L, len(e.sons[i + 1].strVal)) else: - addf(lens, "($1 ? $1->$2 : 0) + ", [rdLoc(a), lenField(p)]) - add(appends, ropecg(p.module, "#appendString($1, $2);$n", tmp.r, rdLoc(a))) + add(lens, lenExpr(p, a)) + add(lens, " + ") + add(appends, ropecg(p.module, "#appendString($1, $2);$n", strLoc(p, tmp), rdLoc(a))) linefmt(p, cpsStmts, "$1 = #rawNewString($2$3);$n", tmp.r, lens, rope(L)) add(p.s(cpsStmts), appends) if d.k == locNone: @@ -1076,19 +1098,24 @@ proc genStrAppend(p: BProc, e: PNode, d: var TLoc) = if skipTypes(e.sons[i + 2].typ, abstractVarRange).kind == tyChar: inc(L) add(appends, ropecg(p.module, "#appendChar($1, $2);$n", - rdLoc(dest), rdLoc(a))) + strLoc(p, dest), rdLoc(a))) else: if e.sons[i + 2].kind in {nkStrLit..nkTripleStrLit}: inc(L, len(e.sons[i + 2].strVal)) else: - addf(lens, "($1 ? $1->$2 : 0) + ", [rdLoc(a), lenField(p)]) + add(lens, lenExpr(p, a)) + add(lens, " + ") add(appends, ropecg(p.module, "#appendString($1, $2);$n", - rdLoc(dest), rdLoc(a))) - initLoc(call, locCall, e, OnHeap) - call.r = ropecg(p.module, "#resizeString($1, $2$3)", [rdLoc(dest), lens, rope(L)]) - genAssignment(p, dest, call, {}) + strLoc(p, dest), rdLoc(a))) + if p.config.selectedGC == gcDestructors: + linefmt(p, cpsStmts, "#prepareAdd($1, $2$3);$n", + addrLoc(p.config, dest), lens, rope(L)) + else: + initLoc(call, locCall, e, OnHeap) + call.r = ropecg(p.module, "#resizeString($1, $2$3)", [rdLoc(dest), lens, rope(L)]) + genAssignment(p, dest, call, {}) + gcUsage(p.config, e) add(p.s(cpsStmts), appends) - gcUsage(p.config, e) proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) = # seq &= x --> @@ -1151,7 +1178,7 @@ proc rawGenNew(p: BProc, a: TLoc, sizeExpr: Rope) = addf(p.module.s[cfsTypeInit3], "$1->finalizer = (void*)$2;$n", [ti, rdLoc(f)]) let args = [getTypeDesc(p.module, typ), ti, sizeExpr] - if a.storage == OnHeap and usesNativeGC(p.config): + if a.storage == OnHeap and usesWriteBarrier(p.config): # use newObjRC1 as an optimization if canFormAcycle(a.t): linefmt(p, cpsStmts, "if ($1) { #nimGCunrefRC1($1); $1 = NIM_NIL; }$n", a.rdLoc) @@ -1182,7 +1209,7 @@ proc genNewSeqAux(p: BProc, dest: TLoc, length: Rope; lenIsZero: bool) = genTypeInfo(p.module, seqtype, dest.lode.info), length] var call: TLoc initLoc(call, locExpr, dest.lode, OnHeap) - if dest.storage == OnHeap and usesNativeGC(p.config): + if dest.storage == OnHeap and usesWriteBarrier(p.config): if canFormAcycle(dest.t): linefmt(p, cpsStmts, "if ($1) { #nimGCunrefRC1($1); $1 = NIM_NIL; }$n", dest.rdLoc) else: @@ -1201,10 +1228,16 @@ proc genNewSeq(p: BProc, e: PNode) = var a, b: TLoc initLocExpr(p, e.sons[1], a) initLocExpr(p, e.sons[2], b) - let lenIsZero = optNilSeqs notin p.options and - e[2].kind == nkIntLit and e[2].intVal == 0 - genNewSeqAux(p, a, b.rdLoc, lenIsZero) - gcUsage(p.config, e) + if p.config.selectedGC == gcDestructors: + let seqtype = skipTypes(e.sons[1].typ, abstractVarRange) + linefmt(p, cpsStmts, "$1.len = $2; $1.p = ($4*) #newSeqPayload($2, sizeof($3));$n", + a.rdLoc, b.rdLoc, getTypeDesc(p.module, seqtype.lastSon), + getSeqPayloadType(p.module, seqtype)) + else: + let lenIsZero = optNilSeqs notin p.options and + e[2].kind == nkIntLit and e[2].intVal == 0 + genNewSeqAux(p, a, b.rdLoc, lenIsZero) + gcUsage(p.config, e) proc genNewSeqOfCap(p: BProc; e: PNode; d: var TLoc) = let seqtype = skipTypes(e.typ, abstractVarRange) @@ -1448,7 +1481,7 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) = putIntoDest(p, b, e, "$1, $1Len_0" % [rdLoc(a)], a.storage) of tyString, tySequence: putIntoDest(p, b, e, - "$1$3, ($1 ? $1->$2 : 0)" % [rdLoc(a), lenField(p), dataField(p)], a.storage) + "$1$3, $2" % [rdLoc(a), lenExpr(p, a), dataField(p)], a.storage) of tyArray: putIntoDest(p, b, e, "$1, $2" % [rdLoc(a), rope(lengthOrd(p.config, a.t))], a.storage) @@ -1492,28 +1525,19 @@ proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) = if op == mHigh: unaryExpr(p, e, d, "($1 ? (#nimCStrLen($1)-1) : -1)") else: unaryExpr(p, e, d, "($1 ? #nimCStrLen($1) : 0)") of tyString: - if not p.module.compileToCpp: - if op == mHigh: unaryExpr(p, e, d, "($1 ? ($1->Sup.len-1) : -1)") - else: unaryExpr(p, e, d, "($1 ? $1->Sup.len : 0)") - else: - if op == mHigh: unaryExpr(p, e, d, "($1 ? ($1->len-1) : -1)") - else: unaryExpr(p, e, d, "($1 ? $1->len : 0)") + var a: TLoc + initLocExpr(p, e.sons[1], a) + var x = lenExpr(p, a) + if op == mHigh: x = "($1-1)" % [x] + putIntoDest(p, d, e, x) of tySequence: + # we go through a temporary here because people write bullshit code. var a, tmp: TLoc initLocExpr(p, e[1], a) getIntTemp(p, tmp) - var frmt: FormatStr - if not p.module.compileToCpp: - if op == mHigh: - frmt = "$1 = ($2 ? ($2->Sup.len-1) : -1);$n" - else: - frmt = "$1 = ($2 ? $2->Sup.len : 0);$n" - else: - if op == mHigh: - frmt = "$1 = ($2 ? ($2->len-1) : -1);$n" - else: - frmt = "$1 = ($2 ? $2->len : 0);$n" - lineCg(p, cpsStmts, frmt, tmp.r, rdLoc(a)) + var x = lenExpr(p, a) + if op == mHigh: x = "($1-1)" % [x] + lineCg(p, cpsStmts, "$1 = $2;$n", tmp.r, x) putIntoDest(p, d, e, tmp.r) of tyArray: # YYY: length(sideeffect) is optimized away incorrectly? @@ -1522,6 +1546,9 @@ proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) = else: internalError(p.config, e.info, "genArrayLen()") proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) = + if p.config.selectedGc == gcDestructors: + genCall(p, e, d) + return var a, b, call: TLoc assert(d.k == locNone) var x = e.sons[1] @@ -1542,16 +1569,19 @@ proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) = gcUsage(p.config, e) proc genSetLengthStr(p: BProc, e: PNode, d: var TLoc) = - var a, b, call: TLoc - if d.k != locNone: internalError(p.config, e.info, "genSetLengthStr") - initLocExpr(p, e.sons[1], a) - initLocExpr(p, e.sons[2], b) + if p.config.selectedGc == gcDestructors: + binaryStmtAddr(p, e, d, "#setLengthStrV2($1, $2);$n") + else: + var a, b, call: TLoc + if d.k != locNone: internalError(p.config, e.info, "genSetLengthStr") + initLocExpr(p, e.sons[1], a) + initLocExpr(p, e.sons[2], b) - initLoc(call, locCall, e, OnHeap) - call.r = ropecg(p.module, "#setLengthStr($1, $2)", [ - rdLoc(a), rdLoc(b)]) - genAssignment(p, a, call, {}) - gcUsage(p.config, e) + initLoc(call, locCall, e, OnHeap) + call.r = ropecg(p.module, "#setLengthStr($1, $2)", [ + rdLoc(a), rdLoc(b)]) + genAssignment(p, a, call, {}) + gcUsage(p.config, e) proc genSwap(p: BProc, e: PNode, d: var TLoc) = # swap(a, b) --> @@ -1803,11 +1833,11 @@ proc genStrEquals(p: BProc, e: PNode, d: var TLoc) = if a.kind in {nkStrLit..nkTripleStrLit} and a.strVal == "": initLocExpr(p, e.sons[2], x) putIntoDest(p, d, e, - ropecg(p.module, "(!($1) || ($1)->$2 == 0)", rdLoc(x), lenField(p))) + ropecg(p.module, "($1 == 0)", lenExpr(p, x))) elif b.kind in {nkStrLit..nkTripleStrLit} and b.strVal == "": initLocExpr(p, e.sons[1], x) putIntoDest(p, d, e, - ropecg(p.module, "(!($1) || ($1)->$2 == 0)", rdLoc(x), lenField(p))) + ropecg(p.module, "($1 == 0)", lenExpr(p, x))) else: binaryExpr(p, e, d, "#eqStrings($1, $2)") @@ -1868,14 +1898,21 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = of mConStrStr: genStrConcat(p, e, d) of mAppendStrCh: - var dest, b, call: TLoc - initLoc(call, locCall, e, OnHeap) - initLocExpr(p, e.sons[1], dest) - initLocExpr(p, e.sons[2], b) - call.r = ropecg(p.module, "#addChar($1, $2)", [rdLoc(dest), rdLoc(b)]) - genAssignment(p, dest, call, {}) + if p.config.selectedGC == gcDestructors: + binaryStmtAddr(p, e, d, "#nimAddCharV1($1, $2);$n") + else: + var dest, b, call: TLoc + initLoc(call, locCall, e, OnHeap) + initLocExpr(p, e.sons[1], dest) + initLocExpr(p, e.sons[2], b) + call.r = ropecg(p.module, "#addChar($1, $2)", [rdLoc(dest), rdLoc(b)]) + genAssignment(p, dest, call, {}) of mAppendStrStr: genStrAppend(p, e, d) - of mAppendSeqElem: genSeqElemAppend(p, e, d) + of mAppendSeqElem: + if p.config.selectedGc == gcDestructors: + genCall(p, e, d) + else: + genSeqElemAppend(p, e, d) of mEqStr: genStrEquals(p, e, d) of mLeStr: binaryExpr(p, e, d, "(#cmpStrings($1, $2) <= 0)") of mLtStr: binaryExpr(p, e, d, "(#cmpStrings($1, $2) < 0)") @@ -1924,8 +1961,9 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) = of mIncl, mExcl, mCard, mLtSet, mLeSet, mEqSet, mMulSet, mPlusSet, mMinusSet, mInSet: genSetOp(p, e, d, op) - of mNewString, mNewStringOfCap, mCopyStr, mCopyStrLast, mExit, - mParseBiggestFloat: + of mCopyStr, mCopyStrLast: + genCall(p, e, d) + of mNewString, mNewStringOfCap, mExit, mParseBiggestFloat: var opr = e.sons[0].sym if lfNoDecl notin opr.loc.flags: discard cgsym(p.module, $opr.loc.r) @@ -2522,6 +2560,13 @@ proc genConstExpr(p: BProc, n: PNode): Rope = result = genConstSimpleList(p, n) of nkObjConstr: result = genConstObjConstr(p, n) + of nkStrLit..nkTripleStrLit: + if p.config.selectedGc == gcDestructors: + result = genStringLiteralV2Const(p.module, n) + else: + var d: TLoc + initLocExpr(p, n, d) + result = rdLoc(d) else: var d: TLoc initLocExpr(p, n, d) diff --git a/compiler/ccgliterals.nim b/compiler/ccgliterals.nim index cfe71375e..34677ec06 100644 --- a/compiler/ccgliterals.nim +++ b/compiler/ccgliterals.nim @@ -53,20 +53,36 @@ proc genStringLiteralV1(m: BModule; n: PNode): Rope = proc genStringLiteralDataOnlyV2(m: BModule, s: string): Rope = result = getTempName(m) - addf(m.s[cfsData], " static const NIM_CHAR $1[$2] = $3;$n", - [result, rope(len(s)+1), makeCString(s)]) + addf(m.s[cfsData], "static const struct {$n" & + " NI cap; void* allocator; NIM_CHAR data[$2];$n" & + "} $1 = { $2, NIM_NIL, $3 };$n", + [result, rope(len(s)), makeCString(s)]) proc genStringLiteralV2(m: BModule; n: PNode): Rope = let id = nodeTableTestOrSet(m.dataCache, n, m.labels) if id == m.labels: + discard cgsym(m, "NimStrPayload") + discard cgsym(m, "NimStringV2") # string literal not found in the cache: let pureLit = genStringLiteralDataOnlyV2(m, n.strVal) result = getTempName(m) - addf(m.s[cfsData], "static const #NimStringV2 $1 = {$2, $2, $3};$n", - [result, rope(len(n.strVal)+1), pureLit]) + addf(m.s[cfsData], "static const NimStringV2 $1 = {$2, (NimStrPayload*)&$3};$n", + [result, rope(len(n.strVal)), pureLit]) else: result = m.tmpBase & rope(id) +proc genStringLiteralV2Const(m: BModule; n: PNode): Rope = + let id = nodeTableTestOrSet(m.dataCache, n, m.labels) + var pureLit: Rope + if id == m.labels: + discard cgsym(m, "NimStrPayload") + discard cgsym(m, "NimStringV2") + # string literal not found in the cache: + pureLit = genStringLiteralDataOnlyV2(m, n.strVal) + else: + pureLit = m.tmpBase & rope(id) + result = "{$1, (NimStrPayload*)&$2}" % [rope(len(n.strVal)), pureLit] + # ------ Version selector --------------------------------------------------- proc genStringLiteralDataOnly(m: BModule; s: string; info: TLineInfo): Rope = diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index a7a2b3fee..69e6558bb 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -16,7 +16,7 @@ const # above X strings a hash-switch for strings is generated proc registerGcRoot(p: BProc, v: PSym) = - if p.config.selectedGC in {gcMarkAndSweep, gcGenerational, gcV2, gcRefc} and + if p.config.selectedGC in {gcMarkAndSweep, gcDestructors, gcV2, gcRefc} and containsGarbageCollectedRef(v.loc.t): # we register a specialized marked proc here; this has the advantage # that it works out of the box for thread local storage then :-) diff --git a/compiler/ccgtrav.nim b/compiler/ccgtrav.nim index 349cf2707..c69bb2c80 100644 --- a/compiler/ccgtrav.nim +++ b/compiler/ccgtrav.nim @@ -7,8 +7,7 @@ # distribution, for details about the copyright. # -## Generates traversal procs for the C backend. Traversal procs are only an -## optimization; the GC works without them too. +## Generates traversal procs for the C backend. # included from cgen.nim @@ -61,6 +60,7 @@ proc parentObj(accessor: Rope; m: BModule): Rope {.inline.} = else: result = accessor +proc genTraverseProcSeq(c: TTraversalClosure, accessor: Rope, typ: PType) proc genTraverseProc(c: TTraversalClosure, accessor: Rope, typ: PType) = if typ == nil: return @@ -93,8 +93,18 @@ proc genTraverseProc(c: TTraversalClosure, accessor: Rope, typ: PType) = let typ = getUniqueType(typ) for i in countup(0, sonsLen(typ) - 1): genTraverseProc(c, ropecg(c.p.module, "$1.Field$2", accessor, i.rope), typ.sons[i]) - of tyRef, tyString, tySequence: + of tyRef: lineCg(p, cpsStmts, c.visitorFrmt, accessor) + of tySequence: + if tfHasAsgn notin typ.flags: + lineCg(p, cpsStmts, c.visitorFrmt, accessor) + elif containsGarbageCollectedRef(typ.lastSon): + # destructor based seqs are themselves not traced but their data is, if + # they contain a GC'ed type: + genTraverseProcSeq(c, accessor, typ) + of tyString: + if tfHasAsgn notin typ.flags: + lineCg(p, cpsStmts, c.visitorFrmt, accessor) of tyProc: if typ.callConv == ccClosure: lineCg(p, cpsStmts, c.visitorFrmt, ropecg(c.p.module, "$1.ClE_0", accessor)) @@ -107,8 +117,11 @@ proc genTraverseProcSeq(c: TTraversalClosure, accessor: Rope, typ: PType) = var i: TLoc getTemp(p, getSysType(c.p.module.g.graph, unknownLineInfo(), tyInt), i) let oldCode = p.s(cpsStmts) - lineF(p, cpsStmts, "for ($1 = 0; $1 < ($2 ? $2->$3 : 0); $1++) {$n", - [i.r, accessor, lenField(c.p)]) + var a: TLoc + a.r = accessor + + lineF(p, cpsStmts, "for ($1 = 0; $1 < $2; $1++) {$n", + [i.r, lenExpr(c.p, a)]) let oldLen = p.s(cpsStmts).len genTraverseProc(c, "$1$3[$2]" % [accessor, i.r, dataField(c.p)], typ.sons[0]) if p.s(cpsStmts).len == oldLen: diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index a16255f6e..59fbfc3e1 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -282,7 +282,7 @@ proc getSimpleTypeDesc(m: BModule, typ: PType): Rope = of tyString: case detectStrVersion(m) of 2: - discard cgsym(m, "string") + discard cgsym(m, "NimStringV2") result = typeNameOrLiteral(m, typ, "NimStringV2") else: discard cgsym(m, "NimStringDesc") @@ -324,6 +324,10 @@ proc getForwardStructFormat(m: BModule): string = if m.compileToCpp: result = "$1 $2;$n" else: result = "typedef $1 $2 $2;$n" +proc seqStar(m: BModule): string = + if m.config.selectedGC == gcDestructors: result = "" + else: result = "*" + proc getTypeForward(m: BModule, typ: PType; sig: SigHash): Rope = result = cacheGetType(m.forwTypeCache, sig) if result != nil: return @@ -355,8 +359,11 @@ proc getTypeDescWeak(m: BModule; t: PType; check: var IntSet): Rope = result = getTypeForward(m, t, hashType(t)) pushType(m, t) of tySequence: - result = getTypeForward(m, t, hashType(t)) & "*" - pushType(m, t) + if m.config.selectedGC == gcDestructors: + result = getTypeDescAux(m, t, check) + else: + result = getTypeForward(m, t, hashType(t)) & seqStar(m) + pushType(m, t) else: result = getTypeDescAux(m, t, check) @@ -487,7 +494,7 @@ proc genRecordFieldsAux(m: BModule, n: PNode, if fieldType.kind == tyArray and tfUncheckedArray in fieldType.flags: addf(result, "$1 $2[SEQ_DECL_SIZE];$n", [getTypeDescAux(m, fieldType.elemType, check), sname]) - elif fieldType.kind in {tySequence, tyOpt}: + elif fieldType.kind == tySequence and m.config.selectedGC != gcDestructors: # we need to use a weak dependency here for trecursive_table. addf(result, "$1 $2;$n", [getTypeDescWeak(m, field.loc.t, check), sname]) elif field.bitsize != 0: @@ -601,6 +608,15 @@ proc resolveStarsInCppType(typ: PType, idx, stars: int): PType = result = if result.kind == tyGenericInst: result.sons[1] else: result.elemType +proc getSeqPayloadType(m: BModule; t: PType): Rope = + result = getTypeForward(m, t, hashType(t)) & "_Content" + when false: + var check = initIntSet() + # XXX remove this duplication: + appcg(m, m.s[cfsSeqTypes], + "struct $2_Content { NI cap; void* allocator; $1 data[SEQ_DECL_SIZE]; };$n", + [getTypeDescAux(m, t.sons[0], check), result]) + proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope = # returns only the type's name var t = origTyp.skipTypes(irrelevantForBackend) @@ -641,7 +657,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope = of tySequence: # no restriction! We have a forward declaration for structs let name = getTypeForward(m, et, hashType et) - result = name & "*" & star + result = name & seqStar(m) & star m.typeCache[sig] = result pushType(m, et) else: @@ -705,20 +721,29 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope = [structOrUnion(t), result]) m.forwTypeCache[sig] = result assert(cacheGetType(m.typeCache, sig) == nil) - m.typeCache[sig] = result & "*" + m.typeCache[sig] = result & seqStar(m) if not isImportedType(t): if skipTypes(t.sons[0], typedescInst).kind != tyEmpty: const cppSeq = "struct $2 : #TGenericSeq {$n" cSeq = "struct $2 {$n" & " #TGenericSeq Sup;$n" - appcg(m, m.s[cfsSeqTypes], - (if m.compileToCpp: cppSeq else: cSeq) & - " $1 data[SEQ_DECL_SIZE];$n" & + if m.config.selectedGC == gcDestructors: + appcg(m, m.s[cfsTypes], + "typedef struct{ NI cap;void* allocator;$1 data[SEQ_DECL_SIZE];}$2_Content;$n" & + "struct $2 {$n" & + " NI len; $2_Content* p;$n" & "};$n", [getTypeDescAux(m, t.sons[0], check), result]) + else: + appcg(m, m.s[cfsSeqTypes], + (if m.compileToCpp: cppSeq else: cSeq) & + " $1 data[SEQ_DECL_SIZE];$n" & + "};$n", [getTypeDescAux(m, t.sons[0], check), result]) + elif m.config.selectedGC == gcDestructors: + internalError(m.config, "cannot map the empty seq type to a C type") else: result = rope("TGenericSeq") - add(result, "*") + add(result, seqStar(m)) of tyArray: var n: BiggestInt = lengthOrd(m.config, t) if n <= 0: n = 1 # make an array of at least one element @@ -1177,7 +1202,13 @@ proc genTypeInfo(m: BModule, t: PType; info: TLineInfo): Rope = else: let x = fakeClosureType(m, t.owner) genTupleInfo(m, x, x, result, info) - of tySequence, tyRef, tyOptAsRef: + of tySequence: + if tfHasAsgn notin t.flags: + genTypeInfoAux(m, t, t, result, info) + if m.config.selectedGC >= gcMarkAndSweep: + let markerProc = genTraverseProc(m, origType, sig) + addf(m.s[cfsTypeInit3], "$1.marker = $2;$n", [result, markerProc]) + of tyRef, tyOptAsRef: genTypeInfoAux(m, t, t, result, info) if m.config.selectedGC >= gcMarkAndSweep: let markerProc = genTraverseProc(m, origType, sig) diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 01a930de6..2cb431ff9 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -230,22 +230,31 @@ proc getTempName(m: BModule): Rope = result = m.tmpBase & rope(m.labels) inc m.labels +proc rdLoc(a: TLoc): Rope = + # 'read' location (deref if indirect) + result = a.r + if lfIndirect in a.flags: result = "(*$1)" % [result] + proc lenField(p: BProc): Rope = result = rope(if p.module.compileToCpp: "len" else: "Sup.len") +proc lenExpr(p: BProc; a: TLoc): Rope = + if p.config.selectedGc == gcDestructors: + result = rdLoc(a) & ".len" + else: + result = "($1 ? $1->$2 : 0)" % [rdLoc(a), lenField(p)] + proc dataField(p: BProc): Rope = - result = rope"->data" + if p.config.selectedGc == gcDestructors: + result = rope".p->data" + else: + result = rope"->data" include ccgliterals include ccgtypes # ------------------------------ Manager of temporaries ------------------ -proc rdLoc(a: TLoc): Rope = - # 'read' location (deref if indirect) - result = a.r - if lfIndirect in a.flags: result = "(*$1)" % [result] - proc addrLoc(conf: ConfigRef; a: TLoc): Rope = result = a.r if lfIndirect notin a.flags and mapType(conf, a.t) != ctArray: @@ -325,7 +334,9 @@ proc resetLoc(p: BProc, loc: var TLoc) = proc constructLoc(p: BProc, loc: TLoc, isTemp = false) = let typ = loc.t - if not isComplexValueType(typ): + if p.config.selectedGc == gcDestructors and skipTypes(typ, abstractInst).kind in {tyString, tySequence}: + linefmt(p, cpsStmts, "$1.len = 0; $1.p = NIM_NIL;$n", rdLoc(loc)) + elif not isComplexValueType(typ): linefmt(p, cpsStmts, "$1 = ($2)0;$n", rdLoc(loc), getTypeDesc(p.module, typ)) else: diff --git a/compiler/commands.nim b/compiler/commands.nim index 1e5384f16..f7c8cf9f2 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -215,7 +215,8 @@ proc testCompileOptionArg*(conf: ConfigRef; switch, arg: string, info: TLineInfo of "refc": result = conf.selectedGC == gcRefc of "v2": result = conf.selectedGC == gcV2 of "markandsweep": result = conf.selectedGC == gcMarkAndSweep - of "generational": result = conf.selectedGC == gcGenerational + of "generational": result = false + of "destructors": result = conf.selectedGC == gcDestructors of "go": result = conf.selectedGC == gcGo of "none": result = conf.selectedGC == gcNone of "stack", "regions": result = conf.selectedGC == gcRegions @@ -436,9 +437,9 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; of "markandsweep": conf.selectedGC = gcMarkAndSweep defineSymbol(conf.symbols, "gcmarkandsweep") - of "generational": - conf.selectedGC = gcGenerational - defineSymbol(conf.symbols, "gcgenerational") + of "destructors": + conf.selectedGC = gcDestructors + defineSymbol(conf.symbols, "gcdestructors") of "go": conf.selectedGC = gcGo defineSymbol(conf.symbols, "gogc") diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim index ba1c42a74..0cf264ac3 100644 --- a/compiler/condsyms.nim +++ b/compiler/condsyms.nim @@ -74,6 +74,7 @@ proc initDefines*(symbols: StringTableRef) = defineSymbol("nimNoZeroTerminator") defineSymbol("nimNotNil") defineSymbol("nimVmExportFixed") + defineSymbol("nimNewRuntime") defineSymbol("nimIncrSeqV3") defineSymbol("nimAshr") defineSymbol("nimNoNilSeqs") diff --git a/compiler/destroyer.nim b/compiler/destroyer.nim index 0395728c2..bd735560a 100644 --- a/compiler/destroyer.nim +++ b/compiler/destroyer.nim @@ -100,12 +100,12 @@ Rule Pattern Transformed into finally: `=destroy`(x) 1.2 var x: sink T; stmts var x: sink T; stmts; ensureEmpty(x) 2 x = f() `=sink`(x, f()) -3 x = lastReadOf z `=sink`(x, z) +3 x = lastReadOf z `=sink`(x, z); wasMoved(z) 4.1 y = sinkParam `=sink`(y, sinkParam) 4.2 x = y `=`(x, y) # a copy 5.1 f_sink(g()) f_sink(g()) 5.2 f_sink(y) f_sink(copy y); # copy unless we can see it's the last read -5.3 f_sink(move y) f_sink(y); reset(y) # explicit moves empties 'y' +5.3 f_sink(move y) f_sink(y); wasMoved(y) # explicit moves empties 'y' 5.4 f_noSink(g()) var tmp = bitwiseCopy(g()); f(tmp); `=destroy`(tmp) Remarks: Rule 1.2 is not yet implemented because ``sink`` is currently @@ -258,8 +258,10 @@ proc registerDropBit(c: var Con; s: PSym) = c.toDropBit[s.id] = result # generate: # if not sinkParam_AliveBit: `=destroy`(sinkParam) - c.destroys.add newTree(nkIfStmt, - newTree(nkElifBranch, newSymNode result, genDestroy(c, s.typ, newSymNode s))) + let t = s.typ.skipTypes({tyGenericInst, tyAlias, tySink}) + if t.destructor != nil: + c.destroys.add newTree(nkIfStmt, + newTree(nkElifBranch, newSymNode result, genDestroy(c, t, newSymNode s))) proc p(n: PNode; c: var Con): PNode @@ -282,6 +284,11 @@ proc destructiveMoveSink(n: PNode; c: var Con): PNode = newIntTypeNode(nkIntLit, 0, getSysType(c.graph, n.info, tyBool))) result.add n +proc genMagicCall(n: PNode; c: var Con; magicname: string; m: TMagic): PNode = + result = newNodeI(nkCall, n.info) + result.add(newSymNode(createMagic(c.graph, magicname, m))) + result.add n + proc moveOrCopy(dest, ri: PNode; c: var Con): PNode = if ri.kind in constrExprs: result = genSink(c, ri.typ, dest) @@ -290,8 +297,10 @@ proc moveOrCopy(dest, ri: PNode; c: var Con): PNode = recurse(ri, ri2) result.add ri2 elif ri.kind == nkSym and isHarmlessVar(ri.sym, c): - result = genSink(c, ri.typ, dest) - result.add p(ri, c) + # Rule 3: `=sink`(x, z); wasMoved(z) + var snk = genSink(c, ri.typ, dest) + snk.add p(ri, c) + result = newTree(nkStmtList, snk, genMagicCall(ri, c, "wasMoved", mWasMoved)) elif ri.kind == nkSym and isSinkParam(ri.sym): result = genSink(c, ri.typ, dest) result.add destructiveMoveSink(ri, c) @@ -313,11 +322,9 @@ proc passCopyToSink(n: PNode; c: var Con): PNode = result.add newTree(nkAsgn, tmp, p(n, c)) result.add tmp -proc genReset(n: PNode; c: var Con): PNode = - result = newNodeI(nkCall, n.info) - result.add(newSymNode(createMagic(c.graph, "reset", mReset))) - # The mReset builtin does not take the address: - result.add n +proc genWasMoved(n: PNode; c: var Con): PNode = + # The mWasMoved builtin does not take the address. + result = genMagicCall(n, c, "wasMoved", mWasMoved) proc destructiveMoveVar(n: PNode; c: var Con): PNode = # generate: (let tmp = v; reset(v); tmp) @@ -334,7 +341,7 @@ proc destructiveMoveVar(n: PNode; c: var Con): PNode = add(v, vpart) result.add v - result.add genReset(n, c) + result.add genWasMoved(n, c) result.add tempAsNode proc p(n: PNode; c: var Con): PNode = diff --git a/compiler/options.nim b/compiler/options.nim index 1873d9d5b..04b14c65f 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -104,8 +104,8 @@ type cmdJsonScript # compile a .json build file TStringSeq* = seq[string] TGCMode* = enum # the selected GC - gcNone, gcBoehm, gcGo, gcRegions, gcMarkAndSweep, gcRefc, - gcV2, gcGenerational + gcNone, gcBoehm, gcGo, gcRegions, gcMarkAndSweep, gcDestructors, + gcRefc, gcV2 IdeCmd* = enum ideNone, ideSug, ideCon, ideDef, ideUse, ideDus, ideChk, ideMod, @@ -373,7 +373,7 @@ proc isDefined*(conf: ConfigRef; symbol: string): bool = else: discard proc importantComments*(conf: ConfigRef): bool {.inline.} = conf.cmd in {cmdDoc, cmdIdeTools} -proc usesNativeGC*(conf: ConfigRef): bool {.inline.} = conf.selectedGC >= gcRefc +proc usesWriteBarrier*(conf: ConfigRef): bool {.inline.} = conf.selectedGC >= gcRefc template compilationCachePresent*(conf: ConfigRef): untyped = conf.symbolFiles in {v2Sf, writeOnlySf} diff --git a/compiler/semasgn.nim b/compiler/semasgn.nim index a05ef7a28..8b2e20efc 100644 --- a/compiler/semasgn.nim +++ b/compiler/semasgn.nim @@ -197,13 +197,10 @@ proc liftBodyAux(c: var TLiftCtx; t: PType; body, x, y: PNode) = case t.kind of tyNone, tyEmpty, tyVoid: discard of tyPointer, tySet, tyBool, tyChar, tyEnum, tyInt..tyUInt64, tyCString, - tyPtr, tyString, tyRef, tyOpt: + tyPtr, tyRef, tyOpt: defaultOp(c, t, body, x, y) - of tyArray, tySequence: + of tyArray: if {tfHasAsgn, tfUncheckedArray} * t.flags == {tfHasAsgn}: - if t.kind == tySequence: - # XXX add 'nil' handling here - body.add newSeqCall(c.c, x, y) let i = declareCounter(c, body, firstOrd(c.c.config, t)) let whileLoop = genWhileLoop(c, i, x) let elemType = t.lastSon @@ -213,6 +210,27 @@ proc liftBodyAux(c: var TLiftCtx; t: PType; body, x, y: PNode) = body.add whileLoop else: defaultOp(c, t, body, x, y) + of tySequence: + # note that tfHasAsgn is propagated so we need the check on + # 'selectedGC' here to determine if we have the new runtime. + if c.c.config.selectedGC == gcDestructors: + discard considerOverloadedOp(c, t, body, x, y) + elif tfHasAsgn in t.flags: + body.add newSeqCall(c.c, x, y) + let i = declareCounter(c, body, firstOrd(c.c.config, t)) + let whileLoop = genWhileLoop(c, i, x) + let elemType = t.lastSon + liftBodyAux(c, elemType, whileLoop.sons[1], x.at(i, elemType), + y.at(i, elemType)) + addIncStmt(c, whileLoop.sons[1], i) + body.add whileLoop + else: + defaultOp(c, t, body, x, y) + of tyString: + if tfHasAsgn in t.flags: + discard considerOverloadedOp(c, t, body, x, y) + else: + defaultOp(c, t, body, x, y) of tyObject, tyDistinct: if not considerOverloadedOp(c, t, body, x, y): if t.sons[0] != nil: diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 170ac799e..3a1278137 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1056,8 +1056,8 @@ proc checkForMetaFields(c: PContext; n: PNode) = case t.kind of tySequence, tySet, tyArray, tyOpenArray, tyVar, tyLent, tyPtr, tyRef, tyProc, tyGenericInvocation, tyGenericInst, tyAlias, tySink: - let start = int ord(t.kind in {tyGenericInvocation, tyGenericInst}) - for i in start ..< t.sons.len: + let start = ord(t.kind in {tyGenericInvocation, tyGenericInst}) + for i in start ..< t.len: checkMeta(t.sons[i]) else: checkMeta(t) @@ -1376,7 +1376,7 @@ proc semOverride(c: PContext, s: PSym, n: PNode) = if obj.kind in {tyGenericBody, tyGenericInst}: obj = obj.lastSon elif obj.kind == tyGenericInvocation: obj = obj.sons[0] else: break - if obj.kind in {tyObject, tyDistinct}: + if obj.kind in {tyObject, tyDistinct, tySequence, tyString}: if obj.destructor.isNil: obj.destructor = s else: @@ -1398,7 +1398,7 @@ proc semOverride(c: PContext, s: PSym, n: PNode) = if t.kind == tyGenericBody: t = t.lastSon elif t.kind == tyGenericInvocation: t = t.sons[0] else: break - if t.kind in {tyObject, tyDistinct, tyEnum}: + if t.kind in {tyObject, tyDistinct, tyEnum, tySequence, tyString}: if t.deepCopy.isNil: t.deepCopy = s else: localError(c.config, n.info, errGenerated, @@ -1427,7 +1427,7 @@ proc semOverride(c: PContext, s: PSym, n: PNode) = elif objB.kind in {tyGenericInvocation, tyGenericInst}: objB = objB.sons[0] else: break - if obj.kind in {tyObject, tyDistinct} and sameType(obj, objB): + if obj.kind in {tyObject, tyDistinct, tySequence, tyString} and sameType(obj, objB): let opr = if s.name.s == "=": addr(obj.assignment) else: addr(obj.sink) if opr[].isNil: opr[] = s @@ -1592,7 +1592,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, if proto.typ.callConv != s.typ.callConv or proto.typ.flags < s.typ.flags: localError(c.config, n.sons[pragmasPos].info, errPragmaOnlyInHeaderOfProcX % ("'" & proto.name.s & "' from " & c.config$proto.info)) - if sfForward notin proto.flags: + if sfForward notin proto.flags and proto.magic == mNone: wrongRedefinition(c, n.info, proto.name.s) excl(proto.flags, sfForward) closeScope(c) # close scope with wrong parameter symbols @@ -1658,7 +1658,8 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, openScope(c) n.sons[bodyPos] = semGenericStmt(c, n.sons[bodyPos]) closeScope(c) - fixupInstantiatedSymbols(c, s) + if s.magic == mNone: + fixupInstantiatedSymbols(c, s) if s.kind == skMethod: semMethodPrototype(c, s, n) if sfImportc in s.flags: # so we just ignore the body after semantic checking for importc: diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 99f2cf20d..1669a7707 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -145,9 +145,7 @@ proc semSet(c: PContext, n: PNode, prev: PType): PType = localError(c.config, n.info, errXExpectsOneTypeParam % "set") addSonSkipIntLit(result, errorType(c)) -proc semContainer(c: PContext, n: PNode, kind: TTypeKind, kindStr: string, - prev: PType): PType = - result = newOrPrevType(kind, prev, c) +proc semContainerArg(c: PContext; n: PNode, kindStr: string; result: PType) = if sonsLen(n) == 2: var base = semTypeNode(c, n.sons[1], nil) if base.kind == tyVoid: @@ -157,6 +155,11 @@ proc semContainer(c: PContext, n: PNode, kind: TTypeKind, kindStr: string, localError(c.config, n.info, errXExpectsOneTypeParam % kindStr) addSonSkipIntLit(result, errorType(c)) +proc semContainer(c: PContext, n: PNode, kind: TTypeKind, kindStr: string, + prev: PType): PType = + result = newOrPrevType(kind, prev, c) + semContainerArg(c, n, kindStr, result) + proc semVarargs(c: PContext, n: PNode, prev: PType): PType = result = newOrPrevType(tyVarargs, prev, c) if sonsLen(n) == 2 or sonsLen(n) == 3: @@ -1507,7 +1510,24 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType = of mRange: result = semRange(c, n, prev) of mSet: result = semSet(c, n, prev) of mOrdinal: result = semOrdinal(c, n, prev) - of mSeq: result = semContainer(c, n, tySequence, "seq", prev) + of mSeq: + if c.config.selectedGc == gcDestructors: + let s = c.graph.sysTypes[tySequence] + assert s != nil + assert prev == nil + result = copyType(s, s.owner, keepId=false) + # XXX figure out why this has children already... + result.sons.setLen 0 + result.n = nil + if c.config.selectedGc == gcDestructors: + result.flags = {tfHasAsgn} + else: + result.flags = {} + semContainerArg(c, n, "seq", result) + else: + result = semContainer(c, n, tySequence, "seq", prev) + if c.config.selectedGc == gcDestructors: + incl result.flags, tfHasAsgn of mOpt: result = semContainer(c, n, tyOpt, "opt", prev) of mVarargs: result = semVarargs(c, n, prev) of mTypeDesc, mTypeTy: @@ -1687,6 +1707,9 @@ proc processMagicType(c: PContext, m: PSym) = of mString: setMagicType(c.config, m, tyString, c.config.target.ptrSize) rawAddSon(m.typ, getSysType(c.graph, m.info, tyChar)) + when false: + if c.config.selectedGc == gcDestructors: + incl m.typ.flags, tfHasAsgn of mCstring: setMagicType(c.config, m, tyCString, c.config.target.ptrSize) rawAddSon(m.typ, getSysType(c.graph, m.info, tyChar)) @@ -1726,6 +1749,10 @@ proc processMagicType(c: PContext, m: PSym) = setMagicType(c.config, m, tySet, 0) of mSeq: setMagicType(c.config, m, tySequence, 0) + if c.config.selectedGc == gcDestructors: + incl m.typ.flags, tfHasAsgn + assert c.graph.sysTypes[tySequence] == nil + c.graph.sysTypes[tySequence] = m.typ of mOpt: setMagicType(c.config, m, tyOpt, 0) of mOrdinal: diff --git a/compiler/transf.nim b/compiler/transf.nim index 3a276dc38..84297aa6a 100644 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -1050,8 +1050,8 @@ proc transformStmt*(g: ModuleGraph; module: PSym, n: PNode): PNode = when useEffectSystem: trackTopLevelStmt(g, module, result) #if n.info ?? "temp.nim": # echo renderTree(result, {renderIds}) - if c.needsDestroyPass: - result = injectDestructorCalls(g, module, result) + #if c.needsDestroyPass: + # result = injectDestructorCalls(g, module, result) incl(result.flags, nfTransf) proc transformExpr*(g: ModuleGraph; module: PSym, n: PNode): PNode = @@ -1063,6 +1063,6 @@ proc transformExpr*(g: ModuleGraph; module: PSym, n: PNode): PNode = liftDefer(c, result) # expressions are not to be injected with destructor calls as that # the list of top level statements needs to be collected before. - if c.needsDestroyPass: - result = injectDestructorCalls(g, module, result) + #if c.needsDestroyPass: + # result = injectDestructorCalls(g, module, result) incl(result.flags, nfTransf) diff --git a/compiler/types.nim b/compiler/types.nim index 80624502c..674819bc5 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -278,6 +278,8 @@ proc analyseObjectWithTypeField(t: PType): TTypeFieldResult = proc isGCRef(t: PType): bool = result = t.kind in GcTypeKinds or (t.kind == tyProc and t.callConv == ccClosure) + if result and t.kind in {tyString, tySequence} and tfHasAsgn in t.flags: + result = false proc containsGarbageCollectedRef*(typ: PType): bool = # returns true if typ contains a reference, sequence or string (all the @@ -1339,14 +1341,23 @@ proc computeSizeAux(conf: ConfigRef; typ: PType, a: var BiggestInt): BiggestInt if typ.callConv == ccClosure: result = 2 * conf.target.ptrSize else: result = conf.target.ptrSize a = conf.target.ptrSize - of tyString, tyNil: + of tyString: + if tfHasAsgn in typ.flags: + result = conf.target.ptrSize * 2 + else: + result = conf.target.ptrSize + of tyNil: result = conf.target.ptrSize a = result of tyCString, tySequence, tyPtr, tyRef, tyVar, tyLent, tyOpenArray: let base = typ.lastSon if base == typ or (base.kind == tyTuple and base.size==szIllegalRecursion): result = szIllegalRecursion - else: result = conf.target.ptrSize + else: + if typ.kind == tySequence and tfHasAsgn in typ.flags: + result = conf.target.ptrSize * 2 + else: + result = conf.target.ptrSize a = result of tyArray: let elemSize = computeSizeAux(conf, typ.sons[1], a) |