turn destructors into finalizers
This commit is contained in:
parent
683c60e2fd
commit
9b31f67859
3 changed files with 40 additions and 6 deletions
|
|
@ -1135,9 +1135,21 @@ proc rawGenNew(p: BProc, a: TLoc, sizeExpr: Rope) =
|
||||||
if sizeExpr.isNil:
|
if sizeExpr.isNil:
|
||||||
sizeExpr = "sizeof($1)" %
|
sizeExpr = "sizeof($1)" %
|
||||||
[getTypeDesc(p.module, bt)]
|
[getTypeDesc(p.module, bt)]
|
||||||
let args = [getTypeDesc(p.module, typ),
|
|
||||||
genTypeInfo(p.module, typ, a.lode.info),
|
let ti = genTypeInfo(p.module, typ, a.lode.info)
|
||||||
sizeExpr]
|
if bt.destructor != nil:
|
||||||
|
# the prototype of a destructor is ``=destroy(x: var T)`` and that of a
|
||||||
|
# finalizer is: ``proc (x: ref T) {.nimcall.}``. We need to check the calling
|
||||||
|
# convention at least:
|
||||||
|
if bt.destructor.typ == nil or bt.destructor.typ.callConv != ccDefault:
|
||||||
|
localError(p.module.config, a.lode.info,
|
||||||
|
"the destructor that is turned into a finalizer needs " &
|
||||||
|
"to have the 'nimcall' calling convention")
|
||||||
|
var f: TLoc
|
||||||
|
initLocExpr(p, newSymNode(bt.destructor), f)
|
||||||
|
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 usesNativeGC(p.config):
|
||||||
# use newObjRC1 as an optimization
|
# use newObjRC1 as an optimization
|
||||||
if canFormAcycle(a.t):
|
if canFormAcycle(a.t):
|
||||||
|
|
|
||||||
22
tests/destructor/turn_destroy_into_finalizer.nim
Normal file
22
tests/destructor/turn_destroy_into_finalizer.nim
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
discard """
|
||||||
|
output: '''true'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
type
|
||||||
|
Foo = object
|
||||||
|
id: int
|
||||||
|
|
||||||
|
var destroyed: int
|
||||||
|
|
||||||
|
proc `=destroy`(x: var Foo) =
|
||||||
|
#echo "finally ", x.id
|
||||||
|
inc destroyed
|
||||||
|
|
||||||
|
proc main =
|
||||||
|
var r: ref Foo
|
||||||
|
for i in 1..50_000:
|
||||||
|
new(r)
|
||||||
|
r.id = i
|
||||||
|
echo destroyed > 30_000
|
||||||
|
|
||||||
|
main()
|
||||||
|
|
@ -6,16 +6,16 @@ when defined(GC_setMaxPause):
|
||||||
GC_setMaxPause 2_000
|
GC_setMaxPause 2_000
|
||||||
|
|
||||||
type
|
type
|
||||||
TTestObj = object of TObject
|
TTestObj = object of RootObj
|
||||||
x: string
|
x: string
|
||||||
|
|
||||||
proc MakeObj(): TTestObj =
|
proc makeObj(): TTestObj =
|
||||||
result.x = "Hello"
|
result.x = "Hello"
|
||||||
|
|
||||||
for i in 1 .. 1_000_000:
|
for i in 1 .. 1_000_000:
|
||||||
when defined(gcMarkAndSweep) or defined(boehmgc):
|
when defined(gcMarkAndSweep) or defined(boehmgc):
|
||||||
GC_fullcollect()
|
GC_fullcollect()
|
||||||
var obj = MakeObj()
|
var obj = makeObj()
|
||||||
if getOccupiedMem() > 300_000: quit("still a leak!")
|
if getOccupiedMem() > 300_000: quit("still a leak!")
|
||||||
# echo GC_getstatistics()
|
# echo GC_getstatistics()
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue