Skip to content

Commit fafaf42

Browse files
committed
Make an interface around gc.* fwiw
1 parent 3483935 commit fafaf42

File tree

13 files changed

+179
-94
lines changed

13 files changed

+179
-94
lines changed

std/assembly/allocator/arena.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import { AL_MASK, MAX_SIZE_32 } from "../internal/allocator";
1212
var startOffset: usize = (HEAP_BASE + AL_MASK) & ~AL_MASK;
1313
var offset: usize = startOffset;
1414

15+
// Memory allocator interface
16+
1517
@global
1618
export function __memory_allocate(size: usize): usize {
1719
if (size) {
@@ -35,9 +37,7 @@ export function __memory_allocate(size: usize): usize {
3537
}
3638

3739
@global
38-
export function __memory_free(ptr: usize): void {
39-
// nop
40-
}
40+
export function __memory_free(ptr: usize): void { /* nop */ }
4141

4242
@global
4343
export function __memory_reset(): void {

std/assembly/allocator/buddy.ts

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -338,8 +338,9 @@ function lower_bucket_limit(bucket: usize): u32 {
338338
return 1;
339339
}
340340

341-
@global
342-
export function __memory_allocate(request: usize): usize {
341+
// Memory allocator interface
342+
343+
@global export function __memory_allocate(request: usize): usize {
343344
var original_bucket: usize, bucket: usize;
344345

345346
/*
@@ -473,8 +474,7 @@ export function __memory_allocate(request: usize): usize {
473474
return 0;
474475
}
475476

476-
@global
477-
export function __memory_free(ptr: usize): void {
477+
@global export function __memory_free(ptr: usize): void {
478478
var bucket: usize, i: usize;
479479

480480
/*
@@ -538,8 +538,3 @@ export function __memory_free(ptr: usize): void {
538538
*/
539539
list_push(buckets$get(bucket), changetype<List>(ptr_for_node(i, bucket)));
540540
}
541-
542-
@global
543-
export function __memory_reset(): void {
544-
unreachable();
545-
}

std/assembly/allocator/emscripten.ts

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,12 @@
1111
declare function _malloc(size: usize): usize;
1212
declare function _free(ptr: usize): void;
1313

14-
@global
15-
export function __memory_allocate(size: usize): usize {
14+
// Memory allocator interface
15+
16+
@global export function __memory_allocate(size: usize): usize {
1617
return _malloc(size);
1718
}
1819

19-
@global
20-
export function __memory_free(ptr: usize): void {
20+
@global export function __memory_free(ptr: usize): void {
2121
_free(ptr);
2222
}
23-
24-
@global
25-
export function __memory_reset(): void {
26-
unreachable();
27-
}

std/assembly/allocator/system.ts

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,12 @@
1010
declare function malloc(size: usize): usize;
1111
declare function free(ptr: usize): void;
1212

13-
@global
14-
export function __memory_allocate(size: usize): usize {
13+
// Memory allocator interface
14+
15+
@global export function __memory_allocate(size: usize): usize {
1516
return malloc(size);
1617
}
1718

18-
@global
19-
export function __memory_free(ptr: usize): void {
19+
@global export function __memory_free(ptr: usize): void {
2020
free(ptr);
2121
}
22-
23-
@global
24-
export function __memory_reset(): void {
25-
unreachable();
26-
}

std/assembly/allocator/tlsf.ts

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -433,11 +433,10 @@ function fls<T>(word: T): T {
433433
/** Reference to the initialized {@link Root} structure, once initialized. */
434434
var ROOT: Root = changetype<Root>(0);
435435

436-
// External interface
436+
// Memory allocator interface
437437

438438
/** Allocates a chunk of memory. */
439-
@global
440-
export function __memory_allocate(size: usize): usize {
439+
@global export function __memory_allocate(size: usize): usize {
441440

442441
// initialize if necessary
443442
var root = ROOT;
@@ -490,8 +489,7 @@ export function __memory_allocate(size: usize): usize {
490489
}
491490

492491
/** Frees the chunk of memory at the specified address. */
493-
@global
494-
export function __memory_free(data: usize): void {
492+
@global export function __memory_free(data: usize): void {
495493
if (data) {
496494
let root = ROOT;
497495
if (root) {
@@ -504,7 +502,6 @@ export function __memory_free(data: usize): void {
504502
}
505503
}
506504

507-
@global
508-
export function __memory_reset(): void {
505+
@global export function __memory_reset(): void {
509506
unreachable();
510507
}

std/assembly/collector/itcm.ts

Lines changed: 44 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,6 @@ import {
1111
MAX_SIZE_32
1212
} from "../internal/allocator";
1313

14-
import {
15-
__gc_iterate_roots
16-
} from "../builtins";
17-
1814
// ╒═══════════════ Managed object layout (32-bit) ════════════════╕
1915
// 3 2 1
2016
// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 bits
@@ -145,7 +141,7 @@ var set2: ManagedObject;
145141
var iter: ManagedObject;
146142

147143
/** Performs a single step according to the current state. */
148-
function gc_step(): void {
144+
function step(): void {
149145
var obj: ManagedObject;
150146
switch (state) {
151147
case State.INIT: {
@@ -158,7 +154,7 @@ function gc_step(): void {
158154
}
159155
case State.IDLE: {
160156
// start by marking roots
161-
__gc_iterate_roots(function mark_root(ref: usize): void {
157+
gc.iterateRoots(function mark_root(ref: usize): void {
162158
if (ref) {
163159
let obj = changetype<ManagedObject>(ref - ManagedObject.SIZE);
164160
obj.makeBlack();
@@ -202,42 +198,50 @@ function gc_step(): void {
202198
}
203199
}
204200

205-
/** Garbage collector interface. */
206-
@global
207-
export namespace gc {
208-
209-
/** Allocates a managed object. */
210-
export function alloc(
211-
size: usize,
212-
visitFn: (ref: usize) => void
213-
): usize {
214-
assert(size <= MAX_SIZE_32 - ManagedObject.SIZE);
215-
var obj = changetype<ManagedObject>(memory.allocate(ManagedObject.SIZE + size));
216-
obj.makeWhite();
217-
obj.visitFn = visitFn;
218-
set1.insert(obj);
219-
return changetype<usize>(obj) + ManagedObject.SIZE;
220-
}
201+
@inline function refToObj(ref: usize): ManagedObject {
202+
return changetype<ManagedObject>(ref - ManagedObject.SIZE);
203+
}
221204

222-
/** Visits a reachable object. Called from the visitFn functions. */
223-
export function visit(obj: ManagedObject): void {
224-
if (state == State.SWEEP) return;
225-
if (obj.isWhite) obj.makeGray();
226-
}
205+
@inline function objToRef(obj: ManagedObject): usize {
206+
return changetype<usize>(obj) + ManagedObject.SIZE;
207+
}
227208

228-
/** References a managed child object from its parent object. */
229-
export function ref(parent: ManagedObject, child: ManagedObject): void {
230-
if (parent.isBlack && child.isWhite) parent.makeGray();
231-
}
209+
// Garbage collector interface
210+
211+
/** Allocates a managed object. */
212+
@global export function __gc_allocate(
213+
size: usize,
214+
visitFn: (ref: usize) => void
215+
): usize {
216+
assert(size <= MAX_SIZE_32 - ManagedObject.SIZE);
217+
var obj = changetype<ManagedObject>(memory.allocate(ManagedObject.SIZE + size));
218+
obj.makeWhite();
219+
obj.visitFn = visitFn;
220+
set1.insert(obj);
221+
return objToRef(obj);
222+
}
232223

233-
/** Performs a full garbage collection cycle. */
234-
export function collect(): void {
235-
// begin collecting if not yet collecting
236-
switch (state) {
237-
case State.INIT:
238-
case State.IDLE: gc_step();
239-
}
240-
// finish the cycle
241-
while (state != State.IDLE) gc_step();
224+
/** Marks a reachable object. Called from the visitFn functions. */
225+
@global export function __gc_mark(ref: usize): void {
226+
var obj = refToObj(ref);
227+
if (state == State.SWEEP) return;
228+
if (obj.isWhite) obj.makeGray();
229+
}
230+
231+
/** Links a managed child object to its parent object. */
232+
@global export function __gc_link(parentRef: usize, childRef: usize): void {
233+
var parent = refToObj(parentRef);
234+
var child = refToObj(childRef);
235+
if (parent.isBlack && child.isWhite) parent.makeGray();
236+
}
237+
238+
/** Performs a full garbage collection cycle. */
239+
@global export function __gc_collect(): void {
240+
// begin collecting if not yet collecting
241+
switch (state) {
242+
case State.INIT:
243+
case State.IDLE: step();
242244
}
245+
// finish the cycle
246+
while (state != State.IDLE) step();
243247
}

std/assembly/gc.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,27 @@ export namespace gc {
22

33
@builtin export declare function iterateRoots(fn: (ref: usize) => void): void; // tslint:disable-line
44

5+
export function allocate(size: usize, visitFn: (ref: usize) => void): usize {
6+
if (isDefined(__gc_allocate)) return __gc_allocate(size, visitFn); // tslint:disable-line
7+
WARNING("Calling 'gc.allocate' requires a garbage collector to be present.");
8+
return <usize>unreachable();
9+
}
10+
11+
export function mark(ref: usize): void {
12+
if (isDefined(__gc_mark)) return __gc_mark(ref); // tslint:disable-line
13+
WARNING("Calling 'gc.mark' requires a garbage collector to be present.");
14+
unreachable();
15+
}
16+
17+
export function link(parentRef: usize, childRef: usize): void {
18+
if (isDefined(__gc_link)) return __gc_link(parentRef, childRef); // tslint:disable-line
19+
WARNING("Calling 'gc.link' requires a garbage collector to be present.");
20+
unreachable();
21+
}
22+
23+
export function collect(): void {
24+
if (isDefined(__gc_collect)) return __gc_collect(); // tslint:disable-line
25+
WARNING("Calling 'gc.collect' requires a garbage collector to be present.");
26+
unreachable();
27+
}
528
}

std/assembly/index.d.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,20 @@ declare namespace memory {
348348
export function reset(): void;
349349
}
350350

351+
/** Garbage collector operations. */
352+
declare namespace gc {
353+
/** Calls the specified function with every reference within the root set. */
354+
export function iterateRoots(fn: (ref: usize) => void): void;
355+
/** Allocates a managed object identified by its visitor function. */
356+
export function allocate(size: usize, visitFn: (ref: usize) => void): usize;
357+
/** Marks a managed object as reachable. */
358+
export function mark(ref: usize): void;
359+
/** Links a managed child with its parent. */
360+
export function link(parentRef: usize, childRef: usize): void;
361+
/** Performs a full garbage collection cycle. */
362+
export function collect(): void;
363+
}
364+
351365
/** Table operations. */
352366
declare namespace table {
353367
/** Copies elements from a passive element segment to a table. */

tests/binaryen/const-expr.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
var binaryen = require("binaryen");
2+
3+
var mod = new binaryen.Module();
4+
5+
var addType = mod.addFunctionType("iii", binaryen.i32, [ binaryen.i32, binaryen.i32 ]);
6+
mod.addFunction("add", addType, [],
7+
mod.i32.add(
8+
mod.get_local(0, binaryen.i32),
9+
mod.get_local(1, binaryen.i32)
10+
)
11+
);
12+
mod.addFunctionExport("add", "add");
13+
14+
var testType = mod.addFunctionType("i", binaryen.i32, []);
15+
mod.addFunction("test", testType, [],
16+
mod.call("add", [
17+
mod.i32.const(1),
18+
mod.i32.const(2)
19+
], binaryen.i32)
20+
);
21+
mod.addFunctionExport("test", "test");
22+
23+
binaryen.setOptimizeLevel(4);
24+
binaryen.setShrinkLevel(0);
25+
binaryen.setDebugInfo(false);
26+
mod.runPasses(["precompute"]);
27+
if (!mod.validate())
28+
console.log("-> does not validate");
29+
console.log(mod.emitText());

tests/binaryen/const-expr.wat

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
(module
2+
(type $iii (func (param i32 i32) (result i32)))
3+
(type $i (func (result i32)))
4+
(export "add" (func $add))
5+
(export "test" (func $test))
6+
(func $add (; 0 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
7+
(i32.add
8+
(get_local $0)
9+
(get_local $1)
10+
)
11+
)
12+
(func $test (; 1 ;) (type $i) (result i32)
13+
(call $add
14+
(i32.const 1)
15+
(i32.const 2)
16+
)
17+
)
18+
)
19+

tests/compiler/std/gc.optimized.wat

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@
167167
(get_local $1)
168168
)
169169
)
170-
(func $~lib/collector/itcm/gc.alloc (; 7 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
170+
(func $~lib/collector/itcm/__gc_allocate (; 7 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
171171
(local $2 i32)
172172
(if
173173
(i32.gt_u
@@ -178,8 +178,8 @@
178178
(call $~lib/env/abort
179179
(i32.const 0)
180180
(i32.const 8)
181-
(i32.const 214)
182-
(i32.const 4)
181+
(i32.const 216)
182+
(i32.const 2)
183183
)
184184
(unreachable)
185185
)
@@ -207,7 +207,13 @@
207207
(i32.const 16)
208208
)
209209
)
210-
(func $start (; 8 ;) (type $v)
210+
(func $~lib/gc/gc.allocate (; 8 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
211+
(call $~lib/collector/itcm/__gc_allocate
212+
(get_local $0)
213+
(get_local $1)
214+
)
215+
)
216+
(func $start (; 9 ;) (type $v)
211217
(set_global $~lib/allocator/arena/startOffset
212218
(i32.const 80)
213219
)
@@ -218,7 +224,7 @@
218224
(i32.const 0)
219225
)
220226
(set_global $std/gc/obj
221-
(call $~lib/collector/itcm/gc.alloc
227+
(call $~lib/gc/gc.allocate
222228
(i32.const 4)
223229
(i32.const 0)
224230
)

0 commit comments

Comments
 (0)