Skip to content

Commit 7f82549

Browse files
committed
free globals
1 parent 2866f7e commit 7f82549

4 files changed

Lines changed: 38 additions & 3 deletions

File tree

src/backend/compiler.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1+
import * as types from '../frontend/types.js'
12
import { tag } from '../frontend/types.js'
23
import * as mods from '../frontend/modules.js'
34
import { Interpreter, interpreter } from '../middle/interpret.js'
45
import { MatchMethods } from '../middle/patterns.js'
56
import { Inferred, Redirect } from '../middle/abstract.js'
67
import { Expanded } from '../middle/expand.js'
78
import { Inlined, opcount } from '../middle/inline.js'
8-
import { refcounts } from '../middle/refcount.js'
9+
import { isreftype, release_method, refcounts } from '../middle/refcount.js'
910
import * as wasm from './wasm.js'
1011
import { irfunc } from '../wasm/ir.js'
1112
import { reset, pipe, Caching, withtime } from '../utils/cache.js'
@@ -14,6 +15,7 @@ import { binding, options } from '../utils/options.js'
1415
import { assigned_globals } from '../frontend/lower.js'
1516
import { core } from '../middle/primitives.js'
1617
import { only } from '../utils/map.js'
18+
import { Def } from '../dwarf/index.js'
1719

1820
export { Pipeline, Compiler, emit, withEmit }
1921

@@ -57,10 +59,26 @@ class Pipeline implements Caching {
5759
for (const [b, T] of gs) this.sources.set(b, T)
5860
if (gs.size > 0) reset(this)
5961
if (opcount(ir) <= 0) return
62+
if (em instanceof wasm.BatchEmitter) this.destructors(gs, em)
6063
wir = wasm.lowerwasm_globals(wir, this.wasm.globals)
6164
em.emit(fns, irfunc(name, wir))
6265
}
6366

67+
private destructors(gs: Map<mods.Binding, types.Type>, em: wasm.BatchEmitter) {
68+
for (const [b, T] of gs) {
69+
if (!isreftype(T)) continue
70+
const ids = this.wasm.globals.get(b)
71+
const fname = `__release_global.${ids[0]}`
72+
const code = mods.MIR(Def(fname))
73+
const value = code.push(code.stmt(mods.xglobal(b), { type: T }))
74+
code.return(code.push(code.stmt(new mods.Invoke(release_method, [value]), { type: types.nil })))
75+
const wir = this.wasm.lower(code)
76+
const func = irfunc(fname, wir)
77+
const calls = wasm.calltree(this.wasm, func)
78+
em.destructor(calls, func)
79+
}
80+
}
81+
6482
async loadcommon(emitter: wasm.Emitter, load: Loader): Promise<this> {
6583
const emit = (m: mods.Method) => {
6684
reset(this)
@@ -117,6 +135,7 @@ class Compiler {
117135
await withEmit(emitIR, async () => { await reload(this.pipe.sources, src, this.load) })
118136
reset(this.pipe)
119137
if (options().memcheck && em.funcs.some(fn => fn.name.startsWith('common.malloc!'))) {
138+
em.main.push(...em.destructors)
120139
const checks = this.pipe.defs.methods(tag('common.checkAllocations'))
121140
this.pipe.emit(only(checks), em)
122141
}

src/backend/wasm.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,12 +263,14 @@ type Emitter = { emit(calls: Map<string, wasm.Func | WSig>, func: wasm.Func): vo
263263
class BatchEmitter implements Emitter {
264264
tables: Tables
265265
main: string[]
266+
destructors: string[]
266267
seen: Set<string>
267268
funcs: wasm.Func[]
268269
imports: wasm.Import[]
269270
constructor(tables: Tables) {
270271
this.tables = tables
271272
this.main = []
273+
this.destructors = []
272274
this.seen = new Set()
273275
this.funcs = []
274276
this.imports = []
@@ -277,6 +279,7 @@ class BatchEmitter implements Emitter {
277279
clone(): BatchEmitter {
278280
const em = new BatchEmitter(this.tables)
279281
em.main = [...this.main]
282+
em.destructors = [...this.destructors]
280283
em.seen = new Set(this.seen)
281284
em.funcs = [...this.funcs]
282285
em.imports = [...this.imports]
@@ -303,6 +306,12 @@ class BatchEmitter implements Emitter {
303306
for (const f of this.tables.funcs) this.emitName(calls, f)
304307
this.main.push(func.name)
305308
}
309+
310+
destructor(calls: Map<string, wasm.Func | WSig>, func: wasm.Func) {
311+
this.emitFunc(calls, func)
312+
for (const f of this.tables.funcs) this.emitName(calls, f)
313+
this.destructors.push(func.name)
314+
}
306315
}
307316

308317
const refTable = 'jsrefs'

src/middle/expand.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,14 @@ import * as types from '../frontend/types.js'
2222
import { Type } from '../frontend/types.js'
2323
import { ValueType, sizeof as wsizeof } from '../wasm/wasm.js'
2424
import * as wasm from '../wasm/wasm.js'
25-
import { MIR, Method, Value, xstring, Global, Invoke, Wasm } from '../frontend/modules.js'
25+
import { MIR, Method, Value, xstring, Global, Invoke, Wasm, xwasm } from '../frontend/modules.js'
2626
import { Def } from '../dwarf/index.js'
2727
import { Inferred, Redirect, Sig, sig as resolveSig } from './abstract.js'
2828
import { wasmPartials } from '../backend/wasm.js'
2929
import { isEqual } from '../utils/isEqual.js'
3030
import { Pipe, Block, Fragment, expr, Branch, Val, Anno, unreachable, asType } from '../utils/ir.js'
3131
import { some } from '../utils/map.js'
3232
import { xcall, xtuple } from '../frontend/lower.js'
33-
import { xwasm } from '../frontend/modules.js'
3433
import { isreftype } from './refcount.js'
3534
import { partial_part, getIntValue, nparts, constValue, partial_set, copy_method } from './primitives.js'
3635
import { inlinePrimitive, InvokeSt, outlinePrimitive, primitive } from './prim_map.js'

test/language.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -935,6 +935,14 @@ test('array values', async () => {
935935
`, { output: '[[1], [1, 2], [1, 2, 3]]' })
936936
})
937937

938+
test('global list release', async () => {
939+
await rv(`
940+
xs = collect(range(1, widen(3)))
941+
xs = collect(range(1, widen(3)))
942+
test length(xs) == 3
943+
`)
944+
})
945+
938946
test('allocs', async () => {
939947
await rv(`
940948
test (allocs 1 + 2) == 0

0 commit comments

Comments
 (0)