From d8373622165f9dbdf12eef8c81204f35a376ff76 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Tue, 3 Apr 2018 10:25:20 +0200 Subject: C codegen: preparations for different seq and string implementations --- lib/core/seqs.nim | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'lib/core/seqs.nim') diff --git a/lib/core/seqs.nim b/lib/core/seqs.nim index c32cf3690..02c192851 100644 --- a/lib/core/seqs.nim +++ b/lib/core/seqs.nim @@ -15,11 +15,11 @@ type len, cap: int data: ptr UncheckedArray[T] +const nimSeqVersion {.core.} = 2 + template frees(s) = dealloc(s.data, s.cap * sizeof(T)) # XXX make code memory safe for overflows in '*' -proc nimSeqLiteral[T](x: openArray[T]): seq[T] {.core.} = - seq[T](len: x.len, cap: x.len, data: x) when defined(nimHasTrace): proc `=trace`[T](s: seq[T]; a: Allocator) = @@ -120,7 +120,7 @@ proc `$`*[T](x: seq[T]): string = result = "@[" var firstElement = true for i in 0.. Date: Tue, 17 Jul 2018 13:19:42 +0200 Subject: WIP: strings/seqs based on destructors --- compiler/ast.nim | 1 + compiler/ccgexprs.nim | 20 +++- compiler/ccgliterals.nim | 8 +- compiler/ccgtypes.nim | 39 +++++-- compiler/cgen.nim | 5 +- compiler/destroyer.nim | 25 +++-- compiler/semstmts.nim | 5 +- compiler/types.nim | 13 ++- lib/core/seqs.nim | 236 +++++++++++++++++++++------------------ lib/core/strs.nim | 25 +++-- lib/system.nim | 12 ++ lib/system/jssys.nim | 1 - tests/destructor/tcustomseqs.nim | 7 +- 13 files changed, 248 insertions(+), 149 deletions(-) (limited to 'lib/core/seqs.nim') diff --git a/compiler/ast.nim b/compiler/ast.nim index 6302c21b9..7cc785ad7 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -626,6 +626,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, diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 689e2483e..0d87cc19d 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -1224,8 +1224,14 @@ proc genNewSeq(p: BProc, e: PNode) = var a, b: TLoc initLocExpr(p, e.sons[1], a) initLocExpr(p, e.sons[2], b) - genNewSeqAux(p, a, b.rdLoc) - 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: + genNewSeqAux(p, a, b.rdLoc) + gcUsage(p.config, e) proc genNewSeqOfCap(p: BProc; e: PNode; d: var TLoc) = let seqtype = skipTypes(e.typ, abstractVarRange) @@ -1543,6 +1549,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: TLoc assert(d.k == locNone) var x = e.sons[1] @@ -1561,8 +1570,11 @@ proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) = gcUsage(p.config, e) proc genSetLengthStr(p: BProc, e: PNode, d: var TLoc) = - binaryStmt(p, e, d, "$1 = #setLengthStr($1, $2);$n") - gcUsage(p.config, e) + if p.config.selectedGc == gcDestructors: + binaryStmtAddr(p, e, d, "#setLengthStrV2($1, $2);$n") + else: + binaryStmt(p, e, d, "$1 = #setLengthStr($1, $2);$n") + gcUsage(p.config, e) proc genSwap(p: BProc, e: PNode, d: var TLoc) = # swap(a, b) --> diff --git a/compiler/ccgliterals.nim b/compiler/ccgliterals.nim index cfe71375e..a06e4e5d0 100644 --- a/compiler/ccgliterals.nim +++ b/compiler/ccgliterals.nim @@ -53,16 +53,20 @@ 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", + addf(m.s[cfsData], "static const struct {$n" & + " NI cap; void* allocator; NIM_CHAR[$2] data;$n" & + "} $1 = { $2, NIM_NIL, $3 };$n", [result, rope(len(s)+1), 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", + addf(m.s[cfsData], "static const NimStringV2 $1 = {$2, (NimStrPayload*)&$3};$n", [result, rope(len(n.strVal)+1), pureLit]) else: result = m.tmpBase & rope(id) diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 756711642..ea06544bb 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -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,7 +359,7 @@ 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)) & "*" + result = getTypeForward(m, t, hashType(t)) & seqStar(m) pushType(m, t) else: result = getTypeDescAux(m, t, check) @@ -487,7 +491,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: # 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 +605,14 @@ 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 = + var check = initIntSet() + result = getTypeForward(m, t, hashType(t)) + # 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 +653,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 +717,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" & - "};$n", [getTypeDescAux(m, t.sons[0], check), result]) + if m.config.selectedGC == gcDestructors: + appcg(m, m.s[cfsSeqTypes], + "struct $2_Content { NI cap; void* allocator; $1 data[SEQ_DECL_SIZE];$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 diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 0ca7533d4..180aa4731 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -250,7 +250,10 @@ proc lenExpr(p: BProc; a: TLoc): Rope = 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 diff --git a/compiler/destroyer.nim b/compiler/destroyer.nim index 0395728c2..c2a74edb1 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 @@ -282,6 +282,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 +295,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 +320,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 +339,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/semstmts.nim b/compiler/semstmts.nim index 6ef03456e..781813795 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1553,7 +1553,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 @@ -1619,7 +1619,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/types.nim b/compiler/types.nim index 66807cf97..76d233e8a 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -1335,14 +1335,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) diff --git a/lib/core/seqs.nim b/lib/core/seqs.nim index 02c192851..4327d2352 100644 --- a/lib/core/seqs.nim +++ b/lib/core/seqs.nim @@ -7,133 +7,157 @@ # distribution, for details about the copyright. # -import allocators, typetraits + +import typetraits +# strs already imported allocators for us. ## Default seq implementation used by Nim's core. type - seq*[T] = object - len, cap: int - data: ptr UncheckedArray[T] + NimSeqPayload {.core.}[T] = object + cap: int + region: Allocator + data: UncheckedArray[T] + + NimSeqV2*[T] = object + len: int + p: ptr NimSeqPayload[T] const nimSeqVersion {.core.} = 2 -template frees(s) = dealloc(s.data, s.cap * sizeof(T)) +template payloadSize(cap): int = cap * sizeof(T) + sizeof(int) + sizeof(Allocator) # XXX make code memory safe for overflows in '*' -when defined(nimHasTrace): - proc `=trace`[T](s: seq[T]; a: Allocator) = - for i in 0 ..< s.len: `=trace`(s.data[i], a) +when false: + # this is currently not part of Nim's type bound operators and so it's + # built into the tracing proc generation just like before. + proc `=trace`[T](s: NimSeqV2[T]) = + for i in 0 ..< s.len: `=trace`(s.data[i]) -proc `=destroy`[T](x: var seq[T]) = - if x.data != nil: +proc `=destroy`[T](x: var NimSeqV2[T]) = + var p = x.p + if p != nil: when not supportsCopyMem(T): - for i in 0.. 0: + copyMem(unsafeAddr a.p.data[0], unsafeAddr b.p.data[0], a.len * sizeof(T)) else: for i in 0..= x.cap: resize(x) - result = addr(x.data[x.len]) - inc x.len - -template add*[T](x: var seq[T]; y: T) = - reserveSlot(x)[] = y - -proc shrink*[T](x: var seq[T]; newLen: int) = - assert newLen <= x.len - assert newLen >= 0 + a.p = b.p + +when false: + proc incrSeqV3(s: PGenericSeq, typ: PNimType): PGenericSeq {.compilerProc.} + proc setLengthSeqV2(s: PGenericSeq, typ: PNimType, newLen: int): PGenericSeq {. + compilerRtl.} + proc newSeq(typ: PNimType, len: int): pointer {.compilerRtl.} + + +type + PayloadBase = object + cap: int + region: Allocator + +proc newSeqPayload(cap, elemSize: int): pointer {.compilerRtl.} = + # we have to use type erasure here as Nim does not support generic + # compilerProcs. Oh well, this will all be inlined anyway. + if cap <= 0: + let region = getLocalAllocator() + var p = cast[ptr PayloadBase](region.alloc(region, cap * elemSize + sizeof(int) + sizeof(Allocator))) + p.region = region + p.cap = cap + result = p + else: + result = nil + +proc prepareSeqAdd(len: int; p: pointer; addlen, elemSize: int): pointer {.compilerRtl.} = + if len+addlen <= len: + result = p + elif p == nil: + result = newSeqPayload(len+addlen, elemSize) + else: + # Note: this means we cannot support things that have internal pointers as + # they get reallocated here. This needs to be documented clearly. + var p = cast[ptr PayloadBase](p) + let region = if p.region == nil: getLocalAllocator() else: p.region + let cap = max(resize(p.cap), len+addlen) + var q = cast[ptr PayloadBase](region.realloc(region, p, + sizeof(int) + sizeof(Allocator) + elemSize * p.cap, + sizeof(int) + sizeof(Allocator) + elemSize * cap)) + q.region = region + q.cap = cap + result = q + +proc shrink*[T](x: var seq[T]; newLen: Natural) = + sysAssert newLen <= x.len, "invalid newLen parameter for 'shrink'" when not supportsCopyMem(T): for i in countdown(x.len - 1, newLen - 1): - `=destroy`(x.data[i]) - x.len = newLen - -proc grow*[T](x: var seq[T]; newLen: int; value: T) = - if newLen <= x.len: return - assert newLen >= 0 - if x.cap == 0: x.cap = newLen - else: x.cap = max(newLen, (x.cap * 3) shr 1) - x.data = cast[type(x.data)](realloc(x.data, x.cap * sizeof(T))) - for i in x.len..= x.cap: resize(x) + result = addr(x.data[x.len]) + inc x.len + + template add*[T](x: var NimSeqV2[T]; y: T) = + reserveSlot(x)[] = y + + template `[]`*[T](x: NimSeqV2[T]; i: Natural): T = + assert i < x.len + x.data[i] + + template `[]=`*[T](x: NimSeqV2[T]; i: Natural; y: T) = + assert i < x.len + x.data[i] = y + + proc `@`*[T](elems: openArray[T]): NimSeqV2[T] = + result.cap = elems.len + result.len = elems.len + result.data = cast[type(result.data)](alloc(result.cap * sizeof(T))) + when supportsCopyMem(T): + copyMem(result.data, unsafeAddr(elems[0]), result.cap * sizeof(T)) else: - result.addQuoted(value) - - result.add("]") + for i in 0.. 0: @@ -96,7 +95,7 @@ proc prepareAdd(s: var NimStringV2; addlen: int) {.compilerRtl.} = copyMem(unsafeAddr s.p.data[0], unsafeAddr oldP.data[0], s.len) elif s.len + addlen > s.p.cap: let cap = max(s.len + addlen, resize(s.p.cap)) - s.p = cast[ptr StrContent](s.p.region.realloc(s.p.region, s.p, + s.p = cast[ptr NimStrPayload](s.p.region.realloc(s.p.region, s.p, oldSize = contentSize(s.p.cap), newSize = contentSize(cap))) s.p.cap = cap @@ -112,7 +111,7 @@ proc toNimStr(str: cstring, len: int): NimStringV2 {.compilerProc.} = result = NimStringV2(len: 0, p: nil) else: let region = getLocalAllocator() - var p = cast[ptr StrContent](region.alloc(region, contentSize(len))) + var p = cast[ptr NimStrPayload](region.alloc(region, contentSize(len))) p.region = region p.cap = len if len > 0: @@ -144,7 +143,7 @@ proc rawNewString(space: int): NimStringV2 {.compilerProc.} = result = NimStringV2(len: 0, p: nil) else: let region = getLocalAllocator() - var p = cast[ptr StrContent](region.alloc(region, contentSize(space))) + var p = cast[ptr NimStrPayload](region.alloc(region, contentSize(space))) p.region = region p.cap = space result = NimStringV2(len: 0, p: p) @@ -154,7 +153,15 @@ proc mnewString(len: int): NimStringV2 {.compilerProc.} = result = NimStringV2(len: 0, p: nil) else: let region = getLocalAllocator() - var p = cast[ptr StrContent](region.alloc(region, contentSize(len))) + var p = cast[ptr NimStrPayload](region.alloc(region, contentSize(len))) p.region = region p.cap = len result = NimStringV2(len: len, p: p) + +proc setLengthStrV2(s: var NimStringV2, newLen: int) {.compilerRtl.} = + if newLen > s.len: + prepareAdd(s, newLen - s.len) + else: + s.len = newLen + # this also only works because the destructor + # looks at s.p and not s.len diff --git a/lib/system.nim b/lib/system.nim index 1defe20ee..2f6f45948 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -230,6 +230,17 @@ proc reset*[T](obj: var T) {.magic: "Reset", noSideEffect.} ## resets an object `obj` to its initial (binary zero) value. This needs to ## be called before any possible `object branch transition`:idx:. +when defined(nimNewRuntime): + proc wasMoved*[T](obj: var T) {.magic: "WasMoved", noSideEffect.} = + ## resets an object `obj` to its initial (binary zero) value to signify + ## it was "moved" and to signify its destructor should do nothing and + ## ideally be optimized away. + discard + + proc move*[T](x: var T): T {.magic: "Move", noSideEffect.} = + result = x + wasMoved(x) + type range*{.magic: "Range".}[T] ## Generic type to construct range types. array*{.magic: "Array".}[I, T] ## Generic type to construct @@ -3310,6 +3321,7 @@ when not defined(JS): #and not defined(nimscript): when hasAlloc: when defined(gcDestructors): include "core/strs" + include "core/seqs" else: include "system/sysstr" {.pop.} diff --git a/lib/system/jssys.nim b/lib/system/jssys.nim index 5fff869f0..e500444ea 100644 --- a/lib/system/jssys.nim +++ b/lib/system/jssys.nim @@ -504,7 +504,6 @@ proc chckNilDisp(p: pointer) {.compilerproc.} = if p == nil: sysFatal(NilAccessError, "cannot dispatch; dispatcher is nil") -const ThisIsSystem = true # for hti.nim include "system/hti" proc isFatPointer(ti: PNimType): bool = diff --git a/tests/destructor/tcustomseqs.nim b/tests/destructor/tcustomseqs.nim index 97d7c07b6..83df0053f 100644 --- a/tests/destructor/tcustomseqs.nim +++ b/tests/destructor/tcustomseqs.nim @@ -43,9 +43,10 @@ proc `=destroy`*[T](x: var myseq[T]) = proc `=`*[T](a: var myseq[T]; b: myseq[T]) = if a.data == b.data: return if a.data != nil: - dealloc(a.data) - inc deallocCount - a.data = nil + `=destroy`(a) + #dealloc(a.data) + #inc deallocCount + #a.data = nil a.len = b.len a.cap = b.cap if b.data != nil: -- cgit 1.4.1-2-gfad0 From ef4b755183f6564cc0f35cdf01794626c4e5fe2f Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 27 Jul 2018 18:20:13 +0200 Subject: allows a destructor to be attached to a tyString/tySequence --- compiler/ast.nim | 6 +++--- compiler/semstmts.nim | 10 +++++----- lib/core/seqs.nim | 12 +++++++++--- lib/core/strs.nim | 17 +++++++++++------ 4 files changed, 28 insertions(+), 17 deletions(-) (limited to 'lib/core/seqs.nim') diff --git a/compiler/ast.nim b/compiler/ast.nim index 3870c82ee..a61ac055e 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -1088,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 @@ -1272,7 +1272,7 @@ proc newType*(kind: TTypeKind, owner: PSym): PType = when debugIds: registerId(result) when false: - if result.id == 205734: + if result.id == 76426: echo "KNID ", kind writeStackTrace() diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 781813795..f7d8b6b7b 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -1017,8 +1017,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) @@ -1337,7 +1337,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: @@ -1359,7 +1359,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, @@ -1388,7 +1388,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 diff --git a/lib/core/seqs.nim b/lib/core/seqs.nim index 4327d2352..4dcf6cbbb 100644 --- a/lib/core/seqs.nim +++ b/lib/core/seqs.nim @@ -34,7 +34,8 @@ when false: proc `=trace`[T](s: NimSeqV2[T]) = for i in 0 ..< s.len: `=trace`(s.data[i]) -proc `=destroy`[T](x: var NimSeqV2[T]) = +proc `=destroy`[T](s: var seq[T]) = + var x = cast[ptr NimSeqV2[T]](addr s) var p = x.p if p != nil: when not supportsCopyMem(T): @@ -43,7 +44,10 @@ proc `=destroy`[T](x: var NimSeqV2[T]) = x.p = nil x.len = 0 -proc `=`[T](a: var NimSeqV2[T]; b: NimSeqV2[T]) = +proc `=`[T](x: var seq[T]; y: seq[T]) = + var a = cast[ptr NimSeqV2[T]](addr x) + var b = cast[ptr NimSeqV2[T]](unsafeAddr y) + if a.p == b.p: return `=destroy`(a) a.len = b.len @@ -56,7 +60,9 @@ proc `=`[T](a: var NimSeqV2[T]; b: NimSeqV2[T]) = for i in 0..