destructors: we are cooking now
This commit is contained in:
parent
fab75fbaf1
commit
6e6a9a721f
9 changed files with 73 additions and 43 deletions
|
|
@ -1808,3 +1808,6 @@ template getBody*(s: PSym): PNode = s.ast[bodyPos]
|
||||||
|
|
||||||
template detailedInfo*(sym: PSym): string =
|
template detailedInfo*(sym: PSym): string =
|
||||||
sym.name.s
|
sym.name.s
|
||||||
|
|
||||||
|
proc isInlineIterator*(s: PSym): bool {.inline.} =
|
||||||
|
s.kind == skIterator and s.typ.callConv != ccClosure
|
||||||
|
|
|
||||||
|
|
@ -745,12 +745,13 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
|
||||||
conf.cppDefine(arg)
|
conf.cppDefine(arg)
|
||||||
of "newruntime":
|
of "newruntime":
|
||||||
expectNoArg(conf, switch, arg, pass, info)
|
expectNoArg(conf, switch, arg, pass, info)
|
||||||
doAssert(conf != nil)
|
if pass in {passCmd2, passPP}:
|
||||||
incl(conf.features, destructor)
|
doAssert(conf != nil)
|
||||||
incl(conf.globalOptions, optNimV2)
|
incl(conf.features, destructor)
|
||||||
defineSymbol(conf.symbols, "nimV2")
|
incl(conf.globalOptions, optNimV2)
|
||||||
conf.selectedGC = gcDestructors
|
defineSymbol(conf.symbols, "nimV2")
|
||||||
defineSymbol(conf.symbols, "gcdestructors")
|
conf.selectedGC = gcDestructors
|
||||||
|
defineSymbol(conf.symbols, "gcdestructors")
|
||||||
of "stylecheck":
|
of "stylecheck":
|
||||||
case arg.normalize
|
case arg.normalize
|
||||||
of "off": conf.globalOptions = conf.globalOptions - {optStyleHint, optStyleError}
|
of "off": conf.globalOptions = conf.globalOptions - {optStyleHint, optStyleError}
|
||||||
|
|
|
||||||
|
|
@ -456,7 +456,7 @@ proc pArg(arg: PNode; c: var Con; isSink: bool): PNode =
|
||||||
result.add arg[0]
|
result.add arg[0]
|
||||||
for i in 1..<arg.len:
|
for i in 1..<arg.len:
|
||||||
result.add pArg(arg[i], c, i < L and parameters[i].kind == tySink)
|
result.add pArg(arg[i], c, i < L and parameters[i].kind == tySink)
|
||||||
elif arg.kind in {nkBracket, nkObjConstr, nkTupleConstr, nkBracket, nkCharLit..nkFloat128Lit}:
|
elif arg.kind in {nkBracket, nkObjConstr, nkTupleConstr, nkBracket, nkCharLit..nkTripleStrLit}:
|
||||||
discard "object construction to sink parameter: nothing to do"
|
discard "object construction to sink parameter: nothing to do"
|
||||||
result = arg
|
result = arg
|
||||||
elif arg.kind == nkSym and isSinkParam(arg.sym):
|
elif arg.kind == nkSym and isSinkParam(arg.sym):
|
||||||
|
|
@ -616,7 +616,21 @@ proc moveOrCopy(dest, ri: PNode; c: var Con): PNode =
|
||||||
else:
|
else:
|
||||||
result = genCopy(c, dest.typ, dest, ri)
|
result = genCopy(c, dest.typ, dest, ri)
|
||||||
result.add p(ri, c)
|
result.add p(ri, c)
|
||||||
|
of nkHiddenSubConv, nkHiddenStdConv:
|
||||||
|
let harmless = ri[1].kind in (nkCallKinds + {nkSym, nkTupleConstr, nkObjConstr,
|
||||||
|
nkBracket, nkBracketExpr, nkNilLit})
|
||||||
|
if harmless:
|
||||||
|
result = moveOrCopy(dest, ri[1], c)
|
||||||
|
var b = newNodeIT(ri.kind, ri.info, ri.typ)
|
||||||
|
b.add ri[0] # add empty node
|
||||||
|
let L = result.len-1
|
||||||
|
b.add result[L]
|
||||||
|
result[L] = b
|
||||||
|
else:
|
||||||
|
result = genCopy(c, dest.typ, dest, ri)
|
||||||
|
result.add p(ri, c)
|
||||||
else:
|
else:
|
||||||
|
# XXX At least string literals can be moved?
|
||||||
result = genCopy(c, dest.typ, dest, ri)
|
result = genCopy(c, dest.typ, dest, ri)
|
||||||
result.add p(ri, c)
|
result.add p(ri, c)
|
||||||
|
|
||||||
|
|
@ -725,7 +739,7 @@ proc injectDestructorCalls*(g: ModuleGraph; owner: PSym; n: PNode): PNode =
|
||||||
when defined(nimDebugDestroys):
|
when defined(nimDebugDestroys):
|
||||||
if owner.name.s == "main":
|
if owner.name.s == "main":
|
||||||
echo "injecting into ", n
|
echo "injecting into ", n
|
||||||
if sfGeneratedOp in owner.flags: return n
|
if sfGeneratedOp in owner.flags or isInlineIterator(owner): return n
|
||||||
var c: Con
|
var c: Con
|
||||||
c.owner = owner
|
c.owner = owner
|
||||||
c.destroys = newNodeI(nkStmtList, n.info)
|
c.destroys = newNodeI(nkStmtList, n.info)
|
||||||
|
|
|
||||||
|
|
@ -309,13 +309,14 @@ proc seqOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||||
proc strOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
proc strOp(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||||
case c.kind
|
case c.kind
|
||||||
of attachedAsgn, attachedDeepCopy:
|
of attachedAsgn, attachedDeepCopy:
|
||||||
|
body.add callCodegenProc(c.graph, "nimAsgnStrV2", c.info, genAddr(c.graph, x), y)
|
||||||
# we generate:
|
# we generate:
|
||||||
# setLen(dest, y.len)
|
# setLen(dest, y.len)
|
||||||
# var i = 0
|
# var i = 0
|
||||||
# while i < y.len: dest[i] = y[i]; inc(i)
|
# while i < y.len: dest[i] = y[i]; inc(i)
|
||||||
# This is usually more efficient than a destroy/create pair.
|
# This is usually more efficient than a destroy/create pair.
|
||||||
body.add setLenStrCall(c.graph, x, y)
|
#body.add setLenStrCall(c.graph, x, y)
|
||||||
forallElements(c, t, body, x, y)
|
#forallElements(c, t, body, x, y)
|
||||||
of attachedSink:
|
of attachedSink:
|
||||||
let moveCall = genBuiltin(c.graph, mMove, "move", x)
|
let moveCall = genBuiltin(c.graph, mMove, "move", x)
|
||||||
moveCall.add y
|
moveCall.add y
|
||||||
|
|
@ -473,8 +474,11 @@ proc liftBodyAux(c: var TLiftCtx; t: PType; body, x, y: PNode) =
|
||||||
tyTypeDesc, tyGenericInvocation, tyForward:
|
tyTypeDesc, tyGenericInvocation, tyForward:
|
||||||
#internalError(c.graph.config, c.info, "assignment requested for type: " & typeToString(t))
|
#internalError(c.graph.config, c.info, "assignment requested for type: " & typeToString(t))
|
||||||
discard
|
discard
|
||||||
|
of tyVar, tyLent:
|
||||||
|
if c.kind != attachedDestructor:
|
||||||
|
liftBodyAux(c, lastSon(t), body, x, y)
|
||||||
of tyOrdinal, tyRange, tyInferred,
|
of tyOrdinal, tyRange, tyInferred,
|
||||||
tyGenericInst, tyStatic, tyVar, tyLent, tyAlias, tySink:
|
tyGenericInst, tyStatic, tyAlias, tySink:
|
||||||
liftBodyAux(c, lastSon(t), body, x, y)
|
liftBodyAux(c, lastSon(t), body, x, y)
|
||||||
|
|
||||||
proc newProcType(info: TLineInfo; owner: PSym): PType =
|
proc newProcType(info: TLineInfo; owner: PSym): PType =
|
||||||
|
|
@ -650,7 +654,7 @@ proc createTypeBoundOps*(c: PContext; orig: PType; info: TLineInfo) =
|
||||||
orig.assignment = canon.assignment
|
orig.assignment = canon.assignment
|
||||||
orig.sink = canon.sink
|
orig.sink = canon.sink
|
||||||
|
|
||||||
#if not isTrival(orig.destructor):
|
if not isTrival(orig.destructor):
|
||||||
#or not isTrival(orig.assignment) or
|
#or not isTrival(orig.assignment) or
|
||||||
# not isTrival(orig.sink):
|
# not isTrival(orig.sink):
|
||||||
# orig.flags.incl tfHasAsgn
|
orig.flags.incl tfHasAsgn
|
||||||
|
|
|
||||||
|
|
@ -772,6 +772,8 @@ proc transformCall(c: PTransf, n: PNode): PTransNode =
|
||||||
elif magic == mProcCall:
|
elif magic == mProcCall:
|
||||||
# but do not change to its dispatcher:
|
# but do not change to its dispatcher:
|
||||||
result = transformSons(c, n[1])
|
result = transformSons(c, n[1])
|
||||||
|
elif magic == mStrToStr:
|
||||||
|
result = transform(c, n[1])
|
||||||
else:
|
else:
|
||||||
let s = transformSons(c, n).PNode
|
let s = transformSons(c, n).PNode
|
||||||
# bugfix: check after 'transformSons' if it's still a method call:
|
# bugfix: check after 'transformSons' if it's still a method call:
|
||||||
|
|
|
||||||
|
|
@ -26,14 +26,6 @@ hash of ``package & "." & module & "." & name`` to save space.
|
||||||
]#
|
]#
|
||||||
|
|
||||||
type
|
type
|
||||||
TNimNode {.compilerProc.} = object # to keep the code generator simple
|
|
||||||
DestructorProc = proc (p: pointer) {.nimcall, benign.}
|
|
||||||
TNimType {.compilerProc.} = object
|
|
||||||
destructor: pointer
|
|
||||||
size: int
|
|
||||||
name: cstring
|
|
||||||
PNimType = ptr TNimType
|
|
||||||
|
|
||||||
RefHeader = object
|
RefHeader = object
|
||||||
rc: int # the object header is now a single RC field.
|
rc: int # the object header is now a single RC field.
|
||||||
# we could remove it in non-debug builds but this seems
|
# we could remove it in non-debug builds but this seems
|
||||||
|
|
|
||||||
|
|
@ -177,17 +177,15 @@ proc nimAsgnStrV2(a: var NimStringV2, b: NimStringV2) {.compilerRtl.} =
|
||||||
frees(a)
|
frees(a)
|
||||||
a.len = b.len
|
a.len = b.len
|
||||||
a.p = b.p
|
a.p = b.p
|
||||||
elif isLiteral(a) or a.p.cap < b.len:
|
|
||||||
let allocator = if a.p != nil and a.p.allocator != nil: a.p.allocator else: getLocalAllocator()
|
|
||||||
# we have to allocate the 'cap' here, consider
|
|
||||||
# 'let y = newStringOfCap(); var x = y'
|
|
||||||
# on the other hand... These get turned into moves now.
|
|
||||||
a.p = cast[ptr NimStrPayload](allocator.alloc(allocator, contentSize(b.len)))
|
|
||||||
a.p.allocator = allocator
|
|
||||||
a.p.cap = b.len
|
|
||||||
a.len = b.len
|
|
||||||
copyMem(unsafeAddr a.p.data[0], unsafeAddr b.p.data[0], b.len+1)
|
|
||||||
else:
|
else:
|
||||||
|
if isLiteral(a) or a.p.cap < b.len:
|
||||||
|
let allocator = if a.p != nil and a.p.allocator != nil: a.p.allocator else: getLocalAllocator()
|
||||||
|
# we have to allocate the 'cap' here, consider
|
||||||
|
# 'let y = newStringOfCap(); var x = y'
|
||||||
|
# on the other hand... These get turned into moves now.
|
||||||
|
frees(a)
|
||||||
|
a.p = cast[ptr NimStrPayload](allocator.alloc(allocator, contentSize(b.len)))
|
||||||
|
a.p.allocator = allocator
|
||||||
|
a.p.cap = b.len
|
||||||
a.len = b.len
|
a.len = b.len
|
||||||
# reuse the storage we already have:
|
|
||||||
copyMem(unsafeAddr a.p.data[0], unsafeAddr b.p.data[0], b.len+1)
|
copyMem(unsafeAddr a.p.data[0], unsafeAddr b.p.data[0], b.len+1)
|
||||||
|
|
|
||||||
|
|
@ -2971,6 +2971,30 @@ proc compiles*(x: untyped): bool {.magic: "Compiles", noSideEffect, compileTime.
|
||||||
when not defined(js) and not defined(nimscript):
|
when not defined(js) and not defined(nimscript):
|
||||||
include "system/ansi_c"
|
include "system/ansi_c"
|
||||||
|
|
||||||
|
when not defined(js):
|
||||||
|
{.push stackTrace:off.}
|
||||||
|
|
||||||
|
when hasThreadSupport and hostOS != "standalone":
|
||||||
|
const insideRLocksModule = false
|
||||||
|
include "system/syslocks"
|
||||||
|
include "system/threadlocalstorage"
|
||||||
|
|
||||||
|
when defined(nimV2):
|
||||||
|
type
|
||||||
|
TNimNode {.compilerProc.} = object # to keep the code generator simple
|
||||||
|
DestructorProc = proc (p: pointer) {.nimcall, benign.}
|
||||||
|
TNimType {.compilerProc.} = object
|
||||||
|
destructor: pointer
|
||||||
|
size: int
|
||||||
|
name: cstring
|
||||||
|
PNimType = ptr TNimType
|
||||||
|
|
||||||
|
when defined(gcDestructors) and not defined(nimscript):
|
||||||
|
include "core/strs"
|
||||||
|
include "core/seqs"
|
||||||
|
|
||||||
|
{.pop.}
|
||||||
|
|
||||||
when not declared(sysFatal):
|
when not declared(sysFatal):
|
||||||
include "system/fatal"
|
include "system/fatal"
|
||||||
|
|
||||||
|
|
@ -3481,15 +3505,6 @@ when not defined(JS): #and not defined(nimscript):
|
||||||
when defined(endb):
|
when defined(endb):
|
||||||
proc endbStep()
|
proc endbStep()
|
||||||
|
|
||||||
when hasThreadSupport and hostOS != "standalone":
|
|
||||||
const insideRLocksModule = false
|
|
||||||
include "system/syslocks"
|
|
||||||
include "system/threadlocalstorage"
|
|
||||||
|
|
||||||
when defined(gcDestructors) and not defined(nimscript):
|
|
||||||
include "core/strs"
|
|
||||||
include "core/seqs"
|
|
||||||
|
|
||||||
when declared(newSeq):
|
when declared(newSeq):
|
||||||
proc cstringArrayToSeq*(a: cstringArray, len: Natural): seq[string] =
|
proc cstringArrayToSeq*(a: cstringArray, len: Natural): seq[string] =
|
||||||
## Converts a ``cstringArray`` to a ``seq[string]``. `a` is supposed to be
|
## Converts a ``cstringArray`` to a ``seq[string]``. `a` is supposed to be
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ discard """
|
||||||
output: '''hi
|
output: '''hi
|
||||||
ho
|
ho
|
||||||
ha
|
ha
|
||||||
7 1'''
|
7 7'''
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import allocators
|
import allocators
|
||||||
|
|
@ -75,7 +75,7 @@ iterator interpolatedFragments*(s: string): tuple[kind: InterpolatedKind,
|
||||||
break
|
break
|
||||||
i = j
|
i = j
|
||||||
|
|
||||||
when true:
|
proc other =
|
||||||
let input = "$test{} $this is ${an{ example}} "
|
let input = "$test{} $this is ${an{ example}} "
|
||||||
let expected = @[(ikVar, "test"), (ikStr, "{} "), (ikVar, "this"),
|
let expected = @[(ikVar, "test"), (ikStr, "{} "), (ikVar, "this"),
|
||||||
(ikStr, " is "), (ikExpr, "an{ example}"), (ikStr, " ")]
|
(ikStr, " is "), (ikExpr, "an{ example}"), (ikStr, " ")]
|
||||||
|
|
@ -84,6 +84,7 @@ when true:
|
||||||
doAssert s == expected[i]
|
doAssert s == expected[i]
|
||||||
inc i
|
inc i
|
||||||
|
|
||||||
|
other()
|
||||||
|
|
||||||
#echo s
|
#echo s
|
||||||
let (a, d) = allocCounters()
|
let (a, d) = allocCounters()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue