gofront 1.6.0 → 1.7.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 (80) hide show
  1. package/README.md +35 -39
  2. package/package.json +37 -4
  3. package/src/backend/js/expressions.js +559 -144
  4. package/src/backend/js/index.js +174 -49
  5. package/src/backend/js/runtime.js +1518 -54
  6. package/src/backend/js/statements.js +91 -73
  7. package/src/backend/js/stdlib/base64.js +12 -0
  8. package/src/backend/js/stdlib/binary.js +102 -0
  9. package/src/backend/js/stdlib/bits.js +15 -1
  10. package/src/backend/js/stdlib/builder.js +28 -9
  11. package/src/backend/js/stdlib/bytes.js +75 -18
  12. package/src/backend/js/stdlib/errors.js +25 -1
  13. package/src/backend/js/stdlib/fmt.js +70 -13
  14. package/src/backend/js/stdlib/hex.js +17 -0
  15. package/src/backend/js/stdlib/html.js +1 -1
  16. package/src/backend/js/stdlib/index.js +28 -0
  17. package/src/backend/js/stdlib/io.js +105 -3
  18. package/src/backend/js/stdlib/json.js +972 -0
  19. package/src/backend/js/stdlib/math.js +13 -1
  20. package/src/backend/js/stdlib/path.js +18 -4
  21. package/src/backend/js/stdlib/rand.js +10 -5
  22. package/src/backend/js/stdlib/sha256.js +12 -0
  23. package/src/backend/js/stdlib/simd.js +24 -0
  24. package/src/backend/js/stdlib/slices.js +52 -26
  25. package/src/backend/js/stdlib/strconv.js +21 -5
  26. package/src/backend/js/stdlib/strings.js +148 -15
  27. package/src/backend/js/stdlib/sync.js +13 -0
  28. package/src/backend/js/stdlib/time.js +90 -19
  29. package/src/backend/js/stdlib/unicode.js +2 -2
  30. package/src/backend/wasm/boundary.js +1225 -41
  31. package/src/backend/wasm/const-fold.js +205 -0
  32. package/src/backend/wasm/emit-builtins.js +220 -76
  33. package/src/backend/wasm/emit-exprs.js +475 -276
  34. package/src/backend/wasm/emit-maps.js +144 -8
  35. package/src/backend/wasm/emit-stdlib.js +12 -3005
  36. package/src/backend/wasm/emit-stmts.js +264 -270
  37. package/src/backend/wasm/emit.js +124 -87
  38. package/src/backend/wasm/encode.js +140 -29
  39. package/src/backend/wasm/index.js +1001 -32
  40. package/src/backend/wasm/optimize.js +17 -6
  41. package/src/backend/wasm/stdlib/bytes.js +5039 -0
  42. package/src/backend/wasm/stdlib/core.js +8903 -0
  43. package/src/backend/wasm/stdlib/index.js +43 -0
  44. package/src/backend/wasm/stdlib/io.js +2161 -0
  45. package/src/backend/wasm/stdlib/packages.js +2400 -0
  46. package/src/backend/wasm/stdlib/pure.js +720 -0
  47. package/src/backend/wasm/stdlib/simd.js +234 -0
  48. package/src/backend/wasm/stdlib/time.js +1200 -0
  49. package/src/backend/wasm/types.js +174 -1
  50. package/src/backend/wasm/wat.js +37 -0
  51. package/src/cli-core.js +1 -1
  52. package/src/compiler.js +18 -4
  53. package/src/dts-parser.js +150 -140
  54. package/src/index.js +2 -6
  55. package/src/lexer.js +80 -29
  56. package/src/lower/boxing.js +1 -7
  57. package/src/lower/captures.js +2 -6
  58. package/src/lower/embedding.js +2 -1
  59. package/src/lower/ownership.js +30 -9
  60. package/src/minifier.js +20 -68
  61. package/src/parser/declarations.js +3 -6
  62. package/src/parser/expressions.js +3 -8
  63. package/src/parser/index.js +18 -3
  64. package/src/parser/statements.js +25 -38
  65. package/src/parser/struct-tag.js +144 -0
  66. package/src/parser/types.js +64 -8
  67. package/src/resolver.js +2 -27
  68. package/src/templ-lexer.js +29 -63
  69. package/src/templ-parser.js +22 -45
  70. package/src/typechecker/assignability.js +126 -13
  71. package/src/typechecker/expressions.js +168 -16
  72. package/src/typechecker/index.js +35 -8
  73. package/src/typechecker/resolve.js +187 -8
  74. package/src/typechecker/statements.js +68 -9
  75. package/src/typechecker/stdlib/core.js +280 -89
  76. package/src/typechecker/stdlib/extended.js +490 -1
  77. package/src/typechecker/stdlib/simd.js +73 -0
  78. package/src/typechecker/stdlib.js +2 -0
  79. package/src/typechecker/types.js +362 -9
  80. package/src/vendor.js +86 -11
@@ -0,0 +1,2400 @@
1
+ // src/backend/wasm/stdlib/packages.js
2
+ // FunctionEmitter mixin: sync, encoding/binary, crypto/sha256, encoding/hex, encoding/base64.
3
+
4
+ import { isSliceType, toWasmType } from "../types.js";
5
+
6
+ const EXT_PKG_CONSTS = {
7
+ sha256: { Size: 32, BlockSize: 64 },
8
+ base64: { StdPadding: 61, NoPadding: -1 },
9
+ };
10
+ const EXT_PKG_SPECIAL = new Set([
11
+ "hex.ErrLength",
12
+ "base64.StdEncoding",
13
+ "base64.URLEncoding",
14
+ "base64.RawStdEncoding",
15
+ "base64.RawURLEncoding",
16
+ "binary.LittleEndian",
17
+ "binary.BigEndian",
18
+ ]);
19
+
20
+ export class ExtendedPackagesEmitter {
21
+ _isExtendedPkgConst(expr) {
22
+ if (!this._isPkgExpr(expr)) return false;
23
+ const pkg = expr.expr.name;
24
+ return (
25
+ EXT_PKG_CONSTS[pkg]?.[expr.field] !== undefined ||
26
+ EXT_PKG_SPECIAL.has(`${pkg}.${expr.field}`)
27
+ );
28
+ }
29
+
30
+ emitExtendedPkgConst(expr, targetWasmType) {
31
+ const pkg = expr.expr.name;
32
+ const field = expr.field;
33
+ const scalarVal = EXT_PKG_CONSTS[pkg]?.[field];
34
+ if (scalarVal !== undefined) {
35
+ if ((targetWasmType ?? "i64") === "i64") {
36
+ this.pushInstruction({ op: "i64.const", value: BigInt(scalarVal) });
37
+ } else {
38
+ this.pushInstruction({ op: "i32.const", value: scalarVal });
39
+ }
40
+ return;
41
+ }
42
+ if (pkg === "hex" && field === "ErrLength") {
43
+ const strIdx = this.mod.internString(
44
+ "encoding/hex: odd length hex string",
45
+ );
46
+ this.pushInstruction({ op: "i32.const", value: strIdx });
47
+ this.pushInstruction({
48
+ op: "call",
49
+ funcIndex: this.mod.getStringImportIndex(),
50
+ });
51
+ this.pushInstruction({ op: "ref.null", heapType: "any" });
52
+ this.pushInstruction({
53
+ op: "call",
54
+ funcIndex: this.mod.resolveFuncIndex("__mk_error"),
55
+ });
56
+ return;
57
+ }
58
+ if (pkg === "base64") {
59
+ const mode =
60
+ field === "URLEncoding"
61
+ ? 1
62
+ : field === "RawStdEncoding"
63
+ ? 2
64
+ : field === "RawURLEncoding"
65
+ ? 3
66
+ : 0;
67
+ const structInfo = this.mod.getStructType("base64.Encoding");
68
+ this.pushInstruction({ op: "i32.const", value: mode });
69
+ this.pushInstruction({
70
+ op: "struct.new",
71
+ typeIndex: structInfo.typeIndex,
72
+ });
73
+ return;
74
+ }
75
+ if (pkg === "binary") {
76
+ const isBig = field === "BigEndian";
77
+ const structInfo = this.mod.getStructType(
78
+ isBig ? "binary.BigEndian" : "binary.LittleEndian",
79
+ );
80
+ this.pushInstruction({ op: "i32.const", value: isBig ? 1 : 0 });
81
+ this.pushInstruction({
82
+ op: "struct.new",
83
+ typeIndex: structInfo.typeIndex,
84
+ });
85
+ return;
86
+ }
87
+ }
88
+
89
+ emitSyncMutexMethodCall(method, recvExpr, _args, _targetWasmType) {
90
+ const recvW = toWasmType(
91
+ recvExpr._type ?? this._resolveExprGoType(recvExpr),
92
+ this.mod.checker,
93
+ this.mod,
94
+ );
95
+ this.emitExpr(recvExpr, recvW);
96
+ this.pushInstruction("drop");
97
+ if (method === "TryLock" || method === "TryRLock") {
98
+ this.pushInstruction({ op: "i32.const", value: 1 });
99
+ }
100
+ }
101
+
102
+ emitSyncOnceMethodCall(method, recvExpr, args, _targetWasmType) {
103
+ if (method !== "Do") return;
104
+ const structInfo = this.mod.getStructType("sync.Once");
105
+ const onceW = {
106
+ kind: "ref",
107
+ nullable: true,
108
+ typeIndex: structInfo.typeIndex,
109
+ };
110
+ const oTmp = this.acquireTemp(onceW);
111
+ this.emitExpr(recvExpr, onceW);
112
+ this.pushInstruction({ op: "local.set", index: oTmp });
113
+
114
+ this.pushInstruction({ op: "local.get", index: oTmp });
115
+ this.pushInstruction({
116
+ op: "struct.get",
117
+ typeIndex: structInfo.typeIndex,
118
+ fieldIndex: 0,
119
+ });
120
+ this.pushInstruction("i32.eqz");
121
+ this.pushInstruction({ op: "if", blockType: "void" });
122
+
123
+ this.pushInstruction({ op: "local.get", index: oTmp });
124
+ this.pushInstruction({ op: "i32.const", value: 1 });
125
+ this.pushInstruction({
126
+ op: "struct.set",
127
+ typeIndex: structInfo.typeIndex,
128
+ fieldIndex: 0,
129
+ });
130
+
131
+ const fnNode = args[0];
132
+ const closureGoType = this._resolveExprGoType(fnNode);
133
+ const closureInfo = this.mod.getClosureType(closureGoType);
134
+ const closureW = {
135
+ kind: "ref",
136
+ nullable: true,
137
+ typeIndex: closureInfo.typeIndex,
138
+ };
139
+ const clTmp = this.acquireTemp(closureW);
140
+ this.emitExpr(fnNode, closureW);
141
+ this.pushInstruction({ op: "local.set", index: clTmp });
142
+
143
+ this.pushInstruction({ op: "local.get", index: clTmp });
144
+ this.pushInstruction({
145
+ op: "struct.get",
146
+ typeIndex: closureInfo.typeIndex,
147
+ fieldIndex: 1,
148
+ });
149
+ this.pushInstruction({ op: "local.get", index: clTmp });
150
+ this.pushInstruction({
151
+ op: "struct.get",
152
+ typeIndex: closureInfo.typeIndex,
153
+ fieldIndex: 0,
154
+ });
155
+ this.pushInstruction({
156
+ op: "call_ref",
157
+ typeIndex: closureInfo.funcTypeIndex,
158
+ });
159
+
160
+ this.releaseTemp(clTmp, closureW);
161
+ this.pushInstruction("end");
162
+ this.releaseTemp(oTmp, onceW);
163
+ }
164
+
165
+ emitSyncWaitGroupMethodCall(method, recvExpr, args, _targetWasmType) {
166
+ const structInfo = this.mod.getStructType("sync.WaitGroup");
167
+ const wgW = {
168
+ kind: "ref",
169
+ nullable: true,
170
+ typeIndex: structInfo.typeIndex,
171
+ };
172
+ const wgTmp = this.acquireTemp(wgW);
173
+ this.emitExpr(recvExpr, wgW);
174
+ this.pushInstruction({ op: "local.set", index: wgTmp });
175
+
176
+ if (method === "Add") {
177
+ const deltaTmp = this.acquireTemp("i64");
178
+ this.emitExpr(args[0], "i64");
179
+ this.pushInstruction({ op: "local.set", index: deltaTmp });
180
+
181
+ this.pushInstruction({ op: "local.get", index: wgTmp });
182
+ this.pushInstruction({ op: "local.get", index: wgTmp });
183
+ this.pushInstruction({
184
+ op: "struct.get",
185
+ typeIndex: structInfo.typeIndex,
186
+ fieldIndex: 0,
187
+ });
188
+ this.pushInstruction({ op: "local.get", index: deltaTmp });
189
+ this.pushInstruction("i64.add");
190
+ this.pushInstruction({
191
+ op: "struct.set",
192
+ typeIndex: structInfo.typeIndex,
193
+ fieldIndex: 0,
194
+ });
195
+ this.releaseTemp(deltaTmp, "i64");
196
+ } else if (method === "Done") {
197
+ this.pushInstruction({ op: "local.get", index: wgTmp });
198
+ this.pushInstruction({ op: "local.get", index: wgTmp });
199
+ this.pushInstruction({
200
+ op: "struct.get",
201
+ typeIndex: structInfo.typeIndex,
202
+ fieldIndex: 0,
203
+ });
204
+ this.pushInstruction({ op: "i64.const", value: 1n });
205
+ this.pushInstruction("i64.sub");
206
+ this.pushInstruction({
207
+ op: "struct.set",
208
+ typeIndex: structInfo.typeIndex,
209
+ fieldIndex: 0,
210
+ });
211
+ }
212
+ this.releaseTemp(wgTmp, wgW);
213
+ }
214
+
215
+ emitBinaryCall(name, call, targetWasmType) {
216
+ const args = call.args;
217
+ if (name === "Size") {
218
+ this._emitBinarySize(args[0]);
219
+ return;
220
+ }
221
+ if (
222
+ name === "AppendUint16" ||
223
+ name === "AppendUint32" ||
224
+ name === "AppendUint64"
225
+ ) {
226
+ this.emitBinaryOrderMethodCall(
227
+ "binary.LittleEndian",
228
+ name,
229
+ null,
230
+ args,
231
+ targetWasmType,
232
+ );
233
+ return;
234
+ }
235
+ if (name === "Read") {
236
+ this._emitBinaryRead(args[0], args[1], args[2]);
237
+ return;
238
+ }
239
+ if (name === "Write") {
240
+ this._emitBinaryWrite(args[0], args[1], args[2]);
241
+ return;
242
+ }
243
+ throw new Error(`Unsupported binary call: binary.${name}`);
244
+ }
245
+
246
+ _emitBinarySize(arg) {
247
+ const t = arg._type ?? this._resolveExprGoType(arg);
248
+ const sizeOf = (gt) => {
249
+ if (!gt) return -1;
250
+ if (gt.kind === "basic") {
251
+ switch (gt.name) {
252
+ case "bool":
253
+ case "int8":
254
+ case "uint8":
255
+ case "byte":
256
+ return 1;
257
+ case "int16":
258
+ case "uint16":
259
+ return 2;
260
+ case "int32":
261
+ case "uint32":
262
+ case "float32":
263
+ case "rune":
264
+ return 4;
265
+ case "int64":
266
+ case "uint64":
267
+ case "float64":
268
+ case "int":
269
+ case "uint":
270
+ case "uintptr":
271
+ return 8;
272
+ default:
273
+ return -1;
274
+ }
275
+ }
276
+ if (gt.kind === "array" || gt.kind === "ArrayType") {
277
+ const es = sizeOf(gt.elem);
278
+ const len = gt.len ?? gt.size ?? 0;
279
+ return es > 0 ? es * len : -1;
280
+ }
281
+ if (
282
+ gt.kind === "pointer" ||
283
+ gt.kind === "PointerType" ||
284
+ gt.kind === "StarExpr"
285
+ ) {
286
+ return sizeOf(gt.base ?? gt.expr ?? gt.operand);
287
+ }
288
+ if (gt.kind === "struct" || gt.kind === "StructType") {
289
+ let total = 0;
290
+ if (gt.fields instanceof Map) {
291
+ for (const fType of gt.fields.values()) {
292
+ const s = sizeOf(fType);
293
+ if (s < 0) return -1;
294
+ total += s;
295
+ }
296
+ return total;
297
+ }
298
+ }
299
+ if (gt.name && this.mod.checker?.types?.has(gt.name)) {
300
+ const resolved = this.mod.checker.types.get(gt.name);
301
+ return sizeOf(resolved.underlying ?? resolved);
302
+ }
303
+ return -1;
304
+ };
305
+ const s = sizeOf(t);
306
+ if (s >= 0) {
307
+ this.pushInstruction({ op: "i64.const", value: BigInt(s) });
308
+ } else {
309
+ this.pushInstruction({ op: "i64.const", value: -1n });
310
+ }
311
+ }
312
+
313
+ _emitBinaryRead(rExpr, orderExpr, dataExpr) {
314
+ const byteGo = { kind: "basic", name: "byte" };
315
+ const sliceInfo = this.mod.getSliceType(byteGo);
316
+ const arrInfo = sliceInfo.arrInfo;
317
+ const sliceW = {
318
+ kind: "ref",
319
+ nullable: true,
320
+ typeIndex: sliceInfo.typeIndex,
321
+ };
322
+ const arrW = {
323
+ kind: "ref",
324
+ nullable: true,
325
+ typeIndex: arrInfo.typeIndex,
326
+ };
327
+
328
+ // If data is a slice ([]byte): read directly into data slice
329
+ const dataType = dataExpr._type ?? this._resolveExprGoType(dataExpr);
330
+ if (isSliceType(dataType, this.mod.checker)) {
331
+ const sTmp = this.acquireTemp(sliceW);
332
+ this.emitExpr(dataExpr, sliceW);
333
+ this.pushInstruction({ op: "local.set", index: sTmp });
334
+
335
+ const rTmp = this.acquireTemp("anyref");
336
+ this.emitExpr(rExpr, "anyref");
337
+ this.pushInstruction({ op: "local.set", index: rTmp });
338
+
339
+ this.pushInstruction({ op: "local.get", index: rTmp });
340
+ this.pushInstruction({ op: "local.get", index: sTmp });
341
+ const dispatchReadIdx = this.mod.resolveFuncIndex(
342
+ "__dispatch_io.Reader_Read",
343
+ );
344
+ this.pushInstruction({ op: "call", funcIndex: dispatchReadIdx });
345
+
346
+ // Drop n (int), return err
347
+ const errTmp = this.acquireTemp("anyref");
348
+ this.pushInstruction({ op: "local.set", index: errTmp });
349
+ this.pushInstruction("drop"); // drop n
350
+ this.pushInstruction({ op: "local.get", index: errTmp });
351
+
352
+ this.releaseTemp(errTmp, "anyref");
353
+ this.releaseTemp(rTmp, "anyref");
354
+ this.releaseTemp(sTmp, sliceW);
355
+ return;
356
+ }
357
+
358
+ // Scalar pointer: determine sz (1, 2, 4, 8)
359
+ let sz = 4;
360
+ const baseType =
361
+ dataType?.base ?? dataType?.expr ?? dataType?.operand ?? dataType;
362
+ if (baseType?.name === "uint16" || baseType?.name === "int16") sz = 2;
363
+ else if (
364
+ baseType?.name === "uint64" ||
365
+ baseType?.name === "int64" ||
366
+ baseType?.name === "int" ||
367
+ baseType?.name === "uint" ||
368
+ baseType?.name === "float64"
369
+ )
370
+ sz = 8;
371
+ else if (
372
+ baseType?.name === "byte" ||
373
+ baseType?.name === "uint8" ||
374
+ baseType?.name === "int8" ||
375
+ baseType?.name === "bool"
376
+ )
377
+ sz = 1;
378
+ else if (baseType?.name === "float32") sz = 4;
379
+
380
+ const arrTmp = this.acquireTemp(arrW);
381
+ this.pushInstruction({ op: "i32.const", value: sz });
382
+ this.pushInstruction({
383
+ op: "array.new_default",
384
+ typeIndex: arrInfo.typeIndex,
385
+ });
386
+ this.pushInstruction({ op: "local.set", index: arrTmp });
387
+
388
+ const bufTmp = this.acquireTemp(sliceW);
389
+ this.pushInstruction({ op: "local.get", index: arrTmp });
390
+ this.pushInstruction({ op: "i32.const", value: 0 });
391
+ this.pushInstruction({ op: "i32.const", value: sz });
392
+ this.pushInstruction({ op: "i32.const", value: sz });
393
+ this.pushInstruction({
394
+ op: "struct.new",
395
+ typeIndex: sliceInfo.typeIndex,
396
+ });
397
+ this.pushInstruction({ op: "local.set", index: bufTmp });
398
+
399
+ const rTmp = this.acquireTemp("anyref");
400
+ this.emitExpr(rExpr, "anyref");
401
+ this.pushInstruction({ op: "local.set", index: rTmp });
402
+
403
+ this.pushInstruction({ op: "local.get", index: rTmp });
404
+ this.pushInstruction({ op: "local.get", index: bufTmp });
405
+ const dispatchReadIdx = this.mod.resolveFuncIndex(
406
+ "__dispatch_io.Reader_Read",
407
+ );
408
+ this.pushInstruction({ op: "call", funcIndex: dispatchReadIdx });
409
+
410
+ const errTmp = this.acquireTemp("anyref");
411
+ const nTmp = this.acquireTemp("i64");
412
+ this.pushInstruction({ op: "local.set", index: errTmp });
413
+ this.pushInstruction({ op: "local.set", index: nTmp });
414
+
415
+ // if err != nil -> return err
416
+ this.pushInstruction({ op: "block", blockType: "anyref" });
417
+ this.pushInstruction({ op: "local.get", index: errTmp });
418
+ this.pushInstruction("ref.is_null");
419
+ this.pushInstruction("i32.eqz");
420
+ this.pushInstruction({ op: "if", blockType: "void" });
421
+ this.pushInstruction({ op: "local.get", index: errTmp });
422
+ this.pushInstruction({ op: "br", depth: 1 });
423
+ this.pushInstruction("end");
424
+
425
+ // if n < sz -> return io.EOF
426
+ this.pushInstruction({ op: "local.get", index: nTmp });
427
+ this.pushInstruction({ op: "i64.const", value: BigInt(sz) });
428
+ this.pushInstruction("i64.lt_s");
429
+ this.pushInstruction({ op: "if", blockType: "void" });
430
+ this.emitIoConst("EOF", "anyref");
431
+ this.pushInstruction({ op: "br", depth: 1 });
432
+ this.pushInstruction("end");
433
+
434
+ // Decode scalar from arrTmp and write to target
435
+ const isAddressOf = dataExpr.kind === "UnaryExpr" && dataExpr.op === "&";
436
+ const targetNode = isAddressOf
437
+ ? (dataExpr.operand ?? dataExpr.expr)
438
+ : {
439
+ kind: "UnaryExpr",
440
+ op: "*",
441
+ operand: { ...dataExpr, _type: dataType },
442
+ _type: baseType,
443
+ };
444
+
445
+ const isBig =
446
+ orderExpr?._type?.name?.includes("BigEndian") ||
447
+ orderExpr?.field === "BigEndian";
448
+
449
+ let wType = "i32";
450
+ if (sz === 8) {
451
+ wType = baseType?.name === "float64" ? "f64" : "i64";
452
+ } else if (sz === 4 && baseType?.name === "float32") {
453
+ wType = "f32";
454
+ }
455
+
456
+ this._emitAssignToTarget(targetNode, wType, baseType, () => {
457
+ if (sz === 1) {
458
+ this.pushInstruction({ op: "local.get", index: arrTmp });
459
+ this.pushInstruction({ op: "i32.const", value: 0 });
460
+ this.pushInstruction({ op: "array.get", typeIndex: arrInfo.typeIndex });
461
+ if (baseType?.name === "int8") {
462
+ this.pushInstruction("i32.extend8_s");
463
+ }
464
+ } else if (sz === 2) {
465
+ if (isBig) {
466
+ this.pushInstruction({ op: "local.get", index: arrTmp });
467
+ this.pushInstruction({ op: "i32.const", value: 0 });
468
+ this.pushInstruction({
469
+ op: "array.get",
470
+ typeIndex: arrInfo.typeIndex,
471
+ });
472
+ this.pushInstruction({ op: "i32.const", value: 8 });
473
+ this.pushInstruction("i32.shl");
474
+ this.pushInstruction({ op: "local.get", index: arrTmp });
475
+ this.pushInstruction({ op: "i32.const", value: 1 });
476
+ this.pushInstruction({
477
+ op: "array.get",
478
+ typeIndex: arrInfo.typeIndex,
479
+ });
480
+ this.pushInstruction("i32.or");
481
+ } else {
482
+ this.pushInstruction({ op: "local.get", index: arrTmp });
483
+ this.pushInstruction({ op: "i32.const", value: 0 });
484
+ this.pushInstruction({
485
+ op: "array.get",
486
+ typeIndex: arrInfo.typeIndex,
487
+ });
488
+ this.pushInstruction({ op: "local.get", index: arrTmp });
489
+ this.pushInstruction({ op: "i32.const", value: 1 });
490
+ this.pushInstruction({
491
+ op: "array.get",
492
+ typeIndex: arrInfo.typeIndex,
493
+ });
494
+ this.pushInstruction({ op: "i32.const", value: 8 });
495
+ this.pushInstruction("i32.shl");
496
+ this.pushInstruction("i32.or");
497
+ }
498
+ if (baseType?.name === "int16") {
499
+ this.pushInstruction("i32.extend16_s");
500
+ }
501
+ } else if (sz === 4) {
502
+ for (let i = 0; i < 4; i++) {
503
+ this.pushInstruction({ op: "local.get", index: arrTmp });
504
+ this.pushInstruction({ op: "i32.const", value: i });
505
+ this.pushInstruction({
506
+ op: "array.get",
507
+ typeIndex: arrInfo.typeIndex,
508
+ });
509
+ }
510
+ if (isBig) {
511
+ const b3 = this.acquireTemp("i32");
512
+ const b2 = this.acquireTemp("i32");
513
+ const b1 = this.acquireTemp("i32");
514
+ const b0 = this.acquireTemp("i32");
515
+ this.pushInstruction({ op: "local.set", index: b3 });
516
+ this.pushInstruction({ op: "local.set", index: b2 });
517
+ this.pushInstruction({ op: "local.set", index: b1 });
518
+ this.pushInstruction({ op: "local.set", index: b0 });
519
+ this.pushInstruction({ op: "local.get", index: b0 });
520
+ this.pushInstruction({ op: "i32.const", value: 24 });
521
+ this.pushInstruction("i32.shl");
522
+ this.pushInstruction({ op: "local.get", index: b1 });
523
+ this.pushInstruction({ op: "i32.const", value: 16 });
524
+ this.pushInstruction("i32.shl");
525
+ this.pushInstruction("i32.or");
526
+ this.pushInstruction({ op: "local.get", index: b2 });
527
+ this.pushInstruction({ op: "i32.const", value: 8 });
528
+ this.pushInstruction("i32.shl");
529
+ this.pushInstruction("i32.or");
530
+ this.pushInstruction({ op: "local.get", index: b3 });
531
+ this.pushInstruction("i32.or");
532
+ this.releaseTemp(b0, "i32");
533
+ this.releaseTemp(b1, "i32");
534
+ this.releaseTemp(b2, "i32");
535
+ this.releaseTemp(b3, "i32");
536
+ } else {
537
+ const b3 = this.acquireTemp("i32");
538
+ const b2 = this.acquireTemp("i32");
539
+ const b1 = this.acquireTemp("i32");
540
+ const b0 = this.acquireTemp("i32");
541
+ this.pushInstruction({ op: "local.set", index: b3 });
542
+ this.pushInstruction({ op: "local.set", index: b2 });
543
+ this.pushInstruction({ op: "local.set", index: b1 });
544
+ this.pushInstruction({ op: "local.set", index: b0 });
545
+ this.pushInstruction({ op: "local.get", index: b0 });
546
+ this.pushInstruction({ op: "local.get", index: b1 });
547
+ this.pushInstruction({ op: "i32.const", value: 8 });
548
+ this.pushInstruction("i32.shl");
549
+ this.pushInstruction("i32.or");
550
+ this.pushInstruction({ op: "local.get", index: b2 });
551
+ this.pushInstruction({ op: "i32.const", value: 16 });
552
+ this.pushInstruction("i32.shl");
553
+ this.pushInstruction("i32.or");
554
+ this.pushInstruction({ op: "local.get", index: b3 });
555
+ this.pushInstruction({ op: "i32.const", value: 24 });
556
+ this.pushInstruction("i32.shl");
557
+ this.pushInstruction("i32.or");
558
+ this.releaseTemp(b0, "i32");
559
+ this.releaseTemp(b1, "i32");
560
+ this.releaseTemp(b2, "i32");
561
+ this.releaseTemp(b3, "i32");
562
+ }
563
+ if (baseType?.name === "float32") {
564
+ this.pushInstruction("f32.reinterpret_i32");
565
+ }
566
+ } else if (sz === 8) {
567
+ const bTmps = [];
568
+ for (let i = 0; i < 8; i++) {
569
+ this.pushInstruction({ op: "local.get", index: arrTmp });
570
+ this.pushInstruction({ op: "i32.const", value: i });
571
+ this.pushInstruction({
572
+ op: "array.get",
573
+ typeIndex: arrInfo.typeIndex,
574
+ });
575
+ this.pushInstruction("i64.extend_i32_u");
576
+ const bt = this.acquireTemp("i64");
577
+ this.pushInstruction({ op: "local.set", index: bt });
578
+ bTmps.push(bt);
579
+ }
580
+ this.pushInstruction({ op: "i64.const", value: 0n });
581
+ for (let i = 0; i < 8; i++) {
582
+ const shift = isBig ? (7 - i) * 8 : i * 8;
583
+ this.pushInstruction({ op: "local.get", index: bTmps[i] });
584
+ if (shift > 0) {
585
+ this.pushInstruction({ op: "i64.const", value: BigInt(shift) });
586
+ this.pushInstruction("i64.shl");
587
+ }
588
+ this.pushInstruction("i64.or");
589
+ }
590
+ for (const bt of bTmps) this.releaseTemp(bt, "i64");
591
+ if (baseType?.name === "float64") {
592
+ this.pushInstruction("f64.reinterpret_i64");
593
+ }
594
+ }
595
+ });
596
+
597
+ // return nil error
598
+ this.pushInstruction({ op: "ref.null", heapType: "any" });
599
+ this.pushInstruction("end"); // end block
600
+
601
+ this.releaseTemp(nTmp, "i64");
602
+ this.releaseTemp(errTmp, "anyref");
603
+ this.releaseTemp(rTmp, "anyref");
604
+ this.releaseTemp(bufTmp, sliceW);
605
+ this.releaseTemp(arrTmp, arrW);
606
+ }
607
+
608
+ _emitBinaryWrite(wExpr, orderExpr, dataExpr) {
609
+ const byteGo = { kind: "basic", name: "byte" };
610
+ const sliceInfo = this.mod.getSliceType(byteGo);
611
+ const arrInfo = sliceInfo.arrInfo;
612
+ const sliceW = {
613
+ kind: "ref",
614
+ nullable: true,
615
+ typeIndex: sliceInfo.typeIndex,
616
+ };
617
+ const arrW = {
618
+ kind: "ref",
619
+ nullable: true,
620
+ typeIndex: arrInfo.typeIndex,
621
+ };
622
+
623
+ const dataType = dataExpr._type ?? this._resolveExprGoType(dataExpr);
624
+ if (isSliceType(dataType, this.mod.checker)) {
625
+ const sTmp = this.acquireTemp(sliceW);
626
+ this.emitExpr(dataExpr, sliceW);
627
+ this.pushInstruction({ op: "local.set", index: sTmp });
628
+
629
+ const wTmp = this.acquireTemp("anyref");
630
+ this.emitExpr(wExpr, "anyref");
631
+ this.pushInstruction({ op: "local.set", index: wTmp });
632
+
633
+ this.pushInstruction({ op: "local.get", index: wTmp });
634
+ this.pushInstruction({ op: "local.get", index: sTmp });
635
+ const dispatchWriteIdx = this.mod.resolveFuncIndex(
636
+ "__dispatch_io.Writer_Write",
637
+ );
638
+ this.pushInstruction({ op: "call", funcIndex: dispatchWriteIdx });
639
+
640
+ const errTmp = this.acquireTemp("anyref");
641
+ this.pushInstruction({ op: "local.set", index: errTmp });
642
+ this.pushInstruction("drop"); // drop n
643
+ this.pushInstruction({ op: "local.get", index: errTmp });
644
+
645
+ this.releaseTemp(errTmp, "anyref");
646
+ this.releaseTemp(wTmp, "anyref");
647
+ this.releaseTemp(sTmp, sliceW);
648
+ return;
649
+ }
650
+
651
+ let sz = 4;
652
+ if (dataType?.name === "uint16" || dataType?.name === "int16") sz = 2;
653
+ else if (
654
+ dataType?.name === "uint64" ||
655
+ dataType?.name === "int64" ||
656
+ dataType?.name === "int" ||
657
+ dataType?.name === "uint" ||
658
+ dataType?.name === "float64"
659
+ )
660
+ sz = 8;
661
+ else if (
662
+ dataType?.name === "byte" ||
663
+ dataType?.name === "uint8" ||
664
+ dataType?.name === "int8" ||
665
+ dataType?.name === "bool"
666
+ )
667
+ sz = 1;
668
+ else if (dataType?.name === "float32") sz = 4;
669
+
670
+ const isBig =
671
+ orderExpr?._type?.name?.includes("BigEndian") ||
672
+ orderExpr?.field === "BigEndian";
673
+
674
+ const arrTmp = this.acquireTemp(arrW);
675
+ this.pushInstruction({ op: "i32.const", value: sz });
676
+ this.pushInstruction({
677
+ op: "array.new_default",
678
+ typeIndex: arrInfo.typeIndex,
679
+ });
680
+ this.pushInstruction({ op: "local.set", index: arrTmp });
681
+
682
+ if (sz === 1) {
683
+ const vTmp = this.acquireTemp("i32");
684
+ this.emitExpr(dataExpr, "i32");
685
+ this.pushInstruction({ op: "local.set", index: vTmp });
686
+
687
+ this.pushInstruction({ op: "local.get", index: arrTmp });
688
+ this.pushInstruction({ op: "i32.const", value: 0 });
689
+ this.pushInstruction({ op: "local.get", index: vTmp });
690
+ this.pushInstruction({ op: "i32.const", value: 0xff });
691
+ this.pushInstruction("i32.and");
692
+ this.pushInstruction({ op: "array.set", typeIndex: arrInfo.typeIndex });
693
+ this.releaseTemp(vTmp, "i32");
694
+ } else if (sz === 2) {
695
+ const vTmp = this.acquireTemp("i32");
696
+ this.emitExpr(dataExpr, "i32");
697
+ this.pushInstruction({ op: "local.set", index: vTmp });
698
+
699
+ // byte 0
700
+ this.pushInstruction({ op: "local.get", index: arrTmp });
701
+ this.pushInstruction({ op: "i32.const", value: 0 });
702
+ this.pushInstruction({ op: "local.get", index: vTmp });
703
+ if (isBig) {
704
+ this.pushInstruction({ op: "i32.const", value: 8 });
705
+ this.pushInstruction("i32.shr_u");
706
+ }
707
+ this.pushInstruction({ op: "i32.const", value: 0xff });
708
+ this.pushInstruction("i32.and");
709
+ this.pushInstruction({ op: "array.set", typeIndex: arrInfo.typeIndex });
710
+
711
+ // byte 1
712
+ this.pushInstruction({ op: "local.get", index: arrTmp });
713
+ this.pushInstruction({ op: "i32.const", value: 1 });
714
+ this.pushInstruction({ op: "local.get", index: vTmp });
715
+ if (!isBig) {
716
+ this.pushInstruction({ op: "i32.const", value: 8 });
717
+ this.pushInstruction("i32.shr_u");
718
+ }
719
+ this.pushInstruction({ op: "i32.const", value: 0xff });
720
+ this.pushInstruction("i32.and");
721
+ this.pushInstruction({ op: "array.set", typeIndex: arrInfo.typeIndex });
722
+ this.releaseTemp(vTmp, "i32");
723
+ } else if (sz === 4) {
724
+ const vTmp = this.acquireTemp("i32");
725
+ if (dataType?.name === "float32") {
726
+ this.emitExpr(dataExpr, "f32");
727
+ this.pushInstruction("i32.reinterpret_f32");
728
+ } else {
729
+ this.emitExpr(dataExpr, "i32");
730
+ }
731
+ this.pushInstruction({ op: "local.set", index: vTmp });
732
+
733
+ for (let i = 0; i < 4; i++) {
734
+ const shift = isBig ? (3 - i) * 8 : i * 8;
735
+ this.pushInstruction({ op: "local.get", index: arrTmp });
736
+ this.pushInstruction({ op: "i32.const", value: i });
737
+ this.pushInstruction({ op: "local.get", index: vTmp });
738
+ if (shift > 0) {
739
+ this.pushInstruction({ op: "i32.const", value: shift });
740
+ this.pushInstruction("i32.shr_u");
741
+ }
742
+ this.pushInstruction({ op: "i32.const", value: 0xff });
743
+ this.pushInstruction("i32.and");
744
+ this.pushInstruction({ op: "array.set", typeIndex: arrInfo.typeIndex });
745
+ }
746
+ this.releaseTemp(vTmp, "i32");
747
+ } else if (sz === 8) {
748
+ const vTmp = this.acquireTemp("i64");
749
+ if (dataType?.name === "float64") {
750
+ this.emitExpr(dataExpr, "f64");
751
+ this.pushInstruction("i64.reinterpret_f64");
752
+ } else {
753
+ this.emitExpr(dataExpr, "i64");
754
+ }
755
+ this.pushInstruction({ op: "local.set", index: vTmp });
756
+
757
+ for (let i = 0; i < 8; i++) {
758
+ const shift = isBig ? (7 - i) * 8 : i * 8;
759
+ this.pushInstruction({ op: "local.get", index: arrTmp });
760
+ this.pushInstruction({ op: "i32.const", value: i });
761
+ this.pushInstruction({ op: "local.get", index: vTmp });
762
+ if (shift > 0) {
763
+ this.pushInstruction({ op: "i64.const", value: BigInt(shift) });
764
+ this.pushInstruction("i64.shr_u");
765
+ }
766
+ this.pushInstruction("i32.wrap_i64");
767
+ this.pushInstruction({ op: "i32.const", value: 0xff });
768
+ this.pushInstruction("i32.and");
769
+ this.pushInstruction({ op: "array.set", typeIndex: arrInfo.typeIndex });
770
+ }
771
+ this.releaseTemp(vTmp, "i64");
772
+ }
773
+
774
+ const bufTmp = this.acquireTemp(sliceW);
775
+ this.pushInstruction({ op: "local.get", index: arrTmp });
776
+ this.pushInstruction({ op: "i32.const", value: 0 });
777
+ this.pushInstruction({ op: "i32.const", value: sz });
778
+ this.pushInstruction({ op: "i32.const", value: sz });
779
+ this.pushInstruction({
780
+ op: "struct.new",
781
+ typeIndex: sliceInfo.typeIndex,
782
+ });
783
+ this.pushInstruction({ op: "local.set", index: bufTmp });
784
+
785
+ const wTmp = this.acquireTemp("anyref");
786
+ this.emitExpr(wExpr, "anyref");
787
+ this.pushInstruction({ op: "local.set", index: wTmp });
788
+
789
+ this.pushInstruction({ op: "local.get", index: wTmp });
790
+ this.pushInstruction({ op: "local.get", index: bufTmp });
791
+ const dispatchWriteIdx = this.mod.resolveFuncIndex(
792
+ "__dispatch_io.Writer_Write",
793
+ );
794
+ this.pushInstruction({ op: "call", funcIndex: dispatchWriteIdx });
795
+
796
+ const errTmp = this.acquireTemp("anyref");
797
+ this.pushInstruction({ op: "local.set", index: errTmp });
798
+ this.pushInstruction("drop"); // drop n
799
+ this.pushInstruction({ op: "local.get", index: errTmp });
800
+
801
+ this.releaseTemp(errTmp, "anyref");
802
+ this.releaseTemp(wTmp, "anyref");
803
+ this.releaseTemp(bufTmp, sliceW);
804
+ this.releaseTemp(arrTmp, arrW);
805
+ }
806
+
807
+ emitBinaryOrderMethodCall(
808
+ recvTypeName,
809
+ method,
810
+ recvExpr,
811
+ args,
812
+ targetWasmType,
813
+ ) {
814
+ const isBig =
815
+ recvTypeName?.includes("BigEndian") ||
816
+ recvExpr?.field === "BigEndian" ||
817
+ false;
818
+
819
+ const byteGo = { kind: "basic", name: "byte" };
820
+ const sliceInfo = this.mod.getSliceType(byteGo);
821
+ const arrInfo = sliceInfo.arrInfo;
822
+ const sliceW = {
823
+ kind: "ref",
824
+ nullable: true,
825
+ typeIndex: sliceInfo.typeIndex,
826
+ };
827
+ const arrW = {
828
+ kind: "ref",
829
+ nullable: true,
830
+ typeIndex: arrInfo.typeIndex,
831
+ };
832
+
833
+ if (method === "String") {
834
+ const strIdx = this.mod.internString(
835
+ isBig ? "BigEndian" : "LittleEndian",
836
+ );
837
+ this.pushInstruction({ op: "i32.const", value: strIdx });
838
+ this.pushInstruction({
839
+ op: "call",
840
+ funcIndex: this.mod.getStringImportIndex(),
841
+ });
842
+ return;
843
+ }
844
+
845
+ if (method === "Uint16") {
846
+ const sTmp = this.acquireTemp(sliceW);
847
+ this.emitExpr(args[0], sliceW);
848
+ this.pushInstruction({ op: "local.set", index: sTmp });
849
+
850
+ const arrTmp = this.acquireTemp(arrW);
851
+ const offTmp = this.acquireTemp("i32");
852
+ const lenTmp = this.acquireTemp("i32");
853
+ this._emitSliceUnpack(sTmp, sliceInfo, {
854
+ arr: arrTmp,
855
+ off: offTmp,
856
+ len: lenTmp,
857
+ });
858
+
859
+ this.pushInstruction({ op: "local.get", index: arrTmp });
860
+ this.pushInstruction({ op: "local.get", index: offTmp });
861
+ this.pushInstruction({ op: "array.get", typeIndex: arrInfo.typeIndex });
862
+
863
+ this.pushInstruction({ op: "local.get", index: arrTmp });
864
+ this.pushInstruction({ op: "local.get", index: offTmp });
865
+ this.pushInstruction({ op: "i32.const", value: 1 });
866
+ this.pushInstruction("i32.add");
867
+ this.pushInstruction({ op: "array.get", typeIndex: arrInfo.typeIndex });
868
+
869
+ if (isBig) {
870
+ // (b0 << 8) | b1
871
+ this.pushInstruction({ op: "local.set", index: lenTmp }); // b1
872
+ this.pushInstruction({ op: "i32.const", value: 8 });
873
+ this.pushInstruction("i32.shl"); // b0 << 8
874
+ this.pushInstruction({ op: "local.get", index: lenTmp });
875
+ this.pushInstruction("i32.or");
876
+ } else {
877
+ // b0 | (b1 << 8)
878
+ this.pushInstruction({ op: "i32.const", value: 8 });
879
+ this.pushInstruction("i32.shl");
880
+ this.pushInstruction("i32.or");
881
+ }
882
+
883
+ if ((targetWasmType ?? "i32") === "i64") {
884
+ this.pushInstruction("i64.extend_i32_u");
885
+ }
886
+ this.releaseTemp(lenTmp, "i32");
887
+ this.releaseTemp(offTmp, "i32");
888
+ this.releaseTemp(arrTmp, arrW);
889
+ this.releaseTemp(sTmp, sliceW);
890
+ return;
891
+ }
892
+
893
+ if (method === "Uint32") {
894
+ const sTmp = this.acquireTemp(sliceW);
895
+ this.emitExpr(args[0], sliceW);
896
+ this.pushInstruction({ op: "local.set", index: sTmp });
897
+
898
+ const arrTmp = this.acquireTemp(arrW);
899
+ const offTmp = this.acquireTemp("i32");
900
+ this._emitSliceUnpack(sTmp, sliceInfo, { arr: arrTmp, off: offTmp });
901
+
902
+ const bTmps = [];
903
+ for (let i = 0; i < 4; i++) {
904
+ this.pushInstruction({ op: "local.get", index: arrTmp });
905
+ this.pushInstruction({ op: "local.get", index: offTmp });
906
+ if (i > 0) {
907
+ this.pushInstruction({ op: "i32.const", value: i });
908
+ this.pushInstruction("i32.add");
909
+ }
910
+ this.pushInstruction({ op: "array.get", typeIndex: arrInfo.typeIndex });
911
+ const bt = this.acquireTemp("i32");
912
+ this.pushInstruction({ op: "local.set", index: bt });
913
+ bTmps.push(bt);
914
+ }
915
+
916
+ this.pushInstruction({ op: "i32.const", value: 0 });
917
+ for (let i = 0; i < 4; i++) {
918
+ const shift = isBig ? (3 - i) * 8 : i * 8;
919
+ this.pushInstruction({ op: "local.get", index: bTmps[i] });
920
+ if (shift > 0) {
921
+ this.pushInstruction({ op: "i32.const", value: shift });
922
+ this.pushInstruction("i32.shl");
923
+ }
924
+ this.pushInstruction("i32.or");
925
+ }
926
+ for (const bt of bTmps) this.releaseTemp(bt, "i32");
927
+
928
+ if ((targetWasmType ?? "i32") === "i64") {
929
+ this.pushInstruction("i64.extend_i32_u");
930
+ }
931
+ this.releaseTemp(offTmp, "i32");
932
+ this.releaseTemp(arrTmp, arrW);
933
+ this.releaseTemp(sTmp, sliceW);
934
+ return;
935
+ }
936
+
937
+ if (method === "Uint64") {
938
+ const sTmp = this.acquireTemp(sliceW);
939
+ this.emitExpr(args[0], sliceW);
940
+ this.pushInstruction({ op: "local.set", index: sTmp });
941
+
942
+ const arrTmp = this.acquireTemp(arrW);
943
+ const offTmp = this.acquireTemp("i32");
944
+ this._emitSliceUnpack(sTmp, sliceInfo, { arr: arrTmp, off: offTmp });
945
+
946
+ const bTmps = [];
947
+ for (let i = 0; i < 8; i++) {
948
+ this.pushInstruction({ op: "local.get", index: arrTmp });
949
+ this.pushInstruction({ op: "local.get", index: offTmp });
950
+ if (i > 0) {
951
+ this.pushInstruction({ op: "i32.const", value: i });
952
+ this.pushInstruction("i32.add");
953
+ }
954
+ this.pushInstruction({ op: "array.get", typeIndex: arrInfo.typeIndex });
955
+ this.pushInstruction("i64.extend_i32_u");
956
+ const bt = this.acquireTemp("i64");
957
+ this.pushInstruction({ op: "local.set", index: bt });
958
+ bTmps.push(bt);
959
+ }
960
+
961
+ this.pushInstruction({ op: "i64.const", value: 0n });
962
+ for (let i = 0; i < 8; i++) {
963
+ const shift = isBig ? (7 - i) * 8 : i * 8;
964
+ this.pushInstruction({ op: "local.get", index: bTmps[i] });
965
+ if (shift > 0) {
966
+ this.pushInstruction({ op: "i64.const", value: BigInt(shift) });
967
+ this.pushInstruction("i64.shl");
968
+ }
969
+ this.pushInstruction("i64.or");
970
+ }
971
+ for (const bt of bTmps) this.releaseTemp(bt, "i64");
972
+
973
+ this.releaseTemp(offTmp, "i32");
974
+ this.releaseTemp(arrTmp, arrW);
975
+ this.releaseTemp(sTmp, sliceW);
976
+ return;
977
+ }
978
+
979
+ if (method === "PutUint16") {
980
+ const sTmp = this.acquireTemp(sliceW);
981
+ this.emitExpr(args[0], sliceW);
982
+ this.pushInstruction({ op: "local.set", index: sTmp });
983
+
984
+ const vTmp = this.acquireTemp("i32");
985
+ this.emitExpr(args[1], "i32");
986
+ this.pushInstruction({ op: "local.set", index: vTmp });
987
+
988
+ const arrTmp = this.acquireTemp(arrW);
989
+ const offTmp = this.acquireTemp("i32");
990
+ this._emitSliceUnpack(sTmp, sliceInfo, { arr: arrTmp, off: offTmp });
991
+
992
+ // b[0]
993
+ this.pushInstruction({ op: "local.get", index: arrTmp });
994
+ this.pushInstruction({ op: "local.get", index: offTmp });
995
+ this.pushInstruction({ op: "local.get", index: vTmp });
996
+ if (isBig) {
997
+ this.pushInstruction({ op: "i32.const", value: 8 });
998
+ this.pushInstruction("i32.shr_u");
999
+ }
1000
+ this.pushInstruction({ op: "i32.const", value: 0xff });
1001
+ this.pushInstruction("i32.and");
1002
+ this.pushInstruction({ op: "array.set", typeIndex: arrInfo.typeIndex });
1003
+
1004
+ // b[1]
1005
+ this.pushInstruction({ op: "local.get", index: arrTmp });
1006
+ this.pushInstruction({ op: "local.get", index: offTmp });
1007
+ this.pushInstruction({ op: "i32.const", value: 1 });
1008
+ this.pushInstruction("i32.add");
1009
+ this.pushInstruction({ op: "local.get", index: vTmp });
1010
+ if (!isBig) {
1011
+ this.pushInstruction({ op: "i32.const", value: 8 });
1012
+ this.pushInstruction("i32.shr_u");
1013
+ }
1014
+ this.pushInstruction({ op: "i32.const", value: 0xff });
1015
+ this.pushInstruction("i32.and");
1016
+ this.pushInstruction({ op: "array.set", typeIndex: arrInfo.typeIndex });
1017
+
1018
+ this.releaseTemp(offTmp, "i32");
1019
+ this.releaseTemp(arrTmp, arrW);
1020
+ this.releaseTemp(vTmp, "i32");
1021
+ this.releaseTemp(sTmp, sliceW);
1022
+ return;
1023
+ }
1024
+
1025
+ if (method === "PutUint32") {
1026
+ const sTmp = this.acquireTemp(sliceW);
1027
+ this.emitExpr(args[0], sliceW);
1028
+ this.pushInstruction({ op: "local.set", index: sTmp });
1029
+
1030
+ const vTmp = this.acquireTemp("i32");
1031
+ this.emitExpr(args[1], "i32");
1032
+ this.pushInstruction({ op: "local.set", index: vTmp });
1033
+
1034
+ const arrTmp = this.acquireTemp(arrW);
1035
+ const offTmp = this.acquireTemp("i32");
1036
+ this._emitSliceUnpack(sTmp, sliceInfo, { arr: arrTmp, off: offTmp });
1037
+
1038
+ for (let i = 0; i < 4; i++) {
1039
+ const shift = isBig ? (3 - i) * 8 : i * 8;
1040
+ this.pushInstruction({ op: "local.get", index: arrTmp });
1041
+ this.pushInstruction({ op: "local.get", index: offTmp });
1042
+ if (i > 0) {
1043
+ this.pushInstruction({ op: "i32.const", value: i });
1044
+ this.pushInstruction("i32.add");
1045
+ }
1046
+ this.pushInstruction({ op: "local.get", index: vTmp });
1047
+ if (shift > 0) {
1048
+ this.pushInstruction({ op: "i32.const", value: shift });
1049
+ this.pushInstruction("i32.shr_u");
1050
+ }
1051
+ this.pushInstruction({ op: "i32.const", value: 0xff });
1052
+ this.pushInstruction("i32.and");
1053
+ this.pushInstruction({ op: "array.set", typeIndex: arrInfo.typeIndex });
1054
+ }
1055
+
1056
+ this.releaseTemp(offTmp, "i32");
1057
+ this.releaseTemp(arrTmp, arrW);
1058
+ this.releaseTemp(vTmp, "i32");
1059
+ this.releaseTemp(sTmp, sliceW);
1060
+ return;
1061
+ }
1062
+
1063
+ if (method === "PutUint64") {
1064
+ const sTmp = this.acquireTemp(sliceW);
1065
+ this.emitExpr(args[0], sliceW);
1066
+ this.pushInstruction({ op: "local.set", index: sTmp });
1067
+
1068
+ const vTmp = this.acquireTemp("i64");
1069
+ this.emitExpr(args[1], "i64");
1070
+ this.pushInstruction({ op: "local.set", index: vTmp });
1071
+
1072
+ const arrTmp = this.acquireTemp(arrW);
1073
+ const offTmp = this.acquireTemp("i32");
1074
+ this._emitSliceUnpack(sTmp, sliceInfo, { arr: arrTmp, off: offTmp });
1075
+
1076
+ for (let i = 0; i < 8; i++) {
1077
+ const shift = isBig ? (7 - i) * 8 : i * 8;
1078
+ this.pushInstruction({ op: "local.get", index: arrTmp });
1079
+ this.pushInstruction({ op: "local.get", index: offTmp });
1080
+ if (i > 0) {
1081
+ this.pushInstruction({ op: "i32.const", value: i });
1082
+ this.pushInstruction("i32.add");
1083
+ }
1084
+ this.pushInstruction({ op: "local.get", index: vTmp });
1085
+ if (shift > 0) {
1086
+ this.pushInstruction({ op: "i64.const", value: BigInt(shift) });
1087
+ this.pushInstruction("i64.shr_u");
1088
+ }
1089
+ this.pushInstruction("i32.wrap_i64");
1090
+ this.pushInstruction({ op: "i32.const", value: 0xff });
1091
+ this.pushInstruction("i32.and");
1092
+ this.pushInstruction({ op: "array.set", typeIndex: arrInfo.typeIndex });
1093
+ }
1094
+
1095
+ this.releaseTemp(offTmp, "i32");
1096
+ this.releaseTemp(arrTmp, arrW);
1097
+ this.releaseTemp(vTmp, "i64");
1098
+ this.releaseTemp(sTmp, sliceW);
1099
+ return;
1100
+ }
1101
+
1102
+ if (
1103
+ method === "AppendUint16" ||
1104
+ method === "AppendUint32" ||
1105
+ method === "AppendUint64"
1106
+ ) {
1107
+ const byteCount =
1108
+ method === "AppendUint16" ? 2 : method === "AppendUint32" ? 4 : 8;
1109
+ const sNode = args[0];
1110
+ const sTmp = this.acquireTemp(sliceW);
1111
+ this.emitExpr(sNode, sliceW);
1112
+ this.pushInstruction({ op: "local.set", index: sTmp });
1113
+
1114
+ const oldArrTmp = this.acquireTemp(arrW);
1115
+ const oldOffTmp = this.acquireTemp("i32");
1116
+ const oldLenTmp = this.acquireTemp("i32");
1117
+ const oldCapTmp = this.acquireTemp("i32");
1118
+ this._emitSliceUnpack(sTmp, sliceInfo, {
1119
+ arr: oldArrTmp,
1120
+ off: oldOffTmp,
1121
+ len: oldLenTmp,
1122
+ cap: oldCapTmp,
1123
+ });
1124
+ this.releaseTemp(sTmp, sliceW);
1125
+
1126
+ const newArrTmp = this.acquireTemp(arrW);
1127
+ const newOffTmp = this.acquireTemp("i32");
1128
+ const newCapTmp = this.acquireTemp("i32");
1129
+ const newLenTmp = this.acquireTemp("i32");
1130
+
1131
+ this.pushInstruction({ op: "local.get", index: oldLenTmp });
1132
+ this.pushInstruction({ op: "i32.const", value: byteCount });
1133
+ this.pushInstruction("i32.add");
1134
+ this.pushInstruction({ op: "local.set", index: newLenTmp });
1135
+
1136
+ this._emitGrowSlice({
1137
+ arrInfo,
1138
+ elemGoType: byteGo,
1139
+ oldArrTmp,
1140
+ oldOffTmp,
1141
+ oldLenTmp,
1142
+ oldCapTmp,
1143
+ newArrTmp,
1144
+ newOffTmp,
1145
+ newLenTmp,
1146
+ newCapTmp,
1147
+ });
1148
+
1149
+ if (byteCount === 2) {
1150
+ const vTmp = this.acquireTemp("i32");
1151
+ this.emitExpr(args[1], "i32");
1152
+ this.pushInstruction({ op: "local.set", index: vTmp });
1153
+
1154
+ for (let i = 0; i < 2; i++) {
1155
+ const shift = isBig ? (1 - i) * 8 : i * 8;
1156
+ this.pushInstruction({ op: "local.get", index: newArrTmp });
1157
+ this.pushInstruction({ op: "local.get", index: newOffTmp });
1158
+ this.pushInstruction({ op: "local.get", index: oldLenTmp });
1159
+ this.pushInstruction("i32.add");
1160
+ if (i > 0) {
1161
+ this.pushInstruction({ op: "i32.const", value: i });
1162
+ this.pushInstruction("i32.add");
1163
+ }
1164
+ this.pushInstruction({ op: "local.get", index: vTmp });
1165
+ if (shift > 0) {
1166
+ this.pushInstruction({ op: "i32.const", value: shift });
1167
+ this.pushInstruction("i32.shr_u");
1168
+ }
1169
+ this.pushInstruction({ op: "i32.const", value: 0xff });
1170
+ this.pushInstruction("i32.and");
1171
+ this.pushInstruction({
1172
+ op: "array.set",
1173
+ typeIndex: arrInfo.typeIndex,
1174
+ });
1175
+ }
1176
+ this.releaseTemp(vTmp, "i32");
1177
+ } else if (byteCount === 4) {
1178
+ const vTmp = this.acquireTemp("i32");
1179
+ this.emitExpr(args[1], "i32");
1180
+ this.pushInstruction({ op: "local.set", index: vTmp });
1181
+
1182
+ for (let i = 0; i < 4; i++) {
1183
+ const shift = isBig ? (3 - i) * 8 : i * 8;
1184
+ this.pushInstruction({ op: "local.get", index: newArrTmp });
1185
+ this.pushInstruction({ op: "local.get", index: newOffTmp });
1186
+ this.pushInstruction({ op: "local.get", index: oldLenTmp });
1187
+ this.pushInstruction("i32.add");
1188
+ if (i > 0) {
1189
+ this.pushInstruction({ op: "i32.const", value: i });
1190
+ this.pushInstruction("i32.add");
1191
+ }
1192
+ this.pushInstruction({ op: "local.get", index: vTmp });
1193
+ if (shift > 0) {
1194
+ this.pushInstruction({ op: "i32.const", value: shift });
1195
+ this.pushInstruction("i32.shr_u");
1196
+ }
1197
+ this.pushInstruction({ op: "i32.const", value: 0xff });
1198
+ this.pushInstruction("i32.and");
1199
+ this.pushInstruction({
1200
+ op: "array.set",
1201
+ typeIndex: arrInfo.typeIndex,
1202
+ });
1203
+ }
1204
+ this.releaseTemp(vTmp, "i32");
1205
+ } else {
1206
+ const vTmp = this.acquireTemp("i64");
1207
+ this.emitExpr(args[1], "i64");
1208
+ this.pushInstruction({ op: "local.set", index: vTmp });
1209
+
1210
+ for (let i = 0; i < 8; i++) {
1211
+ const shift = isBig ? (7 - i) * 8 : i * 8;
1212
+ this.pushInstruction({ op: "local.get", index: newArrTmp });
1213
+ this.pushInstruction({ op: "local.get", index: newOffTmp });
1214
+ this.pushInstruction({ op: "local.get", index: oldLenTmp });
1215
+ this.pushInstruction("i32.add");
1216
+ if (i > 0) {
1217
+ this.pushInstruction({ op: "i32.const", value: i });
1218
+ this.pushInstruction("i32.add");
1219
+ }
1220
+ this.pushInstruction({ op: "local.get", index: vTmp });
1221
+ if (shift > 0) {
1222
+ this.pushInstruction({ op: "i64.const", value: BigInt(shift) });
1223
+ this.pushInstruction("i64.shr_u");
1224
+ }
1225
+ this.pushInstruction("i32.wrap_i64");
1226
+ this.pushInstruction({ op: "i32.const", value: 0xff });
1227
+ this.pushInstruction("i32.and");
1228
+ this.pushInstruction({
1229
+ op: "array.set",
1230
+ typeIndex: arrInfo.typeIndex,
1231
+ });
1232
+ }
1233
+ this.releaseTemp(vTmp, "i64");
1234
+ }
1235
+
1236
+ this.pushInstruction({ op: "local.get", index: newArrTmp });
1237
+ this.pushInstruction({ op: "local.get", index: newOffTmp });
1238
+ this.pushInstruction({ op: "local.get", index: newLenTmp });
1239
+ this.pushInstruction({ op: "local.get", index: newCapTmp });
1240
+ this.pushInstruction({
1241
+ op: "struct.new",
1242
+ typeIndex: sliceInfo.typeIndex,
1243
+ });
1244
+
1245
+ this.releaseTemp(newCapTmp, "i32");
1246
+ this.releaseTemp(newLenTmp, "i32");
1247
+ this.releaseTemp(newOffTmp, "i32");
1248
+ this.releaseTemp(newArrTmp, arrW);
1249
+ this.releaseTemp(oldCapTmp, "i32");
1250
+ this.releaseTemp(oldLenTmp, "i32");
1251
+ this.releaseTemp(oldOffTmp, "i32");
1252
+ this.releaseTemp(oldArrTmp, arrW);
1253
+ return;
1254
+ }
1255
+
1256
+ throw new Error(`Unsupported binary method: ${method}`);
1257
+ }
1258
+
1259
+ emitSha256Call(name, call, _targetWasmType) {
1260
+ const args = call.args;
1261
+ if (name === "Sum256") {
1262
+ const byteGo = { kind: "basic", name: "byte" };
1263
+ const sliceInfo = this.mod.getSliceType(byteGo);
1264
+ const arrInfo = sliceInfo.arrInfo;
1265
+ const sliceW = {
1266
+ kind: "ref",
1267
+ nullable: true,
1268
+ typeIndex: sliceInfo.typeIndex,
1269
+ };
1270
+ const arrW = {
1271
+ kind: "ref",
1272
+ nullable: true,
1273
+ typeIndex: arrInfo.typeIndex,
1274
+ };
1275
+
1276
+ const sTmp = this.acquireTemp(sliceW);
1277
+ this.emitExpr(args[0], sliceW);
1278
+ this.pushInstruction({ op: "local.set", index: sTmp });
1279
+
1280
+ const arrTmp = this.acquireTemp(arrW);
1281
+ const offTmp = this.acquireTemp("i32");
1282
+ const lenTmp = this.acquireTemp("i32");
1283
+ this._emitSliceUnpack(sTmp, sliceInfo, {
1284
+ arr: arrTmp,
1285
+ off: offTmp,
1286
+ len: lenTmp,
1287
+ });
1288
+
1289
+ // raw_bytes_init(len)
1290
+ this.pushInstruction({ op: "local.get", index: lenTmp });
1291
+ this._callStdlib("raw_bytes_init");
1292
+
1293
+ const iLoc = this.acquireTemp("i32");
1294
+ this.pushInstruction({ op: "i32.const", value: 0 });
1295
+ this.pushInstruction({ op: "local.set", index: iLoc });
1296
+
1297
+ this.pushInstruction({ op: "block", blockType: "void" });
1298
+ this.pushInstruction({ op: "loop", blockType: "void" });
1299
+ this.pushInstruction({ op: "local.get", index: iLoc });
1300
+ this.pushInstruction({ op: "local.get", index: lenTmp });
1301
+ this.pushInstruction("i32.ge_s");
1302
+ this.pushInstruction({ op: "br_if", depth: 1 });
1303
+
1304
+ // raw_bytes_push(arr[off + i])
1305
+ this.pushInstruction({ op: "local.get", index: arrTmp });
1306
+ this.pushInstruction({ op: "local.get", index: offTmp });
1307
+ this.pushInstruction({ op: "local.get", index: iLoc });
1308
+ this.pushInstruction("i32.add");
1309
+ this.pushInstruction({ op: "array.get", typeIndex: arrInfo.typeIndex });
1310
+ this._callStdlib("raw_bytes_push");
1311
+
1312
+ this.pushInstruction({ op: "local.get", index: iLoc });
1313
+ this.pushInstruction({ op: "i32.const", value: 1 });
1314
+ this.pushInstruction("i32.add");
1315
+ this.pushInstruction({ op: "local.set", index: iLoc });
1316
+ this.pushInstruction({ op: "br", depth: 0 });
1317
+ this.pushInstruction("end");
1318
+ this.pushInstruction("end");
1319
+
1320
+ // crypto_sha256_sum()
1321
+ this._callStdlib("crypto_sha256_sum");
1322
+ this.pushInstruction("drop"); // 32
1323
+
1324
+ // allocate [32]byte array
1325
+ const arr32Info = this.mod.getArrayType(byteGo);
1326
+ const outArrTmp = this.acquireTemp({
1327
+ kind: "ref",
1328
+ nullable: true,
1329
+ typeIndex: arr32Info.typeIndex,
1330
+ });
1331
+ this.pushInstruction({ op: "i32.const", value: 32 });
1332
+ this.pushInstruction({
1333
+ op: "array.new_default",
1334
+ typeIndex: arr32Info.typeIndex,
1335
+ });
1336
+ this.pushInstruction({ op: "local.set", index: outArrTmp });
1337
+
1338
+ this.pushInstruction({ op: "i32.const", value: 0 });
1339
+ this.pushInstruction({ op: "local.set", index: iLoc });
1340
+
1341
+ this.pushInstruction({ op: "block", blockType: "void" });
1342
+ this.pushInstruction({ op: "loop", blockType: "void" });
1343
+ this.pushInstruction({ op: "local.get", index: iLoc });
1344
+ this.pushInstruction({ op: "i32.const", value: 32 });
1345
+ this.pushInstruction("i32.ge_s");
1346
+ this.pushInstruction({ op: "br_if", depth: 1 });
1347
+
1348
+ this.pushInstruction({ op: "local.get", index: outArrTmp });
1349
+ this.pushInstruction({ op: "local.get", index: iLoc });
1350
+ this.pushInstruction({ op: "local.get", index: iLoc });
1351
+ this._callStdlib("raw_bytes_get");
1352
+ this.pushInstruction({ op: "array.set", typeIndex: arr32Info.typeIndex });
1353
+
1354
+ this.pushInstruction({ op: "local.get", index: iLoc });
1355
+ this.pushInstruction({ op: "i32.const", value: 1 });
1356
+ this.pushInstruction("i32.add");
1357
+ this.pushInstruction({ op: "local.set", index: iLoc });
1358
+ this.pushInstruction({ op: "br", depth: 0 });
1359
+ this.pushInstruction("end");
1360
+ this.pushInstruction("end");
1361
+
1362
+ this.pushInstruction({ op: "local.get", index: outArrTmp });
1363
+
1364
+ this.releaseTemp(outArrTmp, {
1365
+ kind: "ref",
1366
+ nullable: true,
1367
+ typeIndex: arr32Info.typeIndex,
1368
+ });
1369
+ this.releaseTemp(iLoc, "i32");
1370
+ this.releaseTemp(lenTmp, "i32");
1371
+ this.releaseTemp(offTmp, "i32");
1372
+ this.releaseTemp(arrTmp, arrW);
1373
+ this.releaseTemp(sTmp, sliceW);
1374
+ return;
1375
+ }
1376
+
1377
+ if (name === "New") {
1378
+ const structInfo = this.mod.getStructType("sha256.digest");
1379
+ const byteGo = { kind: "basic", name: "byte" };
1380
+ const sliceInfo = this.mod.getSliceType(byteGo);
1381
+ const arrInfo = sliceInfo.arrInfo;
1382
+
1383
+ this.pushInstruction({ op: "ref.null", heapType: arrInfo.typeIndex });
1384
+ this.pushInstruction({ op: "i32.const", value: 0 });
1385
+ this.pushInstruction({ op: "i32.const", value: 0 });
1386
+ this.pushInstruction({ op: "i32.const", value: 0 });
1387
+ this.pushInstruction({
1388
+ op: "struct.new",
1389
+ typeIndex: sliceInfo.typeIndex,
1390
+ });
1391
+ this.pushInstruction({
1392
+ op: "struct.new",
1393
+ typeIndex: structInfo.typeIndex,
1394
+ });
1395
+ return;
1396
+ }
1397
+
1398
+ throw new Error(`Unsupported sha256 call: sha256.${name}`);
1399
+ }
1400
+
1401
+ emitHexCall(name, call, _targetWasmType) {
1402
+ const args = call.args;
1403
+ const byteGo = { kind: "basic", name: "byte" };
1404
+ const sliceInfo = this.mod.getSliceType(byteGo);
1405
+ const arrInfo = sliceInfo.arrInfo;
1406
+ const sliceW = {
1407
+ kind: "ref",
1408
+ nullable: true,
1409
+ typeIndex: sliceInfo.typeIndex,
1410
+ };
1411
+ const arrW = {
1412
+ kind: "ref",
1413
+ nullable: true,
1414
+ typeIndex: arrInfo.typeIndex,
1415
+ };
1416
+
1417
+ if (name === "EncodedLen") {
1418
+ this.emitExpr(args[0], "i64");
1419
+ this.pushInstruction({ op: "i64.const", value: 2n });
1420
+ this.pushInstruction("i64.mul");
1421
+ return;
1422
+ }
1423
+
1424
+ if (name === "DecodedLen") {
1425
+ this.emitExpr(args[0], "i64");
1426
+ this.pushInstruction({ op: "i64.const", value: 2n });
1427
+ this.pushInstruction("i64.div_s");
1428
+ return;
1429
+ }
1430
+
1431
+ if (name === "EncodeToString") {
1432
+ const sTmp = this.acquireTemp(sliceW);
1433
+ this.emitExpr(args[0], sliceW);
1434
+ this.pushInstruction({ op: "local.set", index: sTmp });
1435
+
1436
+ const arrTmp = this.acquireTemp(arrW);
1437
+ const offTmp = this.acquireTemp("i32");
1438
+ const lenTmp = this.acquireTemp("i32");
1439
+ this._emitSliceUnpack(sTmp, sliceInfo, {
1440
+ arr: arrTmp,
1441
+ off: offTmp,
1442
+ len: lenTmp,
1443
+ });
1444
+
1445
+ this.pushInstruction({ op: "local.get", index: lenTmp });
1446
+ this._callStdlib("raw_bytes_init");
1447
+
1448
+ const iLoc = this.acquireTemp("i32");
1449
+ this.pushInstruction({ op: "i32.const", value: 0 });
1450
+ this.pushInstruction({ op: "local.set", index: iLoc });
1451
+
1452
+ this.pushInstruction({ op: "block", blockType: "void" });
1453
+ this.pushInstruction({ op: "loop", blockType: "void" });
1454
+ this.pushInstruction({ op: "local.get", index: iLoc });
1455
+ this.pushInstruction({ op: "local.get", index: lenTmp });
1456
+ this.pushInstruction("i32.ge_s");
1457
+ this.pushInstruction({ op: "br_if", depth: 1 });
1458
+
1459
+ this.pushInstruction({ op: "local.get", index: arrTmp });
1460
+ this.pushInstruction({ op: "local.get", index: offTmp });
1461
+ this.pushInstruction({ op: "local.get", index: iLoc });
1462
+ this.pushInstruction("i32.add");
1463
+ this.pushInstruction({ op: "array.get", typeIndex: arrInfo.typeIndex });
1464
+ this._callStdlib("raw_bytes_push");
1465
+
1466
+ this.pushInstruction({ op: "local.get", index: iLoc });
1467
+ this.pushInstruction({ op: "i32.const", value: 1 });
1468
+ this.pushInstruction("i32.add");
1469
+ this.pushInstruction({ op: "local.set", index: iLoc });
1470
+ this.pushInstruction({ op: "br", depth: 0 });
1471
+ this.pushInstruction("end");
1472
+ this.pushInstruction("end");
1473
+
1474
+ this._callStdlib("hex_encode_to_string");
1475
+
1476
+ this.releaseTemp(iLoc, "i32");
1477
+ this.releaseTemp(lenTmp, "i32");
1478
+ this.releaseTemp(offTmp, "i32");
1479
+ this.releaseTemp(arrTmp, arrW);
1480
+ this.releaseTemp(sTmp, sliceW);
1481
+ return;
1482
+ }
1483
+
1484
+ if (name === "DecodeString") {
1485
+ this.emitExpr(args[0], "externref");
1486
+ this._callStdlib("hex_decode_string");
1487
+ const nTmp = this.acquireTemp("i32");
1488
+ this.pushInstruction({ op: "local.set", index: nTmp });
1489
+
1490
+ this._callStdlib("hex_get_err");
1491
+ const errStrTmp = this.acquireTemp("externref");
1492
+ this.pushInstruction({ op: "local.set", index: errStrTmp });
1493
+
1494
+ const retSliceTmp = this.acquireTemp(sliceW);
1495
+ const retErrTmp = this.acquireTemp("anyref");
1496
+
1497
+ this.pushInstruction({ op: "local.get", index: errStrTmp });
1498
+ this.pushInstruction("ref.is_null");
1499
+ this.pushInstruction("i32.eqz");
1500
+ this.pushInstruction({ op: "if", blockType: "void" });
1501
+
1502
+ // Error case: return nil slice, err
1503
+ this.pushInstruction({ op: "ref.null", heapType: arrInfo.typeIndex });
1504
+ this.pushInstruction({ op: "i32.const", value: 0 });
1505
+ this.pushInstruction({ op: "i32.const", value: 0 });
1506
+ this.pushInstruction({ op: "i32.const", value: 0 });
1507
+ this.pushInstruction({
1508
+ op: "struct.new",
1509
+ typeIndex: sliceInfo.typeIndex,
1510
+ });
1511
+ this.pushInstruction({ op: "local.set", index: retSliceTmp });
1512
+
1513
+ this.pushInstruction({ op: "local.get", index: errStrTmp });
1514
+ this.pushInstruction({ op: "ref.null", heapType: "any" });
1515
+ this.pushInstruction({
1516
+ op: "call",
1517
+ funcIndex: this.mod.resolveFuncIndex("__mk_error"),
1518
+ });
1519
+ this.pushInstruction({ op: "local.set", index: retErrTmp });
1520
+
1521
+ this.pushInstruction("else");
1522
+
1523
+ // Success case: allocate slice and copy bytes
1524
+ const outArrTmp = this.acquireTemp(arrW);
1525
+ this.pushInstruction({ op: "local.get", index: nTmp });
1526
+ this.pushInstruction({
1527
+ op: "array.new_default",
1528
+ typeIndex: arrInfo.typeIndex,
1529
+ });
1530
+ this.pushInstruction({ op: "local.set", index: outArrTmp });
1531
+
1532
+ const iLoc = this.acquireTemp("i32");
1533
+ this.pushInstruction({ op: "i32.const", value: 0 });
1534
+ this.pushInstruction({ op: "local.set", index: iLoc });
1535
+
1536
+ this.pushInstruction({ op: "block", blockType: "void" });
1537
+ this.pushInstruction({ op: "loop", blockType: "void" });
1538
+ this.pushInstruction({ op: "local.get", index: iLoc });
1539
+ this.pushInstruction({ op: "local.get", index: nTmp });
1540
+ this.pushInstruction("i32.ge_s");
1541
+ this.pushInstruction({ op: "br_if", depth: 1 });
1542
+
1543
+ this.pushInstruction({ op: "local.get", index: outArrTmp });
1544
+ this.pushInstruction({ op: "local.get", index: iLoc });
1545
+ this.pushInstruction({ op: "local.get", index: iLoc });
1546
+ this._callStdlib("raw_bytes_get");
1547
+ this.pushInstruction({ op: "array.set", typeIndex: arrInfo.typeIndex });
1548
+
1549
+ this.pushInstruction({ op: "local.get", index: iLoc });
1550
+ this.pushInstruction({ op: "i32.const", value: 1 });
1551
+ this.pushInstruction("i32.add");
1552
+ this.pushInstruction({ op: "local.set", index: iLoc });
1553
+ this.pushInstruction({ op: "br", depth: 0 });
1554
+ this.pushInstruction("end");
1555
+ this.pushInstruction("end");
1556
+
1557
+ this.pushInstruction({ op: "local.get", index: outArrTmp });
1558
+ this.pushInstruction({ op: "i32.const", value: 0 });
1559
+ this.pushInstruction({ op: "local.get", index: nTmp });
1560
+ this.pushInstruction({ op: "local.get", index: nTmp });
1561
+ this.pushInstruction({
1562
+ op: "struct.new",
1563
+ typeIndex: sliceInfo.typeIndex,
1564
+ });
1565
+ this.pushInstruction({ op: "local.set", index: retSliceTmp });
1566
+ this.pushInstruction({ op: "ref.null", heapType: "any" });
1567
+ this.pushInstruction({ op: "local.set", index: retErrTmp });
1568
+
1569
+ this.releaseTemp(iLoc, "i32");
1570
+ this.releaseTemp(outArrTmp, arrW);
1571
+ this.pushInstruction("end");
1572
+
1573
+ this.pushInstruction({ op: "local.get", index: retSliceTmp });
1574
+ this.pushInstruction({ op: "local.get", index: retErrTmp });
1575
+
1576
+ this.releaseTemp(retSliceTmp, sliceW);
1577
+ this.releaseTemp(retErrTmp, "anyref");
1578
+ this.releaseTemp(errStrTmp, "externref");
1579
+ this.releaseTemp(nTmp, "i32");
1580
+ return;
1581
+ }
1582
+
1583
+ if (name === "Encode") {
1584
+ const dstTmp = this.acquireTemp(sliceW);
1585
+ this.emitExpr(args[0], sliceW);
1586
+ this.pushInstruction({ op: "local.set", index: dstTmp });
1587
+
1588
+ const srcTmp = this.acquireTemp(sliceW);
1589
+ this.emitExpr(args[1], sliceW);
1590
+ this.pushInstruction({ op: "local.set", index: srcTmp });
1591
+
1592
+ const srcArr = this.acquireTemp(arrW);
1593
+ const srcOff = this.acquireTemp("i32");
1594
+ const srcLen = this.acquireTemp("i32");
1595
+ this._emitSliceUnpack(srcTmp, sliceInfo, {
1596
+ arr: srcArr,
1597
+ off: srcOff,
1598
+ len: srcLen,
1599
+ });
1600
+
1601
+ this.pushInstruction({ op: "local.get", index: srcLen });
1602
+ this._callStdlib("raw_bytes_init");
1603
+
1604
+ const iLoc = this.acquireTemp("i32");
1605
+ this.pushInstruction({ op: "i32.const", value: 0 });
1606
+ this.pushInstruction({ op: "local.set", index: iLoc });
1607
+
1608
+ this.pushInstruction({ op: "block", blockType: "void" });
1609
+ this.pushInstruction({ op: "loop", blockType: "void" });
1610
+ this.pushInstruction({ op: "local.get", index: iLoc });
1611
+ this.pushInstruction({ op: "local.get", index: srcLen });
1612
+ this.pushInstruction("i32.ge_s");
1613
+ this.pushInstruction({ op: "br_if", depth: 1 });
1614
+
1615
+ this.pushInstruction({ op: "local.get", index: srcArr });
1616
+ this.pushInstruction({ op: "local.get", index: srcOff });
1617
+ this.pushInstruction({ op: "local.get", index: iLoc });
1618
+ this.pushInstruction("i32.add");
1619
+ this.pushInstruction({ op: "array.get", typeIndex: arrInfo.typeIndex });
1620
+ this._callStdlib("raw_bytes_push");
1621
+
1622
+ this.pushInstruction({ op: "local.get", index: iLoc });
1623
+ this.pushInstruction({ op: "i32.const", value: 1 });
1624
+ this.pushInstruction("i32.add");
1625
+ this.pushInstruction({ op: "local.set", index: iLoc });
1626
+ this.pushInstruction({ op: "br", depth: 0 });
1627
+ this.pushInstruction("end");
1628
+ this.pushInstruction("end");
1629
+
1630
+ this._callStdlib("hex_encode_to_string");
1631
+ const strTmp = this.acquireTemp("externref");
1632
+ this.pushInstruction({ op: "local.set", index: strTmp });
1633
+
1634
+ const dstArr = this.acquireTemp(arrW);
1635
+ const dstOff = this.acquireTemp("i32");
1636
+ const dstLen = this.acquireTemp("i32");
1637
+ this._emitSliceUnpack(dstTmp, sliceInfo, {
1638
+ arr: dstArr,
1639
+ off: dstOff,
1640
+ len: dstLen,
1641
+ });
1642
+
1643
+ const hexLenTmp = this.acquireTemp("i32");
1644
+ this.pushInstruction({ op: "local.get", index: strTmp });
1645
+ this.pushInstruction({
1646
+ op: "call",
1647
+ funcIndex: this.mod.getStringLenImportIndex(),
1648
+ });
1649
+ this.pushInstruction({ op: "local.set", index: hexLenTmp });
1650
+
1651
+ this.pushInstruction({ op: "i32.const", value: 0 });
1652
+ this.pushInstruction({ op: "local.set", index: iLoc });
1653
+
1654
+ this.pushInstruction({ op: "block", blockType: "void" });
1655
+ this.pushInstruction({ op: "loop", blockType: "void" });
1656
+ this.pushInstruction({ op: "local.get", index: iLoc });
1657
+ this.pushInstruction({ op: "local.get", index: hexLenTmp });
1658
+ this.pushInstruction("i32.ge_s");
1659
+ this.pushInstruction({ op: "br_if", depth: 1 });
1660
+
1661
+ this.pushInstruction({ op: "local.get", index: dstArr });
1662
+ this.pushInstruction({ op: "local.get", index: dstOff });
1663
+ this.pushInstruction({ op: "local.get", index: iLoc });
1664
+ this.pushInstruction("i32.add");
1665
+ this.pushInstruction({ op: "local.get", index: strTmp });
1666
+ this.pushInstruction({ op: "local.get", index: iLoc });
1667
+ this.pushInstruction({
1668
+ op: "call",
1669
+ funcIndex: this.mod.getStringCodePointAtImportIndex(),
1670
+ });
1671
+ this.pushInstruction({ op: "array.set", typeIndex: arrInfo.typeIndex });
1672
+
1673
+ this.pushInstruction({ op: "local.get", index: iLoc });
1674
+ this.pushInstruction({ op: "i32.const", value: 1 });
1675
+ this.pushInstruction("i32.add");
1676
+ this.pushInstruction({ op: "local.set", index: iLoc });
1677
+ this.pushInstruction({ op: "br", depth: 0 });
1678
+ this.pushInstruction("end");
1679
+ this.pushInstruction("end");
1680
+
1681
+ this.pushInstruction({ op: "local.get", index: hexLenTmp });
1682
+ this.pushInstruction("i64.extend_i32_s");
1683
+
1684
+ this.releaseTemp(hexLenTmp, "i32");
1685
+ this.releaseTemp(dstLen, "i32");
1686
+ this.releaseTemp(dstOff, "i32");
1687
+ this.releaseTemp(dstArr, arrW);
1688
+ this.releaseTemp(strTmp, "externref");
1689
+ this.releaseTemp(iLoc, "i32");
1690
+ this.releaseTemp(srcLen, "i32");
1691
+ this.releaseTemp(srcOff, "i32");
1692
+ this.releaseTemp(srcArr, arrW);
1693
+ this.releaseTemp(srcTmp, sliceW);
1694
+ this.releaseTemp(dstTmp, sliceW);
1695
+ return;
1696
+ }
1697
+
1698
+ if (name === "Decode") {
1699
+ const dstTmp = this.acquireTemp(sliceW);
1700
+ this.emitExpr(args[0], sliceW);
1701
+ this.pushInstruction({ op: "local.set", index: dstTmp });
1702
+
1703
+ const srcTmp = this.acquireTemp(sliceW);
1704
+ this.emitExpr(args[1], sliceW);
1705
+ this.pushInstruction({ op: "local.set", index: srcTmp });
1706
+
1707
+ const srcArr = this.acquireTemp(arrW);
1708
+ const srcOff = this.acquireTemp("i32");
1709
+ const srcLen = this.acquireTemp("i32");
1710
+ this._emitSliceUnpack(srcTmp, sliceInfo, {
1711
+ arr: srcArr,
1712
+ off: srcOff,
1713
+ len: srcLen,
1714
+ });
1715
+
1716
+ this.pushInstruction({ op: "local.get", index: srcLen });
1717
+ this._callStdlib("bytes_to_str_init");
1718
+
1719
+ const iLoc = this.acquireTemp("i32");
1720
+ this.pushInstruction({ op: "i32.const", value: 0 });
1721
+ this.pushInstruction({ op: "local.set", index: iLoc });
1722
+
1723
+ this.pushInstruction({ op: "block", blockType: "void" });
1724
+ this.pushInstruction({ op: "loop", blockType: "void" });
1725
+ this.pushInstruction({ op: "local.get", index: iLoc });
1726
+ this.pushInstruction({ op: "local.get", index: srcLen });
1727
+ this.pushInstruction("i32.ge_s");
1728
+ this.pushInstruction({ op: "br_if", depth: 1 });
1729
+
1730
+ this.pushInstruction({ op: "local.get", index: srcArr });
1731
+ this.pushInstruction({ op: "local.get", index: srcOff });
1732
+ this.pushInstruction({ op: "local.get", index: iLoc });
1733
+ this.pushInstruction("i32.add");
1734
+ this.pushInstruction({ op: "array.get", typeIndex: arrInfo.typeIndex });
1735
+ this._callStdlib("bytes_to_str_push");
1736
+
1737
+ this.pushInstruction({ op: "local.get", index: iLoc });
1738
+ this.pushInstruction({ op: "i32.const", value: 1 });
1739
+ this.pushInstruction("i32.add");
1740
+ this.pushInstruction({ op: "local.set", index: iLoc });
1741
+ this.pushInstruction({ op: "br", depth: 0 });
1742
+ this.pushInstruction("end");
1743
+ this.pushInstruction("end");
1744
+
1745
+ this._callStdlib("bytes_to_str_finish");
1746
+ this._callStdlib("hex_decode_string");
1747
+ const nTmp = this.acquireTemp("i32");
1748
+ this.pushInstruction({ op: "local.set", index: nTmp });
1749
+
1750
+ this._callStdlib("hex_get_err");
1751
+ const errStrTmp = this.acquireTemp("externref");
1752
+ this.pushInstruction({ op: "local.set", index: errStrTmp });
1753
+
1754
+ const retNTmp = this.acquireTemp("i64");
1755
+ const retErrTmp = this.acquireTemp("anyref");
1756
+
1757
+ this.pushInstruction({ op: "local.get", index: errStrTmp });
1758
+ this.pushInstruction("ref.is_null");
1759
+ this.pushInstruction("i32.eqz");
1760
+ this.pushInstruction({ op: "if", blockType: "void" });
1761
+
1762
+ // Error case
1763
+ this.pushInstruction({ op: "i64.const", value: 0n });
1764
+ this.pushInstruction({ op: "local.set", index: retNTmp });
1765
+ this.pushInstruction({ op: "local.get", index: errStrTmp });
1766
+ this.pushInstruction({ op: "ref.null", heapType: "any" });
1767
+ this.pushInstruction({
1768
+ op: "call",
1769
+ funcIndex: this.mod.resolveFuncIndex("__mk_error"),
1770
+ });
1771
+ this.pushInstruction({ op: "local.set", index: retErrTmp });
1772
+
1773
+ this.pushInstruction("else");
1774
+
1775
+ // Success case: copy bytes into dst
1776
+ const dstArr = this.acquireTemp(arrW);
1777
+ const dstOff = this.acquireTemp("i32");
1778
+ const dstLen = this.acquireTemp("i32");
1779
+ this._emitSliceUnpack(dstTmp, sliceInfo, {
1780
+ arr: dstArr,
1781
+ off: dstOff,
1782
+ len: dstLen,
1783
+ });
1784
+
1785
+ this.pushInstruction({ op: "i32.const", value: 0 });
1786
+ this.pushInstruction({ op: "local.set", index: iLoc });
1787
+
1788
+ this.pushInstruction({ op: "block", blockType: "void" });
1789
+ this.pushInstruction({ op: "loop", blockType: "void" });
1790
+ this.pushInstruction({ op: "local.get", index: iLoc });
1791
+ this.pushInstruction({ op: "local.get", index: nTmp });
1792
+ this.pushInstruction("i32.ge_s");
1793
+ this.pushInstruction({ op: "br_if", depth: 1 });
1794
+
1795
+ this.pushInstruction({ op: "local.get", index: dstArr });
1796
+ this.pushInstruction({ op: "local.get", index: dstOff });
1797
+ this.pushInstruction({ op: "local.get", index: iLoc });
1798
+ this.pushInstruction("i32.add");
1799
+ this.pushInstruction({ op: "local.get", index: iLoc });
1800
+ this._callStdlib("raw_bytes_get");
1801
+ this.pushInstruction({ op: "array.set", typeIndex: arrInfo.typeIndex });
1802
+
1803
+ this.pushInstruction({ op: "local.get", index: iLoc });
1804
+ this.pushInstruction({ op: "i32.const", value: 1 });
1805
+ this.pushInstruction("i32.add");
1806
+ this.pushInstruction({ op: "local.set", index: iLoc });
1807
+ this.pushInstruction({ op: "br", depth: 0 });
1808
+ this.pushInstruction("end");
1809
+ this.pushInstruction("end");
1810
+
1811
+ this.pushInstruction({ op: "local.get", index: nTmp });
1812
+ this.pushInstruction("i64.extend_i32_s");
1813
+ this.pushInstruction({ op: "local.set", index: retNTmp });
1814
+ this.pushInstruction({ op: "ref.null", heapType: "any" });
1815
+ this.pushInstruction({ op: "local.set", index: retErrTmp });
1816
+
1817
+ this.releaseTemp(dstLen, "i32");
1818
+ this.releaseTemp(dstOff, "i32");
1819
+ this.releaseTemp(dstArr, arrW);
1820
+ this.pushInstruction("end");
1821
+
1822
+ this.pushInstruction({ op: "local.get", index: retNTmp });
1823
+ this.pushInstruction({ op: "local.get", index: retErrTmp });
1824
+
1825
+ this.releaseTemp(retErrTmp, "anyref");
1826
+ this.releaseTemp(retNTmp, "i64");
1827
+ this.releaseTemp(errStrTmp, "externref");
1828
+ this.releaseTemp(nTmp, "i32");
1829
+ this.releaseTemp(iLoc, "i32");
1830
+ this.releaseTemp(srcLen, "i32");
1831
+ this.releaseTemp(srcOff, "i32");
1832
+ this.releaseTemp(srcArr, arrW);
1833
+ this.releaseTemp(srcTmp, sliceW);
1834
+ this.releaseTemp(dstTmp, sliceW);
1835
+ return;
1836
+ }
1837
+
1838
+ throw new Error(`Unsupported hex call: hex.${name}`);
1839
+ }
1840
+
1841
+ emitBase64Call(name, call, _targetWasmType) {
1842
+ if (name === "NewEncoding") {
1843
+ const structInfo = this.mod.getStructType("base64.Encoding");
1844
+ this.emitExpr(call.args[0], "externref");
1845
+ this._callStdlib("base64_new_encoding");
1846
+ this.pushInstruction({
1847
+ op: "struct.new",
1848
+ typeIndex: structInfo.typeIndex,
1849
+ });
1850
+ return;
1851
+ }
1852
+ throw new Error(`Unsupported base64 call: base64.${name}`);
1853
+ }
1854
+
1855
+ emitBase64EncodingMethodCall(method, recvExpr, args, _targetWasmType) {
1856
+ const structInfo = this.mod.getStructType("base64.Encoding");
1857
+ const encW = {
1858
+ kind: "ref",
1859
+ nullable: true,
1860
+ typeIndex: structInfo.typeIndex,
1861
+ };
1862
+ const modeTmp = this.acquireTemp("i32");
1863
+
1864
+ if (recvExpr?.field === "URLEncoding") {
1865
+ this.pushInstruction({ op: "i32.const", value: 1 });
1866
+ this.pushInstruction({ op: "local.set", index: modeTmp });
1867
+ } else if (recvExpr?.field === "RawStdEncoding") {
1868
+ this.pushInstruction({ op: "i32.const", value: 2 });
1869
+ this.pushInstruction({ op: "local.set", index: modeTmp });
1870
+ } else if (recvExpr?.field === "RawURLEncoding") {
1871
+ this.pushInstruction({ op: "i32.const", value: 3 });
1872
+ this.pushInstruction({ op: "local.set", index: modeTmp });
1873
+ } else if (recvExpr?.field === "StdEncoding") {
1874
+ this.pushInstruction({ op: "i32.const", value: 0 });
1875
+ this.pushInstruction({ op: "local.set", index: modeTmp });
1876
+ } else {
1877
+ const eTmp = this.acquireTemp(encW);
1878
+ this.emitExpr(recvExpr, encW);
1879
+ this.pushInstruction({ op: "local.tee", index: eTmp });
1880
+ this.pushInstruction({
1881
+ op: "struct.get",
1882
+ typeIndex: structInfo.typeIndex,
1883
+ fieldIndex: 0,
1884
+ });
1885
+ this.pushInstruction({ op: "local.set", index: modeTmp });
1886
+ this.releaseTemp(eTmp, encW);
1887
+ }
1888
+
1889
+ if (method === "EncodedLen") {
1890
+ const nTmp = this.acquireTemp("i64");
1891
+ this.emitExpr(args[0], "i64");
1892
+ this.pushInstruction({ op: "local.set", index: nTmp });
1893
+
1894
+ this.pushInstruction({ op: "local.get", index: modeTmp });
1895
+ this.pushInstruction({ op: "i32.const", value: 2 });
1896
+ this.pushInstruction("i32.and");
1897
+ this.pushInstruction({ op: "if", blockType: "i64" });
1898
+ // (n * 8 + 5) / 6
1899
+ this.pushInstruction({ op: "local.get", index: nTmp });
1900
+ this.pushInstruction({ op: "i64.const", value: 8n });
1901
+ this.pushInstruction("i64.mul");
1902
+ this.pushInstruction({ op: "i64.const", value: 5n });
1903
+ this.pushInstruction("i64.add");
1904
+ this.pushInstruction({ op: "i64.const", value: 6n });
1905
+ this.pushInstruction("i64.div_s");
1906
+ this.pushInstruction("else");
1907
+ // (n + 2) / 3 * 4
1908
+ this.pushInstruction({ op: "local.get", index: nTmp });
1909
+ this.pushInstruction({ op: "i64.const", value: 2n });
1910
+ this.pushInstruction("i64.add");
1911
+ this.pushInstruction({ op: "i64.const", value: 3n });
1912
+ this.pushInstruction("i64.div_s");
1913
+ this.pushInstruction({ op: "i64.const", value: 4n });
1914
+ this.pushInstruction("i64.mul");
1915
+ this.pushInstruction("end");
1916
+
1917
+ this.releaseTemp(nTmp, "i64");
1918
+ this.releaseTemp(modeTmp, "i32");
1919
+ return;
1920
+ }
1921
+
1922
+ if (method === "DecodedLen") {
1923
+ this.emitExpr(args[0], "i64");
1924
+ this.pushInstruction({ op: "i64.const", value: 3n });
1925
+ this.pushInstruction("i64.mul");
1926
+ this.pushInstruction({ op: "i64.const", value: 4n });
1927
+ this.pushInstruction("i64.div_s");
1928
+ this.releaseTemp(modeTmp, "i32");
1929
+ return;
1930
+ }
1931
+
1932
+ const byteGo = { kind: "basic", name: "byte" };
1933
+ const sliceInfo = this.mod.getSliceType(byteGo);
1934
+ const arrInfo = sliceInfo.arrInfo;
1935
+ const sliceW = {
1936
+ kind: "ref",
1937
+ nullable: true,
1938
+ typeIndex: sliceInfo.typeIndex,
1939
+ };
1940
+ const arrW = {
1941
+ kind: "ref",
1942
+ nullable: true,
1943
+ typeIndex: arrInfo.typeIndex,
1944
+ };
1945
+
1946
+ if (method === "EncodeToString") {
1947
+ const sTmp = this.acquireTemp(sliceW);
1948
+ this.emitExpr(args[0], sliceW);
1949
+ this.pushInstruction({ op: "local.set", index: sTmp });
1950
+
1951
+ const arrTmp = this.acquireTemp(arrW);
1952
+ const offTmp = this.acquireTemp("i32");
1953
+ const lenTmp = this.acquireTemp("i32");
1954
+ this._emitSliceUnpack(sTmp, sliceInfo, {
1955
+ arr: arrTmp,
1956
+ off: offTmp,
1957
+ len: lenTmp,
1958
+ });
1959
+
1960
+ this.pushInstruction({ op: "local.get", index: lenTmp });
1961
+ this._callStdlib("raw_bytes_init");
1962
+
1963
+ const iLoc = this.acquireTemp("i32");
1964
+ this.pushInstruction({ op: "i32.const", value: 0 });
1965
+ this.pushInstruction({ op: "local.set", index: iLoc });
1966
+
1967
+ this.pushInstruction({ op: "block", blockType: "void" });
1968
+ this.pushInstruction({ op: "loop", blockType: "void" });
1969
+ this.pushInstruction({ op: "local.get", index: iLoc });
1970
+ this.pushInstruction({ op: "local.get", index: lenTmp });
1971
+ this.pushInstruction("i32.ge_s");
1972
+ this.pushInstruction({ op: "br_if", depth: 1 });
1973
+
1974
+ this.pushInstruction({ op: "local.get", index: arrTmp });
1975
+ this.pushInstruction({ op: "local.get", index: offTmp });
1976
+ this.pushInstruction({ op: "local.get", index: iLoc });
1977
+ this.pushInstruction("i32.add");
1978
+ this.pushInstruction({ op: "array.get", typeIndex: arrInfo.typeIndex });
1979
+ this._callStdlib("raw_bytes_push");
1980
+
1981
+ this.pushInstruction({ op: "local.get", index: iLoc });
1982
+ this.pushInstruction({ op: "i32.const", value: 1 });
1983
+ this.pushInstruction("i32.add");
1984
+ this.pushInstruction({ op: "local.set", index: iLoc });
1985
+ this.pushInstruction({ op: "br", depth: 0 });
1986
+ this.pushInstruction("end");
1987
+ this.pushInstruction("end");
1988
+
1989
+ this.pushInstruction({ op: "local.get", index: modeTmp });
1990
+ this._callStdlib("base64_encode_to_string");
1991
+
1992
+ this.releaseTemp(iLoc, "i32");
1993
+ this.releaseTemp(lenTmp, "i32");
1994
+ this.releaseTemp(offTmp, "i32");
1995
+ this.releaseTemp(arrTmp, arrW);
1996
+ this.releaseTemp(sTmp, sliceW);
1997
+ this.releaseTemp(modeTmp, "i32");
1998
+ return;
1999
+ }
2000
+
2001
+ if (method === "DecodeString") {
2002
+ this.pushInstruction({ op: "local.get", index: modeTmp });
2003
+ this.emitExpr(args[0], "externref");
2004
+ this._callStdlib("base64_decode_string");
2005
+ const nTmp = this.acquireTemp("i32");
2006
+ this.pushInstruction({ op: "local.set", index: nTmp });
2007
+
2008
+ this._callStdlib("base64_get_err");
2009
+ const errStrTmp = this.acquireTemp("externref");
2010
+ this.pushInstruction({ op: "local.set", index: errStrTmp });
2011
+
2012
+ const retSliceTmp = this.acquireTemp(sliceW);
2013
+ const retErrTmp = this.acquireTemp("anyref");
2014
+
2015
+ this.pushInstruction({ op: "local.get", index: errStrTmp });
2016
+ this.pushInstruction("ref.is_null");
2017
+ this.pushInstruction("i32.eqz");
2018
+ this.pushInstruction({ op: "if", blockType: "void" });
2019
+
2020
+ // Error case
2021
+ this.pushInstruction({ op: "ref.null", heapType: arrInfo.typeIndex });
2022
+ this.pushInstruction({ op: "i32.const", value: 0 });
2023
+ this.pushInstruction({ op: "i32.const", value: 0 });
2024
+ this.pushInstruction({ op: "i32.const", value: 0 });
2025
+ this.pushInstruction({
2026
+ op: "struct.new",
2027
+ typeIndex: sliceInfo.typeIndex,
2028
+ });
2029
+ this.pushInstruction({ op: "local.set", index: retSliceTmp });
2030
+
2031
+ this.pushInstruction({ op: "local.get", index: errStrTmp });
2032
+ this.pushInstruction({ op: "ref.null", heapType: "any" });
2033
+ this.pushInstruction({
2034
+ op: "call",
2035
+ funcIndex: this.mod.resolveFuncIndex("__mk_error"),
2036
+ });
2037
+ this.pushInstruction({ op: "local.set", index: retErrTmp });
2038
+
2039
+ this.pushInstruction("else");
2040
+
2041
+ // Success case
2042
+ const outArrTmp = this.acquireTemp(arrW);
2043
+ this.pushInstruction({ op: "local.get", index: nTmp });
2044
+ this.pushInstruction({
2045
+ op: "array.new_default",
2046
+ typeIndex: arrInfo.typeIndex,
2047
+ });
2048
+ this.pushInstruction({ op: "local.set", index: outArrTmp });
2049
+
2050
+ const iLoc = this.acquireTemp("i32");
2051
+ this.pushInstruction({ op: "i32.const", value: 0 });
2052
+ this.pushInstruction({ op: "local.set", index: iLoc });
2053
+
2054
+ this.pushInstruction({ op: "block", blockType: "void" });
2055
+ this.pushInstruction({ op: "loop", blockType: "void" });
2056
+ this.pushInstruction({ op: "local.get", index: iLoc });
2057
+ this.pushInstruction({ op: "local.get", index: nTmp });
2058
+ this.pushInstruction("i32.ge_s");
2059
+ this.pushInstruction({ op: "br_if", depth: 1 });
2060
+
2061
+ this.pushInstruction({ op: "local.get", index: outArrTmp });
2062
+ this.pushInstruction({ op: "local.get", index: iLoc });
2063
+ this.pushInstruction({ op: "local.get", index: iLoc });
2064
+ this._callStdlib("raw_bytes_get");
2065
+ this.pushInstruction({ op: "array.set", typeIndex: arrInfo.typeIndex });
2066
+
2067
+ this.pushInstruction({ op: "local.get", index: iLoc });
2068
+ this.pushInstruction({ op: "i32.const", value: 1 });
2069
+ this.pushInstruction("i32.add");
2070
+ this.pushInstruction({ op: "local.set", index: iLoc });
2071
+ this.pushInstruction({ op: "br", depth: 0 });
2072
+ this.pushInstruction("end");
2073
+ this.pushInstruction("end");
2074
+
2075
+ this.pushInstruction({ op: "local.get", index: outArrTmp });
2076
+ this.pushInstruction({ op: "i32.const", value: 0 });
2077
+ this.pushInstruction({ op: "local.get", index: nTmp });
2078
+ this.pushInstruction({ op: "local.get", index: nTmp });
2079
+ this.pushInstruction({
2080
+ op: "struct.new",
2081
+ typeIndex: sliceInfo.typeIndex,
2082
+ });
2083
+ this.pushInstruction({ op: "local.set", index: retSliceTmp });
2084
+ this.pushInstruction({ op: "ref.null", heapType: "any" });
2085
+ this.pushInstruction({ op: "local.set", index: retErrTmp });
2086
+
2087
+ this.releaseTemp(iLoc, "i32");
2088
+ this.releaseTemp(outArrTmp, arrW);
2089
+ this.pushInstruction("end");
2090
+
2091
+ this.pushInstruction({ op: "local.get", index: retSliceTmp });
2092
+ this.pushInstruction({ op: "local.get", index: retErrTmp });
2093
+
2094
+ this.releaseTemp(retSliceTmp, sliceW);
2095
+ this.releaseTemp(retErrTmp, "anyref");
2096
+ this.releaseTemp(errStrTmp, "externref");
2097
+ this.releaseTemp(nTmp, "i32");
2098
+ this.releaseTemp(modeTmp, "i32");
2099
+ return;
2100
+ }
2101
+
2102
+ if (method === "Encode") {
2103
+ const dstTmp = this.acquireTemp(sliceW);
2104
+ this.emitExpr(args[0], sliceW);
2105
+ this.pushInstruction({ op: "local.set", index: dstTmp });
2106
+
2107
+ const srcTmp = this.acquireTemp(sliceW);
2108
+ this.emitExpr(args[1], sliceW);
2109
+ this.pushInstruction({ op: "local.set", index: srcTmp });
2110
+
2111
+ const srcArr = this.acquireTemp(arrW);
2112
+ const srcOff = this.acquireTemp("i32");
2113
+ const srcLen = this.acquireTemp("i32");
2114
+ this._emitSliceUnpack(srcTmp, sliceInfo, {
2115
+ arr: srcArr,
2116
+ off: srcOff,
2117
+ len: srcLen,
2118
+ });
2119
+
2120
+ this.pushInstruction({ op: "local.get", index: srcLen });
2121
+ this._callStdlib("raw_bytes_init");
2122
+
2123
+ const iLoc = this.acquireTemp("i32");
2124
+ this.pushInstruction({ op: "i32.const", value: 0 });
2125
+ this.pushInstruction({ op: "local.set", index: iLoc });
2126
+
2127
+ this.pushInstruction({ op: "block", blockType: "void" });
2128
+ this.pushInstruction({ op: "loop", blockType: "void" });
2129
+ this.pushInstruction({ op: "local.get", index: iLoc });
2130
+ this.pushInstruction({ op: "local.get", index: srcLen });
2131
+ this.pushInstruction("i32.ge_s");
2132
+ this.pushInstruction({ op: "br_if", depth: 1 });
2133
+
2134
+ this.pushInstruction({ op: "local.get", index: srcArr });
2135
+ this.pushInstruction({ op: "local.get", index: srcOff });
2136
+ this.pushInstruction({ op: "local.get", index: iLoc });
2137
+ this.pushInstruction("i32.add");
2138
+ this.pushInstruction({ op: "array.get", typeIndex: arrInfo.typeIndex });
2139
+ this._callStdlib("raw_bytes_push");
2140
+
2141
+ this.pushInstruction({ op: "local.get", index: iLoc });
2142
+ this.pushInstruction({ op: "i32.const", value: 1 });
2143
+ this.pushInstruction("i32.add");
2144
+ this.pushInstruction({ op: "local.set", index: iLoc });
2145
+ this.pushInstruction({ op: "br", depth: 0 });
2146
+ this.pushInstruction("end");
2147
+ this.pushInstruction("end");
2148
+
2149
+ this.pushInstruction({ op: "local.get", index: modeTmp });
2150
+ this._callStdlib("base64_encode_to_string");
2151
+ const strTmp = this.acquireTemp("externref");
2152
+ this.pushInstruction({ op: "local.set", index: strTmp });
2153
+
2154
+ const dstArr = this.acquireTemp(arrW);
2155
+ const dstOff = this.acquireTemp("i32");
2156
+ const dstLen = this.acquireTemp("i32");
2157
+ this._emitSliceUnpack(dstTmp, sliceInfo, {
2158
+ arr: dstArr,
2159
+ off: dstOff,
2160
+ len: dstLen,
2161
+ });
2162
+
2163
+ const b64LenTmp = this.acquireTemp("i32");
2164
+ this.pushInstruction({ op: "local.get", index: strTmp });
2165
+ this.pushInstruction({
2166
+ op: "call",
2167
+ funcIndex: this.mod.getStringLenImportIndex(),
2168
+ });
2169
+ this.pushInstruction({ op: "local.set", index: b64LenTmp });
2170
+
2171
+ this.pushInstruction({ op: "i32.const", value: 0 });
2172
+ this.pushInstruction({ op: "local.set", index: iLoc });
2173
+
2174
+ this.pushInstruction({ op: "block", blockType: "void" });
2175
+ this.pushInstruction({ op: "loop", blockType: "void" });
2176
+ this.pushInstruction({ op: "local.get", index: iLoc });
2177
+ this.pushInstruction({ op: "local.get", index: b64LenTmp });
2178
+ this.pushInstruction("i32.ge_s");
2179
+ this.pushInstruction({ op: "br_if", depth: 1 });
2180
+
2181
+ this.pushInstruction({ op: "local.get", index: dstArr });
2182
+ this.pushInstruction({ op: "local.get", index: dstOff });
2183
+ this.pushInstruction({ op: "local.get", index: iLoc });
2184
+ this.pushInstruction("i32.add");
2185
+ this.pushInstruction({ op: "local.get", index: strTmp });
2186
+ this.pushInstruction({ op: "local.get", index: iLoc });
2187
+ this.pushInstruction({
2188
+ op: "call",
2189
+ funcIndex: this.mod.getStringCodePointAtImportIndex(),
2190
+ });
2191
+ this.pushInstruction({ op: "array.set", typeIndex: arrInfo.typeIndex });
2192
+
2193
+ this.pushInstruction({ op: "local.get", index: iLoc });
2194
+ this.pushInstruction({ op: "i32.const", value: 1 });
2195
+ this.pushInstruction("i32.add");
2196
+ this.pushInstruction({ op: "local.set", index: iLoc });
2197
+ this.pushInstruction({ op: "br", depth: 0 });
2198
+ this.pushInstruction("end");
2199
+ this.pushInstruction("end");
2200
+
2201
+ this.releaseTemp(b64LenTmp, "i32");
2202
+ this.releaseTemp(dstLen, "i32");
2203
+ this.releaseTemp(dstOff, "i32");
2204
+ this.releaseTemp(dstArr, arrW);
2205
+ this.releaseTemp(strTmp, "externref");
2206
+ this.releaseTemp(iLoc, "i32");
2207
+ this.releaseTemp(srcLen, "i32");
2208
+ this.releaseTemp(srcOff, "i32");
2209
+ this.releaseTemp(srcArr, arrW);
2210
+ this.releaseTemp(srcTmp, sliceW);
2211
+ this.releaseTemp(dstTmp, sliceW);
2212
+ this.releaseTemp(modeTmp, "i32");
2213
+ return;
2214
+ }
2215
+
2216
+ if (method === "Decode") {
2217
+ const dstTmp = this.acquireTemp(sliceW);
2218
+ this.emitExpr(args[0], sliceW);
2219
+ this.pushInstruction({ op: "local.set", index: dstTmp });
2220
+
2221
+ const srcTmp = this.acquireTemp(sliceW);
2222
+ this.emitExpr(args[1], sliceW);
2223
+ this.pushInstruction({ op: "local.set", index: srcTmp });
2224
+
2225
+ const srcArr = this.acquireTemp(arrW);
2226
+ const srcOff = this.acquireTemp("i32");
2227
+ const srcLen = this.acquireTemp("i32");
2228
+ this._emitSliceUnpack(srcTmp, sliceInfo, {
2229
+ arr: srcArr,
2230
+ off: srcOff,
2231
+ len: srcLen,
2232
+ });
2233
+
2234
+ this.pushInstruction({ op: "local.get", index: srcLen });
2235
+ this._callStdlib("bytes_to_str_init");
2236
+
2237
+ const iLoc = this.acquireTemp("i32");
2238
+ this.pushInstruction({ op: "i32.const", value: 0 });
2239
+ this.pushInstruction({ op: "local.set", index: iLoc });
2240
+
2241
+ this.pushInstruction({ op: "block", blockType: "void" });
2242
+ this.pushInstruction({ op: "loop", blockType: "void" });
2243
+ this.pushInstruction({ op: "local.get", index: iLoc });
2244
+ this.pushInstruction({ op: "local.get", index: srcLen });
2245
+ this.pushInstruction("i32.ge_s");
2246
+ this.pushInstruction({ op: "br_if", depth: 1 });
2247
+
2248
+ this.pushInstruction({ op: "local.get", index: srcArr });
2249
+ this.pushInstruction({ op: "local.get", index: srcOff });
2250
+ this.pushInstruction({ op: "local.get", index: iLoc });
2251
+ this.pushInstruction("i32.add");
2252
+ this.pushInstruction({ op: "array.get", typeIndex: arrInfo.typeIndex });
2253
+ this._callStdlib("bytes_to_str_push");
2254
+
2255
+ this.pushInstruction({ op: "local.get", index: iLoc });
2256
+ this.pushInstruction({ op: "i32.const", value: 1 });
2257
+ this.pushInstruction("i32.add");
2258
+ this.pushInstruction({ op: "local.set", index: iLoc });
2259
+ this.pushInstruction({ op: "br", depth: 0 });
2260
+ this.pushInstruction("end");
2261
+ this.pushInstruction("end");
2262
+
2263
+ this._callStdlib("bytes_to_str_finish");
2264
+ const srcStrTmp = this.acquireTemp("externref");
2265
+ this.pushInstruction({ op: "local.set", index: srcStrTmp });
2266
+
2267
+ this.pushInstruction({ op: "local.get", index: modeTmp });
2268
+ this.pushInstruction({ op: "local.get", index: srcStrTmp });
2269
+ this._callStdlib("base64_decode_string");
2270
+ const nTmp = this.acquireTemp("i32");
2271
+ this.pushInstruction({ op: "local.set", index: nTmp });
2272
+
2273
+ this._callStdlib("base64_get_err");
2274
+ const errStrTmp = this.acquireTemp("externref");
2275
+ this.pushInstruction({ op: "local.set", index: errStrTmp });
2276
+
2277
+ const retNTmp = this.acquireTemp("i64");
2278
+ const retErrTmp = this.acquireTemp("anyref");
2279
+
2280
+ this.pushInstruction({ op: "local.get", index: errStrTmp });
2281
+ this.pushInstruction("ref.is_null");
2282
+ this.pushInstruction("i32.eqz");
2283
+ this.pushInstruction({ op: "if", blockType: "void" });
2284
+
2285
+ // Error case
2286
+ this.pushInstruction({ op: "i64.const", value: 0n });
2287
+ this.pushInstruction({ op: "local.set", index: retNTmp });
2288
+ this.pushInstruction({ op: "local.get", index: errStrTmp });
2289
+ this.pushInstruction({ op: "ref.null", heapType: "any" });
2290
+ this.pushInstruction({
2291
+ op: "call",
2292
+ funcIndex: this.mod.resolveFuncIndex("__mk_error"),
2293
+ });
2294
+ this.pushInstruction({ op: "local.set", index: retErrTmp });
2295
+
2296
+ this.pushInstruction("else");
2297
+
2298
+ // Success case: copy bytes into dst
2299
+ const dstArr = this.acquireTemp(arrW);
2300
+ const dstOff = this.acquireTemp("i32");
2301
+ const dstLen = this.acquireTemp("i32");
2302
+ this._emitSliceUnpack(dstTmp, sliceInfo, {
2303
+ arr: dstArr,
2304
+ off: dstOff,
2305
+ len: dstLen,
2306
+ });
2307
+
2308
+ this.pushInstruction({ op: "i32.const", value: 0 });
2309
+ this.pushInstruction({ op: "local.set", index: iLoc });
2310
+
2311
+ this.pushInstruction({ op: "block", blockType: "void" });
2312
+ this.pushInstruction({ op: "loop", blockType: "void" });
2313
+ this.pushInstruction({ op: "local.get", index: iLoc });
2314
+ this.pushInstruction({ op: "local.get", index: nTmp });
2315
+ this.pushInstruction("i32.ge_s");
2316
+ this.pushInstruction({ op: "br_if", depth: 1 });
2317
+
2318
+ this.pushInstruction({ op: "local.get", index: dstArr });
2319
+ this.pushInstruction({ op: "local.get", index: dstOff });
2320
+ this.pushInstruction({ op: "local.get", index: iLoc });
2321
+ this.pushInstruction("i32.add");
2322
+ this.pushInstruction({ op: "local.get", index: iLoc });
2323
+ this._callStdlib("raw_bytes_get");
2324
+ this.pushInstruction({ op: "array.set", typeIndex: arrInfo.typeIndex });
2325
+
2326
+ this.pushInstruction({ op: "local.get", index: iLoc });
2327
+ this.pushInstruction({ op: "i32.const", value: 1 });
2328
+ this.pushInstruction("i32.add");
2329
+ this.pushInstruction({ op: "local.set", index: iLoc });
2330
+ this.pushInstruction({ op: "br", depth: 0 });
2331
+ this.pushInstruction("end");
2332
+ this.pushInstruction("end");
2333
+
2334
+ this.pushInstruction({ op: "local.get", index: nTmp });
2335
+ this.pushInstruction("i64.extend_i32_s");
2336
+ this.pushInstruction({ op: "local.set", index: retNTmp });
2337
+ this.pushInstruction({ op: "ref.null", heapType: "any" });
2338
+ this.pushInstruction({ op: "local.set", index: retErrTmp });
2339
+
2340
+ this.releaseTemp(dstLen, "i32");
2341
+ this.releaseTemp(dstOff, "i32");
2342
+ this.releaseTemp(dstArr, arrW);
2343
+ this.pushInstruction("end");
2344
+
2345
+ this.pushInstruction({ op: "local.get", index: retNTmp });
2346
+ this.pushInstruction({ op: "local.get", index: retErrTmp });
2347
+
2348
+ this.releaseTemp(retErrTmp, "anyref");
2349
+ this.releaseTemp(retNTmp, "i64");
2350
+ this.releaseTemp(errStrTmp, "externref");
2351
+ this.releaseTemp(nTmp, "i32");
2352
+ this.releaseTemp(srcStrTmp, "externref");
2353
+ this.releaseTemp(iLoc, "i32");
2354
+ this.releaseTemp(srcLen, "i32");
2355
+ this.releaseTemp(srcOff, "i32");
2356
+ this.releaseTemp(srcArr, arrW);
2357
+ this.releaseTemp(srcTmp, sliceW);
2358
+ this.releaseTemp(dstTmp, sliceW);
2359
+ this.releaseTemp(modeTmp, "i32");
2360
+ return;
2361
+ }
2362
+
2363
+ if (method === "WithPadding") {
2364
+ const padTmp = this.acquireTemp("i64");
2365
+ this.emitExpr(args[0], "i64");
2366
+ this.pushInstruction({ op: "local.set", index: padTmp });
2367
+
2368
+ const newModeTmp = this.acquireTemp("i32");
2369
+ this.pushInstruction({ op: "local.get", index: padTmp });
2370
+ this.pushInstruction({ op: "i64.const", value: -1n });
2371
+ this.pushInstruction("i64.eq");
2372
+ this.pushInstruction({ op: "if", blockType: "void" });
2373
+ this.pushInstruction({ op: "local.get", index: modeTmp });
2374
+ this.pushInstruction({ op: "i32.const", value: 1 });
2375
+ this.pushInstruction("i32.and");
2376
+ this.pushInstruction({ op: "i32.const", value: 2 });
2377
+ this.pushInstruction("i32.or");
2378
+ this.pushInstruction({ op: "local.set", index: newModeTmp });
2379
+ this.pushInstruction("else");
2380
+ this.pushInstruction({ op: "local.get", index: modeTmp });
2381
+ this.pushInstruction({ op: "i32.const", value: 1 });
2382
+ this.pushInstruction("i32.and");
2383
+ this.pushInstruction({ op: "local.set", index: newModeTmp });
2384
+ this.pushInstruction("end");
2385
+
2386
+ this.pushInstruction({ op: "local.get", index: newModeTmp });
2387
+ this.pushInstruction({
2388
+ op: "struct.new",
2389
+ typeIndex: structInfo.typeIndex,
2390
+ });
2391
+
2392
+ this.releaseTemp(newModeTmp, "i32");
2393
+ this.releaseTemp(padTmp, "i64");
2394
+ this.releaseTemp(modeTmp, "i32");
2395
+ return;
2396
+ }
2397
+
2398
+ throw new Error(`Unsupported base64 method: ${method}`);
2399
+ }
2400
+ }