gofront 1.5.1 → 1.6.1

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