Fix destructor injections for global variables (#11230)

* attach global destructors at end of mainModule
* Add testcase
* Minor cleanup
* Inject topLevelVar temporaries' destructors early
* Fix megatest
This commit is contained in:
Clyybber 2019-05-13 08:28:33 +02:00 • committed by Andreas Rumpf
commit 0c869eaa47
7 changed files with 45 additions and 8 deletions

View file

@ -1963,6 +1963,9 @@ proc myClose(graph: ModuleGraph; b: PPassContext, n: PNode): PNode =
result = n result = n
if b == nil: return if b == nil: return
var m = BModule(b) var m = BModule(b)
if sfMainModule in m.module.flags:
for destructorCall in graph.globalDestructors:
n.add destructorCall
if passes.skipCodegen(m.config, n): return if passes.skipCodegen(m.config, n): return
# if the module is cached, we don't regenerate the main proc # if the module is cached, we don't regenerate the main proc
# nor the dispatchers? But if the dispatchers changed? # nor the dispatchers? But if the dispatchers changed?

View file

@ -316,10 +316,6 @@ proc makePtrType(c: Con, baseType: PType): PType =
result = newType(tyPtr, c.owner) result = newType(tyPtr, c.owner)
addSonSkipIntLit(result, baseType) addSonSkipIntLit(result, baseType)
proc addDestroy(c: var Con; n: PNode) =
# append to front:
c.destroys = newTree(nkStmtList, n, c.destroys)
proc genOp(c: Con; t: PType; kind: TTypeAttachedOp; dest, ri: PNode): PNode = proc genOp(c: Con; t: PType; kind: TTypeAttachedOp; dest, ri: PNode): PNode =
var op = t.attachedOps[kind] var op = t.attachedOps[kind]
@ -738,7 +734,7 @@ proc p(n: PNode; c: var Con): PNode =
c.addTopVar v c.addTopVar v
# make sure it's destroyed at the end of the proc: # make sure it's destroyed at the end of the proc:
if not isUnpackedTuple(it[0].sym): if not isUnpackedTuple(it[0].sym):
c.addDestroy genDestroy(c, v.typ, v) c.destroys.add genDestroy(c, v.typ, v)
if ri.kind != nkEmpty: if ri.kind != nkEmpty:
let r = moveOrCopy(v, ri, c) let r = moveOrCopy(v, ri, c)
result.add r result.add r
@ -757,7 +753,7 @@ proc p(n: PNode; c: var Con): PNode =
sinkExpr.add n sinkExpr.add n
result.add sinkExpr result.add sinkExpr
result.add tmp result.add tmp
c.addDestroy genDestroy(c, n.typ, tmp) c.destroys.add genDestroy(c, n.typ, tmp)
else: else:
result = n result = n
of nkAsgn, nkFastAsgn: of nkAsgn, nkFastAsgn:
@ -799,6 +795,19 @@ proc p(n: PNode; c: var Con): PNode =
result = copyNode(n) result = copyNode(n)
recurse(n, result) recurse(n, result)
proc extractDestroysForTemporaries(c: Con, destroys: PNode): PNode =
result = newNodeI(nkStmtList, destroys.info)
for i in 0 ..< destroys.len:
if destroys[i][1][0].sym.kind == skTemp:
result.add destroys[i]
destroys[i] = c.emptyNode
proc reverseDestroys(destroys: PNode) =
var reversed: seq[PNode]
for i in countdown(destroys.len - 1, 0):
reversed.add(destroys[i])
destroys.sons = reversed
proc injectDestructorCalls*(g: ModuleGraph; owner: PSym; n: PNode): PNode = proc injectDestructorCalls*(g: ModuleGraph; owner: PSym; n: PNode): PNode =
if sfGeneratedOp in owner.flags or isInlineIterator(owner): return n if sfGeneratedOp in owner.flags or isInlineIterator(owner): return n
var c: Con var c: Con
@ -821,7 +830,7 @@ proc injectDestructorCalls*(g: ModuleGraph; owner: PSym; n: PNode): PNode =
for i in 1 ..< params.len: for i in 1 ..< params.len:
let param = params[i].sym let param = params[i].sym
if isSinkTypeForParam(param.typ) and hasDestructor(param.typ.skipTypes({tySink})): if isSinkTypeForParam(param.typ) and hasDestructor(param.typ.skipTypes({tySink})):
c.addDestroy genDestroy(c, param.typ.skipTypes({tyGenericInst, tyAlias, tySink}), params[i]) c.destroys.add genDestroy(c, param.typ.skipTypes({tyGenericInst, tyAlias, tySink}), params[i])
#if optNimV2 in c.graph.config.globalOptions: #if optNimV2 in c.graph.config.globalOptions:
# injectDefaultCalls(n, c) # injectDefaultCalls(n, c)
@ -830,6 +839,11 @@ proc injectDestructorCalls*(g: ModuleGraph; owner: PSym; n: PNode): PNode =
if c.topLevelVars.len > 0: if c.topLevelVars.len > 0:
result.add c.topLevelVars result.add c.topLevelVars
if c.destroys.len > 0: if c.destroys.len > 0:
reverseDestroys(c.destroys)
if owner.kind == skModule:
result.add newTryFinally(body, extractDestroysForTemporaries(c, c.destroys))
g.globalDestructors.add c.destroys
else:
result.add newTryFinally(body, c.destroys) result.add newTryFinally(body, c.destroys)
else: else:
result.add body result.add body

View file

@ -71,6 +71,7 @@ type
onDefinition*: proc (graph: ModuleGraph; s: PSym; info: TLineInfo) {.nimcall.} onDefinition*: proc (graph: ModuleGraph; s: PSym; info: TLineInfo) {.nimcall.}
onDefinitionResolveForward*: proc (graph: ModuleGraph; s: PSym; info: TLineInfo) {.nimcall.} onDefinitionResolveForward*: proc (graph: ModuleGraph; s: PSym; info: TLineInfo) {.nimcall.}
onUsage*: proc (graph: ModuleGraph; s: PSym; info: TLineInfo) {.nimcall.} onUsage*: proc (graph: ModuleGraph; s: PSym; info: TLineInfo) {.nimcall.}
globalDestructors*: seq[PNode]
TPassContext* = object of RootObj # the pass's context TPassContext* = object of RootObj # the pass's context
PPassContext* = ref TPassContext PPassContext* = ref TPassContext

View file

@ -0,0 +1,8 @@
type Obj* = object
v*: int
proc `=destroy`(this: var Obj) =
echo "igotdestroyed"
this.v = -1
var test* = Obj(v: 42)

View file

@ -6,6 +6,7 @@ discard """
10 10
destroyed! destroyed!
''' '''
joinable: false
""" """
type type

View file

@ -0,0 +1,9 @@
discard """
cmd: '''nim c --newruntime $file'''
output: '''(v: 42)
igotdestroyed'''
"""
import objFile
echo test

View file

@ -3,6 +3,7 @@ discard """
output: '''5 output: '''5
vseq destroy vseq destroy
''' '''
joinable: false
""" """
type type
opt*[T] = object opt*[T] = object