archetype-ecs 1.4.2 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/README.md +79 -14
  2. package/bench/allocations-1m.js +1 -1
  3. package/bench/component-churn-bench.js +193 -0
  4. package/bench/iterate.wat +95 -0
  5. package/bench/multi-ecs-bench.js +1 -1
  6. package/bench/run-js-vs-go-ts.sh +147 -0
  7. package/bench/typed-vs-bitecs-1m.js +1 -1
  8. package/bench/typed-vs-untyped.js +1 -1
  9. package/bench/vs-bitecs.js +1 -1
  10. package/bench/wasm-iteration-bench.js +289 -0
  11. package/dist/{src/ComponentRegistry.d.ts → ComponentRegistry.d.ts} +8 -3
  12. package/dist/{src/EntityManager.d.ts → EntityManager.d.ts} +15 -10
  13. package/dist/{src/EntityManager.js → EntityManager.js} +196 -95
  14. package/dist/{src/System.d.ts → System.d.ts} +4 -0
  15. package/dist/{src/System.js → System.js} +25 -5
  16. package/dist/WasmArena.d.ts +13 -0
  17. package/dist/WasmArena.js +48 -0
  18. package/dist/{src/index.d.ts → index.d.ts} +7 -9
  19. package/dist/{src/index.js → index.js} +2 -0
  20. package/dist/wasm-kernels.d.ts +10 -0
  21. package/dist/wasm-kernels.js +59 -0
  22. package/package.json +12 -7
  23. package/src/ComponentRegistry.ts +7 -3
  24. package/src/EntityManager.ts +209 -119
  25. package/src/System.ts +34 -9
  26. package/src/WasmArena.ts +83 -0
  27. package/src/index.ts +16 -11
  28. package/src/iterate.wat +135 -0
  29. package/src/wasm-kernels.ts +68 -0
  30. package/tests/EntityManager.test.ts +51 -86
  31. package/tests/System.test.ts +184 -0
  32. package/tests/types.ts +1 -1
  33. package/tsconfig.json +2 -2
  34. package/tsconfig.test.json +13 -0
  35. package/dist/tests/EntityManager.test.d.ts +0 -1
  36. package/dist/tests/EntityManager.test.js +0 -651
  37. package/dist/tests/System.test.d.ts +0 -1
  38. package/dist/tests/System.test.js +0 -630
  39. package/dist/tests/types.d.ts +0 -1
  40. package/dist/tests/types.js +0 -129
  41. /package/dist/{src/ComponentRegistry.js → ComponentRegistry.js} +0 -0
  42. /package/dist/{src/Profiler.d.ts → Profiler.d.ts} +0 -0
  43. /package/dist/{src/Profiler.js → Profiler.js} +0 -0
package/src/System.ts CHANGED
@@ -66,7 +66,8 @@ export class System {
66
66
 
67
67
  tick?(): void;
68
68
 
69
- run(): void {
69
+ /** Process hooks and tick without clearing removed-data snapshots. */
70
+ _runCore(): void {
70
71
  for (const hook of this._hooks) {
71
72
  for (const id of hook.buffer) hook.handler(id);
72
73
  hook.buffer.clear();
@@ -74,6 +75,11 @@ export class System {
74
75
  if (this.tick) this.tick();
75
76
  }
76
77
 
78
+ run(): void {
79
+ this._runCore();
80
+ this.em.commitRemovals();
81
+ }
82
+
77
83
  dispose(): void {
78
84
  for (const unsub of this._unsubs) unsub();
79
85
  this._unsubs.length = 0;
@@ -101,6 +107,8 @@ interface FunctionalHook {
101
107
 
102
108
  export interface FunctionalSystem {
103
109
  (): void;
110
+ /** @internal Process hooks and tick without clearing removed-data snapshots. */
111
+ _runCore(): void;
104
112
  dispose(): void;
105
113
  }
106
114
 
@@ -108,7 +116,7 @@ export function createSystem(em: EntityManager, constructor: FunctionalSystemCon
108
116
  const hooks: FunctionalHook[] = [];
109
117
 
110
118
  const sys: SystemContext = {
111
- onAdded(...args: any[]) {
119
+ onAdded(...args: [...ComponentDef[], HookCallback]) {
112
120
  const callback = args[args.length - 1] as HookCallback;
113
121
  const types = args.slice(0, -1) as ComponentDef[];
114
122
  const buffer = new Set<EntityId>();
@@ -127,7 +135,7 @@ export function createSystem(em: EntityManager, constructor: FunctionalSystemCon
127
135
  hooks.push({ unsubs, buffer, callback });
128
136
  },
129
137
 
130
- onRemoved(...args: any[]) {
138
+ onRemoved(...args: [...ComponentDef[], HookCallback]) {
131
139
  const callback = args[args.length - 1] as HookCallback;
132
140
  const types = args.slice(0, -1) as ComponentDef[];
133
141
  const buffer = new Set<EntityId>();
@@ -150,7 +158,7 @@ export function createSystem(em: EntityManager, constructor: FunctionalSystemCon
150
158
 
151
159
  const tick = constructor(sys);
152
160
 
153
- function system() {
161
+ function runCore() {
154
162
  for (const hook of hooks) {
155
163
  for (const id of hook.buffer) hook.callback(id);
156
164
  hook.buffer.clear();
@@ -158,6 +166,13 @@ export function createSystem(em: EntityManager, constructor: FunctionalSystemCon
158
166
  if (tick) tick();
159
167
  }
160
168
 
169
+ function system() {
170
+ runCore();
171
+ em.commitRemovals();
172
+ }
173
+
174
+ system._runCore = runCore;
175
+
161
176
  system.dispose = function () {
162
177
  for (const hook of hooks) {
163
178
  for (const unsub of hook.unsubs) unsub();
@@ -171,7 +186,7 @@ export function createSystem(em: EntityManager, constructor: FunctionalSystemCon
171
186
  // ── Activator ────────────────────────────────────────────
172
187
 
173
188
  interface Runnable {
174
- run(): void;
189
+ _runCore(): void;
175
190
  dispose(): void;
176
191
  }
177
192
 
@@ -180,17 +195,27 @@ export interface Pipeline {
180
195
  dispose(): void;
181
196
  }
182
197
 
198
+ function isSystemClass(entry: Function): entry is new (em: EntityManager) => System {
199
+ let proto = entry.prototype;
200
+ while (proto) {
201
+ proto = Object.getPrototypeOf(proto);
202
+ if (proto === System.prototype) return true;
203
+ }
204
+ return false;
205
+ }
206
+
183
207
  export function createSystems(em: EntityManager, entries: (FunctionalSystemConstructor | (new (em: EntityManager) => System))[]): Pipeline {
184
208
  const systems: Runnable[] = entries.map(Entry => {
185
- if ('prototype' in Entry && Entry.prototype instanceof System) {
186
- return new (Entry as new (em: EntityManager) => System)(em);
209
+ if (isSystemClass(Entry)) {
210
+ return new Entry(em);
187
211
  }
188
212
  const sys = createSystem(em, Entry as FunctionalSystemConstructor);
189
- return { run: sys, dispose: sys.dispose };
213
+ return { _runCore: sys._runCore, dispose: sys.dispose };
190
214
  });
191
215
 
192
216
  function pipeline() {
193
- for (let i = 0; i < systems.length; i++) systems[i].run();
217
+ for (let i = 0; i < systems.length; i++) systems[i]._runCore();
218
+ em.commitRemovals();
194
219
  }
195
220
 
196
221
  pipeline.dispose = function () {
@@ -0,0 +1,83 @@
1
+ import type { SoAArrayValue } from './EntityManager.js';
2
+
3
+ export type NumericTypedArrayConstructor =
4
+ | typeof Float32Array | typeof Float64Array
5
+ | typeof Int8Array | typeof Int16Array | typeof Int32Array
6
+ | typeof Uint8Array | typeof Uint16Array | typeof Uint32Array;
7
+
8
+ interface ViewRegistration {
9
+ fields: Record<string, SoAArrayValue>;
10
+ field: string;
11
+ offset: number;
12
+ Ctor: NumericTypedArrayConstructor;
13
+ count: number;
14
+ }
15
+
16
+ const ALIGN = 16; // 16-byte alignment for SIMD
17
+
18
+ export class WasmArena {
19
+ memory: WebAssembly.Memory;
20
+ private nextOffset: number = 0;
21
+ private views: ViewRegistration[] = [];
22
+
23
+ constructor(initialPages = 2048, maxPages = 16384) {
24
+ this.memory = new WebAssembly.Memory({ initial: initialPages, maximum: maxPages });
25
+ }
26
+
27
+ alloc(byteLength: number): number {
28
+ // Align up to 16 bytes
29
+ const aligned = (this.nextOffset + ALIGN - 1) & ~(ALIGN - 1);
30
+ const end = aligned + byteLength;
31
+
32
+ if (end > this.memory.buffer.byteLength) {
33
+ const needed = Math.ceil((end - this.memory.buffer.byteLength) / 65536);
34
+ this.memory.grow(needed);
35
+ this.handleGrow();
36
+ }
37
+
38
+ this.nextOffset = end;
39
+ return aligned;
40
+ }
41
+
42
+ createView<T extends SoAArrayValue>(
43
+ Ctor: NumericTypedArrayConstructor,
44
+ offset: number,
45
+ count: number,
46
+ fields: Record<string, SoAArrayValue>,
47
+ field: string
48
+ ): T {
49
+ const view = new Ctor(this.memory.buffer, offset, count) as unknown as T;
50
+ this.views.push({ fields, field, offset, Ctor, count });
51
+ fields[field] = view;
52
+ return view;
53
+ }
54
+
55
+ private handleGrow(): void {
56
+ const buf = this.memory.buffer;
57
+ for (const reg of this.views) {
58
+ reg.fields[reg.field] = new reg.Ctor(buf, reg.offset, reg.count);
59
+ }
60
+ }
61
+
62
+ /** Update a registered view to point to a new (larger) allocation. */
63
+ updateView(
64
+ fields: Record<string, SoAArrayValue>,
65
+ field: string,
66
+ offset: number,
67
+ Ctor: NumericTypedArrayConstructor,
68
+ count: number
69
+ ): void {
70
+ // Find and update the existing registration
71
+ for (const reg of this.views) {
72
+ if (reg.fields === fields && reg.field === field) {
73
+ reg.offset = offset;
74
+ reg.Ctor = Ctor;
75
+ reg.count = count;
76
+ fields[field] = new Ctor(this.memory.buffer, offset, count);
77
+ return;
78
+ }
79
+ }
80
+ // Not found — register as new
81
+ this.createView(Ctor, offset, count, fields, field);
82
+ }
83
+ }
package/src/index.ts CHANGED
@@ -1,21 +1,26 @@
1
1
  export { createEntityManager } from './EntityManager.js';
2
- export type { EntityId, FieldRef, ArchetypeView, EntityManager, SerializedData } from './EntityManager.js';
2
+ export type { EntityId, ArchetypeView, EntityManager, SerializedData } from './EntityManager.js';
3
3
  export { createSystem, createSystems, System, OnAdded, OnRemoved } from './System.js';
4
4
  export type { SystemContext, FunctionalSystemConstructor, FunctionalSystem, Pipeline } from './System.js';
5
5
  export { profiler } from './Profiler.js';
6
6
  export type { Profiler, ProfilerEntry } from './Profiler.js';
7
7
  export { TYPED, componentSchemas, parseTypeSpec } from './ComponentRegistry.js';
8
- export type { ComponentDef, TypeSpec } from './ComponentRegistry.js';
8
+ export type { ComponentDef, FieldRef, TypeSpec } from './ComponentRegistry.js';
9
+ export { WasmArena } from './WasmArena.js';
10
+ export { instantiateKernels, isWasmSimdAvailable } from './wasm-kernels.js';
11
+ export type { IterateKernels } from './wasm-kernels.js';
9
12
 
10
- import { parseTypeSpec, componentSchemas, type ComponentDef, type TypeSpec } from './ComponentRegistry.js';
11
- import type { FieldRef } from './EntityManager.js';
13
+ import { parseTypeSpec, componentSchemas, type ComponentDef, type FieldRef, type TypeSpec } from './ComponentRegistry.js';
12
14
 
15
+ // Tag component (no fields)
13
16
  export function component(name: string): ComponentDef;
14
- export function component<F extends readonly string[]>(name: string, type: string, fields: F): ComponentDef & { readonly [K in F[number]]: FieldRef };
15
- export function component<S extends Record<string, string>>(name: string, schema: S): ComponentDef & { readonly [K in keyof S]: FieldRef };
16
- export function component(name: string, typeOrSchema?: string | Record<string, string>, fields?: string[]): ComponentDef {
17
+ // Uniform type with field list
18
+ export function component<const F extends readonly string[]>(name: string, type: string, fields: F): ComponentDef<F[number]>;
19
+ // Schema object with mixed types
20
+ export function component<S extends Record<string, string>>(name: string, schema: S): ComponentDef<Extract<keyof S, string>>;
21
+ export function component(name: string, typeOrSchema?: string | Record<string, string>, fields?: string[]): ComponentDef<string> {
17
22
  const sym = Symbol(name);
18
- const comp: any = { _sym: sym, _name: name };
23
+ const comp: Record<string, unknown> = { _sym: sym, _name: name };
19
24
 
20
25
  let schema: Record<string, TypeSpec> | undefined;
21
26
 
@@ -24,13 +29,13 @@ export function component(name: string, typeOrSchema?: string | Record<string, s
24
29
  schema = {};
25
30
  for (const f of fields) {
26
31
  schema[f] = spec;
27
- comp[f] = { _sym: sym, _field: f };
32
+ comp[f] = { _sym: sym, _field: f } satisfies FieldRef;
28
33
  }
29
34
  } else if (typeOrSchema && typeof typeOrSchema === 'object') {
30
35
  schema = {};
31
36
  for (const [field, type] of Object.entries(typeOrSchema)) {
32
37
  schema[field] = parseTypeSpec(type);
33
- comp[field] = { _sym: sym, _field: field };
38
+ comp[field] = { _sym: sym, _field: field } satisfies FieldRef;
34
39
  }
35
40
  }
36
41
 
@@ -38,5 +43,5 @@ export function component(name: string, typeOrSchema?: string | Record<string, s
38
43
  componentSchemas.set(sym, schema);
39
44
  }
40
45
 
41
- return comp;
46
+ return comp as ComponentDef<string>;
42
47
  }
@@ -0,0 +1,135 @@
1
+ (module
2
+ (memory (import "env" "memory") 1)
3
+
4
+ ;; Scalar loop: px[i] += vx[i]; py[i] += vy[i]
5
+ ;; params: byte offsets for px, py, vx, vy arrays + element count
6
+ (func (export "iterate_scalar")
7
+ (param $px i32) (param $py i32) (param $vx i32) (param $vy i32) (param $count i32)
8
+ (local $i i32)
9
+ (local $off i32)
10
+ (local.set $i (i32.const 0))
11
+ (block $break
12
+ (loop $loop
13
+ (br_if $break (i32.ge_u (local.get $i) (local.get $count)))
14
+ (local.set $off (i32.shl (local.get $i) (i32.const 2)))
15
+ ;; px[i] += vx[i]
16
+ (f32.store
17
+ (i32.add (local.get $px) (local.get $off))
18
+ (f32.add
19
+ (f32.load (i32.add (local.get $px) (local.get $off)))
20
+ (f32.load (i32.add (local.get $vx) (local.get $off)))
21
+ )
22
+ )
23
+ ;; py[i] += vy[i]
24
+ (f32.store
25
+ (i32.add (local.get $py) (local.get $off))
26
+ (f32.add
27
+ (f32.load (i32.add (local.get $py) (local.get $off)))
28
+ (f32.load (i32.add (local.get $vy) (local.get $off)))
29
+ )
30
+ )
31
+ (local.set $i (i32.add (local.get $i) (i32.const 1)))
32
+ (br $loop)
33
+ )
34
+ )
35
+ )
36
+
37
+ ;; SIMD loop: processes 4 floats at a time using v128 / f32x4
38
+ (func (export "iterate_simd")
39
+ (param $px i32) (param $py i32) (param $vx i32) (param $vy i32) (param $count i32)
40
+ (local $i i32)
41
+ (local $off i32)
42
+ (local $end4 i32)
43
+ ;; end4 = count & ~3 (round down to multiple of 4)
44
+ (local.set $end4 (i32.and (local.get $count) (i32.const -4)))
45
+ ;; SIMD loop: 4 elements per iteration
46
+ (local.set $i (i32.const 0))
47
+ (block $break
48
+ (loop $loop
49
+ (br_if $break (i32.ge_u (local.get $i) (local.get $end4)))
50
+ (local.set $off (i32.shl (local.get $i) (i32.const 2)))
51
+ ;; px[i..i+4] += vx[i..i+4]
52
+ (v128.store
53
+ (i32.add (local.get $px) (local.get $off))
54
+ (f32x4.add
55
+ (v128.load (i32.add (local.get $px) (local.get $off)))
56
+ (v128.load (i32.add (local.get $vx) (local.get $off)))
57
+ )
58
+ )
59
+ ;; py[i..i+4] += vy[i..i+4]
60
+ (v128.store
61
+ (i32.add (local.get $py) (local.get $off))
62
+ (f32x4.add
63
+ (v128.load (i32.add (local.get $py) (local.get $off)))
64
+ (v128.load (i32.add (local.get $vy) (local.get $off)))
65
+ )
66
+ )
67
+ (local.set $i (i32.add (local.get $i) (i32.const 4)))
68
+ (br $loop)
69
+ )
70
+ )
71
+ ;; Scalar remainder
72
+ (block $break2
73
+ (loop $loop2
74
+ (br_if $break2 (i32.ge_u (local.get $i) (local.get $count)))
75
+ (local.set $off (i32.shl (local.get $i) (i32.const 2)))
76
+ (f32.store
77
+ (i32.add (local.get $px) (local.get $off))
78
+ (f32.add
79
+ (f32.load (i32.add (local.get $px) (local.get $off)))
80
+ (f32.load (i32.add (local.get $vx) (local.get $off)))
81
+ )
82
+ )
83
+ (f32.store
84
+ (i32.add (local.get $py) (local.get $off))
85
+ (f32.add
86
+ (f32.load (i32.add (local.get $py) (local.get $off)))
87
+ (f32.load (i32.add (local.get $vy) (local.get $off)))
88
+ )
89
+ )
90
+ (local.set $i (i32.add (local.get $i) (i32.const 1)))
91
+ (br $loop2)
92
+ )
93
+ )
94
+ )
95
+
96
+ ;; Generic f32 add: dst[i] += src[i], SIMD 4-wide + scalar remainder
97
+ (func (export "add_f32")
98
+ (param $dst i32) (param $src i32) (param $count i32)
99
+ (local $i i32)
100
+ (local $off i32)
101
+ (local $end4 i32)
102
+ (local.set $end4 (i32.and (local.get $count) (i32.const -4)))
103
+ (local.set $i (i32.const 0))
104
+ (block $break
105
+ (loop $loop
106
+ (br_if $break (i32.ge_u (local.get $i) (local.get $end4)))
107
+ (local.set $off (i32.shl (local.get $i) (i32.const 2)))
108
+ (v128.store
109
+ (i32.add (local.get $dst) (local.get $off))
110
+ (f32x4.add
111
+ (v128.load (i32.add (local.get $dst) (local.get $off)))
112
+ (v128.load (i32.add (local.get $src) (local.get $off)))
113
+ )
114
+ )
115
+ (local.set $i (i32.add (local.get $i) (i32.const 4)))
116
+ (br $loop)
117
+ )
118
+ )
119
+ (block $break2
120
+ (loop $loop2
121
+ (br_if $break2 (i32.ge_u (local.get $i) (local.get $count)))
122
+ (local.set $off (i32.shl (local.get $i) (i32.const 2)))
123
+ (f32.store
124
+ (i32.add (local.get $dst) (local.get $off))
125
+ (f32.add
126
+ (f32.load (i32.add (local.get $dst) (local.get $off)))
127
+ (f32.load (i32.add (local.get $src) (local.get $off)))
128
+ )
129
+ )
130
+ (local.set $i (i32.add (local.get $i) (i32.const 1)))
131
+ (br $loop2)
132
+ )
133
+ )
134
+ )
135
+ )
@@ -0,0 +1,68 @@
1
+ // Auto-generated from src/iterate.wat — do not edit by hand
2
+ const ITERATE_WASM = new Uint8Array([
3
+ 0,97,115,109,1,0,0,0,1,15,2,96,5,127,127,127,127,127,0,96,
4
+ 3,127,127,127,0,2,15,1,3,101,110,118,6,109,101,109,111,114,121,2,
5
+ 0,1,3,4,3,0,0,1,7,43,3,14,105,116,101,114,97,116,101,95,
6
+ 115,99,97,108,97,114,0,0,12,105,116,101,114,97,116,101,95,115,105,109,
7
+ 100,0,1,7,97,100,100,95,102,51,50,0,2,10,148,3,3,87,1,2,
8
+ 127,65,0,33,5,2,64,3,64,32,5,32,4,79,13,1,32,5,65,2,
9
+ 116,33,6,32,0,32,6,106,32,0,32,6,106,42,2,0,32,2,32,6,
10
+ 106,42,2,0,146,56,2,0,32,1,32,6,106,32,1,32,6,106,42,2,
11
+ 0,32,3,32,6,106,42,2,0,146,56,2,0,32,5,65,1,106,33,5,
12
+ 12,0,11,11,11,183,1,1,3,127,32,4,65,124,113,33,7,65,0,33,
13
+ 5,2,64,3,64,32,5,32,7,79,13,1,32,5,65,2,116,33,6,32,
14
+ 0,32,6,106,32,0,32,6,106,253,0,4,0,32,2,32,6,106,253,0,
15
+ 4,0,253,228,1,253,11,4,0,32,1,32,6,106,32,1,32,6,106,253,
16
+ 0,4,0,32,3,32,6,106,253,0,4,0,253,228,1,253,11,4,0,32,
17
+ 5,65,4,106,33,5,12,0,11,11,2,64,3,64,32,5,32,4,79,13,
18
+ 1,32,5,65,2,116,33,6,32,0,32,6,106,32,0,32,6,106,42,2,
19
+ 0,32,2,32,6,106,42,2,0,146,56,2,0,32,1,32,6,106,32,1,
20
+ 32,6,106,42,2,0,32,3,32,6,106,42,2,0,146,56,2,0,32,5,
21
+ 65,1,106,33,5,12,0,11,11,11,128,1,1,3,127,32,2,65,124,113,
22
+ 33,5,65,0,33,3,2,64,3,64,32,3,32,5,79,13,1,32,3,65,
23
+ 2,116,33,4,32,0,32,4,106,32,0,32,4,106,253,0,4,0,32,1,
24
+ 32,4,106,253,0,4,0,253,228,1,253,11,4,0,32,3,65,4,106,33,
25
+ 3,12,0,11,11,2,64,3,64,32,3,32,2,79,13,1,32,3,65,2,
26
+ 116,33,4,32,0,32,4,106,32,0,32,4,106,42,2,0,32,1,32,4,
27
+ 106,42,2,0,146,56,2,0,32,3,65,1,106,33,3,12,0,11,11,11
28
+ ]); // 500 bytes
29
+
30
+ export interface IterateKernels {
31
+ iterate_scalar(px: number, py: number, vx: number, vy: number, count: number): void;
32
+ iterate_simd(px: number, py: number, vx: number, vy: number, count: number): void;
33
+ add_f32(dst: number, src: number, count: number): void;
34
+ }
35
+
36
+ // Cached compiled module (shared across all EntityManager instances)
37
+ let cachedModule: WebAssembly.Module | null = null;
38
+
39
+ function getCompiledModule(): WebAssembly.Module {
40
+ if (!cachedModule) {
41
+ cachedModule = new WebAssembly.Module(ITERATE_WASM);
42
+ }
43
+ return cachedModule;
44
+ }
45
+
46
+ /** Returns true if the runtime supports WebAssembly SIMD. Result is cached. */
47
+ export function isWasmSimdAvailable(): boolean {
48
+ if (cachedModule !== null) return true;
49
+ try {
50
+ getCompiledModule();
51
+ return true;
52
+ } catch {
53
+ return false;
54
+ }
55
+ }
56
+
57
+ export async function instantiateKernels(memory: WebAssembly.Memory): Promise<IterateKernels> {
58
+ const module = getCompiledModule();
59
+ const instance = await WebAssembly.instantiate(module, { env: { memory } });
60
+ return instance.exports as unknown as IterateKernels;
61
+ }
62
+
63
+ /** Synchronous instantiation — only for small modules (<4KB). Used internally. */
64
+ export function instantiateKernelsSync(memory: WebAssembly.Memory): IterateKernels {
65
+ const module = getCompiledModule();
66
+ const instance = new WebAssembly.Instance(module, { env: { memory } });
67
+ return instance.exports as unknown as IterateKernels;
68
+ }