diff --git a/std/assembly/gc.ts b/std/assembly/gc.ts
index 4edf24aa..e117ff23 100644
--- a/std/assembly/gc.ts
+++ b/std/assembly/gc.ts
@@ -1,16 +1,48 @@
///
+import { E_NOTIMPLEMENTED } from "./util/error";
+
+// @ts-ignore
+@lazy
+var GC_ROOT = new Set();
+
/** Garbage collector interface. */
export namespace gc {
/** Whether the garbage collector interface is implemented. */
// @ts-ignore: decorator
@lazy
- export const IMPLEMENTED: bool = isDefined(__ref_collect);
+ export const implemented: bool = isDefined(__ref_collect);
/** Performs a full garbage collection cycle. */
export function collect(): void {
if (isDefined(__ref_collect)) __ref_collect();
- else WARNING("missing implementation: gc.collect");
+ else throw new Error(E_NOTIMPLEMENTED);
+ }
+
+ /** Retains a reference, making sure that it doesn't become collected. */
+ export function retain(ref: usize): void {
+ var root = GC_ROOT;
+ if (!root.has(ref)) {
+ root.add(ref);
+ if (implemented) {
+ if (isDefined(__ref_link)) __ref_link(ref, changetype(root));
+ else if (isDefined(__ref_retain)) __ref_retain(ref);
+ else assert(false);
+ }
+ }
+ }
+
+ /** Releases a reference, allowing it to become collected. */
+ export function release(ref: usize): void {
+ var root = GC_ROOT;
+ if (root.has(ref)) {
+ root.delete(ref);
+ if (implemented) {
+ if (isDefined(__ref_link)) __ref_unlink(ref, changetype(root));
+ else if (isDefined(__ref_retain)) __ref_release(ref);
+ else assert(false);
+ }
+ }
}
}
diff --git a/std/assembly/index.d.ts b/std/assembly/index.d.ts
index 68a648d6..67f655cb 100644
--- a/std/assembly/index.d.ts
+++ b/std/assembly/index.d.ts
@@ -974,6 +974,8 @@ declare function bswap16(value: T): T;
/** Memory operations. */
declare namespace memory {
+ /** Whether the memory managed interface is implemented. */
+ export const implemented: bool;
/** Returns the current memory size in units of pages. One page is 64kb. */
export function size(): i32;
/** Grows linear memory by a given unsigned delta of pages. One page is 64kb. Returns the previous memory size in units of pages or `-1` on failure. */
@@ -985,9 +987,9 @@ declare namespace memory {
/** Repeats `src` of length `srcLength` `count` times at `dst`. */
export function repeat(dst: usize, src: usize, srcLength: usize, count: usize): void;
/** Copies elements from a passive element segment to a table. */
- // export function init(segmentIndex: u32, srcOffset: usize, dstOffset: usize, n: usize): void;
+ export function init(segmentIndex: u32, srcOffset: usize, dstOffset: usize, n: usize): void;
/** Prevents further use of a passive element segment. */
- // export function drop(segmentIndex: u32): void;
+ export function drop(segmentIndex: u32): void;
/** Copies elements from one region of a table to another region. */
export function allocate(size: usize): usize;
/** Disposes a chunk of memory by its pointer. */
@@ -1000,20 +1002,24 @@ declare namespace memory {
/** Garbage collector operations. */
declare namespace gc {
- /** Allocates a managed object identified by its visitor function. */
- export function allocate(size: usize, visitFn: (ref: usize) => void): usize;
+ /** Whether the garbage collector interface is implemented. */
+ export const implemented: bool;
/** Performs a full garbage collection cycle. */
export function collect(): void;
+ /** Retains a reference, making sure that it doesn't become collected. */
+ export function retain(ref: usize): void;
+ /** Releases a reference, allowing it to become collected. */
+ export function release(ref: usize): void;
}
/** Table operations. */
declare namespace table {
/** Copies elements from a passive element segment to a table. */
- // export function init(elementIndex: u32, srcOffset: u32, dstOffset: u32, n: u32): void;
+ export function init(elementIndex: u32, srcOffset: u32, dstOffset: u32, n: u32): void;
/** Prevents further use of a passive element segment. */
- // export function drop(elementIndex: u32): void;
+ export function drop(elementIndex: u32): void;
/** Copies elements from one region of a table to another region. */
- // export function copy(dest: u32, src: u32, n: u32): void;
+ export function copy(dest: u32, src: u32, n: u32): void;
}
/** Class representing a generic, fixed-length raw binary data buffer. */
diff --git a/std/assembly/memory.ts b/std/assembly/memory.ts
index 46ee6c44..6865c362 100644
--- a/std/assembly/memory.ts
+++ b/std/assembly/memory.ts
@@ -1,6 +1,7 @@
///
import { memcmp, memmove, memset } from "./util/memory";
+import { E_NOTIMPLEMENTED } from "./util/error";
// @ts-ignore: decorator
@builtin
@@ -9,6 +10,11 @@ export declare const HEAP_BASE: usize;
/** Memory manager interface. */
export namespace memory {
+ /** Whether the memory managed interface is implemented. */
+ // @ts-ignore: decorator
+ @lazy
+ export const implemented: bool = isDefined(__mem_allocate);
+
/** Gets the size of the memory in pages. */
// @ts-ignore: decorator
@builtin
@@ -37,14 +43,14 @@ export namespace memory {
// @ts-ignore: decorator
@unsafe
export function init(segmentIndex: u32, srcOffset: usize, dstOffset: usize, n: usize): void {
- unreachable(); // not yet implemented
+ throw new Error(E_NOTIMPLEMENTED);
}
/** Drops a memory segment. */
// @ts-ignore: decorator
@unsafe
export function drop(segmentIndex: u32): void {
- unreachable(); // not yet implemented
+ throw new Error(E_NOTIMPLEMENTED);
}
/** Dynamically allocates a section of memory and returns its address. */
@@ -52,7 +58,7 @@ export namespace memory {
@unsafe
export function allocate(size: usize): usize {
if (isDefined(__mem_allocate)) return __mem_allocate(size);
- else return unreachable();
+ else throw new Error(E_NOTIMPLEMENTED);
}
/** Dynamically frees a section of memory by the previously allocated address. */
@@ -60,7 +66,7 @@ export namespace memory {
@unsafe
export function free(ptr: usize): void {
if (isDefined(__mem_free)) __mem_free(ptr);
- else unreachable();
+ else throw new Error(E_NOTIMPLEMENTED);
}
/** Resets the memory to its initial state. Arena allocator only. */
@@ -68,7 +74,7 @@ export namespace memory {
@unsafe
export function reset(): void {
if (isDefined(__mem_reset)) __mem_reset();
- else unreachable();
+ else throw new Error(E_NOTIMPLEMENTED);
}
/** Repeats a section of memory at a specific address. */
diff --git a/std/assembly/table.ts b/std/assembly/table.ts
index cc312ade..5598bc88 100644
--- a/std/assembly/table.ts
+++ b/std/assembly/table.ts
@@ -1,14 +1,16 @@
+import { E_NOTIMPLEMENTED } from "./util/error";
+
export namespace table {
export function copy(dst: u32, src: u32, n: u32): void {
- ERROR("not implemented: table.copy");
+ throw new Error(E_NOTIMPLEMENTED);
}
export function init(elementIndex: u32, srcOffset: u32, dstOffset: u32, n: u32): void {
- ERROR("not implemented: table.init");
+ throw new Error(E_NOTIMPLEMENTED);
}
export function drop(elementIndex: u32): void {
- ERROR("not implemented: table.drop");
+ throw new Error(E_NOTIMPLEMENTED);
}
}
diff --git a/std/assembly/util/error.ts b/std/assembly/util/error.ts
index c9c1dbc1..cbee8cbf 100644
--- a/std/assembly/util/error.ts
+++ b/std/assembly/util/error.ts
@@ -16,3 +16,7 @@ export const E_EMPTYARRAY: string = "Array is empty";
// @ts-ignore: decorator
@lazy @inline
export const E_HOLEYARRAY: string = "Element type must be nullable if array is holey";
+
+// @ts-ignore: decorator
+@lazy @inline
+export const E_NOTIMPLEMENTED: string = "Not implemented";
diff --git a/tests/compiler/gc.optimized.wat b/tests/compiler/gc.optimized.wat
new file mode 100644
index 00000000..36430769
--- /dev/null
+++ b/tests/compiler/gc.optimized.wat
@@ -0,0 +1,1118 @@
+(module
+ (type $FUNCSIG$v (func))
+ (type $FUNCSIG$ii (func (param i32) (result i32)))
+ (type $FUNCSIG$iii (func (param i32 i32) (result i32)))
+ (type $FUNCSIG$viiii (func (param i32 i32 i32 i32)))
+ (type $FUNCSIG$vi (func (param i32)))
+ (type $FUNCSIG$viiddddd (func (param i32 i32 f64 f64 f64 f64 f64)))
+ (type $FUNCSIG$vii (func (param i32 i32)))
+ (type $FUNCSIG$iiii (func (param i32 i32 i32) (result i32)))
+ (type $FUNCSIG$i (func (result i32)))
+ (import "env" "abort" (func $~lib/env/abort (param i32 i32 i32 i32)))
+ (import "env" "trace" (func $~lib/env/trace (param i32 i32 f64 f64 f64 f64 f64)))
+ (memory $0 1)
+ (data (i32.const 8) "\02\00\00\00\1e")
+ (data (i32.const 24) "~\00l\00i\00b\00/\00r\00u\00n\00t\00i\00m\00e\00.\00t\00s")
+ (data (i32.const 56) "\02\00\00\00\16")
+ (data (i32.const 72) "g\00c\00.\00r\00e\00g\00i\00s\00t\00e\00r")
+ (data (i32.const 96) "\02\00\00\00\n")
+ (data (i32.const 112) "g\00c\00.\00t\00s")
+ (data (i32.const 128) "\02\00\00\00&")
+ (data (i32.const 144) "~\00l\00i\00b\00/\00a\00r\00r\00a\00y\00b\00u\00f\00f\00e\00r\00.\00t\00s")
+ (data (i32.const 184) "\02\00\00\00\0e")
+ (data (i32.const 200) "g\00c\00.\00l\00i\00n\00k")
+ (data (i32.const 216) "\02\00\00\00\12")
+ (data (i32.const 232) "g\00c\00.\00u\00n\00l\00i\00n\00k")
+ (data (i32.const 256) "\02\00\00\00\14")
+ (data (i32.const 272) "g\00c\00.\00c\00o\00l\00l\00e\00c\00t")
+ (table $0 1 funcref)
+ (elem (i32.const 0) $null)
+ (global $gc/_dummy/collect_count (mut i32) (i32.const 0))
+ (global $gc/_dummy/register_count (mut i32) (i32.const 0))
+ (global $gc/_dummy/register_ref (mut i32) (i32.const 0))
+ (global $gc/_dummy/link_count (mut i32) (i32.const 0))
+ (global $gc/_dummy/link_ref (mut i32) (i32.const 0))
+ (global $gc/_dummy/link_parentRef (mut i32) (i32.const 0))
+ (global $gc/_dummy/unlink_count (mut i32) (i32.const 0))
+ (global $gc/_dummy/unlink_ref (mut i32) (i32.const 0))
+ (global $gc/_dummy/unlink_parentRef (mut i32) (i32.const 0))
+ (global $~lib/allocator/arena/startOffset (mut i32) (i32.const 0))
+ (global $~lib/allocator/arena/offset (mut i32) (i32.const 0))
+ (global $~lib/gc/gc.implemented i32 (i32.const 1))
+ (global $~lib/gc/GC_ROOT (mut i32) (i32.const 0))
+ (global $~lib/started (mut i32) (i32.const 0))
+ (global $~lib/capabilities i32 (i32.const 2))
+ (export "memory" (memory $0))
+ (export "table" (table $0))
+ (export "main" (func $gc/main))
+ (export "gc.implemented" (global $~lib/gc/gc.implemented))
+ (export "gc.collect" (func $~lib/gc/gc.collect))
+ (export "gc.retain" (func $~lib/gc/gc.retain))
+ (export "gc.release" (func $~lib/gc/gc.release))
+ (export ".capabilities" (global $~lib/capabilities))
+ (func $~lib/allocator/arena/__mem_allocate (; 2 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32)
+ (local $1 i32)
+ (local $2 i32)
+ (local $3 i32)
+ local.get $0
+ i32.const 1073741824
+ i32.gt_u
+ if
+ unreachable
+ end
+ global.get $~lib/allocator/arena/offset
+ local.tee $1
+ local.get $0
+ i32.const 1
+ local.get $0
+ i32.const 1
+ i32.gt_u
+ select
+ i32.add
+ i32.const 7
+ i32.add
+ i32.const -8
+ i32.and
+ local.tee $0
+ current_memory
+ local.tee $2
+ i32.const 16
+ i32.shl
+ i32.gt_u
+ if
+ local.get $2
+ local.get $0
+ local.get $1
+ i32.sub
+ i32.const 65535
+ i32.add
+ i32.const -65536
+ i32.and
+ i32.const 16
+ i32.shr_u
+ local.tee $3
+ local.get $2
+ local.get $3
+ i32.gt_s
+ select
+ grow_memory
+ i32.const 0
+ i32.lt_s
+ if
+ local.get $3
+ grow_memory
+ i32.const 0
+ i32.lt_s
+ if
+ unreachable
+ end
+ end
+ end
+ local.get $0
+ global.set $~lib/allocator/arena/offset
+ local.get $1
+ )
+ (func $~lib/runtime/allocate (; 3 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32)
+ (local $1 i32)
+ i32.const 1
+ i32.const 32
+ local.get $0
+ i32.const 15
+ i32.add
+ i32.clz
+ i32.sub
+ i32.shl
+ call $~lib/allocator/arena/__mem_allocate
+ local.tee $1
+ i32.const -1520547049
+ i32.store
+ local.get $1
+ local.get $0
+ i32.store offset=4
+ local.get $1
+ i32.const 0
+ i32.store offset=8
+ local.get $1
+ i32.const 0
+ i32.store offset=12
+ local.get $1
+ i32.const 16
+ i32.add
+ )
+ (func $gc/_dummy/__ref_register (; 4 ;) (type $FUNCSIG$vi) (param $0 i32)
+ i32.const 72
+ i32.const 1
+ local.get $0
+ f64.convert_i32_u
+ f64.const 0
+ f64.const 0
+ f64.const 0
+ f64.const 0
+ call $~lib/env/trace
+ global.get $gc/_dummy/register_count
+ i32.const 1
+ i32.add
+ global.set $gc/_dummy/register_count
+ local.get $0
+ global.set $gc/_dummy/register_ref
+ )
+ (func $~lib/runtime/register (; 5 ;) (type $FUNCSIG$iii) (param $0 i32) (param $1 i32) (result i32)
+ (local $2 i32)
+ local.get $0
+ i32.const 292
+ i32.le_u
+ if
+ i32.const 0
+ i32.const 24
+ i32.const 149
+ i32.const 4
+ call $~lib/env/abort
+ unreachable
+ end
+ local.get $0
+ i32.const 16
+ i32.sub
+ local.tee $2
+ i32.load
+ i32.const -1520547049
+ i32.ne
+ if
+ i32.const 0
+ i32.const 24
+ i32.const 151
+ i32.const 4
+ call $~lib/env/abort
+ unreachable
+ end
+ local.get $2
+ local.get $1
+ i32.store
+ local.get $0
+ call $gc/_dummy/__ref_register
+ local.get $0
+ )
+ (func $~lib/memory/memory.fill (; 6 ;) (type $FUNCSIG$vii) (param $0 i32) (param $1 i32)
+ (local $2 i32)
+ block $~lib/util/memory/memset|inlined.0
+ local.get $1
+ i32.eqz
+ br_if $~lib/util/memory/memset|inlined.0
+ local.get $0
+ i32.const 0
+ i32.store8
+ local.get $0
+ local.get $1
+ i32.add
+ i32.const 1
+ i32.sub
+ i32.const 0
+ i32.store8
+ local.get $1
+ i32.const 2
+ i32.le_u
+ br_if $~lib/util/memory/memset|inlined.0
+ local.get $0
+ i32.const 1
+ i32.add
+ i32.const 0
+ i32.store8
+ local.get $0
+ i32.const 2
+ i32.add
+ i32.const 0
+ i32.store8
+ local.get $0
+ local.get $1
+ i32.add
+ local.tee $2
+ i32.const 2
+ i32.sub
+ i32.const 0
+ i32.store8
+ local.get $2
+ i32.const 3
+ i32.sub
+ i32.const 0
+ i32.store8
+ local.get $1
+ i32.const 6
+ i32.le_u
+ br_if $~lib/util/memory/memset|inlined.0
+ local.get $0
+ i32.const 3
+ i32.add
+ i32.const 0
+ i32.store8
+ local.get $0
+ local.get $1
+ i32.add
+ i32.const 4
+ i32.sub
+ i32.const 0
+ i32.store8
+ local.get $1
+ i32.const 8
+ i32.le_u
+ br_if $~lib/util/memory/memset|inlined.0
+ local.get $1
+ i32.const 0
+ local.get $0
+ i32.sub
+ i32.const 3
+ i32.and
+ local.tee $1
+ i32.sub
+ local.set $2
+ local.get $0
+ local.get $1
+ i32.add
+ local.tee $0
+ i32.const 0
+ i32.store
+ local.get $2
+ i32.const -4
+ i32.and
+ local.tee $1
+ local.get $0
+ i32.add
+ i32.const 4
+ i32.sub
+ i32.const 0
+ i32.store
+ local.get $1
+ i32.const 8
+ i32.le_u
+ br_if $~lib/util/memory/memset|inlined.0
+ local.get $0
+ i32.const 4
+ i32.add
+ i32.const 0
+ i32.store
+ local.get $0
+ i32.const 8
+ i32.add
+ i32.const 0
+ i32.store
+ local.get $0
+ local.get $1
+ i32.add
+ local.tee $2
+ i32.const 12
+ i32.sub
+ i32.const 0
+ i32.store
+ local.get $2
+ i32.const 8
+ i32.sub
+ i32.const 0
+ i32.store
+ local.get $1
+ i32.const 24
+ i32.le_u
+ br_if $~lib/util/memory/memset|inlined.0
+ local.get $0
+ i32.const 12
+ i32.add
+ i32.const 0
+ i32.store
+ local.get $0
+ i32.const 16
+ i32.add
+ i32.const 0
+ i32.store
+ local.get $0
+ i32.const 20
+ i32.add
+ i32.const 0
+ i32.store
+ local.get $0
+ i32.const 24
+ i32.add
+ i32.const 0
+ i32.store
+ local.get $0
+ local.get $1
+ i32.add
+ local.tee $2
+ i32.const 28
+ i32.sub
+ i32.const 0
+ i32.store
+ local.get $2
+ i32.const 24
+ i32.sub
+ i32.const 0
+ i32.store
+ local.get $2
+ i32.const 20
+ i32.sub
+ i32.const 0
+ i32.store
+ local.get $2
+ i32.const 16
+ i32.sub
+ i32.const 0
+ i32.store
+ local.get $0
+ i32.const 4
+ i32.and
+ i32.const 24
+ i32.add
+ local.tee $2
+ local.get $0
+ i32.add
+ local.set $0
+ local.get $1
+ local.get $2
+ i32.sub
+ local.set $1
+ loop $continue|0
+ local.get $1
+ i32.const 32
+ i32.ge_u
+ if
+ local.get $0
+ i64.const 0
+ i64.store
+ local.get $0
+ i32.const 8
+ i32.add
+ i64.const 0
+ i64.store
+ local.get $0
+ i32.const 16
+ i32.add
+ i64.const 0
+ i64.store
+ local.get $0
+ i32.const 24
+ i32.add
+ i64.const 0
+ i64.store
+ local.get $1
+ i32.const 32
+ i32.sub
+ local.set $1
+ local.get $0
+ i32.const 32
+ i32.add
+ local.set $0
+ br $continue|0
+ end
+ end
+ end
+ )
+ (func $~lib/arraybuffer/ArrayBuffer#constructor (; 7 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32)
+ (local $1 i32)
+ local.get $0
+ i32.const 1073741808
+ i32.gt_u
+ if
+ i32.const 0
+ i32.const 144
+ i32.const 25
+ i32.const 43
+ call $~lib/env/abort
+ unreachable
+ end
+ local.get $0
+ call $~lib/runtime/allocate
+ local.tee $1
+ local.get $0
+ call $~lib/memory/memory.fill
+ local.get $1
+ i32.const 4
+ call $~lib/runtime/register
+ )
+ (func $gc/_dummy/__ref_link (; 8 ;) (type $FUNCSIG$vii) (param $0 i32) (param $1 i32)
+ i32.const 200
+ i32.const 2
+ local.get $0
+ f64.convert_i32_u
+ local.get $1
+ f64.convert_i32_u
+ f64.const 0
+ f64.const 0
+ f64.const 0
+ call $~lib/env/trace
+ global.get $gc/_dummy/link_count
+ i32.const 1
+ i32.add
+ global.set $gc/_dummy/link_count
+ local.get $0
+ global.set $gc/_dummy/link_ref
+ local.get $0
+ global.set $gc/_dummy/link_parentRef
+ )
+ (func $gc/_dummy/__ref_unlink (; 9 ;) (type $FUNCSIG$vii) (param $0 i32) (param $1 i32)
+ i32.const 232
+ i32.const 2
+ local.get $0
+ f64.convert_i32_u
+ local.get $1
+ f64.convert_i32_u
+ f64.const 0
+ f64.const 0
+ f64.const 0
+ call $~lib/env/trace
+ global.get $gc/_dummy/unlink_count
+ i32.const 1
+ i32.add
+ global.set $gc/_dummy/unlink_count
+ local.get $0
+ global.set $gc/_dummy/unlink_ref
+ local.get $1
+ global.set $gc/_dummy/unlink_parentRef
+ )
+ (func $~lib/set/Set#clear (; 10 ;) (type $FUNCSIG$vi) (param $0 i32)
+ (local $1 i32)
+ (local $2 i32)
+ (local $3 i32)
+ local.get $0
+ local.tee $2
+ local.set $1
+ i32.const 16
+ call $~lib/arraybuffer/ArrayBuffer#constructor
+ local.tee $0
+ local.get $1
+ i32.load
+ local.tee $3
+ i32.ne
+ if
+ local.get $3
+ if
+ local.get $3
+ local.get $2
+ call $gc/_dummy/__ref_unlink
+ end
+ local.get $0
+ local.get $2
+ call $gc/_dummy/__ref_link
+ end
+ local.get $1
+ local.get $0
+ i32.store
+ local.get $1
+ i32.const 3
+ i32.store offset=4
+ i32.const 32
+ call $~lib/arraybuffer/ArrayBuffer#constructor
+ local.tee $0
+ local.get $1
+ local.tee $2
+ i32.load offset=8
+ local.tee $3
+ i32.ne
+ if
+ local.get $3
+ if
+ local.get $3
+ local.get $2
+ call $gc/_dummy/__ref_unlink
+ end
+ local.get $0
+ local.get $2
+ call $gc/_dummy/__ref_link
+ end
+ local.get $1
+ local.get $0
+ i32.store offset=8
+ local.get $1
+ i32.const 4
+ i32.store offset=12
+ local.get $1
+ i32.const 0
+ i32.store offset=16
+ local.get $1
+ i32.const 0
+ i32.store offset=20
+ )
+ (func $~lib/set/Set#constructor (; 11 ;) (type $FUNCSIG$i) (result i32)
+ (local $0 i32)
+ i32.const 24
+ call $~lib/runtime/allocate
+ i32.const 3
+ call $~lib/runtime/register
+ local.tee $0
+ i32.const 0
+ i32.store
+ local.get $0
+ i32.const 0
+ i32.store offset=4
+ local.get $0
+ i32.const 0
+ i32.store offset=8
+ local.get $0
+ i32.const 0
+ i32.store offset=12
+ local.get $0
+ i32.const 0
+ i32.store offset=16
+ local.get $0
+ i32.const 0
+ i32.store offset=20
+ local.get $0
+ call $~lib/set/Set#clear
+ local.get $0
+ )
+ (func $~lib/util/hash/hash32 (; 12 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32)
+ local.get $0
+ i32.const 255
+ i32.and
+ i32.const -2128831035
+ i32.xor
+ i32.const 16777619
+ i32.mul
+ local.get $0
+ i32.const 8
+ i32.shr_u
+ i32.const 255
+ i32.and
+ i32.xor
+ i32.const 16777619
+ i32.mul
+ local.get $0
+ i32.const 16
+ i32.shr_u
+ i32.const 255
+ i32.and
+ i32.xor
+ i32.const 16777619
+ i32.mul
+ local.get $0
+ i32.const 24
+ i32.shr_u
+ i32.xor
+ i32.const 16777619
+ i32.mul
+ )
+ (func $~lib/set/Set#find (; 13 ;) (type $FUNCSIG$iiii) (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
+ local.get $0
+ i32.load
+ local.get $0
+ i32.load offset=4
+ local.get $2
+ i32.and
+ i32.const 2
+ i32.shl
+ i32.add
+ i32.load
+ local.set $2
+ loop $continue|0
+ local.get $2
+ if
+ local.get $2
+ i32.load offset=4
+ i32.const 1
+ i32.and
+ i32.eqz
+ local.tee $0
+ if
+ local.get $2
+ i32.load
+ local.get $1
+ i32.eq
+ local.set $0
+ end
+ local.get $0
+ if
+ local.get $2
+ return
+ end
+ local.get $2
+ i32.load offset=4
+ i32.const -2
+ i32.and
+ local.set $2
+ br $continue|0
+ end
+ end
+ i32.const 0
+ )
+ (func $~lib/set/Set#has (; 14 ;) (type $FUNCSIG$iii) (param $0 i32) (param $1 i32) (result i32)
+ local.get $0
+ local.get $1
+ local.get $1
+ call $~lib/util/hash/hash32
+ call $~lib/set/Set#find
+ i32.const 0
+ i32.ne
+ )
+ (func $~lib/set/Set#rehash (; 15 ;) (type $FUNCSIG$vii) (param $0 i32) (param $1 i32)
+ (local $2 i32)
+ (local $3 i32)
+ (local $4 i32)
+ (local $5 i32)
+ (local $6 i32)
+ (local $7 i32)
+ (local $8 i32)
+ local.get $1
+ i32.const 1
+ i32.add
+ local.tee $2
+ i32.const 2
+ i32.shl
+ call $~lib/arraybuffer/ArrayBuffer#constructor
+ local.set $4
+ local.get $2
+ f64.convert_i32_s
+ f64.const 2.6666666666666665
+ f64.mul
+ i32.trunc_f64_s
+ local.tee $6
+ i32.const 3
+ i32.shl
+ call $~lib/arraybuffer/ArrayBuffer#constructor
+ local.set $5
+ local.get $0
+ i32.load offset=8
+ local.tee $2
+ local.get $0
+ i32.load offset=16
+ i32.const 3
+ i32.shl
+ i32.add
+ local.set $7
+ local.get $5
+ local.set $3
+ loop $continue|0
+ local.get $2
+ local.get $7
+ i32.ne
+ if
+ local.get $2
+ i32.load offset=4
+ i32.const 1
+ i32.and
+ i32.eqz
+ if
+ local.get $3
+ local.get $2
+ i32.load
+ i32.store
+ local.get $3
+ local.get $2
+ i32.load
+ call $~lib/util/hash/hash32
+ local.get $1
+ i32.and
+ i32.const 2
+ i32.shl
+ local.get $4
+ i32.add
+ local.tee $8
+ i32.load
+ i32.store offset=4
+ local.get $8
+ local.get $3
+ i32.store
+ local.get $3
+ i32.const 8
+ i32.add
+ local.set $3
+ end
+ local.get $2
+ i32.const 8
+ i32.add
+ local.set $2
+ br $continue|0
+ end
+ end
+ local.get $0
+ local.tee $3
+ local.set $2
+ local.get $4
+ local.tee $0
+ local.get $2
+ i32.load
+ local.tee $4
+ i32.ne
+ if
+ local.get $4
+ if
+ local.get $4
+ local.get $3
+ call $gc/_dummy/__ref_unlink
+ end
+ local.get $0
+ local.get $3
+ call $gc/_dummy/__ref_link
+ end
+ local.get $2
+ local.get $0
+ i32.store
+ local.get $2
+ local.get $1
+ i32.store offset=4
+ local.get $5
+ local.tee $0
+ local.get $2
+ local.tee $1
+ i32.load offset=8
+ local.tee $3
+ i32.ne
+ if
+ local.get $3
+ if
+ local.get $3
+ local.get $2
+ call $gc/_dummy/__ref_unlink
+ end
+ local.get $0
+ local.get $2
+ call $gc/_dummy/__ref_link
+ end
+ local.get $1
+ local.get $0
+ i32.store offset=8
+ local.get $1
+ local.get $6
+ i32.store offset=12
+ local.get $1
+ local.get $1
+ i32.load offset=20
+ i32.store offset=16
+ )
+ (func $~lib/set/Set#add (; 16 ;) (type $FUNCSIG$vii) (param $0 i32) (param $1 i32)
+ (local $2 i32)
+ (local $3 i32)
+ (local $4 i32)
+ local.get $0
+ local.get $1
+ local.get $1
+ call $~lib/util/hash/hash32
+ local.tee $3
+ call $~lib/set/Set#find
+ i32.eqz
+ if
+ local.get $0
+ i32.load offset=16
+ local.get $0
+ i32.load offset=12
+ i32.eq
+ if
+ local.get $0
+ local.get $0
+ i32.load offset=20
+ local.get $0
+ i32.load offset=12
+ f64.convert_i32_s
+ f64.const 0.75
+ f64.mul
+ i32.trunc_f64_s
+ i32.lt_s
+ if (result i32)
+ local.get $0
+ i32.load offset=4
+ else
+ local.get $0
+ i32.load offset=4
+ i32.const 1
+ i32.shl
+ i32.const 1
+ i32.or
+ end
+ call $~lib/set/Set#rehash
+ end
+ local.get $0
+ i32.load offset=8
+ local.set $2
+ local.get $0
+ local.get $0
+ i32.load offset=16
+ local.tee $4
+ i32.const 1
+ i32.add
+ i32.store offset=16
+ local.get $4
+ i32.const 3
+ i32.shl
+ local.get $2
+ i32.add
+ local.tee $2
+ local.get $1
+ i32.store
+ local.get $0
+ local.get $0
+ i32.load offset=20
+ i32.const 1
+ i32.add
+ i32.store offset=20
+ local.get $2
+ local.get $0
+ i32.load
+ local.get $0
+ i32.load offset=4
+ local.get $3
+ i32.and
+ i32.const 2
+ i32.shl
+ i32.add
+ local.tee $0
+ i32.load
+ i32.store offset=4
+ local.get $0
+ local.get $2
+ i32.store
+ end
+ )
+ (func $~lib/gc/gc.retain (; 17 ;) (type $FUNCSIG$vi) (param $0 i32)
+ (local $1 i32)
+ global.get $~lib/gc/GC_ROOT
+ local.tee $1
+ local.get $0
+ call $~lib/set/Set#has
+ i32.eqz
+ if
+ local.get $1
+ local.get $0
+ call $~lib/set/Set#add
+ local.get $0
+ local.get $1
+ call $gc/_dummy/__ref_link
+ end
+ )
+ (func $~lib/set/Set#delete (; 18 ;) (type $FUNCSIG$vii) (param $0 i32) (param $1 i32)
+ (local $2 i32)
+ local.get $0
+ local.get $1
+ local.get $1
+ call $~lib/util/hash/hash32
+ call $~lib/set/Set#find
+ local.tee $1
+ i32.eqz
+ if
+ return
+ end
+ local.get $1
+ local.get $1
+ i32.load offset=4
+ i32.const 1
+ i32.or
+ i32.store offset=4
+ local.get $0
+ local.get $0
+ i32.load offset=20
+ i32.const 1
+ i32.sub
+ i32.store offset=20
+ local.get $0
+ i32.load offset=4
+ i32.const 1
+ i32.shr_u
+ local.tee $2
+ i32.const 1
+ i32.add
+ i32.const 4
+ local.get $0
+ i32.load offset=20
+ local.tee $1
+ i32.const 4
+ local.get $1
+ i32.gt_u
+ select
+ i32.ge_u
+ local.tee $1
+ if (result i32)
+ local.get $0
+ i32.load offset=20
+ local.get $0
+ i32.load offset=12
+ f64.convert_i32_s
+ f64.const 0.75
+ f64.mul
+ i32.trunc_f64_s
+ i32.lt_s
+ else
+ local.get $1
+ end
+ if
+ local.get $0
+ local.get $2
+ call $~lib/set/Set#rehash
+ end
+ )
+ (func $~lib/gc/gc.release (; 19 ;) (type $FUNCSIG$vi) (param $0 i32)
+ (local $1 i32)
+ global.get $~lib/gc/GC_ROOT
+ local.tee $1
+ local.get $0
+ call $~lib/set/Set#has
+ if
+ local.get $1
+ local.get $0
+ call $~lib/set/Set#delete
+ local.get $0
+ local.get $1
+ call $gc/_dummy/__ref_unlink
+ end
+ )
+ (func $~lib/gc/gc.collect (; 20 ;) (type $FUNCSIG$v)
+ i32.const 272
+ i32.const 0
+ f64.const 0
+ f64.const 0
+ f64.const 0
+ f64.const 0
+ f64.const 0
+ call $~lib/env/trace
+ global.get $gc/_dummy/collect_count
+ i32.const 1
+ i32.add
+ global.set $gc/_dummy/collect_count
+ )
+ (func $gc/main (; 21 ;) (type $FUNCSIG$v)
+ (local $0 i32)
+ (local $1 i32)
+ (local $2 i32)
+ (local $3 i32)
+ global.get $~lib/started
+ i32.eqz
+ if
+ i32.const 296
+ global.set $~lib/allocator/arena/startOffset
+ global.get $~lib/allocator/arena/startOffset
+ global.set $~lib/allocator/arena/offset
+ call $~lib/set/Set#constructor
+ global.set $~lib/gc/GC_ROOT
+ i32.const 1
+ global.set $~lib/started
+ end
+ i32.const 0
+ call $~lib/runtime/allocate
+ i32.const 1
+ call $~lib/runtime/register
+ local.set $2
+ global.get $gc/_dummy/link_count
+ local.set $3
+ global.get $gc/_dummy/unlink_count
+ local.set $0
+ global.get $gc/_dummy/collect_count
+ local.set $1
+ local.get $2
+ call $~lib/gc/gc.retain
+ global.get $gc/_dummy/link_count
+ local.get $3
+ i32.const 1
+ i32.add
+ i32.ne
+ if
+ i32.const 0
+ i32.const 112
+ i32.const 18
+ i32.const 2
+ call $~lib/env/abort
+ unreachable
+ end
+ global.get $gc/_dummy/unlink_count
+ local.get $0
+ i32.ne
+ if
+ i32.const 0
+ i32.const 112
+ i32.const 19
+ i32.const 2
+ call $~lib/env/abort
+ unreachable
+ end
+ global.get $gc/_dummy/collect_count
+ local.get $1
+ i32.ne
+ if
+ i32.const 0
+ i32.const 112
+ i32.const 20
+ i32.const 2
+ call $~lib/env/abort
+ unreachable
+ end
+ global.get $gc/_dummy/link_count
+ local.set $3
+ global.get $gc/_dummy/unlink_count
+ local.set $0
+ global.get $gc/_dummy/collect_count
+ local.set $1
+ local.get $2
+ call $~lib/gc/gc.release
+ global.get $gc/_dummy/link_count
+ local.get $3
+ i32.ne
+ if
+ i32.const 0
+ i32.const 112
+ i32.const 27
+ i32.const 2
+ call $~lib/env/abort
+ unreachable
+ end
+ global.get $gc/_dummy/unlink_count
+ local.get $0
+ i32.const 1
+ i32.add
+ i32.ne
+ if
+ i32.const 0
+ i32.const 112
+ i32.const 28
+ i32.const 2
+ call $~lib/env/abort
+ unreachable
+ end
+ global.get $gc/_dummy/collect_count
+ local.get $1
+ i32.ne
+ if
+ i32.const 0
+ i32.const 112
+ i32.const 29
+ i32.const 2
+ call $~lib/env/abort
+ unreachable
+ end
+ global.get $gc/_dummy/link_count
+ local.set $0
+ global.get $gc/_dummy/unlink_count
+ local.set $1
+ global.get $gc/_dummy/collect_count
+ local.set $2
+ call $~lib/gc/gc.collect
+ global.get $gc/_dummy/link_count
+ local.get $0
+ i32.ne
+ if
+ i32.const 0
+ i32.const 112
+ i32.const 36
+ i32.const 2
+ call $~lib/env/abort
+ unreachable
+ end
+ global.get $gc/_dummy/unlink_count
+ local.get $1
+ i32.ne
+ if
+ i32.const 0
+ i32.const 112
+ i32.const 37
+ i32.const 2
+ call $~lib/env/abort
+ unreachable
+ end
+ global.get $gc/_dummy/collect_count
+ local.get $2
+ i32.const 1
+ i32.add
+ i32.ne
+ if
+ i32.const 0
+ i32.const 112
+ i32.const 38
+ i32.const 2
+ call $~lib/env/abort
+ unreachable
+ end
+ )
+ (func $null (; 22 ;) (type $FUNCSIG$v)
+ nop
+ )
+)
diff --git a/tests/compiler/gc.ts b/tests/compiler/gc.ts
new file mode 100644
index 00000000..af6cb670
--- /dev/null
+++ b/tests/compiler/gc.ts
@@ -0,0 +1,39 @@
+import "allocator/arena";
+import { link_count, unlink_count, collect_count } from "./gc/_dummy";
+export { gc };
+
+class Ref {}
+
+@start export function main(): void {
+ var ref = new Ref();
+
+ assert(gc.implemented);
+
+ var previous_link_count = link_count;
+ var previous_unlink_count = unlink_count;
+ var previous_collect_count = collect_count;
+
+ gc.retain(changetype(ref));
+
+ assert(link_count == previous_link_count + 1);
+ assert(unlink_count == previous_unlink_count);
+ assert(collect_count == previous_collect_count);
+ previous_link_count = link_count;
+ previous_unlink_count = unlink_count;
+ previous_collect_count = collect_count;
+
+ gc.release(changetype(ref));
+
+ assert(link_count == previous_link_count);
+ assert(unlink_count == previous_unlink_count + 1);
+ assert(collect_count == previous_collect_count);
+ previous_link_count = link_count;
+ previous_unlink_count = unlink_count;
+ previous_collect_count = collect_count;
+
+ gc.collect();
+
+ assert(link_count == previous_link_count);
+ assert(unlink_count == previous_unlink_count);
+ assert(collect_count == previous_collect_count + 1);
+}
diff --git a/tests/compiler/gc.untouched.wat b/tests/compiler/gc.untouched.wat
new file mode 100644
index 00000000..607482d5
--- /dev/null
+++ b/tests/compiler/gc.untouched.wat
@@ -0,0 +1,1349 @@
+(module
+ (type $FUNCSIG$v (func))
+ (type $FUNCSIG$ii (func (param i32) (result i32)))
+ (type $FUNCSIG$iii (func (param i32 i32) (result i32)))
+ (type $FUNCSIG$viiii (func (param i32 i32 i32 i32)))
+ (type $FUNCSIG$vi (func (param i32)))
+ (type $FUNCSIG$viiddddd (func (param i32 i32 f64 f64 f64 f64 f64)))
+ (type $FUNCSIG$viii (func (param i32 i32 i32)))
+ (type $FUNCSIG$vii (func (param i32 i32)))
+ (type $FUNCSIG$iiii (func (param i32 i32 i32) (result i32)))
+ (import "env" "abort" (func $~lib/env/abort (param i32 i32 i32 i32)))
+ (import "env" "trace" (func $~lib/env/trace (param i32 i32 f64 f64 f64 f64 f64)))
+ (memory $0 1)
+ (data (i32.const 8) "\02\00\00\00\1e\00\00\00\00\00\00\00\00\00\00\00~\00l\00i\00b\00/\00r\00u\00n\00t\00i\00m\00e\00.\00t\00s\00")
+ (data (i32.const 56) "\02\00\00\00\16\00\00\00\00\00\00\00\00\00\00\00g\00c\00.\00r\00e\00g\00i\00s\00t\00e\00r\00")
+ (data (i32.const 96) "\02\00\00\00\n\00\00\00\00\00\00\00\00\00\00\00g\00c\00.\00t\00s\00")
+ (data (i32.const 128) "\02\00\00\00&\00\00\00\00\00\00\00\00\00\00\00~\00l\00i\00b\00/\00a\00r\00r\00a\00y\00b\00u\00f\00f\00e\00r\00.\00t\00s\00")
+ (data (i32.const 184) "\02\00\00\00\0e\00\00\00\00\00\00\00\00\00\00\00g\00c\00.\00l\00i\00n\00k\00")
+ (data (i32.const 216) "\02\00\00\00\12\00\00\00\00\00\00\00\00\00\00\00g\00c\00.\00u\00n\00l\00i\00n\00k\00")
+ (data (i32.const 256) "\02\00\00\00\14\00\00\00\00\00\00\00\00\00\00\00g\00c\00.\00c\00o\00l\00l\00e\00c\00t\00")
+ (table $0 1 funcref)
+ (elem (i32.const 0) $null)
+ (global $gc/_dummy/collect_count (mut i32) (i32.const 0))
+ (global $gc/_dummy/register_count (mut i32) (i32.const 0))
+ (global $gc/_dummy/register_ref (mut i32) (i32.const 0))
+ (global $gc/_dummy/link_count (mut i32) (i32.const 0))
+ (global $gc/_dummy/link_ref (mut i32) (i32.const 0))
+ (global $gc/_dummy/link_parentRef (mut i32) (i32.const 0))
+ (global $gc/_dummy/unlink_count (mut i32) (i32.const 0))
+ (global $gc/_dummy/unlink_ref (mut i32) (i32.const 0))
+ (global $gc/_dummy/unlink_parentRef (mut i32) (i32.const 0))
+ (global $~lib/runtime/HEADER_SIZE i32 (i32.const 16))
+ (global $~lib/runtime/HEADER_MAGIC i32 (i32.const -1520547049))
+ (global $~lib/allocator/arena/startOffset (mut i32) (i32.const 0))
+ (global $~lib/allocator/arena/offset (mut i32) (i32.const 0))
+ (global $~lib/ASC_NO_ASSERT i32 (i32.const 0))
+ (global $~lib/gc/gc.implemented i32 (i32.const 1))
+ (global $~lib/runtime/MAX_BYTELENGTH i32 (i32.const 1073741808))
+ (global $~lib/gc/GC_ROOT (mut i32) (i32.const 0))
+ (global $~lib/started (mut i32) (i32.const 0))
+ (global $~lib/memory/HEAP_BASE i32 (i32.const 292))
+ (global $~lib/capabilities i32 (i32.const 2))
+ (export "memory" (memory $0))
+ (export "table" (table $0))
+ (export "main" (func $gc/main))
+ (export "gc.implemented" (global $~lib/gc/gc.implemented))
+ (export "gc.collect" (func $~lib/gc/gc.collect))
+ (export "gc.retain" (func $~lib/gc/gc.retain))
+ (export "gc.release" (func $~lib/gc/gc.release))
+ (export ".capabilities" (global $~lib/capabilities))
+ (func $~lib/runtime/ADJUSTOBLOCK (; 2 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32)
+ i32.const 1
+ i32.const 32
+ local.get $0
+ global.get $~lib/runtime/HEADER_SIZE
+ i32.add
+ i32.const 1
+ i32.sub
+ i32.clz
+ i32.sub
+ i32.shl
+ )
+ (func $~lib/allocator/arena/__mem_allocate (; 3 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32)
+ (local $1 i32)
+ (local $2 i32)
+ (local $3 i32)
+ (local $4 i32)
+ (local $5 i32)
+ (local $6 i32)
+ local.get $0
+ i32.const 1073741824
+ i32.gt_u
+ if
+ unreachable
+ end
+ global.get $~lib/allocator/arena/offset
+ local.set $1
+ local.get $1
+ local.get $0
+ local.tee $2
+ i32.const 1
+ local.tee $3
+ local.get $2
+ local.get $3
+ i32.gt_u
+ select
+ i32.add
+ i32.const 7
+ i32.add
+ i32.const 7
+ i32.const -1
+ i32.xor
+ i32.and
+ local.set $4
+ current_memory
+ local.set $5
+ local.get $4
+ local.get $5
+ i32.const 16
+ i32.shl
+ i32.gt_u
+ if
+ local.get $4
+ local.get $1
+ i32.sub
+ i32.const 65535
+ i32.add
+ i32.const 65535
+ i32.const -1
+ i32.xor
+ i32.and
+ i32.const 16
+ i32.shr_u
+ local.set $2
+ local.get $5
+ local.tee $3
+ local.get $2
+ local.tee $6
+ local.get $3
+ local.get $6
+ i32.gt_s
+ select
+ local.set $3
+ local.get $3
+ grow_memory
+ i32.const 0
+ i32.lt_s
+ if
+ local.get $2
+ grow_memory
+ i32.const 0
+ i32.lt_s
+ if
+ unreachable
+ end
+ end
+ end
+ local.get $4
+ global.set $~lib/allocator/arena/offset
+ local.get $1
+ )
+ (func $~lib/memory/memory.allocate (; 4 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32)
+ local.get $0
+ call $~lib/allocator/arena/__mem_allocate
+ return
+ )
+ (func $~lib/runtime/allocate (; 5 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32)
+ (local $1 i32)
+ local.get $0
+ call $~lib/runtime/ADJUSTOBLOCK
+ call $~lib/memory/memory.allocate
+ local.set $1
+ local.get $1
+ global.get $~lib/runtime/HEADER_MAGIC
+ i32.store
+ local.get $1
+ local.get $0
+ i32.store offset=4
+ local.get $1
+ i32.const 0
+ i32.store offset=8
+ local.get $1
+ i32.const 0
+ i32.store offset=12
+ local.get $1
+ global.get $~lib/runtime/HEADER_SIZE
+ i32.add
+ )
+ (func $gc/_dummy/__ref_register (; 6 ;) (type $FUNCSIG$vi) (param $0 i32)
+ i32.const 72
+ i32.const 1
+ local.get $0
+ f64.convert_i32_u
+ f64.const 0
+ f64.const 0
+ f64.const 0
+ f64.const 0
+ call $~lib/env/trace
+ global.get $gc/_dummy/register_count
+ i32.const 1
+ i32.add
+ global.set $gc/_dummy/register_count
+ local.get $0
+ global.set $gc/_dummy/register_ref
+ )
+ (func $~lib/runtime/register (; 7 ;) (type $FUNCSIG$iii) (param $0 i32) (param $1 i32) (result i32)
+ (local $2 i32)
+ local.get $0
+ global.get $~lib/memory/HEAP_BASE
+ i32.gt_u
+ i32.eqz
+ if
+ i32.const 0
+ i32.const 24
+ i32.const 149
+ i32.const 4
+ call $~lib/env/abort
+ unreachable
+ end
+ local.get $0
+ global.get $~lib/runtime/HEADER_SIZE
+ i32.sub
+ local.set $2
+ local.get $2
+ i32.load
+ global.get $~lib/runtime/HEADER_MAGIC
+ i32.eq
+ i32.eqz
+ if
+ i32.const 0
+ i32.const 24
+ i32.const 151
+ i32.const 4
+ call $~lib/env/abort
+ unreachable
+ end
+ local.get $2
+ local.get $1
+ i32.store
+ local.get $0
+ call $gc/_dummy/__ref_register
+ local.get $0
+ )
+ (func $gc/Ref#constructor (; 8 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32)
+ local.get $0
+ i32.eqz
+ if
+ i32.const 0
+ call $~lib/runtime/allocate
+ i32.const 1
+ call $~lib/runtime/register
+ local.set $0
+ end
+ local.get $0
+ )
+ (func $~lib/memory/memory.fill (; 9 ;) (type $FUNCSIG$viii) (param $0 i32) (param $1 i32) (param $2 i32)
+ (local $3 i32)
+ (local $4 i32)
+ (local $5 i32)
+ (local $6 i64)
+ block $~lib/util/memory/memset|inlined.0
+ local.get $2
+ i32.eqz
+ if
+ br $~lib/util/memory/memset|inlined.0
+ end
+ local.get $0
+ local.get $1
+ i32.store8
+ local.get $0
+ local.get $2
+ i32.add
+ i32.const 1
+ i32.sub
+ local.get $1
+ i32.store8
+ local.get $2
+ i32.const 2
+ i32.le_u
+ if
+ br $~lib/util/memory/memset|inlined.0
+ end
+ local.get $0
+ i32.const 1
+ i32.add
+ local.get $1
+ i32.store8
+ local.get $0
+ i32.const 2
+ i32.add
+ local.get $1
+ i32.store8
+ local.get $0
+ local.get $2
+ i32.add
+ i32.const 2
+ i32.sub
+ local.get $1
+ i32.store8
+ local.get $0
+ local.get $2
+ i32.add
+ i32.const 3
+ i32.sub
+ local.get $1
+ i32.store8
+ local.get $2
+ i32.const 6
+ i32.le_u
+ if
+ br $~lib/util/memory/memset|inlined.0
+ end
+ local.get $0
+ i32.const 3
+ i32.add
+ local.get $1
+ i32.store8
+ local.get $0
+ local.get $2
+ i32.add
+ i32.const 4
+ i32.sub
+ local.get $1
+ i32.store8
+ local.get $2
+ i32.const 8
+ i32.le_u
+ if
+ br $~lib/util/memory/memset|inlined.0
+ end
+ i32.const 0
+ local.get $0
+ i32.sub
+ i32.const 3
+ i32.and
+ local.set $5
+ local.get $0
+ local.get $5
+ i32.add
+ local.set $0
+ local.get $2
+ local.get $5
+ i32.sub
+ local.set $2
+ local.get $2
+ i32.const -4
+ i32.and
+ local.set $2
+ i32.const -1
+ i32.const 255
+ i32.div_u
+ local.get $1
+ i32.const 255
+ i32.and
+ i32.mul
+ local.set $4
+ local.get $0
+ local.get $4
+ i32.store
+ local.get $0
+ local.get $2
+ i32.add
+ i32.const 4
+ i32.sub
+ local.get $4
+ i32.store
+ local.get $2
+ i32.const 8
+ i32.le_u
+ if
+ br $~lib/util/memory/memset|inlined.0
+ end
+ local.get $0
+ i32.const 4
+ i32.add
+ local.get $4
+ i32.store
+ local.get $0
+ i32.const 8
+ i32.add
+ local.get $4
+ i32.store
+ local.get $0
+ local.get $2
+ i32.add
+ i32.const 12
+ i32.sub
+ local.get $4
+ i32.store
+ local.get $0
+ local.get $2
+ i32.add
+ i32.const 8
+ i32.sub
+ local.get $4
+ i32.store
+ local.get $2
+ i32.const 24
+ i32.le_u
+ if
+ br $~lib/util/memory/memset|inlined.0
+ end
+ local.get $0
+ i32.const 12
+ i32.add
+ local.get $4
+ i32.store
+ local.get $0
+ i32.const 16
+ i32.add
+ local.get $4
+ i32.store
+ local.get $0
+ i32.const 20
+ i32.add
+ local.get $4
+ i32.store
+ local.get $0
+ i32.const 24
+ i32.add
+ local.get $4
+ i32.store
+ local.get $0
+ local.get $2
+ i32.add
+ i32.const 28
+ i32.sub
+ local.get $4
+ i32.store
+ local.get $0
+ local.get $2
+ i32.add
+ i32.const 24
+ i32.sub
+ local.get $4
+ i32.store
+ local.get $0
+ local.get $2
+ i32.add
+ i32.const 20
+ i32.sub
+ local.get $4
+ i32.store
+ local.get $0
+ local.get $2
+ i32.add
+ i32.const 16
+ i32.sub
+ local.get $4
+ i32.store
+ i32.const 24
+ local.get $0
+ i32.const 4
+ i32.and
+ i32.add
+ local.set $5
+ local.get $0
+ local.get $5
+ i32.add
+ local.set $0
+ local.get $2
+ local.get $5
+ i32.sub
+ local.set $2
+ local.get $4
+ i64.extend_i32_u
+ local.get $4
+ i64.extend_i32_u
+ i64.const 32
+ i64.shl
+ i64.or
+ local.set $6
+ block $break|0
+ loop $continue|0
+ local.get $2
+ i32.const 32
+ i32.ge_u
+ if
+ block
+ local.get $0
+ local.get $6
+ i64.store
+ local.get $0
+ i32.const 8
+ i32.add
+ local.get $6
+ i64.store
+ local.get $0
+ i32.const 16
+ i32.add
+ local.get $6
+ i64.store
+ local.get $0
+ i32.const 24
+ i32.add
+ local.get $6
+ i64.store
+ local.get $2
+ i32.const 32
+ i32.sub
+ local.set $2
+ local.get $0
+ i32.const 32
+ i32.add
+ local.set $0
+ end
+ br $continue|0
+ end
+ end
+ end
+ end
+ )
+ (func $~lib/arraybuffer/ArrayBuffer#constructor (; 10 ;) (type $FUNCSIG$iii) (param $0 i32) (param $1 i32) (result i32)
+ (local $2 i32)
+ (local $3 i32)
+ local.get $1
+ global.get $~lib/runtime/MAX_BYTELENGTH
+ i32.gt_u
+ if
+ i32.const 0
+ i32.const 144
+ i32.const 25
+ i32.const 43
+ call $~lib/env/abort
+ unreachable
+ end
+ block $~lib/runtime/ALLOCATE|inlined.0 (result i32)
+ local.get $1
+ local.set $2
+ local.get $2
+ call $~lib/runtime/allocate
+ end
+ local.set $3
+ local.get $3
+ i32.const 0
+ local.get $1
+ call $~lib/memory/memory.fill
+ block $~lib/runtime/REGISTER<~lib/arraybuffer/ArrayBuffer>|inlined.0 (result i32)
+ local.get $3
+ local.set $2
+ local.get $2
+ i32.const 4
+ call $~lib/runtime/register
+ end
+ )
+ (func $gc/_dummy/__ref_link (; 11 ;) (type $FUNCSIG$vii) (param $0 i32) (param $1 i32)
+ i32.const 200
+ i32.const 2
+ local.get $0
+ f64.convert_i32_u
+ local.get $1
+ f64.convert_i32_u
+ f64.const 0
+ f64.const 0
+ f64.const 0
+ call $~lib/env/trace
+ global.get $gc/_dummy/link_count
+ i32.const 1
+ i32.add
+ global.set $gc/_dummy/link_count
+ local.get $0
+ global.set $gc/_dummy/link_ref
+ local.get $0
+ global.set $gc/_dummy/link_parentRef
+ )
+ (func $gc/_dummy/__ref_unlink (; 12 ;) (type $FUNCSIG$vii) (param $0 i32) (param $1 i32)
+ i32.const 232
+ i32.const 2
+ local.get $0
+ f64.convert_i32_u
+ local.get $1
+ f64.convert_i32_u
+ f64.const 0
+ f64.const 0
+ f64.const 0
+ call $~lib/env/trace
+ global.get $gc/_dummy/unlink_count
+ i32.const 1
+ i32.add
+ global.set $gc/_dummy/unlink_count
+ local.get $0
+ global.set $gc/_dummy/unlink_ref
+ local.get $1
+ global.set $gc/_dummy/unlink_parentRef
+ )
+ (func $~lib/set/Set#clear (; 13 ;) (type $FUNCSIG$vi) (param $0 i32)
+ (local $1 i32)
+ (local $2 i32)
+ (local $3 i32)
+ local.get $0
+ local.tee $1
+ i32.const 0
+ i32.const 16
+ call $~lib/arraybuffer/ArrayBuffer#constructor
+ local.tee $2
+ local.get $1
+ i32.load
+ local.tee $3
+ i32.ne
+ if (result i32)
+ local.get $3
+ if
+ local.get $3
+ local.get $1
+ call $gc/_dummy/__ref_unlink
+ end
+ local.get $2
+ local.get $1
+ call $gc/_dummy/__ref_link
+ local.get $2
+ else
+ local.get $2
+ end
+ i32.store
+ local.get $0
+ i32.const 4
+ i32.const 1
+ i32.sub
+ i32.store offset=4
+ local.get $0
+ local.tee $1
+ i32.const 0
+ i32.const 32
+ call $~lib/arraybuffer/ArrayBuffer#constructor
+ local.tee $3
+ local.get $1
+ i32.load offset=8
+ local.tee $2
+ i32.ne
+ if (result i32)
+ local.get $2
+ if
+ local.get $2
+ local.get $1
+ call $gc/_dummy/__ref_unlink
+ end
+ local.get $3
+ local.get $1
+ call $gc/_dummy/__ref_link
+ local.get $3
+ else
+ local.get $3
+ end
+ i32.store offset=8
+ local.get $0
+ i32.const 4
+ i32.store offset=12
+ local.get $0
+ i32.const 0
+ i32.store offset=16
+ local.get $0
+ i32.const 0
+ i32.store offset=20
+ )
+ (func $~lib/set/Set#constructor (; 14 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32)
+ block (result i32)
+ local.get $0
+ i32.eqz
+ if
+ i32.const 24
+ call $~lib/runtime/allocate
+ i32.const 3
+ call $~lib/runtime/register
+ local.set $0
+ end
+ local.get $0
+ i32.const 0
+ i32.store
+ local.get $0
+ i32.const 0
+ i32.store offset=4
+ local.get $0
+ i32.const 0
+ i32.store offset=8
+ local.get $0
+ i32.const 0
+ i32.store offset=12
+ local.get $0
+ i32.const 0
+ i32.store offset=16
+ local.get $0
+ i32.const 0
+ i32.store offset=20
+ local.get $0
+ end
+ call $~lib/set/Set#clear
+ local.get $0
+ )
+ (func $~lib/util/hash/hash32 (; 15 ;) (type $FUNCSIG$ii) (param $0 i32) (result i32)
+ (local $1 i32)
+ i32.const -2128831035
+ local.set $1
+ local.get $1
+ local.get $0
+ i32.const 255
+ i32.and
+ i32.xor
+ i32.const 16777619
+ i32.mul
+ local.set $1
+ local.get $1
+ local.get $0
+ i32.const 8
+ i32.shr_u
+ i32.const 255
+ i32.and
+ i32.xor
+ i32.const 16777619
+ i32.mul
+ local.set $1
+ local.get $1
+ local.get $0
+ i32.const 16
+ i32.shr_u
+ i32.const 255
+ i32.and
+ i32.xor
+ i32.const 16777619
+ i32.mul
+ local.set $1
+ local.get $1
+ local.get $0
+ i32.const 24
+ i32.shr_u
+ i32.xor
+ i32.const 16777619
+ i32.mul
+ local.set $1
+ local.get $1
+ )
+ (func $~lib/set/Set#find (; 16 ;) (type $FUNCSIG$iiii) (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
+ (local $3 i32)
+ (local $4 i32)
+ local.get $0
+ i32.load
+ local.get $2
+ local.get $0
+ i32.load offset=4
+ i32.and
+ i32.const 4
+ i32.mul
+ i32.add
+ i32.load
+ local.set $3
+ block $break|0
+ loop $continue|0
+ local.get $3
+ if
+ block
+ local.get $3
+ i32.load offset=4
+ i32.const 1
+ i32.and
+ i32.eqz
+ local.tee $4
+ if (result i32)
+ local.get $3
+ i32.load
+ local.get $1
+ i32.eq
+ else
+ local.get $4
+ end
+ if
+ local.get $3
+ return
+ end
+ local.get $3
+ i32.load offset=4
+ i32.const 1
+ i32.const -1
+ i32.xor
+ i32.and
+ local.set $3
+ end
+ br $continue|0
+ end
+ end
+ end
+ i32.const 0
+ )
+ (func $~lib/set/Set#has (; 17 ;) (type $FUNCSIG$iii) (param $0 i32) (param $1 i32) (result i32)
+ (local $2 i32)
+ local.get $0
+ local.get $1
+ block $~lib/util/hash/HASH|inlined.0 (result i32)
+ local.get $1
+ local.set $2
+ local.get $2
+ call $~lib/util/hash/hash32
+ br $~lib/util/hash/HASH|inlined.0
+ end
+ call $~lib/set/Set#find
+ i32.const 0
+ i32.ne
+ )
+ (func $~lib/set/Set#rehash (; 18 ;) (type $FUNCSIG$vii) (param $0 i32) (param $1 i32)
+ (local $2 i32)
+ (local $3 i32)
+ (local $4 i32)
+ (local $5 i32)
+ (local $6 i32)
+ (local $7 i32)
+ (local $8 i32)
+ (local $9 i32)
+ (local $10 i32)
+ (local $11 i32)
+ (local $12 i32)
+ local.get $1
+ i32.const 1
+ i32.add
+ local.set $2
+ i32.const 0
+ local.get $2
+ i32.const 4
+ i32.mul
+ call $~lib/arraybuffer/ArrayBuffer#constructor
+ local.set $3
+ local.get $2
+ f64.convert_i32_s
+ f64.const 2.6666666666666665
+ f64.mul
+ i32.trunc_f64_s
+ local.set $4
+ i32.const 0
+ local.get $4
+ block $~lib/set/ENTRY_SIZE|inlined.1 (result i32)
+ i32.const 8
+ end
+ i32.mul
+ call $~lib/arraybuffer/ArrayBuffer#constructor
+ local.set $5
+ local.get $0
+ i32.load offset=8
+ local.set $6
+ local.get $6
+ local.get $0
+ i32.load offset=16
+ block $~lib/set/ENTRY_SIZE|inlined.2 (result i32)
+ i32.const 8
+ end
+ i32.mul
+ i32.add
+ local.set $7
+ local.get $5
+ local.set $8
+ block $break|0
+ loop $continue|0
+ local.get $6
+ local.get $7
+ i32.ne
+ if
+ block
+ local.get $6
+ local.set $9
+ local.get $9
+ i32.load offset=4
+ i32.const 1
+ i32.and
+ i32.eqz
+ if
+ local.get $8
+ local.set $10
+ local.get $10
+ local.get $9
+ i32.load
+ i32.store
+ block $~lib/util/hash/HASH|inlined.2 (result i32)
+ local.get $9
+ i32.load
+ local.set $11
+ local.get $11
+ call $~lib/util/hash/hash32
+ br $~lib/util/hash/HASH|inlined.2
+ end
+ local.get $1
+ i32.and
+ local.set $11
+ local.get $3
+ local.get $11
+ i32.const 4
+ i32.mul
+ i32.add
+ local.set $12
+ local.get $10
+ local.get $12
+ i32.load
+ i32.store offset=4
+ local.get $12
+ local.get $8
+ i32.store
+ local.get $8
+ block $~lib/set/ENTRY_SIZE|inlined.3 (result i32)
+ i32.const 8
+ end
+ i32.add
+ local.set $8
+ end
+ local.get $6
+ block $~lib/set/ENTRY_SIZE|inlined.4 (result i32)
+ i32.const 8
+ end
+ i32.add
+ local.set $6
+ end
+ br $continue|0
+ end
+ end
+ end
+ local.get $0
+ local.tee $9
+ local.get $3
+ local.tee $12
+ local.get $9
+ i32.load
+ local.tee $11
+ i32.ne
+ if (result i32)
+ local.get $11
+ if
+ local.get $11
+ local.get $9
+ call $gc/_dummy/__ref_unlink
+ end
+ local.get $12
+ local.get $9
+ call $gc/_dummy/__ref_link
+ local.get $12
+ else
+ local.get $12
+ end
+ i32.store
+ local.get $0
+ local.get $1
+ i32.store offset=4
+ local.get $0
+ local.tee $9
+ local.get $5
+ local.tee $11
+ local.get $9
+ i32.load offset=8
+ local.tee $12
+ i32.ne
+ if (result i32)
+ local.get $12
+ if
+ local.get $12
+ local.get $9
+ call $gc/_dummy/__ref_unlink
+ end
+ local.get $11
+ local.get $9
+ call $gc/_dummy/__ref_link
+ local.get $11
+ else
+ local.get $11
+ end
+ i32.store offset=8
+ local.get $0
+ local.get $4
+ i32.store offset=12
+ local.get $0
+ local.get $0
+ i32.load offset=20
+ i32.store offset=16
+ )
+ (func $~lib/set/Set#add (; 19 ;) (type $FUNCSIG$vii) (param $0 i32) (param $1 i32)
+ (local $2 i32)
+ (local $3 i32)
+ (local $4 i32)
+ (local $5 i32)
+ block $~lib/util/hash/HASH|inlined.1 (result i32)
+ local.get $1
+ local.set $2
+ local.get $2
+ call $~lib/util/hash/hash32
+ br $~lib/util/hash/HASH|inlined.1
+ end
+ local.set $3
+ local.get $0
+ local.get $1
+ local.get $3
+ call $~lib/set/Set#find
+ local.set $4
+ local.get $4
+ i32.eqz
+ if
+ local.get $0
+ i32.load offset=16
+ local.get $0
+ i32.load offset=12
+ i32.eq
+ if
+ local.get $0
+ local.get $0
+ i32.load offset=20
+ local.get $0
+ i32.load offset=12
+ f64.convert_i32_s
+ f64.const 0.75
+ f64.mul
+ i32.trunc_f64_s
+ i32.lt_s
+ if (result i32)
+ local.get $0
+ i32.load offset=4
+ else
+ local.get $0
+ i32.load offset=4
+ i32.const 1
+ i32.shl
+ i32.const 1
+ i32.or
+ end
+ call $~lib/set/Set#rehash
+ end
+ local.get $0
+ i32.load offset=8
+ local.set $2
+ local.get $2
+ block (result i32)
+ local.get $0
+ local.get $0
+ i32.load offset=16
+ local.tee $5
+ i32.const 1
+ i32.add
+ i32.store offset=16
+ local.get $5
+ end
+ block $~lib/set/ENTRY_SIZE|inlined.5 (result i32)
+ i32.const 8
+ end
+ i32.mul
+ i32.add
+ local.set $4
+ local.get $4
+ local.get $1
+ i32.store
+ local.get $0
+ local.get $0
+ i32.load offset=20
+ i32.const 1
+ i32.add
+ i32.store offset=20
+ local.get $0
+ i32.load
+ local.get $3
+ local.get $0
+ i32.load offset=4
+ i32.and
+ i32.const 4
+ i32.mul
+ i32.add
+ local.set $5
+ local.get $4
+ local.get $5
+ i32.load
+ i32.store offset=4
+ local.get $5
+ local.get $4
+ i32.store
+ end
+ )
+ (func $~lib/gc/gc.retain (; 20 ;) (type $FUNCSIG$vi) (param $0 i32)
+ (local $1 i32)
+ global.get $~lib/gc/GC_ROOT
+ local.set $1
+ local.get $1
+ local.get $0
+ call $~lib/set/Set#has
+ i32.eqz
+ if
+ local.get $1
+ local.get $0
+ call $~lib/set/Set#add
+ local.get $0
+ local.get $1
+ call $gc/_dummy/__ref_link
+ end
+ )
+ (func $~lib/set/Set#delete (; 21 ;) (type $FUNCSIG$iii) (param $0 i32) (param $1 i32) (result i32)
+ (local $2 i32)
+ (local $3 i32)
+ (local $4 i32)
+ (local $5 i32)
+ local.get $0
+ local.get $1
+ block $~lib/util/hash/HASH|inlined.3 (result i32)
+ local.get $1
+ local.set $2
+ local.get $2
+ call $~lib/util/hash/hash32
+ br $~lib/util/hash/HASH|inlined.3
+ end
+ call $~lib/set/Set#find
+ local.set $3
+ local.get $3
+ i32.eqz
+ if
+ i32.const 0
+ return
+ end
+ local.get $3
+ local.get $3
+ i32.load offset=4
+ i32.const 1
+ i32.or
+ i32.store offset=4
+ local.get $0
+ local.get $0
+ i32.load offset=20
+ i32.const 1
+ i32.sub
+ i32.store offset=20
+ local.get $0
+ i32.load offset=4
+ i32.const 1
+ i32.shr_u
+ local.set $4
+ local.get $4
+ i32.const 1
+ i32.add
+ i32.const 4
+ local.tee $2
+ local.get $0
+ i32.load offset=20
+ local.tee $5
+ local.get $2
+ local.get $5
+ i32.gt_u
+ select
+ i32.ge_u
+ local.tee $2
+ if (result i32)
+ local.get $0
+ i32.load offset=20
+ local.get $0
+ i32.load offset=12
+ f64.convert_i32_s
+ f64.const 0.75
+ f64.mul
+ i32.trunc_f64_s
+ i32.lt_s
+ else
+ local.get $2
+ end
+ if
+ local.get $0
+ local.get $4
+ call $~lib/set/Set#rehash
+ end
+ i32.const 1
+ )
+ (func $~lib/gc/gc.release (; 22 ;) (type $FUNCSIG$vi) (param $0 i32)
+ (local $1 i32)
+ global.get $~lib/gc/GC_ROOT
+ local.set $1
+ local.get $1
+ local.get $0
+ call $~lib/set/Set#has
+ if
+ local.get $1
+ local.get $0
+ call $~lib/set/Set#delete
+ drop
+ local.get $0
+ local.get $1
+ call $gc/_dummy/__ref_unlink
+ end
+ )
+ (func $gc/_dummy/__ref_collect (; 23 ;) (type $FUNCSIG$v)
+ i32.const 272
+ i32.const 0
+ f64.const 0
+ f64.const 0
+ f64.const 0
+ f64.const 0
+ f64.const 0
+ call $~lib/env/trace
+ global.get $gc/_dummy/collect_count
+ i32.const 1
+ i32.add
+ global.set $gc/_dummy/collect_count
+ )
+ (func $~lib/gc/gc.collect (; 24 ;) (type $FUNCSIG$v)
+ call $gc/_dummy/__ref_collect
+ )
+ (func $gc/main (; 25 ;) (type $FUNCSIG$v)
+ (local $0 i32)
+ (local $1 i32)
+ (local $2 i32)
+ (local $3 i32)
+ global.get $~lib/started
+ i32.eqz
+ if
+ call $start
+ i32.const 1
+ global.set $~lib/started
+ end
+ i32.const 0
+ call $gc/Ref#constructor
+ local.set $0
+ global.get $~lib/gc/gc.implemented
+ i32.eqz
+ if
+ i32.const 0
+ i32.const 112
+ i32.const 10
+ i32.const 2
+ call $~lib/env/abort
+ unreachable
+ end
+ global.get $gc/_dummy/link_count
+ local.set $1
+ global.get $gc/_dummy/unlink_count
+ local.set $2
+ global.get $gc/_dummy/collect_count
+ local.set $3
+ local.get $0
+ call $~lib/gc/gc.retain
+ global.get $gc/_dummy/link_count
+ local.get $1
+ i32.const 1
+ i32.add
+ i32.eq
+ i32.eqz
+ if
+ i32.const 0
+ i32.const 112
+ i32.const 18
+ i32.const 2
+ call $~lib/env/abort
+ unreachable
+ end
+ global.get $gc/_dummy/unlink_count
+ local.get $2
+ i32.eq
+ i32.eqz
+ if
+ i32.const 0
+ i32.const 112
+ i32.const 19
+ i32.const 2
+ call $~lib/env/abort
+ unreachable
+ end
+ global.get $gc/_dummy/collect_count
+ local.get $3
+ i32.eq
+ i32.eqz
+ if
+ i32.const 0
+ i32.const 112
+ i32.const 20
+ i32.const 2
+ call $~lib/env/abort
+ unreachable
+ end
+ global.get $gc/_dummy/link_count
+ local.set $1
+ global.get $gc/_dummy/unlink_count
+ local.set $2
+ global.get $gc/_dummy/collect_count
+ local.set $3
+ local.get $0
+ call $~lib/gc/gc.release
+ global.get $gc/_dummy/link_count
+ local.get $1
+ i32.eq
+ i32.eqz
+ if
+ i32.const 0
+ i32.const 112
+ i32.const 27
+ i32.const 2
+ call $~lib/env/abort
+ unreachable
+ end
+ global.get $gc/_dummy/unlink_count
+ local.get $2
+ i32.const 1
+ i32.add
+ i32.eq
+ i32.eqz
+ if
+ i32.const 0
+ i32.const 112
+ i32.const 28
+ i32.const 2
+ call $~lib/env/abort
+ unreachable
+ end
+ global.get $gc/_dummy/collect_count
+ local.get $3
+ i32.eq
+ i32.eqz
+ if
+ i32.const 0
+ i32.const 112
+ i32.const 29
+ i32.const 2
+ call $~lib/env/abort
+ unreachable
+ end
+ global.get $gc/_dummy/link_count
+ local.set $1
+ global.get $gc/_dummy/unlink_count
+ local.set $2
+ global.get $gc/_dummy/collect_count
+ local.set $3
+ call $~lib/gc/gc.collect
+ global.get $gc/_dummy/link_count
+ local.get $1
+ i32.eq
+ i32.eqz
+ if
+ i32.const 0
+ i32.const 112
+ i32.const 36
+ i32.const 2
+ call $~lib/env/abort
+ unreachable
+ end
+ global.get $gc/_dummy/unlink_count
+ local.get $2
+ i32.eq
+ i32.eqz
+ if
+ i32.const 0
+ i32.const 112
+ i32.const 37
+ i32.const 2
+ call $~lib/env/abort
+ unreachable
+ end
+ global.get $gc/_dummy/collect_count
+ local.get $3
+ i32.const 1
+ i32.add
+ i32.eq
+ i32.eqz
+ if
+ i32.const 0
+ i32.const 112
+ i32.const 38
+ i32.const 2
+ call $~lib/env/abort
+ unreachable
+ end
+ )
+ (func $start (; 26 ;) (type $FUNCSIG$v)
+ global.get $~lib/memory/HEAP_BASE
+ i32.const 7
+ i32.add
+ i32.const 7
+ i32.const -1
+ i32.xor
+ i32.and
+ global.set $~lib/allocator/arena/startOffset
+ global.get $~lib/allocator/arena/startOffset
+ global.set $~lib/allocator/arena/offset
+ i32.const 0
+ call $~lib/set/Set#constructor
+ global.set $~lib/gc/GC_ROOT
+ )
+ (func $null (; 27 ;) (type $FUNCSIG$v)
+ )
+)