gofront 1.4.0 → 1.6.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 (77) hide show
  1. package/README.md +174 -403
  2. package/package.json +16 -19
  3. package/src/{codegen → backend/js}/expressions.js +265 -77
  4. package/src/{codegen → backend/js}/index.js +120 -89
  5. package/src/{codegen → backend/js}/runtime.js +102 -0
  6. package/src/{codegen → backend/js}/source-map.js +32 -0
  7. package/src/{codegen → backend/js}/statements.js +139 -64
  8. package/src/backend/js/stdlib/bits.js +32 -0
  9. package/src/{codegen → backend/js}/stdlib/errors.js +2 -2
  10. package/src/{codegen → backend/js}/stdlib/fmt.js +26 -8
  11. package/src/{codegen → backend/js}/stdlib/index.js +6 -0
  12. package/src/{codegen → backend/js}/stdlib/maps.js +1 -1
  13. package/src/{codegen → backend/js}/stdlib/path.js +2 -2
  14. package/src/backend/js/stdlib/shared.js +17 -0
  15. package/src/{codegen → backend/js}/stdlib/slices.js +1 -1
  16. package/src/{codegen → backend/js}/stdlib/sort.js +1 -1
  17. package/src/backend/js/stdlib/strconv.js +58 -0
  18. package/src/{codegen → backend/js}/stdlib/strings.js +4 -1
  19. package/src/{codegen → backend/js}/stdlib/testing.js +2 -2
  20. package/src/{codegen → backend/js}/stdlib/time.js +3 -3
  21. package/src/{codegen → backend/js}/templ.js +3 -3
  22. package/src/backend/wasm/boundary.js +1798 -0
  23. package/src/backend/wasm/emit-builtins.js +1103 -0
  24. package/src/backend/wasm/emit-exprs.js +1908 -0
  25. package/src/backend/wasm/emit-maps.js +1863 -0
  26. package/src/backend/wasm/emit-shared.js +519 -0
  27. package/src/backend/wasm/emit-stdlib.js +3006 -0
  28. package/src/backend/wasm/emit-stmts.js +2472 -0
  29. package/src/backend/wasm/emit.js +1376 -0
  30. package/src/backend/wasm/encode.js +937 -0
  31. package/src/backend/wasm/glue.js +144 -0
  32. package/src/backend/wasm/index.js +2790 -0
  33. package/src/backend/wasm/monomorph.js +711 -0
  34. package/src/backend/wasm/optimize.js +227 -0
  35. package/src/backend/wasm/types.js +544 -0
  36. package/src/backend/wasm/wat.js +302 -0
  37. package/src/cli-core.js +323 -75
  38. package/src/compiler.js +447 -14
  39. package/src/dev-server.js +56 -15
  40. package/src/index.js +99 -120
  41. package/src/lexer.js +18 -0
  42. package/src/lower/boxing.js +35 -0
  43. package/src/lower/captures.js +172 -0
  44. package/src/lower/embedding.js +30 -0
  45. package/src/lower/escape.js +164 -0
  46. package/src/lower/functions.js +302 -0
  47. package/src/lower/globals.js +316 -0
  48. package/src/lower/index.js +118 -0
  49. package/src/lower/ownership.js +137 -0
  50. package/src/lower/range.js +67 -0
  51. package/src/lower/walk.js +25 -0
  52. package/src/minifier.js +2 -0
  53. package/src/parser/index.js +8 -3
  54. package/src/resolver.js +3 -1
  55. package/src/test-runner.js +94 -20
  56. package/src/typechecker/assignability.js +42 -1
  57. package/src/typechecker/expressions.js +182 -3
  58. package/src/typechecker/index.js +261 -5
  59. package/src/typechecker/resolve.js +35 -6
  60. package/src/typechecker/stdlib/core.js +34 -19
  61. package/src/typechecker/stdlib/extended.js +18 -3
  62. package/src/typechecker/stdlib/shared.js +53 -0
  63. package/src/typechecker/stdlib.js +2 -0
  64. package/src/typechecker/types.js +259 -6
  65. package/src/vendor.js +2 -2
  66. package/src/codegen/stdlib/strconv.js +0 -33
  67. /package/src/{codegen → backend/js}/stdlib/builder.js +0 -0
  68. /package/src/{codegen → backend/js}/stdlib/bytes.js +0 -0
  69. /package/src/{codegen → backend/js}/stdlib/gom.js +0 -0
  70. /package/src/{codegen → backend/js}/stdlib/html.js +0 -0
  71. /package/src/{codegen → backend/js}/stdlib/io.js +0 -0
  72. /package/src/{codegen → backend/js}/stdlib/math.js +0 -0
  73. /package/src/{codegen → backend/js}/stdlib/os.js +0 -0
  74. /package/src/{codegen → backend/js}/stdlib/rand.js +0 -0
  75. /package/src/{codegen → backend/js}/stdlib/regexp.js +0 -0
  76. /package/src/{codegen → backend/js}/stdlib/unicode.js +0 -0
  77. /package/src/{codegen → backend/js}/stdlib/utf8.js +0 -0
@@ -0,0 +1,1863 @@
1
+ // src/backend/wasm/emit-maps.js
2
+ // FunctionEmitter mixin: map runtime helpers (key hash/eq, get/set/delete,
3
+ // iteration, clone) and zero values.
4
+
5
+ import {
6
+ isArrayType,
7
+ isInterfaceType,
8
+ isPointerToStruct,
9
+ isStringType,
10
+ toWasmType,
11
+ } from "./types.js";
12
+
13
+ export class MapsEmitter {
14
+ emitMapHelper(fn) {
15
+ const kind = fn._mapHelperKind;
16
+ const mapInfo = fn._mapInfo;
17
+ switch (kind) {
18
+ case "make":
19
+ this.emitMapMake(mapInfo);
20
+ break;
21
+ case "get":
22
+ this.emitMapGet(mapInfo);
23
+ break;
24
+ case "get_ok":
25
+ this.emitMapGetOk(mapInfo);
26
+ break;
27
+ case "set":
28
+ this.emitMapSet(mapInfo);
29
+ break;
30
+ case "delete":
31
+ this.emitMapDelete(mapInfo);
32
+ break;
33
+ case "len":
34
+ this.emitMapLen(mapInfo);
35
+ break;
36
+ case "clear":
37
+ this.emitMapClear(mapInfo);
38
+ break;
39
+ case "keys":
40
+ this.emitMapKeys(mapInfo);
41
+ break;
42
+ case "values":
43
+ this.emitMapValues(mapInfo);
44
+ break;
45
+ case "clone":
46
+ this.emitMapClone(mapInfo);
47
+ break;
48
+ }
49
+ }
50
+
51
+ // Struct info for a Go type used as a map key (named struct or alias).
52
+ _structInfoForGoType(goType) {
53
+ let t = goType;
54
+ while (t && (t.kind === "TypeName" || t.kind === "Ident")) {
55
+ const info = this.mod.getStructType(t.name);
56
+ if (info) return info;
57
+ const resolved = this.mod.checker?.types?.get(t.name);
58
+ if (!resolved || resolved === t) break;
59
+ t = resolved;
60
+ }
61
+ if (t?.kind === "named") return this.mod.getStructType(t.name) ?? null;
62
+ if ((t?.kind === "struct" || t?.kind === "StructType") && t.name)
63
+ return this.mod.getStructType(t.name) ?? null;
64
+ return null;
65
+ }
66
+
67
+ _unsupportedMapKey(keyGoType) {
68
+ if (isArrayType(keyGoType, this.mod.checker))
69
+ return "array-typed map keys are not yet supported in wasm packages (planned)";
70
+ if (isInterfaceType(keyGoType, this.mod.checker))
71
+ return "interface-typed map keys are not yet supported in wasm packages (planned)";
72
+ return null;
73
+ }
74
+
75
+ emitKeyHash(keyLocal, keyGoType) {
76
+ if (isStringType(keyGoType, this.mod.checker)) {
77
+ this.pushInstruction({ op: "local.get", index: keyLocal });
78
+ this.pushInstruction({
79
+ op: "call",
80
+ funcIndex: this.mod.getStringHashImportIndex(),
81
+ });
82
+ return;
83
+ }
84
+ const wType = toWasmType(keyGoType, this.mod.checker, this.mod);
85
+ if (wType === "i64") {
86
+ this.pushInstruction({ op: "local.get", index: keyLocal });
87
+ this.pushInstruction("i32.wrap_i64");
88
+ this.pushInstruction({ op: "local.get", index: keyLocal });
89
+ this.pushInstruction({ op: "i64.const", value: 32n });
90
+ this.pushInstruction("i64.shr_u");
91
+ this.pushInstruction("i32.wrap_i64");
92
+ this.pushInstruction("i32.xor");
93
+ const tmp = this.allocLocal(null, "i32");
94
+ this.pushInstruction({ op: "local.tee", index: tmp });
95
+ this.pushInstruction({ op: "local.get", index: tmp });
96
+ this.pushInstruction({ op: "i32.const", value: 16 });
97
+ this.pushInstruction("i32.shr_u");
98
+ this.pushInstruction("i32.xor");
99
+ this.pushInstruction({ op: "i32.const", value: 0x45d9f3b });
100
+ this.pushInstruction("i32.mul");
101
+ return;
102
+ }
103
+ if (wType === "i32") {
104
+ const tmp = this.allocLocal(null, "i32");
105
+ this.pushInstruction({ op: "local.get", index: keyLocal });
106
+ this.pushInstruction({ op: "local.tee", index: tmp });
107
+ this.pushInstruction({ op: "local.get", index: tmp });
108
+ this.pushInstruction({ op: "i32.const", value: 16 });
109
+ this.pushInstruction("i32.shr_u");
110
+ this.pushInstruction("i32.xor");
111
+ this.pushInstruction({ op: "i32.const", value: 0x45d9f3b });
112
+ this.pushInstruction("i32.mul");
113
+ return;
114
+ }
115
+ // Floats: `x + 0.0` folds -0 onto +0 (they are equal keys in Go) and
116
+ // leaves NaN as NaN (never equal, so the hash value is irrelevant).
117
+ if (wType === "f32") {
118
+ this.pushInstruction({ op: "local.get", index: keyLocal });
119
+ this.pushInstruction({ op: "f32.const", value: 0 });
120
+ this.pushInstruction("f32.add");
121
+ this.pushInstruction("i32.reinterpret_f32");
122
+ return;
123
+ }
124
+ if (wType === "f64") {
125
+ this.pushInstruction({ op: "local.get", index: keyLocal });
126
+ this.pushInstruction({ op: "f64.const", value: 0 });
127
+ this.pushInstruction("f64.add");
128
+ this.pushInstruction("i64.reinterpret_f64");
129
+ this.pushInstruction("i32.wrap_i64");
130
+ return;
131
+ }
132
+ const structInfo = this._structInfoForGoType(keyGoType);
133
+ if (
134
+ structInfo &&
135
+ !isPointerToStruct(keyGoType, this.mod.checker, this.mod)
136
+ ) {
137
+ // h = 17; for each field: h = h*31 + hash(field)
138
+ const h = this.allocLocal(null, "i32");
139
+ this.pushInstruction({ op: "i32.const", value: 17 });
140
+ this.pushInstruction({ op: "local.set", index: h });
141
+ for (let i = 0; i < structInfo.fields.length; i++) {
142
+ const f = structInfo.fields[i];
143
+ const ft = this.allocLocal(null, f.wType);
144
+ this.pushInstruction({ op: "local.get", index: keyLocal });
145
+ this.pushInstruction({
146
+ op: "struct.get",
147
+ typeIndex: structInfo.typeIndex,
148
+ fieldIndex: i,
149
+ });
150
+ this.pushInstruction({ op: "local.set", index: ft });
151
+ this.pushInstruction({ op: "local.get", index: h });
152
+ this.pushInstruction({ op: "i32.const", value: 31 });
153
+ this.pushInstruction("i32.mul");
154
+ this.emitKeyHash(ft, f.goType);
155
+ this.pushInstruction("i32.add");
156
+ this.pushInstruction({ op: "local.set", index: h });
157
+ }
158
+ this.pushInstruction({ op: "local.get", index: h });
159
+ return;
160
+ }
161
+ const unsupported = this._unsupportedMapKey(keyGoType);
162
+ if (unsupported) throw new Error(unsupported);
163
+ // Pointers/channels: identity equality via ref.eq; no stable hash is
164
+ // available for GC references, so they share a single bucket.
165
+ this.pushInstruction({ op: "i32.const", value: 0 });
166
+ }
167
+
168
+ emitKeyEq(k1Local, k2Local, keyGoType) {
169
+ if (isStringType(keyGoType, this.mod.checker)) {
170
+ this.pushInstruction({ op: "local.get", index: k1Local });
171
+ this.pushInstruction({ op: "local.get", index: k2Local });
172
+ this.pushInstruction({
173
+ op: "call",
174
+ funcIndex: this.mod.getStringCmpImportIndex("=="),
175
+ });
176
+ return;
177
+ }
178
+ const wType = toWasmType(keyGoType, this.mod.checker, this.mod);
179
+ if (wType === "i64") {
180
+ this.pushInstruction({ op: "local.get", index: k1Local });
181
+ this.pushInstruction({ op: "local.get", index: k2Local });
182
+ this.pushInstruction("i64.eq");
183
+ return;
184
+ }
185
+ if (wType === "i32") {
186
+ this.pushInstruction({ op: "local.get", index: k1Local });
187
+ this.pushInstruction({ op: "local.get", index: k2Local });
188
+ this.pushInstruction("i32.eq");
189
+ return;
190
+ }
191
+ if (wType === "f32") {
192
+ this.pushInstruction({ op: "local.get", index: k1Local });
193
+ this.pushInstruction({ op: "local.get", index: k2Local });
194
+ this.pushInstruction("f32.eq");
195
+ return;
196
+ }
197
+ if (wType === "f64") {
198
+ this.pushInstruction({ op: "local.get", index: k1Local });
199
+ this.pushInstruction({ op: "local.get", index: k2Local });
200
+ this.pushInstruction("f64.eq");
201
+ return;
202
+ }
203
+ const structInfo = this._structInfoForGoType(keyGoType);
204
+ if (
205
+ structInfo &&
206
+ !isPointerToStruct(keyGoType, this.mod.checker, this.mod)
207
+ ) {
208
+ if (structInfo.fields.length === 0) {
209
+ this.pushInstruction({ op: "i32.const", value: 1 });
210
+ return;
211
+ }
212
+ for (let i = 0; i < structInfo.fields.length; i++) {
213
+ const f = structInfo.fields[i];
214
+ const f1 = this.allocLocal(null, f.wType);
215
+ const f2 = this.allocLocal(null, f.wType);
216
+ for (const [src, dst] of [
217
+ [k1Local, f1],
218
+ [k2Local, f2],
219
+ ]) {
220
+ this.pushInstruction({ op: "local.get", index: src });
221
+ this.pushInstruction({
222
+ op: "struct.get",
223
+ typeIndex: structInfo.typeIndex,
224
+ fieldIndex: i,
225
+ });
226
+ this.pushInstruction({ op: "local.set", index: dst });
227
+ }
228
+ this.emitKeyEq(f1, f2, f.goType);
229
+ if (i > 0) this.pushInstruction("i32.and");
230
+ }
231
+ return;
232
+ }
233
+ const unsupported = this._unsupportedMapKey(keyGoType);
234
+ if (unsupported) throw new Error(unsupported);
235
+ this.pushInstruction({ op: "local.get", index: k1Local });
236
+ this.pushInstruction({ op: "local.get", index: k2Local });
237
+ this.pushInstruction("ref.eq");
238
+ }
239
+
240
+ emitElemLt(v1Loc, v2Loc, elemGoType) {
241
+ if (isStringType(elemGoType, this.mod.checker)) {
242
+ this.pushInstruction({ op: "local.get", index: v1Loc });
243
+ this.pushInstruction({ op: "local.get", index: v2Loc });
244
+ this.pushInstruction({
245
+ op: "call",
246
+ funcIndex: this.mod.getStringCmpImportIndex("<"),
247
+ });
248
+ return;
249
+ }
250
+ const wType = toWasmType(elemGoType, this.mod.checker, this.mod);
251
+ if (wType === "i64") {
252
+ this.pushInstruction({ op: "local.get", index: v1Loc });
253
+ this.pushInstruction({ op: "local.get", index: v2Loc });
254
+ this.pushInstruction("i64.lt_s");
255
+ return;
256
+ }
257
+ if (wType === "i32") {
258
+ this.pushInstruction({ op: "local.get", index: v1Loc });
259
+ this.pushInstruction({ op: "local.get", index: v2Loc });
260
+ this.pushInstruction("i32.lt_s");
261
+ return;
262
+ }
263
+ if (wType === "f32") {
264
+ this.pushInstruction({ op: "local.get", index: v1Loc });
265
+ this.pushInstruction({ op: "local.get", index: v2Loc });
266
+ this.pushInstruction("f32.lt");
267
+ return;
268
+ }
269
+ if (wType === "f64") {
270
+ this.pushInstruction({ op: "local.get", index: v1Loc });
271
+ this.pushInstruction({ op: "local.get", index: v2Loc });
272
+ this.pushInstruction("f64.lt");
273
+ return;
274
+ }
275
+ this.pushInstruction({ op: "i32.const", value: 0 });
276
+ }
277
+
278
+ emitMapMake(mapInfo) {
279
+ const nBucketsLoc = this.allocLocal(null, "i32");
280
+ const cLoc = this.allocLocal(null, "i32");
281
+ const bucketsLoc = this.allocLocal(null, {
282
+ kind: "ref",
283
+ nullable: true,
284
+ typeIndex: mapInfo.bucketsTypeIndex,
285
+ });
286
+ const entriesLoc = this.allocLocal(null, {
287
+ kind: "ref",
288
+ nullable: true,
289
+ typeIndex: mapInfo.entriesTypeIndex,
290
+ });
291
+
292
+ // nBuckets = 16
293
+ this.pushInstruction({ op: "i32.const", value: 16 });
294
+ this.pushInstruction({ op: "local.set", index: nBucketsLoc });
295
+
296
+ // while (nBuckets < cap * 2) { nBuckets <<= 1; }
297
+ this.pushInstruction({ op: "block", blockType: "void" });
298
+ this.pushInstruction({ op: "loop", blockType: "void" });
299
+ this.pushInstruction({ op: "local.get", index: nBucketsLoc });
300
+ this.pushInstruction({ op: "local.get", index: 0 });
301
+ this.pushInstruction({ op: "i32.const", value: 1 });
302
+ this.pushInstruction("i32.shl");
303
+ this.pushInstruction("i32.ge_s");
304
+ this.pushInstruction({ op: "br_if", depth: 1 });
305
+ this.pushInstruction({ op: "local.get", index: nBucketsLoc });
306
+ this.pushInstruction({ op: "i32.const", value: 1 });
307
+ this.pushInstruction("i32.shl");
308
+ this.pushInstruction({ op: "local.set", index: nBucketsLoc });
309
+ this.pushInstruction({ op: "br", depth: 0 });
310
+ this.pushInstruction("end");
311
+ this.pushInstruction("end");
312
+
313
+ // c = cap > 8 ? cap : 8
314
+ this.pushInstruction({ op: "local.get", index: 0 });
315
+ this.pushInstruction({ op: "i32.const", value: 8 });
316
+ this.pushInstruction("i32.gt_s");
317
+ this.pushInstruction({ op: "if", blockType: "i32" });
318
+ this.pushInstruction({ op: "local.get", index: 0 });
319
+ this.pushInstruction("else");
320
+ this.pushInstruction({ op: "i32.const", value: 8 });
321
+ this.pushInstruction("end");
322
+ this.pushInstruction({ op: "local.set", index: cLoc });
323
+
324
+ // buckets = array.new $map_buckets (-1, nBuckets)
325
+ this.pushInstruction({ op: "i32.const", value: -1 });
326
+ this.pushInstruction({ op: "local.get", index: nBucketsLoc });
327
+ this.pushInstruction({
328
+ op: "array.new",
329
+ typeIndex: mapInfo.bucketsTypeIndex,
330
+ });
331
+ this.pushInstruction({ op: "local.set", index: bucketsLoc });
332
+
333
+ // entries = array.new_default $map_entries (c)
334
+ this.pushInstruction({ op: "local.get", index: cLoc });
335
+ this.pushInstruction({
336
+ op: "array.new_default",
337
+ typeIndex: mapInfo.entriesTypeIndex,
338
+ });
339
+ this.pushInstruction({ op: "local.set", index: entriesLoc });
340
+
341
+ // struct.new $map_K_V
342
+ this.pushInstruction({ op: "local.get", index: bucketsLoc });
343
+ this.pushInstruction({ op: "local.get", index: entriesLoc });
344
+ this.pushInstruction({ op: "i32.const", value: 0 }); // len
345
+ this.pushInstruction({ op: "local.get", index: cLoc }); // cap
346
+ this.pushInstruction({ op: "i32.const", value: 0 }); // count
347
+ this.pushInstruction({ op: "i32.const", value: -1 }); // head
348
+ this.pushInstruction({ op: "i32.const", value: -1 }); // tail
349
+ this.pushInstruction({ op: "i32.const", value: -1 }); // free_head
350
+ this.pushInstruction({ op: "local.get", index: nBucketsLoc }); // num_buckets
351
+ this.pushInstruction({ op: "struct.new", typeIndex: mapInfo.typeIndex });
352
+ this.pushInstruction({ op: "return" });
353
+ }
354
+
355
+ emitMapGet(mapInfo) {
356
+ const hLoc = this.allocLocal(null, "i32");
357
+ const bLoc = this.allocLocal(null, "i32");
358
+ const idxLoc = this.allocLocal(null, "i32");
359
+ const entryLoc = this.allocLocal(null, {
360
+ kind: "ref",
361
+ nullable: true,
362
+ typeIndex: mapInfo.entryTypeIndex,
363
+ });
364
+ const entryKeyLoc = this.allocLocal(null, mapInfo.keyWType);
365
+
366
+ // If m == null -> return zero
367
+ this.pushInstruction({ op: "local.get", index: 0 });
368
+ this.pushInstruction("ref.is_null");
369
+ this.pushInstruction({ op: "if", blockType: "void" });
370
+ this.emitZeroValue(mapInfo.valGoType, mapInfo.valWType);
371
+ this.pushInstruction({ op: "return" });
372
+ this.pushInstruction("end");
373
+
374
+ // h = hash(key)
375
+ this.emitKeyHash(1, mapInfo.keyGoType);
376
+ this.pushInstruction({ op: "local.set", index: hLoc });
377
+
378
+ // b = h & (m.num_buckets - 1)
379
+ this.pushInstruction({ op: "local.get", index: hLoc });
380
+ this.pushInstruction({ op: "local.get", index: 0 });
381
+ this.pushInstruction({
382
+ op: "struct.get",
383
+ typeIndex: mapInfo.typeIndex,
384
+ fieldIndex: 8,
385
+ });
386
+ this.pushInstruction({ op: "i32.const", value: 1 });
387
+ this.pushInstruction("i32.sub");
388
+ this.pushInstruction("i32.and");
389
+ this.pushInstruction({ op: "local.set", index: bLoc });
390
+
391
+ // idx = m.buckets[b]
392
+ this.pushInstruction({ op: "local.get", index: 0 });
393
+ this.pushInstruction({
394
+ op: "struct.get",
395
+ typeIndex: mapInfo.typeIndex,
396
+ fieldIndex: 0,
397
+ });
398
+ this.pushInstruction({ op: "local.get", index: bLoc });
399
+ this.pushInstruction({
400
+ op: "array.get",
401
+ typeIndex: mapInfo.bucketsTypeIndex,
402
+ });
403
+ this.pushInstruction({ op: "local.set", index: idxLoc });
404
+
405
+ // Loop while idx != -1
406
+ this.pushInstruction({ op: "block", blockType: "void" });
407
+ this.pushInstruction({ op: "loop", blockType: "void" });
408
+ this.pushInstruction({ op: "local.get", index: idxLoc });
409
+ this.pushInstruction({ op: "i32.const", value: -1 });
410
+ this.pushInstruction("i32.eq");
411
+ this.pushInstruction({ op: "br_if", depth: 1 });
412
+
413
+ this.pushInstruction({ op: "local.get", index: 0 });
414
+ this.pushInstruction({
415
+ op: "struct.get",
416
+ typeIndex: mapInfo.typeIndex,
417
+ fieldIndex: 1,
418
+ });
419
+ this.pushInstruction({ op: "local.get", index: idxLoc });
420
+ this.pushInstruction({
421
+ op: "array.get",
422
+ typeIndex: mapInfo.entriesTypeIndex,
423
+ });
424
+ this.pushInstruction({ op: "local.set", index: entryLoc });
425
+
426
+ this.pushInstruction({ op: "local.get", index: entryLoc });
427
+ this.pushInstruction({
428
+ op: "struct.get",
429
+ typeIndex: mapInfo.entryTypeIndex,
430
+ fieldIndex: 5,
431
+ });
432
+ this.pushInstruction({ op: "i32.const", value: 1 });
433
+ this.pushInstruction("i32.eq");
434
+ this.pushInstruction({ op: "if", blockType: "void" });
435
+
436
+ this.pushInstruction({ op: "local.get", index: entryLoc });
437
+ this.pushInstruction({
438
+ op: "struct.get",
439
+ typeIndex: mapInfo.entryTypeIndex,
440
+ fieldIndex: 0,
441
+ });
442
+ this.pushInstruction({ op: "local.set", index: entryKeyLoc });
443
+
444
+ this.emitKeyEq(1, entryKeyLoc, mapInfo.keyGoType);
445
+ this.pushInstruction({ op: "if", blockType: "void" });
446
+ this.pushInstruction({ op: "local.get", index: entryLoc });
447
+ this.pushInstruction({
448
+ op: "struct.get",
449
+ typeIndex: mapInfo.entryTypeIndex,
450
+ fieldIndex: 1,
451
+ });
452
+ this.pushInstruction({ op: "return" });
453
+ this.pushInstruction("end");
454
+ this.pushInstruction("end");
455
+
456
+ this.pushInstruction({ op: "local.get", index: entryLoc });
457
+ this.pushInstruction({
458
+ op: "struct.get",
459
+ typeIndex: mapInfo.entryTypeIndex,
460
+ fieldIndex: 2,
461
+ });
462
+ this.pushInstruction({ op: "local.set", index: idxLoc });
463
+ this.pushInstruction({ op: "br", depth: 0 });
464
+ this.pushInstruction("end");
465
+ this.pushInstruction("end");
466
+
467
+ // Not found
468
+ this.emitZeroValue(mapInfo.valGoType, mapInfo.valWType);
469
+ this.pushInstruction({ op: "return" });
470
+ }
471
+
472
+ emitMapGetOk(mapInfo) {
473
+ const hLoc = this.allocLocal(null, "i32");
474
+ const bLoc = this.allocLocal(null, "i32");
475
+ const idxLoc = this.allocLocal(null, "i32");
476
+ const entryLoc = this.allocLocal(null, {
477
+ kind: "ref",
478
+ nullable: true,
479
+ typeIndex: mapInfo.entryTypeIndex,
480
+ });
481
+ const entryKeyLoc = this.allocLocal(null, mapInfo.keyWType);
482
+
483
+ // If m == null -> return zero, false
484
+ this.pushInstruction({ op: "local.get", index: 0 });
485
+ this.pushInstruction("ref.is_null");
486
+ this.pushInstruction({ op: "if", blockType: "void" });
487
+ this.emitZeroValue(mapInfo.valGoType, mapInfo.valWType);
488
+ this.pushInstruction({ op: "i32.const", value: 0 });
489
+ this.pushInstruction({ op: "return" });
490
+ this.pushInstruction("end");
491
+
492
+ this.emitKeyHash(1, mapInfo.keyGoType);
493
+ this.pushInstruction({ op: "local.set", index: hLoc });
494
+
495
+ this.pushInstruction({ op: "local.get", index: hLoc });
496
+ this.pushInstruction({ op: "local.get", index: 0 });
497
+ this.pushInstruction({
498
+ op: "struct.get",
499
+ typeIndex: mapInfo.typeIndex,
500
+ fieldIndex: 8,
501
+ });
502
+ this.pushInstruction({ op: "i32.const", value: 1 });
503
+ this.pushInstruction("i32.sub");
504
+ this.pushInstruction("i32.and");
505
+ this.pushInstruction({ op: "local.set", index: bLoc });
506
+
507
+ this.pushInstruction({ op: "local.get", index: 0 });
508
+ this.pushInstruction({
509
+ op: "struct.get",
510
+ typeIndex: mapInfo.typeIndex,
511
+ fieldIndex: 0,
512
+ });
513
+ this.pushInstruction({ op: "local.get", index: bLoc });
514
+ this.pushInstruction({
515
+ op: "array.get",
516
+ typeIndex: mapInfo.bucketsTypeIndex,
517
+ });
518
+ this.pushInstruction({ op: "local.set", index: idxLoc });
519
+
520
+ this.pushInstruction({ op: "block", blockType: "void" });
521
+ this.pushInstruction({ op: "loop", blockType: "void" });
522
+ this.pushInstruction({ op: "local.get", index: idxLoc });
523
+ this.pushInstruction({ op: "i32.const", value: -1 });
524
+ this.pushInstruction("i32.eq");
525
+ this.pushInstruction({ op: "br_if", depth: 1 });
526
+
527
+ this.pushInstruction({ op: "local.get", index: 0 });
528
+ this.pushInstruction({
529
+ op: "struct.get",
530
+ typeIndex: mapInfo.typeIndex,
531
+ fieldIndex: 1,
532
+ });
533
+ this.pushInstruction({ op: "local.get", index: idxLoc });
534
+ this.pushInstruction({
535
+ op: "array.get",
536
+ typeIndex: mapInfo.entriesTypeIndex,
537
+ });
538
+ this.pushInstruction({ op: "local.set", index: entryLoc });
539
+
540
+ this.pushInstruction({ op: "local.get", index: entryLoc });
541
+ this.pushInstruction({
542
+ op: "struct.get",
543
+ typeIndex: mapInfo.entryTypeIndex,
544
+ fieldIndex: 5,
545
+ });
546
+ this.pushInstruction({ op: "i32.const", value: 1 });
547
+ this.pushInstruction("i32.eq");
548
+ this.pushInstruction({ op: "if", blockType: "void" });
549
+
550
+ this.pushInstruction({ op: "local.get", index: entryLoc });
551
+ this.pushInstruction({
552
+ op: "struct.get",
553
+ typeIndex: mapInfo.entryTypeIndex,
554
+ fieldIndex: 0,
555
+ });
556
+ this.pushInstruction({ op: "local.set", index: entryKeyLoc });
557
+
558
+ this.emitKeyEq(1, entryKeyLoc, mapInfo.keyGoType);
559
+ this.pushInstruction({ op: "if", blockType: "void" });
560
+ this.pushInstruction({ op: "local.get", index: entryLoc });
561
+ this.pushInstruction({
562
+ op: "struct.get",
563
+ typeIndex: mapInfo.entryTypeIndex,
564
+ fieldIndex: 1,
565
+ });
566
+ this.pushInstruction({ op: "i32.const", value: 1 });
567
+ this.pushInstruction({ op: "return" });
568
+ this.pushInstruction("end");
569
+ this.pushInstruction("end");
570
+
571
+ this.pushInstruction({ op: "local.get", index: entryLoc });
572
+ this.pushInstruction({
573
+ op: "struct.get",
574
+ typeIndex: mapInfo.entryTypeIndex,
575
+ fieldIndex: 2,
576
+ });
577
+ this.pushInstruction({ op: "local.set", index: idxLoc });
578
+ this.pushInstruction({ op: "br", depth: 0 });
579
+ this.pushInstruction("end");
580
+ this.pushInstruction("end");
581
+
582
+ this.emitZeroValue(mapInfo.valGoType, mapInfo.valWType);
583
+ this.pushInstruction({ op: "i32.const", value: 0 });
584
+ this.pushInstruction({ op: "return" });
585
+ }
586
+
587
+ emitMapSet(mapInfo) {
588
+ const hLoc = this.allocLocal(null, "i32");
589
+ const bLoc = this.allocLocal(null, "i32");
590
+ const idxLoc = this.allocLocal(null, "i32");
591
+ const entryLoc = this.allocLocal(null, {
592
+ kind: "ref",
593
+ nullable: true,
594
+ typeIndex: mapInfo.entryTypeIndex,
595
+ });
596
+ const newIdxLoc = this.allocLocal(null, "i32");
597
+ const oldTailLoc = this.allocLocal(null, "i32");
598
+ const tempLoc = this.allocLocal(null, "i32");
599
+ const newEntriesLoc = this.allocLocal(null, {
600
+ kind: "ref",
601
+ nullable: true,
602
+ typeIndex: mapInfo.entriesTypeIndex,
603
+ });
604
+ const newBucketsLoc = this.allocLocal(null, {
605
+ kind: "ref",
606
+ nullable: true,
607
+ typeIndex: mapInfo.bucketsTypeIndex,
608
+ });
609
+ const currLoc = this.allocLocal(null, "i32");
610
+ const testKeyLoc = this.allocLocal(null, mapInfo.keyWType);
611
+
612
+ // 1. Check nil
613
+ this.pushInstruction({ op: "local.get", index: 0 });
614
+ this.pushInstruction("ref.is_null");
615
+ this.pushInstruction({ op: "if", blockType: "void" });
616
+ this.emitPanic("assignment to entry in nil map");
617
+ this.pushInstruction("end");
618
+
619
+ // 2. Hash & bucket
620
+ this.emitKeyHash(1, mapInfo.keyGoType);
621
+ this.pushInstruction({ op: "local.set", index: hLoc });
622
+
623
+ this.pushInstruction({ op: "local.get", index: hLoc });
624
+ this.pushInstruction({ op: "local.get", index: 0 });
625
+ this.pushInstruction({
626
+ op: "struct.get",
627
+ typeIndex: mapInfo.typeIndex,
628
+ fieldIndex: 8,
629
+ });
630
+ this.pushInstruction({ op: "i32.const", value: 1 });
631
+ this.pushInstruction("i32.sub");
632
+ this.pushInstruction("i32.and");
633
+ this.pushInstruction({ op: "local.set", index: bLoc });
634
+
635
+ // 3. Search existing key
636
+ this.pushInstruction({ op: "local.get", index: 0 });
637
+ this.pushInstruction({
638
+ op: "struct.get",
639
+ typeIndex: mapInfo.typeIndex,
640
+ fieldIndex: 0,
641
+ });
642
+ this.pushInstruction({ op: "local.get", index: bLoc });
643
+ this.pushInstruction({
644
+ op: "array.get",
645
+ typeIndex: mapInfo.bucketsTypeIndex,
646
+ });
647
+ this.pushInstruction({ op: "local.set", index: idxLoc });
648
+
649
+ this.pushInstruction({ op: "block", blockType: "void" });
650
+ this.pushInstruction({ op: "loop", blockType: "void" });
651
+ this.pushInstruction({ op: "local.get", index: idxLoc });
652
+ this.pushInstruction({ op: "i32.const", value: -1 });
653
+ this.pushInstruction("i32.eq");
654
+ this.pushInstruction({ op: "br_if", depth: 1 });
655
+
656
+ this.pushInstruction({ op: "local.get", index: 0 });
657
+ this.pushInstruction({
658
+ op: "struct.get",
659
+ typeIndex: mapInfo.typeIndex,
660
+ fieldIndex: 1,
661
+ });
662
+ this.pushInstruction({ op: "local.get", index: idxLoc });
663
+ this.pushInstruction({
664
+ op: "array.get",
665
+ typeIndex: mapInfo.entriesTypeIndex,
666
+ });
667
+ this.pushInstruction({ op: "local.set", index: entryLoc });
668
+
669
+ this.pushInstruction({ op: "local.get", index: entryLoc });
670
+ this.pushInstruction({
671
+ op: "struct.get",
672
+ typeIndex: mapInfo.entryTypeIndex,
673
+ fieldIndex: 5,
674
+ });
675
+ this.pushInstruction({ op: "i32.const", value: 1 });
676
+ this.pushInstruction("i32.eq");
677
+ this.pushInstruction({ op: "if", blockType: "void" });
678
+
679
+ this.pushInstruction({ op: "local.get", index: entryLoc });
680
+ this.pushInstruction({
681
+ op: "struct.get",
682
+ typeIndex: mapInfo.entryTypeIndex,
683
+ fieldIndex: 0,
684
+ });
685
+ this.pushInstruction({ op: "local.set", index: testKeyLoc });
686
+
687
+ this.emitKeyEq(1, testKeyLoc, mapInfo.keyGoType);
688
+ this.pushInstruction({ op: "if", blockType: "void" });
689
+ // Key exists: update val in place
690
+ this.pushInstruction({ op: "local.get", index: entryLoc });
691
+ this.pushInstruction({ op: "local.get", index: 2 });
692
+ this.pushInstruction({
693
+ op: "struct.set",
694
+ typeIndex: mapInfo.entryTypeIndex,
695
+ fieldIndex: 1,
696
+ });
697
+ this.pushInstruction({ op: "return" });
698
+ this.pushInstruction("end");
699
+ this.pushInstruction("end");
700
+
701
+ this.pushInstruction({ op: "local.get", index: entryLoc });
702
+ this.pushInstruction({
703
+ op: "struct.get",
704
+ typeIndex: mapInfo.entryTypeIndex,
705
+ fieldIndex: 2,
706
+ });
707
+ this.pushInstruction({ op: "local.set", index: idxLoc });
708
+ this.pushInstruction({ op: "br", depth: 0 });
709
+ this.pushInstruction("end");
710
+ this.pushInstruction("end");
711
+
712
+ // 4. Key not found: insert
713
+ // Check grow entries: count >= cap && free_head == -1
714
+ this.pushInstruction({ op: "local.get", index: 0 });
715
+ this.pushInstruction({
716
+ op: "struct.get",
717
+ typeIndex: mapInfo.typeIndex,
718
+ fieldIndex: 4,
719
+ });
720
+ this.pushInstruction({ op: "local.get", index: 0 });
721
+ this.pushInstruction({
722
+ op: "struct.get",
723
+ typeIndex: mapInfo.typeIndex,
724
+ fieldIndex: 3,
725
+ });
726
+ this.pushInstruction("i32.ge_s");
727
+ this.pushInstruction({ op: "local.get", index: 0 });
728
+ this.pushInstruction({
729
+ op: "struct.get",
730
+ typeIndex: mapInfo.typeIndex,
731
+ fieldIndex: 7,
732
+ });
733
+ this.pushInstruction({ op: "i32.const", value: -1 });
734
+ this.pushInstruction("i32.eq");
735
+ this.pushInstruction("i32.and");
736
+ this.pushInstruction({ op: "if", blockType: "void" });
737
+
738
+ this.pushInstruction({ op: "local.get", index: 0 });
739
+ this.pushInstruction({
740
+ op: "struct.get",
741
+ typeIndex: mapInfo.typeIndex,
742
+ fieldIndex: 3,
743
+ });
744
+ this.pushInstruction({ op: "i32.const", value: 1 });
745
+ this.pushInstruction("i32.shl");
746
+ this.pushInstruction({ op: "local.tee", index: tempLoc });
747
+
748
+ this.pushInstruction({
749
+ op: "array.new_default",
750
+ typeIndex: mapInfo.entriesTypeIndex,
751
+ });
752
+ this.pushInstruction({ op: "local.set", index: newEntriesLoc });
753
+
754
+ this.pushInstruction({ op: "local.get", index: newEntriesLoc });
755
+ this.pushInstruction({ op: "i32.const", value: 0 });
756
+ this.pushInstruction({ op: "local.get", index: 0 });
757
+ this.pushInstruction({
758
+ op: "struct.get",
759
+ typeIndex: mapInfo.typeIndex,
760
+ fieldIndex: 1,
761
+ });
762
+ this.pushInstruction({ op: "i32.const", value: 0 });
763
+ this.pushInstruction({ op: "local.get", index: 0 });
764
+ this.pushInstruction({
765
+ op: "struct.get",
766
+ typeIndex: mapInfo.typeIndex,
767
+ fieldIndex: 4,
768
+ });
769
+ this.pushInstruction({
770
+ op: "array.copy",
771
+ typeIndexDst: mapInfo.entriesTypeIndex,
772
+ typeIndexSrc: mapInfo.entriesTypeIndex,
773
+ });
774
+
775
+ this.pushInstruction({ op: "local.get", index: 0 });
776
+ this.pushInstruction({ op: "local.get", index: newEntriesLoc });
777
+ this.pushInstruction({
778
+ op: "struct.set",
779
+ typeIndex: mapInfo.typeIndex,
780
+ fieldIndex: 1,
781
+ });
782
+
783
+ this.pushInstruction({ op: "local.get", index: 0 });
784
+ this.pushInstruction({ op: "local.get", index: tempLoc });
785
+ this.pushInstruction({
786
+ op: "struct.set",
787
+ typeIndex: mapInfo.typeIndex,
788
+ fieldIndex: 3,
789
+ });
790
+ this.pushInstruction("end");
791
+
792
+ // Check grow buckets: len >= num_buckets
793
+ this.pushInstruction({ op: "local.get", index: 0 });
794
+ this.pushInstruction({
795
+ op: "struct.get",
796
+ typeIndex: mapInfo.typeIndex,
797
+ fieldIndex: 2,
798
+ });
799
+ this.pushInstruction({ op: "local.get", index: 0 });
800
+ this.pushInstruction({
801
+ op: "struct.get",
802
+ typeIndex: mapInfo.typeIndex,
803
+ fieldIndex: 8,
804
+ });
805
+ this.pushInstruction("i32.ge_s");
806
+ this.pushInstruction({ op: "if", blockType: "void" });
807
+
808
+ this.pushInstruction({ op: "local.get", index: 0 });
809
+ this.pushInstruction({
810
+ op: "struct.get",
811
+ typeIndex: mapInfo.typeIndex,
812
+ fieldIndex: 8,
813
+ });
814
+ this.pushInstruction({ op: "i32.const", value: 1 });
815
+ this.pushInstruction("i32.shl");
816
+ this.pushInstruction({ op: "local.set", index: tempLoc });
817
+
818
+ this.pushInstruction({ op: "i32.const", value: -1 });
819
+ this.pushInstruction({ op: "local.get", index: tempLoc });
820
+ this.pushInstruction({
821
+ op: "array.new",
822
+ typeIndex: mapInfo.bucketsTypeIndex,
823
+ });
824
+ this.pushInstruction({ op: "local.set", index: newBucketsLoc });
825
+
826
+ this.pushInstruction({ op: "local.get", index: 0 });
827
+ this.pushInstruction({ op: "local.get", index: newBucketsLoc });
828
+ this.pushInstruction({
829
+ op: "struct.set",
830
+ typeIndex: mapInfo.typeIndex,
831
+ fieldIndex: 0,
832
+ });
833
+
834
+ this.pushInstruction({ op: "local.get", index: 0 });
835
+ this.pushInstruction({ op: "local.get", index: tempLoc });
836
+ this.pushInstruction({
837
+ op: "struct.set",
838
+ typeIndex: mapInfo.typeIndex,
839
+ fieldIndex: 8,
840
+ });
841
+
842
+ // Rehash active entries: curr = m.head
843
+ this.pushInstruction({ op: "local.get", index: 0 });
844
+ this.pushInstruction({
845
+ op: "struct.get",
846
+ typeIndex: mapInfo.typeIndex,
847
+ fieldIndex: 5,
848
+ });
849
+ this.pushInstruction({ op: "local.set", index: currLoc });
850
+
851
+ const rehashKeyLoc = this.allocLocal(null, mapInfo.keyWType);
852
+ const rehashBLoc = this.allocLocal(null, "i32");
853
+
854
+ this.pushInstruction({ op: "block", blockType: "void" });
855
+ this.pushInstruction({ op: "loop", blockType: "void" });
856
+ this.pushInstruction({ op: "local.get", index: currLoc });
857
+ this.pushInstruction({ op: "i32.const", value: -1 });
858
+ this.pushInstruction("i32.eq");
859
+ this.pushInstruction({ op: "br_if", depth: 1 });
860
+
861
+ this.pushInstruction({ op: "local.get", index: 0 });
862
+ this.pushInstruction({
863
+ op: "struct.get",
864
+ typeIndex: mapInfo.typeIndex,
865
+ fieldIndex: 1,
866
+ });
867
+ this.pushInstruction({ op: "local.get", index: currLoc });
868
+ this.pushInstruction({
869
+ op: "array.get",
870
+ typeIndex: mapInfo.entriesTypeIndex,
871
+ });
872
+ this.pushInstruction({ op: "local.set", index: entryLoc });
873
+
874
+ this.pushInstruction({ op: "local.get", index: entryLoc });
875
+ this.pushInstruction({
876
+ op: "struct.get",
877
+ typeIndex: mapInfo.entryTypeIndex,
878
+ fieldIndex: 0,
879
+ });
880
+ this.pushInstruction({ op: "local.set", index: rehashKeyLoc });
881
+
882
+ this.emitKeyHash(rehashKeyLoc, mapInfo.keyGoType);
883
+ this.pushInstruction({ op: "local.get", index: tempLoc });
884
+ this.pushInstruction({ op: "i32.const", value: 1 });
885
+ this.pushInstruction("i32.sub");
886
+ this.pushInstruction("i32.and");
887
+ this.pushInstruction({ op: "local.set", index: rehashBLoc });
888
+
889
+ this.pushInstruction({ op: "local.get", index: entryLoc });
890
+ this.pushInstruction({ op: "local.get", index: newBucketsLoc });
891
+ this.pushInstruction({ op: "local.get", index: rehashBLoc });
892
+ this.pushInstruction({
893
+ op: "array.get",
894
+ typeIndex: mapInfo.bucketsTypeIndex,
895
+ });
896
+ this.pushInstruction({
897
+ op: "struct.set",
898
+ typeIndex: mapInfo.entryTypeIndex,
899
+ fieldIndex: 2,
900
+ });
901
+
902
+ this.pushInstruction({ op: "local.get", index: newBucketsLoc });
903
+ this.pushInstruction({ op: "local.get", index: rehashBLoc });
904
+ this.pushInstruction({ op: "local.get", index: currLoc });
905
+ this.pushInstruction({
906
+ op: "array.set",
907
+ typeIndex: mapInfo.bucketsTypeIndex,
908
+ });
909
+
910
+ this.pushInstruction({ op: "local.get", index: entryLoc });
911
+ this.pushInstruction({
912
+ op: "struct.get",
913
+ typeIndex: mapInfo.entryTypeIndex,
914
+ fieldIndex: 4,
915
+ });
916
+ this.pushInstruction({ op: "local.set", index: currLoc });
917
+ this.pushInstruction({ op: "br", depth: 0 });
918
+ this.pushInstruction("end");
919
+ this.pushInstruction("end");
920
+
921
+ // Recompute bLoc
922
+ this.pushInstruction({ op: "local.get", index: hLoc });
923
+ this.pushInstruction({ op: "local.get", index: 0 });
924
+ this.pushInstruction({
925
+ op: "struct.get",
926
+ typeIndex: mapInfo.typeIndex,
927
+ fieldIndex: 8,
928
+ });
929
+ this.pushInstruction({ op: "i32.const", value: 1 });
930
+ this.pushInstruction("i32.sub");
931
+ this.pushInstruction("i32.and");
932
+ this.pushInstruction({ op: "local.set", index: bLoc });
933
+ this.pushInstruction("end"); // end if len >= num_buckets
934
+
935
+ // Slot index newIdx
936
+ this.pushInstruction({ op: "local.get", index: 0 });
937
+ this.pushInstruction({
938
+ op: "struct.get",
939
+ typeIndex: mapInfo.typeIndex,
940
+ fieldIndex: 7,
941
+ });
942
+ this.pushInstruction({ op: "i32.const", value: -1 });
943
+ this.pushInstruction("i32.ne");
944
+ this.pushInstruction({ op: "if", blockType: "void" });
945
+ // Pop free list
946
+ this.pushInstruction({ op: "local.get", index: 0 });
947
+ this.pushInstruction({
948
+ op: "struct.get",
949
+ typeIndex: mapInfo.typeIndex,
950
+ fieldIndex: 7,
951
+ });
952
+ this.pushInstruction({ op: "local.set", index: newIdxLoc });
953
+
954
+ this.pushInstruction({ op: "local.get", index: 0 });
955
+ this.pushInstruction({
956
+ op: "struct.get",
957
+ typeIndex: mapInfo.typeIndex,
958
+ fieldIndex: 1,
959
+ });
960
+ this.pushInstruction({ op: "local.get", index: newIdxLoc });
961
+ this.pushInstruction({
962
+ op: "array.get",
963
+ typeIndex: mapInfo.entriesTypeIndex,
964
+ });
965
+ this.pushInstruction({
966
+ op: "struct.get",
967
+ typeIndex: mapInfo.entryTypeIndex,
968
+ fieldIndex: 2,
969
+ });
970
+ this.pushInstruction({ op: "local.set", index: tempLoc });
971
+
972
+ this.pushInstruction({ op: "local.get", index: 0 });
973
+ this.pushInstruction({ op: "local.get", index: tempLoc });
974
+ this.pushInstruction({
975
+ op: "struct.set",
976
+ typeIndex: mapInfo.typeIndex,
977
+ fieldIndex: 7,
978
+ });
979
+ this.pushInstruction("else");
980
+ // newIdx = count; count++
981
+ this.pushInstruction({ op: "local.get", index: 0 });
982
+ this.pushInstruction({
983
+ op: "struct.get",
984
+ typeIndex: mapInfo.typeIndex,
985
+ fieldIndex: 4,
986
+ });
987
+ this.pushInstruction({ op: "local.set", index: newIdxLoc });
988
+
989
+ this.pushInstruction({ op: "local.get", index: 0 });
990
+ this.pushInstruction({ op: "local.get", index: newIdxLoc });
991
+ this.pushInstruction({ op: "i32.const", value: 1 });
992
+ this.pushInstruction("i32.add");
993
+ this.pushInstruction({
994
+ op: "struct.set",
995
+ typeIndex: mapInfo.typeIndex,
996
+ fieldIndex: 4,
997
+ });
998
+ this.pushInstruction("end");
999
+
1000
+ // oldTail = m.tail
1001
+ this.pushInstruction({ op: "local.get", index: 0 });
1002
+ this.pushInstruction({
1003
+ op: "struct.get",
1004
+ typeIndex: mapInfo.typeIndex,
1005
+ fieldIndex: 6,
1006
+ });
1007
+ this.pushInstruction({ op: "local.set", index: oldTailLoc });
1008
+
1009
+ // new_entry = struct.new (key, val, next=buckets[b], order_prev=oldTail, order_next=-1, active=1)
1010
+ this.pushInstruction({ op: "local.get", index: 1 });
1011
+ this.pushInstruction({ op: "local.get", index: 2 });
1012
+ this.pushInstruction({ op: "local.get", index: 0 });
1013
+ this.pushInstruction({
1014
+ op: "struct.get",
1015
+ typeIndex: mapInfo.typeIndex,
1016
+ fieldIndex: 0,
1017
+ });
1018
+ this.pushInstruction({ op: "local.get", index: bLoc });
1019
+ this.pushInstruction({
1020
+ op: "array.get",
1021
+ typeIndex: mapInfo.bucketsTypeIndex,
1022
+ });
1023
+ this.pushInstruction({ op: "local.get", index: oldTailLoc });
1024
+ this.pushInstruction({ op: "i32.const", value: -1 });
1025
+ this.pushInstruction({ op: "i32.const", value: 1 });
1026
+ this.pushInstruction({
1027
+ op: "struct.new",
1028
+ typeIndex: mapInfo.entryTypeIndex,
1029
+ });
1030
+ this.pushInstruction({ op: "local.set", index: entryLoc });
1031
+
1032
+ // entries[newIdx] = new_entry
1033
+ this.pushInstruction({ op: "local.get", index: 0 });
1034
+ this.pushInstruction({
1035
+ op: "struct.get",
1036
+ typeIndex: mapInfo.typeIndex,
1037
+ fieldIndex: 1,
1038
+ });
1039
+ this.pushInstruction({ op: "local.get", index: newIdxLoc });
1040
+ this.pushInstruction({ op: "local.get", index: entryLoc });
1041
+ this.pushInstruction({
1042
+ op: "array.set",
1043
+ typeIndex: mapInfo.entriesTypeIndex,
1044
+ });
1045
+
1046
+ // buckets[b] = newIdx
1047
+ this.pushInstruction({ op: "local.get", index: 0 });
1048
+ this.pushInstruction({
1049
+ op: "struct.get",
1050
+ typeIndex: mapInfo.typeIndex,
1051
+ fieldIndex: 0,
1052
+ });
1053
+ this.pushInstruction({ op: "local.get", index: bLoc });
1054
+ this.pushInstruction({ op: "local.get", index: newIdxLoc });
1055
+ this.pushInstruction({
1056
+ op: "array.set",
1057
+ typeIndex: mapInfo.bucketsTypeIndex,
1058
+ });
1059
+
1060
+ // Link insertion order
1061
+ this.pushInstruction({ op: "local.get", index: oldTailLoc });
1062
+ this.pushInstruction({ op: "i32.const", value: -1 });
1063
+ this.pushInstruction("i32.ne");
1064
+ this.pushInstruction({ op: "if", blockType: "void" });
1065
+ this.pushInstruction({ op: "local.get", index: 0 });
1066
+ this.pushInstruction({
1067
+ op: "struct.get",
1068
+ typeIndex: mapInfo.typeIndex,
1069
+ fieldIndex: 1,
1070
+ });
1071
+ this.pushInstruction({ op: "local.get", index: oldTailLoc });
1072
+ this.pushInstruction({
1073
+ op: "array.get",
1074
+ typeIndex: mapInfo.entriesTypeIndex,
1075
+ });
1076
+ this.pushInstruction({ op: "local.get", index: newIdxLoc });
1077
+ this.pushInstruction({
1078
+ op: "struct.set",
1079
+ typeIndex: mapInfo.entryTypeIndex,
1080
+ fieldIndex: 4,
1081
+ });
1082
+ this.pushInstruction("else");
1083
+ this.pushInstruction({ op: "local.get", index: 0 });
1084
+ this.pushInstruction({ op: "local.get", index: newIdxLoc });
1085
+ this.pushInstruction({
1086
+ op: "struct.set",
1087
+ typeIndex: mapInfo.typeIndex,
1088
+ fieldIndex: 5,
1089
+ });
1090
+ this.pushInstruction("end");
1091
+
1092
+ // m.tail = newIdx
1093
+ this.pushInstruction({ op: "local.get", index: 0 });
1094
+ this.pushInstruction({ op: "local.get", index: newIdxLoc });
1095
+ this.pushInstruction({
1096
+ op: "struct.set",
1097
+ typeIndex: mapInfo.typeIndex,
1098
+ fieldIndex: 6,
1099
+ });
1100
+
1101
+ // m.len++
1102
+ this.pushInstruction({ op: "local.get", index: 0 });
1103
+ this.pushInstruction({ op: "local.get", index: 0 });
1104
+ this.pushInstruction({
1105
+ op: "struct.get",
1106
+ typeIndex: mapInfo.typeIndex,
1107
+ fieldIndex: 2,
1108
+ });
1109
+ this.pushInstruction({ op: "i32.const", value: 1 });
1110
+ this.pushInstruction("i32.add");
1111
+ this.pushInstruction({
1112
+ op: "struct.set",
1113
+ typeIndex: mapInfo.typeIndex,
1114
+ fieldIndex: 2,
1115
+ });
1116
+ this.pushInstruction({ op: "return" });
1117
+ }
1118
+
1119
+ emitMapDelete(mapInfo) {
1120
+ const hLoc = this.allocLocal(null, "i32");
1121
+ const bLoc = this.allocLocal(null, "i32");
1122
+ const idxLoc = this.allocLocal(null, "i32");
1123
+ const prevLoc = this.allocLocal(null, "i32");
1124
+ const entryLoc = this.allocLocal(null, {
1125
+ kind: "ref",
1126
+ nullable: true,
1127
+ typeIndex: mapInfo.entryTypeIndex,
1128
+ });
1129
+ const orderPrevLoc = this.allocLocal(null, "i32");
1130
+ const orderNextLoc = this.allocLocal(null, "i32");
1131
+ const testKeyLoc = this.allocLocal(null, mapInfo.keyWType);
1132
+
1133
+ this.pushInstruction({ op: "local.get", index: 0 });
1134
+ this.pushInstruction("ref.is_null");
1135
+ this.pushInstruction({ op: "if", blockType: "void" });
1136
+ this.pushInstruction({ op: "return" });
1137
+ this.pushInstruction("end");
1138
+
1139
+ this.emitKeyHash(1, mapInfo.keyGoType);
1140
+ this.pushInstruction({ op: "local.set", index: hLoc });
1141
+
1142
+ this.pushInstruction({ op: "local.get", index: hLoc });
1143
+ this.pushInstruction({ op: "local.get", index: 0 });
1144
+ this.pushInstruction({
1145
+ op: "struct.get",
1146
+ typeIndex: mapInfo.typeIndex,
1147
+ fieldIndex: 8,
1148
+ });
1149
+ this.pushInstruction({ op: "i32.const", value: 1 });
1150
+ this.pushInstruction("i32.sub");
1151
+ this.pushInstruction("i32.and");
1152
+ this.pushInstruction({ op: "local.set", index: bLoc });
1153
+
1154
+ this.pushInstruction({ op: "local.get", index: 0 });
1155
+ this.pushInstruction({
1156
+ op: "struct.get",
1157
+ typeIndex: mapInfo.typeIndex,
1158
+ fieldIndex: 0,
1159
+ });
1160
+ this.pushInstruction({ op: "local.get", index: bLoc });
1161
+ this.pushInstruction({
1162
+ op: "array.get",
1163
+ typeIndex: mapInfo.bucketsTypeIndex,
1164
+ });
1165
+ this.pushInstruction({ op: "local.set", index: idxLoc });
1166
+
1167
+ this.pushInstruction({ op: "i32.const", value: -1 });
1168
+ this.pushInstruction({ op: "local.set", index: prevLoc });
1169
+
1170
+ this.pushInstruction({ op: "block", blockType: "void" });
1171
+ this.pushInstruction({ op: "loop", blockType: "void" });
1172
+ this.pushInstruction({ op: "local.get", index: idxLoc });
1173
+ this.pushInstruction({ op: "i32.const", value: -1 });
1174
+ this.pushInstruction("i32.eq");
1175
+ this.pushInstruction({ op: "br_if", depth: 1 });
1176
+
1177
+ this.pushInstruction({ op: "local.get", index: 0 });
1178
+ this.pushInstruction({
1179
+ op: "struct.get",
1180
+ typeIndex: mapInfo.typeIndex,
1181
+ fieldIndex: 1,
1182
+ });
1183
+ this.pushInstruction({ op: "local.get", index: idxLoc });
1184
+ this.pushInstruction({
1185
+ op: "array.get",
1186
+ typeIndex: mapInfo.entriesTypeIndex,
1187
+ });
1188
+ this.pushInstruction({ op: "local.set", index: entryLoc });
1189
+
1190
+ this.pushInstruction({ op: "local.get", index: entryLoc });
1191
+ this.pushInstruction({
1192
+ op: "struct.get",
1193
+ typeIndex: mapInfo.entryTypeIndex,
1194
+ fieldIndex: 5,
1195
+ });
1196
+ this.pushInstruction({ op: "i32.const", value: 1 });
1197
+ this.pushInstruction("i32.eq");
1198
+ this.pushInstruction({ op: "if", blockType: "void" });
1199
+
1200
+ this.pushInstruction({ op: "local.get", index: entryLoc });
1201
+ this.pushInstruction({
1202
+ op: "struct.get",
1203
+ typeIndex: mapInfo.entryTypeIndex,
1204
+ fieldIndex: 0,
1205
+ });
1206
+ this.pushInstruction({ op: "local.set", index: testKeyLoc });
1207
+
1208
+ this.emitKeyEq(1, testKeyLoc, mapInfo.keyGoType);
1209
+ this.pushInstruction({ op: "if", blockType: "void" });
1210
+ // Unlink bucket
1211
+ this.pushInstruction({ op: "local.get", index: prevLoc });
1212
+ this.pushInstruction({ op: "i32.const", value: -1 });
1213
+ this.pushInstruction("i32.ne");
1214
+ this.pushInstruction({ op: "if", blockType: "void" });
1215
+ this.pushInstruction({ op: "local.get", index: 0 });
1216
+ this.pushInstruction({
1217
+ op: "struct.get",
1218
+ typeIndex: mapInfo.typeIndex,
1219
+ fieldIndex: 1,
1220
+ });
1221
+ this.pushInstruction({ op: "local.get", index: prevLoc });
1222
+ this.pushInstruction({
1223
+ op: "array.get",
1224
+ typeIndex: mapInfo.entriesTypeIndex,
1225
+ });
1226
+ this.pushInstruction({ op: "local.get", index: entryLoc });
1227
+ this.pushInstruction({
1228
+ op: "struct.get",
1229
+ typeIndex: mapInfo.entryTypeIndex,
1230
+ fieldIndex: 2,
1231
+ });
1232
+ this.pushInstruction({
1233
+ op: "struct.set",
1234
+ typeIndex: mapInfo.entryTypeIndex,
1235
+ fieldIndex: 2,
1236
+ });
1237
+ this.pushInstruction("else");
1238
+ this.pushInstruction({ op: "local.get", index: 0 });
1239
+ this.pushInstruction({
1240
+ op: "struct.get",
1241
+ typeIndex: mapInfo.typeIndex,
1242
+ fieldIndex: 0,
1243
+ });
1244
+ this.pushInstruction({ op: "local.get", index: bLoc });
1245
+ this.pushInstruction({ op: "local.get", index: entryLoc });
1246
+ this.pushInstruction({
1247
+ op: "struct.get",
1248
+ typeIndex: mapInfo.entryTypeIndex,
1249
+ fieldIndex: 2,
1250
+ });
1251
+ this.pushInstruction({
1252
+ op: "array.set",
1253
+ typeIndex: mapInfo.bucketsTypeIndex,
1254
+ });
1255
+ this.pushInstruction("end");
1256
+
1257
+ // Unlink order
1258
+ this.pushInstruction({ op: "local.get", index: entryLoc });
1259
+ this.pushInstruction({
1260
+ op: "struct.get",
1261
+ typeIndex: mapInfo.entryTypeIndex,
1262
+ fieldIndex: 3,
1263
+ });
1264
+ this.pushInstruction({ op: "local.set", index: orderPrevLoc });
1265
+
1266
+ this.pushInstruction({ op: "local.get", index: entryLoc });
1267
+ this.pushInstruction({
1268
+ op: "struct.get",
1269
+ typeIndex: mapInfo.entryTypeIndex,
1270
+ fieldIndex: 4,
1271
+ });
1272
+ this.pushInstruction({ op: "local.set", index: orderNextLoc });
1273
+
1274
+ this.pushInstruction({ op: "local.get", index: orderPrevLoc });
1275
+ this.pushInstruction({ op: "i32.const", value: -1 });
1276
+ this.pushInstruction("i32.ne");
1277
+ this.pushInstruction({ op: "if", blockType: "void" });
1278
+ this.pushInstruction({ op: "local.get", index: 0 });
1279
+ this.pushInstruction({
1280
+ op: "struct.get",
1281
+ typeIndex: mapInfo.typeIndex,
1282
+ fieldIndex: 1,
1283
+ });
1284
+ this.pushInstruction({ op: "local.get", index: orderPrevLoc });
1285
+ this.pushInstruction({
1286
+ op: "array.get",
1287
+ typeIndex: mapInfo.entriesTypeIndex,
1288
+ });
1289
+ this.pushInstruction({ op: "local.get", index: orderNextLoc });
1290
+ this.pushInstruction({
1291
+ op: "struct.set",
1292
+ typeIndex: mapInfo.entryTypeIndex,
1293
+ fieldIndex: 4,
1294
+ });
1295
+ this.pushInstruction("else");
1296
+ this.pushInstruction({ op: "local.get", index: 0 });
1297
+ this.pushInstruction({ op: "local.get", index: orderNextLoc });
1298
+ this.pushInstruction({
1299
+ op: "struct.set",
1300
+ typeIndex: mapInfo.typeIndex,
1301
+ fieldIndex: 5,
1302
+ });
1303
+ this.pushInstruction("end");
1304
+
1305
+ this.pushInstruction({ op: "local.get", index: orderNextLoc });
1306
+ this.pushInstruction({ op: "i32.const", value: -1 });
1307
+ this.pushInstruction("i32.ne");
1308
+ this.pushInstruction({ op: "if", blockType: "void" });
1309
+ this.pushInstruction({ op: "local.get", index: 0 });
1310
+ this.pushInstruction({
1311
+ op: "struct.get",
1312
+ typeIndex: mapInfo.typeIndex,
1313
+ fieldIndex: 1,
1314
+ });
1315
+ this.pushInstruction({ op: "local.get", index: orderNextLoc });
1316
+ this.pushInstruction({
1317
+ op: "array.get",
1318
+ typeIndex: mapInfo.entriesTypeIndex,
1319
+ });
1320
+ this.pushInstruction({ op: "local.get", index: orderPrevLoc });
1321
+ this.pushInstruction({
1322
+ op: "struct.set",
1323
+ typeIndex: mapInfo.entryTypeIndex,
1324
+ fieldIndex: 3,
1325
+ });
1326
+ this.pushInstruction("else");
1327
+ this.pushInstruction({ op: "local.get", index: 0 });
1328
+ this.pushInstruction({ op: "local.get", index: orderPrevLoc });
1329
+ this.pushInstruction({
1330
+ op: "struct.set",
1331
+ typeIndex: mapInfo.typeIndex,
1332
+ fieldIndex: 6,
1333
+ });
1334
+ this.pushInstruction("end");
1335
+
1336
+ // Mark inactive & free list
1337
+ this.pushInstruction({ op: "local.get", index: entryLoc });
1338
+ this.pushInstruction({ op: "i32.const", value: 0 });
1339
+ this.pushInstruction({
1340
+ op: "struct.set",
1341
+ typeIndex: mapInfo.entryTypeIndex,
1342
+ fieldIndex: 5,
1343
+ });
1344
+
1345
+ this.pushInstruction({ op: "local.get", index: entryLoc });
1346
+ this.pushInstruction({ op: "local.get", index: 0 });
1347
+ this.pushInstruction({
1348
+ op: "struct.get",
1349
+ typeIndex: mapInfo.typeIndex,
1350
+ fieldIndex: 7,
1351
+ });
1352
+ this.pushInstruction({
1353
+ op: "struct.set",
1354
+ typeIndex: mapInfo.entryTypeIndex,
1355
+ fieldIndex: 2,
1356
+ });
1357
+
1358
+ this.pushInstruction({ op: "local.get", index: 0 });
1359
+ this.pushInstruction({ op: "local.get", index: idxLoc });
1360
+ this.pushInstruction({
1361
+ op: "struct.set",
1362
+ typeIndex: mapInfo.typeIndex,
1363
+ fieldIndex: 7,
1364
+ });
1365
+
1366
+ // m.len--
1367
+ this.pushInstruction({ op: "local.get", index: 0 });
1368
+ this.pushInstruction({ op: "local.get", index: 0 });
1369
+ this.pushInstruction({
1370
+ op: "struct.get",
1371
+ typeIndex: mapInfo.typeIndex,
1372
+ fieldIndex: 2,
1373
+ });
1374
+ this.pushInstruction({ op: "i32.const", value: 1 });
1375
+ this.pushInstruction("i32.sub");
1376
+ this.pushInstruction({
1377
+ op: "struct.set",
1378
+ typeIndex: mapInfo.typeIndex,
1379
+ fieldIndex: 2,
1380
+ });
1381
+ this.pushInstruction({ op: "return" });
1382
+ this.pushInstruction("end");
1383
+ this.pushInstruction("end");
1384
+
1385
+ this.pushInstruction({ op: "local.get", index: idxLoc });
1386
+ this.pushInstruction({ op: "local.set", index: prevLoc });
1387
+ this.pushInstruction({ op: "local.get", index: entryLoc });
1388
+ this.pushInstruction({
1389
+ op: "struct.get",
1390
+ typeIndex: mapInfo.entryTypeIndex,
1391
+ fieldIndex: 2,
1392
+ });
1393
+ this.pushInstruction({ op: "local.set", index: idxLoc });
1394
+ this.pushInstruction({ op: "br", depth: 0 });
1395
+ this.pushInstruction("end");
1396
+ this.pushInstruction("end");
1397
+ this.pushInstruction({ op: "return" });
1398
+ }
1399
+
1400
+ emitMapLen(mapInfo) {
1401
+ this.pushInstruction({ op: "local.get", index: 0 });
1402
+ this.pushInstruction("ref.is_null");
1403
+ this.pushInstruction({ op: "if", blockType: "i32" });
1404
+ this.pushInstruction({ op: "i32.const", value: 0 });
1405
+ this.pushInstruction("else");
1406
+ this.pushInstruction({ op: "local.get", index: 0 });
1407
+ this.pushInstruction({
1408
+ op: "struct.get",
1409
+ typeIndex: mapInfo.typeIndex,
1410
+ fieldIndex: 2,
1411
+ });
1412
+ this.pushInstruction("end");
1413
+ this.pushInstruction({ op: "return" });
1414
+ }
1415
+
1416
+ emitMapClear(mapInfo) {
1417
+ const iLoc = this.allocLocal(null, "i32");
1418
+ const entryLoc = this.allocLocal(null, {
1419
+ kind: "ref",
1420
+ nullable: true,
1421
+ typeIndex: mapInfo.entryTypeIndex,
1422
+ });
1423
+
1424
+ this.pushInstruction({ op: "local.get", index: 0 });
1425
+ this.pushInstruction("ref.is_null");
1426
+ this.pushInstruction({ op: "if", blockType: "void" });
1427
+ this.pushInstruction({ op: "return" });
1428
+ this.pushInstruction("end");
1429
+
1430
+ // buckets[i] = -1
1431
+ this.pushInstruction({ op: "i32.const", value: 0 });
1432
+ this.pushInstruction({ op: "local.set", index: iLoc });
1433
+ this.pushInstruction({ op: "block", blockType: "void" });
1434
+ this.pushInstruction({ op: "loop", blockType: "void" });
1435
+ this.pushInstruction({ op: "local.get", index: iLoc });
1436
+ this.pushInstruction({ op: "local.get", index: 0 });
1437
+ this.pushInstruction({
1438
+ op: "struct.get",
1439
+ typeIndex: mapInfo.typeIndex,
1440
+ fieldIndex: 8,
1441
+ });
1442
+ this.pushInstruction("i32.ge_s");
1443
+ this.pushInstruction({ op: "br_if", depth: 1 });
1444
+
1445
+ this.pushInstruction({ op: "local.get", index: 0 });
1446
+ this.pushInstruction({
1447
+ op: "struct.get",
1448
+ typeIndex: mapInfo.typeIndex,
1449
+ fieldIndex: 0,
1450
+ });
1451
+ this.pushInstruction({ op: "local.get", index: iLoc });
1452
+ this.pushInstruction({ op: "i32.const", value: -1 });
1453
+ this.pushInstruction({
1454
+ op: "array.set",
1455
+ typeIndex: mapInfo.bucketsTypeIndex,
1456
+ });
1457
+
1458
+ this.pushInstruction({ op: "local.get", index: iLoc });
1459
+ this.pushInstruction({ op: "i32.const", value: 1 });
1460
+ this.pushInstruction("i32.add");
1461
+ this.pushInstruction({ op: "local.set", index: iLoc });
1462
+ this.pushInstruction({ op: "br", depth: 0 });
1463
+ this.pushInstruction("end");
1464
+ this.pushInstruction("end");
1465
+
1466
+ // entries[i].active = 0
1467
+ this.pushInstruction({ op: "i32.const", value: 0 });
1468
+ this.pushInstruction({ op: "local.set", index: iLoc });
1469
+ this.pushInstruction({ op: "block", blockType: "void" });
1470
+ this.pushInstruction({ op: "loop", blockType: "void" });
1471
+ this.pushInstruction({ op: "local.get", index: iLoc });
1472
+ this.pushInstruction({ op: "local.get", index: 0 });
1473
+ this.pushInstruction({
1474
+ op: "struct.get",
1475
+ typeIndex: mapInfo.typeIndex,
1476
+ fieldIndex: 4,
1477
+ });
1478
+ this.pushInstruction("i32.ge_s");
1479
+ this.pushInstruction({ op: "br_if", depth: 1 });
1480
+
1481
+ this.pushInstruction({ op: "local.get", index: 0 });
1482
+ this.pushInstruction({
1483
+ op: "struct.get",
1484
+ typeIndex: mapInfo.typeIndex,
1485
+ fieldIndex: 1,
1486
+ });
1487
+ this.pushInstruction({ op: "local.get", index: iLoc });
1488
+ this.pushInstruction({
1489
+ op: "array.get",
1490
+ typeIndex: mapInfo.entriesTypeIndex,
1491
+ });
1492
+ this.pushInstruction({ op: "local.tee", index: entryLoc });
1493
+ this.pushInstruction("ref.is_null");
1494
+ this.pushInstruction({ op: "if", blockType: "void" });
1495
+ this.pushInstruction("else");
1496
+ this.pushInstruction({ op: "local.get", index: entryLoc });
1497
+ this.pushInstruction({ op: "i32.const", value: 0 });
1498
+ this.pushInstruction({
1499
+ op: "struct.set",
1500
+ typeIndex: mapInfo.entryTypeIndex,
1501
+ fieldIndex: 5,
1502
+ });
1503
+ this.pushInstruction("end");
1504
+
1505
+ this.pushInstruction({ op: "local.get", index: iLoc });
1506
+ this.pushInstruction({ op: "i32.const", value: 1 });
1507
+ this.pushInstruction("i32.add");
1508
+ this.pushInstruction({ op: "local.set", index: iLoc });
1509
+ this.pushInstruction({ op: "br", depth: 0 });
1510
+ this.pushInstruction("end");
1511
+ this.pushInstruction("end");
1512
+
1513
+ this.pushInstruction({ op: "local.get", index: 0 });
1514
+ this.pushInstruction({ op: "i32.const", value: 0 });
1515
+ this.pushInstruction({
1516
+ op: "struct.set",
1517
+ typeIndex: mapInfo.typeIndex,
1518
+ fieldIndex: 2,
1519
+ });
1520
+ this.pushInstruction({ op: "local.get", index: 0 });
1521
+ this.pushInstruction({ op: "i32.const", value: 0 });
1522
+ this.pushInstruction({
1523
+ op: "struct.set",
1524
+ typeIndex: mapInfo.typeIndex,
1525
+ fieldIndex: 4,
1526
+ });
1527
+ this.pushInstruction({ op: "local.get", index: 0 });
1528
+ this.pushInstruction({ op: "i32.const", value: -1 });
1529
+ this.pushInstruction({
1530
+ op: "struct.set",
1531
+ typeIndex: mapInfo.typeIndex,
1532
+ fieldIndex: 5,
1533
+ });
1534
+ this.pushInstruction({ op: "local.get", index: 0 });
1535
+ this.pushInstruction({ op: "i32.const", value: -1 });
1536
+ this.pushInstruction({
1537
+ op: "struct.set",
1538
+ typeIndex: mapInfo.typeIndex,
1539
+ fieldIndex: 6,
1540
+ });
1541
+ this.pushInstruction({ op: "local.get", index: 0 });
1542
+ this.pushInstruction({ op: "i32.const", value: -1 });
1543
+ this.pushInstruction({
1544
+ op: "struct.set",
1545
+ typeIndex: mapInfo.typeIndex,
1546
+ fieldIndex: 7,
1547
+ });
1548
+ this.pushInstruction({ op: "return" });
1549
+ }
1550
+
1551
+ emitMapKeys(mapInfo) {
1552
+ const sliceInfo = this.mod.getSliceType(mapInfo.keyGoType);
1553
+ const lenLoc = this.allocLocal(null, "i32");
1554
+ const arrLoc = this.allocLocal(null, {
1555
+ kind: "ref",
1556
+ nullable: true,
1557
+ typeIndex: sliceInfo.arrInfo.typeIndex,
1558
+ });
1559
+ const iLoc = this.allocLocal(null, "i32");
1560
+ const idxLoc = this.allocLocal(null, "i32");
1561
+ const entryLoc = this.allocLocal(null, {
1562
+ kind: "ref",
1563
+ nullable: true,
1564
+ typeIndex: mapInfo.entryTypeIndex,
1565
+ });
1566
+
1567
+ this.pushInstruction({ op: "local.get", index: 0 });
1568
+ this.pushInstruction("ref.is_null");
1569
+ this.pushInstruction({ op: "if", blockType: "void" });
1570
+ this.pushInstruction({
1571
+ op: "global.get",
1572
+ index: sliceInfo.emptyGlobalIndex,
1573
+ });
1574
+ this.pushInstruction({ op: "return" });
1575
+ this.pushInstruction("end");
1576
+
1577
+ this.pushInstruction({ op: "local.get", index: 0 });
1578
+ this.pushInstruction({
1579
+ op: "struct.get",
1580
+ typeIndex: mapInfo.typeIndex,
1581
+ fieldIndex: 2,
1582
+ });
1583
+ this.pushInstruction({ op: "local.set", index: lenLoc });
1584
+
1585
+ this.pushInstruction({ op: "local.get", index: lenLoc });
1586
+ this.pushInstruction({
1587
+ op: "array.new_default",
1588
+ typeIndex: sliceInfo.arrInfo.typeIndex,
1589
+ });
1590
+ this.pushInstruction({ op: "local.set", index: arrLoc });
1591
+
1592
+ this.pushInstruction({ op: "i32.const", value: 0 });
1593
+ this.pushInstruction({ op: "local.set", index: iLoc });
1594
+
1595
+ this.pushInstruction({ op: "local.get", index: 0 });
1596
+ this.pushInstruction({
1597
+ op: "struct.get",
1598
+ typeIndex: mapInfo.typeIndex,
1599
+ fieldIndex: 5,
1600
+ });
1601
+ this.pushInstruction({ op: "local.set", index: idxLoc });
1602
+
1603
+ this.pushInstruction({ op: "block", blockType: "void" });
1604
+ this.pushInstruction({ op: "loop", blockType: "void" });
1605
+ this.pushInstruction({ op: "local.get", index: idxLoc });
1606
+ this.pushInstruction({ op: "i32.const", value: -1 });
1607
+ this.pushInstruction("i32.eq");
1608
+ this.pushInstruction({ op: "br_if", depth: 1 });
1609
+
1610
+ this.pushInstruction({ op: "local.get", index: 0 });
1611
+ this.pushInstruction({
1612
+ op: "struct.get",
1613
+ typeIndex: mapInfo.typeIndex,
1614
+ fieldIndex: 1,
1615
+ });
1616
+ this.pushInstruction({ op: "local.get", index: idxLoc });
1617
+ this.pushInstruction({
1618
+ op: "array.get",
1619
+ typeIndex: mapInfo.entriesTypeIndex,
1620
+ });
1621
+ this.pushInstruction({ op: "local.set", index: entryLoc });
1622
+
1623
+ this.pushInstruction({ op: "local.get", index: arrLoc });
1624
+ this.pushInstruction({ op: "local.get", index: iLoc });
1625
+ this.pushInstruction({ op: "local.get", index: entryLoc });
1626
+ this.pushInstruction({
1627
+ op: "struct.get",
1628
+ typeIndex: mapInfo.entryTypeIndex,
1629
+ fieldIndex: 0,
1630
+ });
1631
+ this.pushInstruction({
1632
+ op: "array.set",
1633
+ typeIndex: sliceInfo.arrInfo.typeIndex,
1634
+ });
1635
+
1636
+ this.pushInstruction({ op: "local.get", index: iLoc });
1637
+ this.pushInstruction({ op: "i32.const", value: 1 });
1638
+ this.pushInstruction("i32.add");
1639
+ this.pushInstruction({ op: "local.set", index: iLoc });
1640
+
1641
+ this.pushInstruction({ op: "local.get", index: entryLoc });
1642
+ this.pushInstruction({
1643
+ op: "struct.get",
1644
+ typeIndex: mapInfo.entryTypeIndex,
1645
+ fieldIndex: 4,
1646
+ });
1647
+ this.pushInstruction({ op: "local.set", index: idxLoc });
1648
+ this.pushInstruction({ op: "br", depth: 0 });
1649
+ this.pushInstruction("end");
1650
+ this.pushInstruction("end");
1651
+
1652
+ this.pushInstruction({ op: "local.get", index: arrLoc });
1653
+ this.pushInstruction({ op: "i32.const", value: 0 });
1654
+ this.pushInstruction({ op: "local.get", index: lenLoc });
1655
+ this.pushInstruction({ op: "local.get", index: lenLoc });
1656
+ this.pushInstruction({
1657
+ op: "struct.new",
1658
+ typeIndex: sliceInfo.typeIndex,
1659
+ });
1660
+ this.pushInstruction({ op: "return" });
1661
+ }
1662
+
1663
+ emitMapValues(mapInfo) {
1664
+ const sliceInfo = this.mod.getSliceType(mapInfo.valGoType);
1665
+ const lenLoc = this.allocLocal(null, "i32");
1666
+ const arrLoc = this.allocLocal(null, {
1667
+ kind: "ref",
1668
+ nullable: true,
1669
+ typeIndex: sliceInfo.arrInfo.typeIndex,
1670
+ });
1671
+ const iLoc = this.allocLocal(null, "i32");
1672
+ const idxLoc = this.allocLocal(null, "i32");
1673
+ const entryLoc = this.allocLocal(null, {
1674
+ kind: "ref",
1675
+ nullable: true,
1676
+ typeIndex: mapInfo.entryTypeIndex,
1677
+ });
1678
+
1679
+ this.pushInstruction({ op: "local.get", index: 0 });
1680
+ this.pushInstruction("ref.is_null");
1681
+ this.pushInstruction({ op: "if", blockType: "void" });
1682
+ this.pushInstruction({
1683
+ op: "global.get",
1684
+ index: sliceInfo.emptyGlobalIndex,
1685
+ });
1686
+ this.pushInstruction({ op: "return" });
1687
+ this.pushInstruction("end");
1688
+
1689
+ this.pushInstruction({ op: "local.get", index: 0 });
1690
+ this.pushInstruction({
1691
+ op: "struct.get",
1692
+ typeIndex: mapInfo.typeIndex,
1693
+ fieldIndex: 2,
1694
+ });
1695
+ this.pushInstruction({ op: "local.set", index: lenLoc });
1696
+
1697
+ this.pushInstruction({ op: "local.get", index: lenLoc });
1698
+ this.pushInstruction({
1699
+ op: "array.new_default",
1700
+ typeIndex: sliceInfo.arrInfo.typeIndex,
1701
+ });
1702
+ this.pushInstruction({ op: "local.set", index: arrLoc });
1703
+
1704
+ this.pushInstruction({ op: "i32.const", value: 0 });
1705
+ this.pushInstruction({ op: "local.set", index: iLoc });
1706
+
1707
+ this.pushInstruction({ op: "local.get", index: 0 });
1708
+ this.pushInstruction({
1709
+ op: "struct.get",
1710
+ typeIndex: mapInfo.typeIndex,
1711
+ fieldIndex: 5,
1712
+ });
1713
+ this.pushInstruction({ op: "local.set", index: idxLoc });
1714
+
1715
+ this.pushInstruction({ op: "block", blockType: "void" });
1716
+ this.pushInstruction({ op: "loop", blockType: "void" });
1717
+ this.pushInstruction({ op: "local.get", index: idxLoc });
1718
+ this.pushInstruction({ op: "i32.const", value: -1 });
1719
+ this.pushInstruction("i32.eq");
1720
+ this.pushInstruction({ op: "br_if", depth: 1 });
1721
+
1722
+ this.pushInstruction({ op: "local.get", index: 0 });
1723
+ this.pushInstruction({
1724
+ op: "struct.get",
1725
+ typeIndex: mapInfo.typeIndex,
1726
+ fieldIndex: 1,
1727
+ });
1728
+ this.pushInstruction({ op: "local.get", index: idxLoc });
1729
+ this.pushInstruction({
1730
+ op: "array.get",
1731
+ typeIndex: mapInfo.entriesTypeIndex,
1732
+ });
1733
+ this.pushInstruction({ op: "local.set", index: entryLoc });
1734
+
1735
+ this.pushInstruction({ op: "local.get", index: arrLoc });
1736
+ this.pushInstruction({ op: "local.get", index: iLoc });
1737
+ this.pushInstruction({ op: "local.get", index: entryLoc });
1738
+ this.pushInstruction({
1739
+ op: "struct.get",
1740
+ typeIndex: mapInfo.entryTypeIndex,
1741
+ fieldIndex: 1,
1742
+ });
1743
+ this.pushInstruction({
1744
+ op: "array.set",
1745
+ typeIndex: sliceInfo.arrInfo.typeIndex,
1746
+ });
1747
+
1748
+ this.pushInstruction({ op: "local.get", index: iLoc });
1749
+ this.pushInstruction({ op: "i32.const", value: 1 });
1750
+ this.pushInstruction("i32.add");
1751
+ this.pushInstruction({ op: "local.set", index: iLoc });
1752
+
1753
+ this.pushInstruction({ op: "local.get", index: entryLoc });
1754
+ this.pushInstruction({
1755
+ op: "struct.get",
1756
+ typeIndex: mapInfo.entryTypeIndex,
1757
+ fieldIndex: 4,
1758
+ });
1759
+ this.pushInstruction({ op: "local.set", index: idxLoc });
1760
+ this.pushInstruction({ op: "br", depth: 0 });
1761
+ this.pushInstruction("end");
1762
+ this.pushInstruction("end");
1763
+
1764
+ this.pushInstruction({ op: "local.get", index: arrLoc });
1765
+ this.pushInstruction({ op: "i32.const", value: 0 });
1766
+ this.pushInstruction({ op: "local.get", index: lenLoc });
1767
+ this.pushInstruction({ op: "local.get", index: lenLoc });
1768
+ this.pushInstruction({
1769
+ op: "struct.new",
1770
+ typeIndex: sliceInfo.typeIndex,
1771
+ });
1772
+ this.pushInstruction({ op: "return" });
1773
+ }
1774
+
1775
+ emitMapClone(mapInfo) {
1776
+ const dstLoc = this.allocLocal(null, mapInfo.wType);
1777
+ const idxLoc = this.allocLocal(null, "i32");
1778
+ const entryLoc = this.allocLocal(null, {
1779
+ kind: "ref",
1780
+ nullable: true,
1781
+ typeIndex: mapInfo.entryTypeIndex,
1782
+ });
1783
+
1784
+ this.pushInstruction({ op: "local.get", index: 0 });
1785
+ this.pushInstruction("ref.is_null");
1786
+ this.pushInstruction({ op: "if", blockType: "void" });
1787
+ this.pushInstruction({ op: "ref.null", heapType: mapInfo.typeIndex });
1788
+ this.pushInstruction({ op: "return" });
1789
+ this.pushInstruction("end");
1790
+
1791
+ this.pushInstruction({ op: "local.get", index: 0 });
1792
+ this.pushInstruction({
1793
+ op: "struct.get",
1794
+ typeIndex: mapInfo.typeIndex,
1795
+ fieldIndex: 2,
1796
+ });
1797
+ this.pushInstruction({
1798
+ op: "call",
1799
+ funcIndex: this.mod.resolveFuncIndex(mapInfo.makeFuncName),
1800
+ });
1801
+ this.pushInstruction({ op: "local.set", index: dstLoc });
1802
+
1803
+ this.pushInstruction({ op: "local.get", index: 0 });
1804
+ this.pushInstruction({
1805
+ op: "struct.get",
1806
+ typeIndex: mapInfo.typeIndex,
1807
+ fieldIndex: 5,
1808
+ });
1809
+ this.pushInstruction({ op: "local.set", index: idxLoc });
1810
+
1811
+ this.pushInstruction({ op: "block", blockType: "void" });
1812
+ this.pushInstruction({ op: "loop", blockType: "void" });
1813
+ this.pushInstruction({ op: "local.get", index: idxLoc });
1814
+ this.pushInstruction({ op: "i32.const", value: -1 });
1815
+ this.pushInstruction("i32.eq");
1816
+ this.pushInstruction({ op: "br_if", depth: 1 });
1817
+
1818
+ this.pushInstruction({ op: "local.get", index: 0 });
1819
+ this.pushInstruction({
1820
+ op: "struct.get",
1821
+ typeIndex: mapInfo.typeIndex,
1822
+ fieldIndex: 1,
1823
+ });
1824
+ this.pushInstruction({ op: "local.get", index: idxLoc });
1825
+ this.pushInstruction({
1826
+ op: "array.get",
1827
+ typeIndex: mapInfo.entriesTypeIndex,
1828
+ });
1829
+ this.pushInstruction({ op: "local.set", index: entryLoc });
1830
+
1831
+ this.pushInstruction({ op: "local.get", index: dstLoc });
1832
+ this.pushInstruction({ op: "local.get", index: entryLoc });
1833
+ this.pushInstruction({
1834
+ op: "struct.get",
1835
+ typeIndex: mapInfo.entryTypeIndex,
1836
+ fieldIndex: 0,
1837
+ });
1838
+ this.pushInstruction({ op: "local.get", index: entryLoc });
1839
+ this.pushInstruction({
1840
+ op: "struct.get",
1841
+ typeIndex: mapInfo.entryTypeIndex,
1842
+ fieldIndex: 1,
1843
+ });
1844
+ this.pushInstruction({
1845
+ op: "call",
1846
+ funcIndex: this.mod.resolveFuncIndex(mapInfo.setFuncName),
1847
+ });
1848
+
1849
+ this.pushInstruction({ op: "local.get", index: entryLoc });
1850
+ this.pushInstruction({
1851
+ op: "struct.get",
1852
+ typeIndex: mapInfo.entryTypeIndex,
1853
+ fieldIndex: 4,
1854
+ });
1855
+ this.pushInstruction({ op: "local.set", index: idxLoc });
1856
+ this.pushInstruction({ op: "br", depth: 0 });
1857
+ this.pushInstruction("end");
1858
+ this.pushInstruction("end");
1859
+
1860
+ this.pushInstruction({ op: "local.get", index: dstLoc });
1861
+ this.pushInstruction({ op: "return" });
1862
+ }
1863
+ }