diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index 249c65fe99..13463cf357 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -56,7 +56,7 @@ type TProc{.final.} = object procDef: PNode prc: PSym - data: PRope + locals: PRope options: TOptions module: BModule g: PGlobals @@ -955,8 +955,8 @@ proc genSym(p: var TProc, n: PNode, r: var TCompRes) = elif not p.g.generatedSyms.containsOrIncl(s.id): var r2: TCompRes genProc(p, s, r2) - #app(p.g.code, mergeStmt(r2)) - app(r.com, mergeStmt(r2)) + app(p.locals, mergeStmt(r2)) + #app(r.com, mergeStmt(r2)) else: if s.loc.r == nil: InternalError(n.info, "symbol has no generated name: " & s.name.s) @@ -1454,16 +1454,17 @@ proc genProc(oldProc: var TProc, prc: PSym, r: var TCompRes) = resultAsgn = nil name = mangleName(prc) header = generateHeader(p, prc.typ) - if (prc.typ.sons[0] != nil) and sfPure notin prc.flags: + if prc.typ.sons[0] != nil and sfPure notin prc.flags: resultSym = prc.ast.sons[resultPos].sym - resultAsgn = ropef("var $1 = $2;$n", [mangleName(resultSym), + resultAsgn = ropef("var $# = $#;$n", [mangleName(resultSym), createVar(p, resultSym.typ, isIndirect(resultSym))]) gen(p, prc.ast.sons[resultPos], a) if a.com != nil: appf(returnStmt, "$1;$n", [a.com]) - returnStmt = ropef("return $1;$n", [a.res]) + returnStmt = ropef("return $#;$n", [a.res]) genStmt(p, prc.getBody, r) - r.com = ropef("function $1($2) {$n$3$4$5}$n", - [name, header, resultAsgn, genProcBody(p, prc, r), returnStmt]) + r.com = ropef("function $#($#) {$n$#$#$#$#}$n", + [name, header, p.locals, resultAsgn, + genProcBody(p, prc, r), returnStmt]) r.res = nil #if gVerbosity >= 3: # echo "END generated code for: " & prc.name.s @@ -1515,9 +1516,10 @@ proc genStmt(p: var TProc, n: PNode, r: var TCompRes) = nkFromStmt, nkTemplateDef, nkMacroDef, nkPragma: nil of nkProcDef, nkMethodDef, nkConverterDef: var s = n.sons[namePos].sym - if {sfExportc, sfCompilerProc} * s.flags == {sfExportc}: - var r2: TCompRes - genSym(p, n.sons[namePos], r2) + if {sfExportc, sfCompilerProc} * s.flags == {sfExportc}: + #var r2: TCompRes + genSym(p, n.sons[namePos], r) + r.res = nil of nkGotoState, nkState: internalError(n.info, "first class iterators not implemented") else: @@ -1630,7 +1632,7 @@ proc myProcess(b: PPassContext, n: PNode): PNode = if m.module == nil: InternalError(n.info, "myProcess") initProc(p, globals, m, nil, m.module.options) genModule(p, n, r) - app(p.g.code, p.data) + app(p.g.code, p.locals) app(p.g.code, mergeStmt(r)) proc myClose(b: PPassContext, n: PNode): PNode = diff --git a/tests/gc/closureleak.nim b/tests/gc/closureleak.nim new file mode 100644 index 0000000000..c3eeac07b1 --- /dev/null +++ b/tests/gc/closureleak.nim @@ -0,0 +1,33 @@ +discard """ + outputsub: "true" +""" + +from strutils import join + +type + TFoo * = object + id: int + func: proc(){.closure.} +var foo_counter = 0 +var alive_foos = newseq[int](0) + +proc free*(some: ref TFoo) = + #echo "Tfoo #", some.id, " freed" + alive_foos.del alive_foos.find(some.id) +proc newFoo*(): ref TFoo = + new result, free + + result.id = foo_counter + alive_foos.add result.id + inc foo_counter + +for i in 0 .. <10: + discard newFoo() + +for i in 0 .. <10: + let f = newFoo() + f.func = proc = + echo f.id + +gc_fullcollect() +echo alive_foos.len <= 2 diff --git a/tests/js/test2.nim b/tests/js/test2.nim new file mode 100644 index 0000000000..1342ed15d9 --- /dev/null +++ b/tests/js/test2.nim @@ -0,0 +1,23 @@ +discard """ + cmd: "nimrod js --hints:on -r $# $#" + output: '''foo +js 3.14''' +""" + +# This file tests the JavaScript generator + +# #335 +proc foo() = + var bar = "foo" + proc baz() = + echo bar + baz() +foo() + +# #376 +when not defined(JS): + proc foo(val: float): string = "no js " & $val +else: + proc foo(val: float): string = "js " & $val + +echo foo(3.14) diff --git a/tests/specials.nim b/tests/specials.nim index 173ebd2f80..30bb6f4237 100644 --- a/tests/specials.nim +++ b/tests/specials.nim @@ -131,6 +131,7 @@ proc runGcTests(r: var TResults, options: string) = test "gcleak3" test "weakrefs" test "cycleleak" + test "closureleak" # ------------------------- threading tests ----------------------------------- diff --git a/todo.txt b/todo.txt index 9b1082a811..de9210314b 100644 --- a/todo.txt +++ b/todo.txt @@ -75,6 +75,7 @@ Concurrency an ``injectLoop`` pragma - 'writes: []' effect; track reads/writes for shared types - use the effect system for static deadlock prevention and race detection +- ``~`` operator for effects - introduce 'noaddr' pragma to prevent taking the address of a location; this is very handy to prevent aliasing of global data