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.
- package/README.md +35 -39
- package/package.json +37 -4
- package/src/backend/js/expressions.js +559 -144
- package/src/backend/js/index.js +174 -49
- package/src/backend/js/runtime.js +1518 -54
- package/src/backend/js/statements.js +91 -73
- package/src/backend/js/stdlib/base64.js +12 -0
- package/src/backend/js/stdlib/binary.js +102 -0
- package/src/backend/js/stdlib/bits.js +15 -1
- package/src/backend/js/stdlib/builder.js +28 -9
- package/src/backend/js/stdlib/bytes.js +75 -18
- package/src/backend/js/stdlib/errors.js +25 -1
- package/src/backend/js/stdlib/fmt.js +70 -13
- package/src/backend/js/stdlib/hex.js +17 -0
- package/src/backend/js/stdlib/html.js +1 -1
- package/src/backend/js/stdlib/index.js +28 -0
- package/src/backend/js/stdlib/io.js +105 -3
- package/src/backend/js/stdlib/json.js +972 -0
- package/src/backend/js/stdlib/math.js +13 -1
- package/src/backend/js/stdlib/path.js +18 -4
- package/src/backend/js/stdlib/rand.js +10 -5
- package/src/backend/js/stdlib/sha256.js +12 -0
- package/src/backend/js/stdlib/simd.js +24 -0
- package/src/backend/js/stdlib/slices.js +52 -26
- package/src/backend/js/stdlib/strconv.js +21 -5
- package/src/backend/js/stdlib/strings.js +148 -15
- package/src/backend/js/stdlib/sync.js +13 -0
- package/src/backend/js/stdlib/time.js +90 -19
- package/src/backend/js/stdlib/unicode.js +2 -2
- package/src/backend/wasm/boundary.js +1225 -41
- package/src/backend/wasm/const-fold.js +205 -0
- package/src/backend/wasm/emit-builtins.js +220 -76
- package/src/backend/wasm/emit-exprs.js +475 -276
- package/src/backend/wasm/emit-maps.js +144 -8
- package/src/backend/wasm/emit-stdlib.js +12 -3005
- package/src/backend/wasm/emit-stmts.js +264 -270
- package/src/backend/wasm/emit.js +124 -87
- package/src/backend/wasm/encode.js +140 -29
- package/src/backend/wasm/index.js +1001 -32
- package/src/backend/wasm/optimize.js +17 -6
- package/src/backend/wasm/stdlib/bytes.js +5039 -0
- package/src/backend/wasm/stdlib/core.js +8903 -0
- package/src/backend/wasm/stdlib/index.js +43 -0
- package/src/backend/wasm/stdlib/io.js +2161 -0
- package/src/backend/wasm/stdlib/packages.js +2400 -0
- package/src/backend/wasm/stdlib/pure.js +720 -0
- package/src/backend/wasm/stdlib/simd.js +234 -0
- package/src/backend/wasm/stdlib/time.js +1200 -0
- package/src/backend/wasm/types.js +174 -1
- package/src/backend/wasm/wat.js +37 -0
- package/src/cli-core.js +1 -1
- package/src/compiler.js +18 -4
- package/src/dts-parser.js +150 -140
- package/src/index.js +2 -6
- package/src/lexer.js +80 -29
- package/src/lower/boxing.js +1 -7
- package/src/lower/captures.js +2 -6
- package/src/lower/embedding.js +2 -1
- package/src/lower/ownership.js +30 -9
- package/src/minifier.js +20 -68
- package/src/parser/declarations.js +3 -6
- package/src/parser/expressions.js +3 -8
- package/src/parser/index.js +18 -3
- package/src/parser/statements.js +25 -38
- package/src/parser/struct-tag.js +144 -0
- package/src/parser/types.js +64 -8
- package/src/resolver.js +2 -27
- package/src/templ-lexer.js +29 -63
- package/src/templ-parser.js +22 -45
- package/src/typechecker/assignability.js +126 -13
- package/src/typechecker/expressions.js +168 -16
- package/src/typechecker/index.js +35 -8
- package/src/typechecker/resolve.js +187 -8
- package/src/typechecker/statements.js +68 -9
- package/src/typechecker/stdlib/core.js +280 -89
- package/src/typechecker/stdlib/extended.js +490 -1
- package/src/typechecker/stdlib/simd.js +73 -0
- package/src/typechecker/stdlib.js +2 -0
- package/src/typechecker/types.js +362 -9
- package/src/vendor.js +86 -11
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// src/backend/wasm/emit-exprs.js
|
|
2
2
|
// FunctionEmitter mixin: expression emission (literals, operators, indexing, conversions).
|
|
3
3
|
|
|
4
|
+
import { foldConstExpr } from "./const-fold.js";
|
|
4
5
|
import {
|
|
5
6
|
getMapKeyValTypes,
|
|
6
7
|
isAnyType,
|
|
@@ -65,8 +66,7 @@ export class ExprsEmitter {
|
|
|
65
66
|
this.emitCloneStruct(sInfo, structWType);
|
|
66
67
|
}
|
|
67
68
|
}
|
|
68
|
-
|
|
69
|
-
this.pushInstruction({ op: "struct.new", typeIndex: box.typeIndex });
|
|
69
|
+
this._emitBoxValue(this.mod.getIfaceBoxType(goType));
|
|
70
70
|
return;
|
|
71
71
|
}
|
|
72
72
|
|
|
@@ -83,15 +83,23 @@ export class ExprsEmitter {
|
|
|
83
83
|
|
|
84
84
|
// Scalar type -> box into struct
|
|
85
85
|
const scalarType = goType ?? { kind: "basic", name: "int" };
|
|
86
|
-
const box = this.mod.
|
|
86
|
+
const box = this.mod.getIfaceBoxType(scalarType);
|
|
87
87
|
this._emitRawExpr(expr, box.wType);
|
|
88
|
-
this.
|
|
88
|
+
this._emitBoxValue(box);
|
|
89
89
|
return;
|
|
90
90
|
}
|
|
91
91
|
|
|
92
92
|
this._emitRawExpr(expr, targetWasmType);
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
+
_emitBoxValue(box) {
|
|
96
|
+
this.pushInstruction({
|
|
97
|
+
op: "ref.null",
|
|
98
|
+
heapType: box.tagTypeIndex,
|
|
99
|
+
});
|
|
100
|
+
this.pushInstruction({ op: "struct.new", typeIndex: box.typeIndex });
|
|
101
|
+
}
|
|
102
|
+
|
|
95
103
|
_resolveExprGoType(expr) {
|
|
96
104
|
if (expr._type) return expr._type;
|
|
97
105
|
if (expr.kind === "BasicLit") {
|
|
@@ -121,6 +129,17 @@ export class ExprsEmitter {
|
|
|
121
129
|
}
|
|
122
130
|
|
|
123
131
|
_emitRawExpr(expr, targetWasmType = null) {
|
|
132
|
+
if (expr.kind === "BinaryExpr" || expr.kind === "UnaryExpr") {
|
|
133
|
+
const folded = foldConstExpr(expr, (name) =>
|
|
134
|
+
this.mod.pkgConsts?.get(name),
|
|
135
|
+
);
|
|
136
|
+
if (folded) {
|
|
137
|
+
folded._type = expr._type;
|
|
138
|
+
this.emitBasicLit(folded, targetWasmType);
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
124
143
|
switch (expr.kind) {
|
|
125
144
|
case "BasicLit":
|
|
126
145
|
this.emitBasicLit(expr, targetWasmType);
|
|
@@ -157,6 +176,16 @@ export class ExprsEmitter {
|
|
|
157
176
|
this.emitMathConst(expr.field, targetWasmType);
|
|
158
177
|
else if (this._isUtf8Const(expr))
|
|
159
178
|
this.emitUtf8Const(expr.field, targetWasmType);
|
|
179
|
+
else if (this._isStrconvConst(expr))
|
|
180
|
+
this.emitStrconvConst(expr.field, targetWasmType);
|
|
181
|
+
else if (this._isPathConst(expr))
|
|
182
|
+
this.emitPathConst(expr.field, targetWasmType);
|
|
183
|
+
else if (this._isIoConst(expr))
|
|
184
|
+
this.emitIoConst(expr.field, targetWasmType);
|
|
185
|
+
else if (this._isTimeConst(expr))
|
|
186
|
+
this.emitTimeConst(expr.field, targetWasmType);
|
|
187
|
+
else if (this._isExtendedPkgConst?.(expr))
|
|
188
|
+
this.emitExtendedPkgConst(expr, targetWasmType);
|
|
160
189
|
else this.emitSelectorExpr(expr);
|
|
161
190
|
break;
|
|
162
191
|
}
|
|
@@ -218,35 +247,7 @@ export class ExprsEmitter {
|
|
|
218
247
|
if (capturedNames.length === 0) {
|
|
219
248
|
this.pushInstruction({ op: "ref.null", heapType: "any" });
|
|
220
249
|
} else {
|
|
221
|
-
const envFields =
|
|
222
|
-
for (const name of capturedNames) {
|
|
223
|
-
const isBoxed = this.mutatedCaptures.has(name);
|
|
224
|
-
const goType = this._findCapturedVarGoType(name);
|
|
225
|
-
if (isBoxed) {
|
|
226
|
-
const boxInfo = this.mod.getBoxType(goType);
|
|
227
|
-
envFields.push({
|
|
228
|
-
name,
|
|
229
|
-
goType,
|
|
230
|
-
isBoxed: true,
|
|
231
|
-
boxInfo,
|
|
232
|
-
wType: {
|
|
233
|
-
kind: "ref",
|
|
234
|
-
nullable: true,
|
|
235
|
-
typeIndex: boxInfo.typeIndex,
|
|
236
|
-
},
|
|
237
|
-
});
|
|
238
|
-
} else {
|
|
239
|
-
const wType = this.toWasmType(goType);
|
|
240
|
-
envFields.push({
|
|
241
|
-
name,
|
|
242
|
-
goType,
|
|
243
|
-
isBoxed: false,
|
|
244
|
-
boxInfo: null,
|
|
245
|
-
wType,
|
|
246
|
-
});
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
+
const envFields = this._buildEnvFields(capturedNames);
|
|
250
251
|
const envInfo = this.mod.getEnvType(envFields);
|
|
251
252
|
|
|
252
253
|
for (const field of envFields) {
|
|
@@ -274,6 +275,17 @@ export class ExprsEmitter {
|
|
|
274
275
|
|
|
275
276
|
emitCompositeLit(lit) {
|
|
276
277
|
const litType = lit._type ?? lit.typeExpr?._type ?? lit.typeExpr;
|
|
278
|
+
if (
|
|
279
|
+
litType?.kind === "simd" ||
|
|
280
|
+
litType?.name === "simd.F32x4" ||
|
|
281
|
+
litType?.underlying?.kind === "simd" ||
|
|
282
|
+
(lit.typeExpr?.kind === "SelectorExpr" &&
|
|
283
|
+
lit.typeExpr.field === "F32x4" &&
|
|
284
|
+
lit.typeExpr.expr?.name === "simd")
|
|
285
|
+
) {
|
|
286
|
+
this.emitSimdCompositeLit(lit);
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
277
289
|
if (isMapType(litType, this.mod.checker)) {
|
|
278
290
|
const { keyType, valType } = getMapKeyValTypes(litType, this.mod.checker);
|
|
279
291
|
const mapInfo = this.mod.getMapType(keyType, valType);
|
|
@@ -363,7 +375,10 @@ export class ExprsEmitter {
|
|
|
363
375
|
const typeName =
|
|
364
376
|
lit.typeExpr?.name ??
|
|
365
377
|
(litType?.kind === "named" ? litType.name : litType?.name);
|
|
366
|
-
|
|
378
|
+
let structInfo = typeName ? this.mod.getStructType(typeName) : null;
|
|
379
|
+
if (!structInfo) {
|
|
380
|
+
structInfo = this._resolveStructInfo(lit);
|
|
381
|
+
}
|
|
367
382
|
if (!structInfo) {
|
|
368
383
|
throw new Error(`Unknown struct in CompositeLit: ${typeName}`);
|
|
369
384
|
}
|
|
@@ -780,6 +795,59 @@ export class ExprsEmitter {
|
|
|
780
795
|
this.pushInstruction({ op: "local.set", index: dstArrTmp });
|
|
781
796
|
|
|
782
797
|
const iTmp = this.acquireTemp("i32");
|
|
798
|
+
|
|
799
|
+
// If copying within the same array and shifting right (dstOff > srcOff),
|
|
800
|
+
// copy backwards to prevent clobbering overlapping elements.
|
|
801
|
+
this.pushInstruction({ op: "local.get", index: dstArrTmp });
|
|
802
|
+
this.pushInstruction({ op: "local.get", index: srcArrTmp });
|
|
803
|
+
this.pushInstruction("ref.eq");
|
|
804
|
+
this.pushInstruction({ op: "local.get", index: dstOffTmp });
|
|
805
|
+
this.pushInstruction({ op: "local.get", index: srcOffTmp });
|
|
806
|
+
this.pushInstruction("i32.gt_u");
|
|
807
|
+
this.pushInstruction("i32.and");
|
|
808
|
+
this.pushInstruction({ op: "if", blockType: "void" });
|
|
809
|
+
|
|
810
|
+
// Backwards copy: i from lenTmp - 1 down to 0
|
|
811
|
+
this.pushInstruction({ op: "local.get", index: lenTmp });
|
|
812
|
+
this.pushInstruction({ op: "i32.const", value: 1 });
|
|
813
|
+
this.pushInstruction("i32.sub");
|
|
814
|
+
this.pushInstruction({ op: "local.set", index: iTmp });
|
|
815
|
+
|
|
816
|
+
this.pushInstruction({ op: "block", blockType: "void" });
|
|
817
|
+
this.pushInstruction({ op: "loop", blockType: "void" });
|
|
818
|
+
this.pushInstruction({ op: "local.get", index: iTmp });
|
|
819
|
+
this.pushInstruction({ op: "i32.const", value: 0 });
|
|
820
|
+
this.pushInstruction("i32.lt_s");
|
|
821
|
+
this.pushInstruction({ op: "br_if", depth: 1 });
|
|
822
|
+
|
|
823
|
+
this.pushInstruction({ op: "local.get", index: dstArrTmp });
|
|
824
|
+
this.pushInstruction({ op: "local.get", index: dstOffTmp });
|
|
825
|
+
this.pushInstruction({ op: "local.get", index: iTmp });
|
|
826
|
+
this.pushInstruction("i32.add");
|
|
827
|
+
|
|
828
|
+
this.pushInstruction({ op: "local.get", index: srcArrTmp });
|
|
829
|
+
this.pushInstruction({ op: "local.get", index: srcOffTmp });
|
|
830
|
+
this.pushInstruction({ op: "local.get", index: iTmp });
|
|
831
|
+
this.pushInstruction("i32.add");
|
|
832
|
+
this.pushInstruction({ op: "array.get", typeIndex: arrInfo.typeIndex });
|
|
833
|
+
|
|
834
|
+
if (sInfo) {
|
|
835
|
+
this.emitCloneStruct(sInfo, arrInfo.elemWType);
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
this.pushInstruction({ op: "array.set", typeIndex: arrInfo.typeIndex });
|
|
839
|
+
|
|
840
|
+
this.pushInstruction({ op: "local.get", index: iTmp });
|
|
841
|
+
this.pushInstruction({ op: "i32.const", value: 1 });
|
|
842
|
+
this.pushInstruction("i32.sub");
|
|
843
|
+
this.pushInstruction({ op: "local.set", index: iTmp });
|
|
844
|
+
this.pushInstruction({ op: "br", depth: 0 });
|
|
845
|
+
this.pushInstruction("end");
|
|
846
|
+
this.pushInstruction("end");
|
|
847
|
+
|
|
848
|
+
this.pushInstruction("else");
|
|
849
|
+
|
|
850
|
+
// Forwards copy: i from 0 up to lenTmp - 1
|
|
783
851
|
this.pushInstruction({ op: "i32.const", value: 0 });
|
|
784
852
|
this.pushInstruction({ op: "local.set", index: iTmp });
|
|
785
853
|
|
|
@@ -815,6 +883,8 @@ export class ExprsEmitter {
|
|
|
815
883
|
this.pushInstruction("end");
|
|
816
884
|
this.pushInstruction("end");
|
|
817
885
|
|
|
886
|
+
this.pushInstruction("end");
|
|
887
|
+
|
|
818
888
|
this.releaseTemp(iTmp, "i32");
|
|
819
889
|
this.releaseTemp(dstArrTmp, {
|
|
820
890
|
kind: "ref",
|
|
@@ -964,6 +1034,31 @@ export class ExprsEmitter {
|
|
|
964
1034
|
nullable: true,
|
|
965
1035
|
typeIndex: arrInfo.typeIndex,
|
|
966
1036
|
};
|
|
1037
|
+
|
|
1038
|
+
const rawBaseType = baseNode._type ?? this._resolveExprGoType(baseNode);
|
|
1039
|
+
const baseType =
|
|
1040
|
+
rawBaseType?.kind === "pointer" ? rawBaseType.base : rawBaseType;
|
|
1041
|
+
const arrayLen =
|
|
1042
|
+
baseType?.kind === "array" ? (baseType.len ?? baseType.size) : null;
|
|
1043
|
+
let constIdx = null;
|
|
1044
|
+
if (indexNode.kind === "BasicLit" && indexNode.litKind === "INT") {
|
|
1045
|
+
try {
|
|
1046
|
+
const v = Number(indexNode.value);
|
|
1047
|
+
if (Number.isInteger(v)) constIdx = v;
|
|
1048
|
+
} catch {}
|
|
1049
|
+
}
|
|
1050
|
+
if (
|
|
1051
|
+
arrayLen !== null &&
|
|
1052
|
+
arrayLen !== undefined &&
|
|
1053
|
+
constIdx !== null &&
|
|
1054
|
+
constIdx >= 0 &&
|
|
1055
|
+
constIdx < arrayLen
|
|
1056
|
+
) {
|
|
1057
|
+
this.emitExpr(baseNode, arrWType);
|
|
1058
|
+
this.pushInstruction({ op: "i32.const", value: constIdx });
|
|
1059
|
+
return;
|
|
1060
|
+
}
|
|
1061
|
+
|
|
967
1062
|
const arrTmp = this.acquireTemp(arrWType);
|
|
968
1063
|
this.emitExpr(baseNode, arrWType);
|
|
969
1064
|
this.pushInstruction({ op: "local.tee", index: arrTmp });
|
|
@@ -998,14 +1093,16 @@ export class ExprsEmitter {
|
|
|
998
1093
|
(lit.litKind === "INT" ? "i64" : lit.litKind === "FLOAT" ? "f64" : "i32");
|
|
999
1094
|
|
|
1000
1095
|
if (lit.litKind === "INT") {
|
|
1001
|
-
const
|
|
1096
|
+
const s = String(lit.value);
|
|
1097
|
+
const clean = /^0[0-7]+$/.test(s) ? `0o${s.slice(1)}` : s;
|
|
1098
|
+
const n = Number(clean);
|
|
1002
1099
|
if (wType === "i32") {
|
|
1003
1100
|
this.pushInstruction({ op: "i32.const", value: n | 0 });
|
|
1004
1101
|
} else if (wType === "f64" || wType === "f32") {
|
|
1005
1102
|
// Untyped integer constant in a float context (`x * 2`).
|
|
1006
1103
|
this.pushInstruction({ op: `${wType}.const`, value: n });
|
|
1007
1104
|
} else {
|
|
1008
|
-
this.pushInstruction({ op: "i64.const", value: BigInt(
|
|
1105
|
+
this.pushInstruction({ op: "i64.const", value: BigInt(clean) });
|
|
1009
1106
|
}
|
|
1010
1107
|
return;
|
|
1011
1108
|
}
|
|
@@ -1029,31 +1126,7 @@ export class ExprsEmitter {
|
|
|
1029
1126
|
}
|
|
1030
1127
|
|
|
1031
1128
|
if (lit.litKind === "NIL") {
|
|
1032
|
-
|
|
1033
|
-
if (
|
|
1034
|
-
(lit._type && isSliceType(lit._type, this.mod.checker)) ||
|
|
1035
|
-
(effectiveType &&
|
|
1036
|
-
typeof effectiveType === "object" &&
|
|
1037
|
-
typeof effectiveType.typeIndex === "number" &&
|
|
1038
|
-
this.mod.getSliceTypeByIndex(effectiveType.typeIndex))
|
|
1039
|
-
) {
|
|
1040
|
-
const elemType = lit._type ? this._getSliceElemType(lit._type) : null;
|
|
1041
|
-
const sliceInfo = elemType
|
|
1042
|
-
? this.mod.getSliceType(elemType)
|
|
1043
|
-
: this.mod.getSliceTypeByIndex(effectiveType.typeIndex);
|
|
1044
|
-
if (sliceInfo) {
|
|
1045
|
-
this.pushInstruction({
|
|
1046
|
-
op: "global.get",
|
|
1047
|
-
index: sliceInfo.emptyGlobalIndex,
|
|
1048
|
-
});
|
|
1049
|
-
return;
|
|
1050
|
-
}
|
|
1051
|
-
}
|
|
1052
|
-
const heapType =
|
|
1053
|
-
typeof effectiveType === "object" && effectiveType !== null
|
|
1054
|
-
? (effectiveType.typeIndex ?? effectiveType.heapType ?? "any")
|
|
1055
|
-
: "any";
|
|
1056
|
-
this.pushInstruction({ op: "ref.null", heapType });
|
|
1129
|
+
this._emitNilValue(lit._type, targetWasmType);
|
|
1057
1130
|
return;
|
|
1058
1131
|
}
|
|
1059
1132
|
|
|
@@ -1068,6 +1141,42 @@ export class ExprsEmitter {
|
|
|
1068
1141
|
}
|
|
1069
1142
|
}
|
|
1070
1143
|
|
|
1144
|
+
_emitNilValue(goType, targetWasmType) {
|
|
1145
|
+
const effectiveType = targetWasmType ?? this.toWasmType(goType);
|
|
1146
|
+
if (
|
|
1147
|
+
(goType && isSliceType(goType, this.mod.checker)) ||
|
|
1148
|
+
(effectiveType &&
|
|
1149
|
+
typeof effectiveType === "object" &&
|
|
1150
|
+
typeof effectiveType.typeIndex === "number" &&
|
|
1151
|
+
this.mod.getSliceTypeByIndex(effectiveType.typeIndex))
|
|
1152
|
+
) {
|
|
1153
|
+
const elemType = goType ? this._getSliceElemType(goType) : null;
|
|
1154
|
+
const sliceInfo = elemType
|
|
1155
|
+
? this.mod.getSliceType(elemType)
|
|
1156
|
+
: this.mod.getSliceTypeByIndex(effectiveType.typeIndex);
|
|
1157
|
+
if (sliceInfo) {
|
|
1158
|
+
this.pushInstruction({
|
|
1159
|
+
op: "global.get",
|
|
1160
|
+
index: sliceInfo.emptyGlobalIndex,
|
|
1161
|
+
});
|
|
1162
|
+
return;
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1165
|
+
const heapType =
|
|
1166
|
+
typeof effectiveType === "object" && effectiveType !== null
|
|
1167
|
+
? (effectiveType.typeIndex ?? effectiveType.heapType ?? "any")
|
|
1168
|
+
: "any";
|
|
1169
|
+
this.pushInstruction({ op: "ref.null", heapType });
|
|
1170
|
+
}
|
|
1171
|
+
|
|
1172
|
+
_coerceIntWidth(srcType, targetWasmType) {
|
|
1173
|
+
if (srcType === "i32" && targetWasmType === "i64") {
|
|
1174
|
+
this.pushInstruction("i64.extend_i32_s");
|
|
1175
|
+
} else if (srcType === "i64" && targetWasmType === "i32") {
|
|
1176
|
+
this.pushInstruction("i32.wrap_i64");
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
1179
|
+
|
|
1071
1180
|
emitIdent(ident, targetWasmType = null) {
|
|
1072
1181
|
if (ident.name === "true") {
|
|
1073
1182
|
this.pushInstruction({ op: "i32.const", value: 1 });
|
|
@@ -1078,33 +1187,7 @@ export class ExprsEmitter {
|
|
|
1078
1187
|
return;
|
|
1079
1188
|
}
|
|
1080
1189
|
if (ident.name === "nil") {
|
|
1081
|
-
|
|
1082
|
-
if (
|
|
1083
|
-
(ident._type && isSliceType(ident._type, this.mod.checker)) ||
|
|
1084
|
-
(effectiveType &&
|
|
1085
|
-
typeof effectiveType === "object" &&
|
|
1086
|
-
typeof effectiveType.typeIndex === "number" &&
|
|
1087
|
-
this.mod.getSliceTypeByIndex(effectiveType.typeIndex))
|
|
1088
|
-
) {
|
|
1089
|
-
const elemType = ident._type
|
|
1090
|
-
? this._getSliceElemType(ident._type)
|
|
1091
|
-
: null;
|
|
1092
|
-
const sliceInfo = elemType
|
|
1093
|
-
? this.mod.getSliceType(elemType)
|
|
1094
|
-
: this.mod.getSliceTypeByIndex(effectiveType.typeIndex);
|
|
1095
|
-
if (sliceInfo) {
|
|
1096
|
-
this.pushInstruction({
|
|
1097
|
-
op: "global.get",
|
|
1098
|
-
index: sliceInfo.emptyGlobalIndex,
|
|
1099
|
-
});
|
|
1100
|
-
return;
|
|
1101
|
-
}
|
|
1102
|
-
}
|
|
1103
|
-
const heapType =
|
|
1104
|
-
typeof effectiveType === "object" && effectiveType !== null
|
|
1105
|
-
? (effectiveType.typeIndex ?? effectiveType.heapType ?? "any")
|
|
1106
|
-
: "any";
|
|
1107
|
-
this.pushInstruction({ op: "ref.null", heapType });
|
|
1190
|
+
this._emitNilValue(ident._type, targetWasmType);
|
|
1108
1191
|
return;
|
|
1109
1192
|
}
|
|
1110
1193
|
|
|
@@ -1120,33 +1203,21 @@ export class ExprsEmitter {
|
|
|
1120
1203
|
} else {
|
|
1121
1204
|
this.pushInstruction({ op: "local.get", index: localInfo.index });
|
|
1122
1205
|
}
|
|
1123
|
-
|
|
1124
|
-
this.pushInstruction("i64.extend_i32_s");
|
|
1125
|
-
} else if (localInfo.type === "i64" && targetWasmType === "i32") {
|
|
1126
|
-
this.pushInstruction("i32.wrap_i64");
|
|
1127
|
-
}
|
|
1206
|
+
this._coerceIntWidth(localInfo.type, targetWasmType);
|
|
1128
1207
|
return;
|
|
1129
1208
|
}
|
|
1130
1209
|
|
|
1131
1210
|
if (this.cachedGlobals.has(ident.name)) {
|
|
1132
1211
|
const cached = this.cachedGlobals.get(ident.name);
|
|
1133
1212
|
this.pushInstruction({ op: "local.get", index: cached.index });
|
|
1134
|
-
|
|
1135
|
-
this.pushInstruction("i64.extend_i32_s");
|
|
1136
|
-
} else if (cached.globalInfo.type === "i64" && targetWasmType === "i32") {
|
|
1137
|
-
this.pushInstruction("i32.wrap_i64");
|
|
1138
|
-
}
|
|
1213
|
+
this._coerceIntWidth(cached.globalInfo.type, targetWasmType);
|
|
1139
1214
|
return;
|
|
1140
1215
|
}
|
|
1141
1216
|
|
|
1142
1217
|
const globalInfo = this.mod.resolveGlobal(ident.name);
|
|
1143
1218
|
if (globalInfo) {
|
|
1144
1219
|
this.pushInstruction({ op: "global.get", index: globalInfo.index });
|
|
1145
|
-
|
|
1146
|
-
this.pushInstruction("i64.extend_i32_s");
|
|
1147
|
-
} else if (globalInfo.type === "i64" && targetWasmType === "i32") {
|
|
1148
|
-
this.pushInstruction("i32.wrap_i64");
|
|
1149
|
-
}
|
|
1220
|
+
this._coerceIntWidth(globalInfo.type, targetWasmType);
|
|
1150
1221
|
return;
|
|
1151
1222
|
}
|
|
1152
1223
|
|
|
@@ -1158,11 +1229,6 @@ export class ExprsEmitter {
|
|
|
1158
1229
|
);
|
|
1159
1230
|
return;
|
|
1160
1231
|
}
|
|
1161
|
-
if (this.mod.isNonLiteralConst(ident.name)) {
|
|
1162
|
-
throw new Error(
|
|
1163
|
-
`constant '${ident.name}' has a non-literal value, which the wasm backend does not support yet (planned)`,
|
|
1164
|
-
);
|
|
1165
|
-
}
|
|
1166
1232
|
|
|
1167
1233
|
const trampName = `_tramp$${ident.name}`;
|
|
1168
1234
|
const trampFuncIdx = this.mod.resolveFuncIndex(trampName);
|
|
@@ -1256,6 +1322,13 @@ export class ExprsEmitter {
|
|
|
1256
1322
|
break;
|
|
1257
1323
|
|
|
1258
1324
|
case "&": {
|
|
1325
|
+
if (operand.kind === "Ident") {
|
|
1326
|
+
const loc = this.resolveLocal(operand.name);
|
|
1327
|
+
if (loc?.isBoxed) {
|
|
1328
|
+
this.pushInstruction({ op: "local.get", index: loc.index });
|
|
1329
|
+
return;
|
|
1330
|
+
}
|
|
1331
|
+
}
|
|
1259
1332
|
if (operand.kind === "CompositeLit") {
|
|
1260
1333
|
this.emitExpr(operand);
|
|
1261
1334
|
return;
|
|
@@ -1526,6 +1599,26 @@ export class ExprsEmitter {
|
|
|
1526
1599
|
this.pushInstruction(`${wType}.mul`);
|
|
1527
1600
|
this.emitNarrowIntWrap(goType);
|
|
1528
1601
|
break;
|
|
1602
|
+
case "/":
|
|
1603
|
+
if (wType === "f32" || wType === "f64") {
|
|
1604
|
+
this.pushInstruction(`${wType}.div`);
|
|
1605
|
+
} else {
|
|
1606
|
+
this.pushInstruction(signed ? `${wType}.div_s` : `${wType}.div_u`);
|
|
1607
|
+
this.emitNarrowIntWrap(goType);
|
|
1608
|
+
}
|
|
1609
|
+
break;
|
|
1610
|
+
case "%":
|
|
1611
|
+
this.pushInstruction(signed ? `${wType}.rem_s` : `${wType}.rem_u`);
|
|
1612
|
+
this.emitNarrowIntWrap(goType);
|
|
1613
|
+
break;
|
|
1614
|
+
case "<<":
|
|
1615
|
+
this.pushInstruction(`${wType}.shl`);
|
|
1616
|
+
this.emitNarrowIntWrap(goType);
|
|
1617
|
+
break;
|
|
1618
|
+
case ">>":
|
|
1619
|
+
this.pushInstruction(signed ? `${wType}.shr_s` : `${wType}.shr_u`);
|
|
1620
|
+
this.emitNarrowIntWrap(goType);
|
|
1621
|
+
break;
|
|
1529
1622
|
|
|
1530
1623
|
case "&":
|
|
1531
1624
|
this.pushInstruction(`${wType}.and`);
|
|
@@ -1576,45 +1669,21 @@ export class ExprsEmitter {
|
|
|
1576
1669
|
}
|
|
1577
1670
|
break;
|
|
1578
1671
|
case "<":
|
|
1579
|
-
if (isStringType(goType, this.mod.checker) || wType === "externref") {
|
|
1580
|
-
const cmpIdx = this.mod.getStringCmpImportIndex("<");
|
|
1581
|
-
this.pushInstruction({ op: "call", funcIndex: cmpIdx });
|
|
1582
|
-
} else if (wType === "f32" || wType === "f64") {
|
|
1583
|
-
this.pushInstruction(`${wType}.lt`);
|
|
1584
|
-
} else {
|
|
1585
|
-
this.pushInstruction(`${wType}.lt_${signed ? "s" : "u"}`);
|
|
1586
|
-
}
|
|
1587
|
-
break;
|
|
1588
1672
|
case "<=":
|
|
1589
|
-
if (isStringType(goType, this.mod.checker) || wType === "externref") {
|
|
1590
|
-
const cmpIdx = this.mod.getStringCmpImportIndex("<=");
|
|
1591
|
-
this.pushInstruction({ op: "call", funcIndex: cmpIdx });
|
|
1592
|
-
} else if (wType === "f32" || wType === "f64") {
|
|
1593
|
-
this.pushInstruction(`${wType}.le`);
|
|
1594
|
-
} else {
|
|
1595
|
-
this.pushInstruction(`${wType}.le_${signed ? "s" : "u"}`);
|
|
1596
|
-
}
|
|
1597
|
-
break;
|
|
1598
1673
|
case ">":
|
|
1674
|
+
case ">=": {
|
|
1599
1675
|
if (isStringType(goType, this.mod.checker) || wType === "externref") {
|
|
1600
|
-
const cmpIdx = this.mod.getStringCmpImportIndex(
|
|
1601
|
-
this.pushInstruction({ op: "call", funcIndex: cmpIdx });
|
|
1602
|
-
} else if (wType === "f32" || wType === "f64") {
|
|
1603
|
-
this.pushInstruction(`${wType}.gt`);
|
|
1604
|
-
} else {
|
|
1605
|
-
this.pushInstruction(`${wType}.gt_${signed ? "s" : "u"}`);
|
|
1606
|
-
}
|
|
1607
|
-
break;
|
|
1608
|
-
case ">=":
|
|
1609
|
-
if (isStringType(goType, this.mod.checker) || wType === "externref") {
|
|
1610
|
-
const cmpIdx = this.mod.getStringCmpImportIndex(">=");
|
|
1676
|
+
const cmpIdx = this.mod.getStringCmpImportIndex(op);
|
|
1611
1677
|
this.pushInstruction({ op: "call", funcIndex: cmpIdx });
|
|
1612
|
-
} else if (wType === "f32" || wType === "f64") {
|
|
1613
|
-
this.pushInstruction(`${wType}.ge`);
|
|
1614
1678
|
} else {
|
|
1615
|
-
|
|
1679
|
+
const name =
|
|
1680
|
+
op === "<" ? "lt" : op === "<=" ? "le" : op === ">" ? "gt" : "ge";
|
|
1681
|
+
const suffix =
|
|
1682
|
+
wType === "f32" || wType === "f64" ? "" : `_${signed ? "s" : "u"}`;
|
|
1683
|
+
this.pushInstruction(`${wType}.${name}${suffix}`);
|
|
1616
1684
|
}
|
|
1617
1685
|
break;
|
|
1686
|
+
}
|
|
1618
1687
|
|
|
1619
1688
|
default:
|
|
1620
1689
|
throw new Error(`Unsupported binary operator: ${op}`);
|
|
@@ -1662,6 +1731,56 @@ export class ExprsEmitter {
|
|
|
1662
1731
|
}
|
|
1663
1732
|
|
|
1664
1733
|
const signed = isSigned(goType);
|
|
1734
|
+
const is64 = wType === "i64";
|
|
1735
|
+
const divOp = `${wType}.${op === "/" ? "div" : "rem"}_${signed ? "s" : "u"}`;
|
|
1736
|
+
|
|
1737
|
+
let constDivisor = null;
|
|
1738
|
+
if (right.kind === "BasicLit" && right.litKind === "INT") {
|
|
1739
|
+
try {
|
|
1740
|
+
constDivisor = BigInt(right.value);
|
|
1741
|
+
} catch {}
|
|
1742
|
+
}
|
|
1743
|
+
|
|
1744
|
+
if (constDivisor !== null && constDivisor !== 0n && constDivisor !== -1n) {
|
|
1745
|
+
// Specialize unsigned powers-of-two to shifts or bitwise masks
|
|
1746
|
+
if (
|
|
1747
|
+
!signed &&
|
|
1748
|
+
constDivisor > 0n &&
|
|
1749
|
+
(constDivisor & (constDivisor - 1n)) === 0n
|
|
1750
|
+
) {
|
|
1751
|
+
let k = 0n;
|
|
1752
|
+
let temp = constDivisor;
|
|
1753
|
+
while (temp > 1n) {
|
|
1754
|
+
temp >>= 1n;
|
|
1755
|
+
k++;
|
|
1756
|
+
}
|
|
1757
|
+
if (op === "/") {
|
|
1758
|
+
this.emitExpr(left, wType);
|
|
1759
|
+
this.pushInstruction({
|
|
1760
|
+
op: `${wType}.const`,
|
|
1761
|
+
value: is64 ? k : Number(k),
|
|
1762
|
+
});
|
|
1763
|
+
this.pushInstruction(`${wType}.shr_u`);
|
|
1764
|
+
} else {
|
|
1765
|
+
this.emitExpr(left, wType);
|
|
1766
|
+
this.pushInstruction({
|
|
1767
|
+
op: `${wType}.const`,
|
|
1768
|
+
value: is64 ? constDivisor - 1n : Number(constDivisor - 1n),
|
|
1769
|
+
});
|
|
1770
|
+
this.pushInstruction(`${wType}.and`);
|
|
1771
|
+
}
|
|
1772
|
+
if (!is64) this.emitNarrowIntWrap(goType);
|
|
1773
|
+
return;
|
|
1774
|
+
}
|
|
1775
|
+
|
|
1776
|
+
// Constant divisor != 0 and != -1: no dynamic zero or overflow check needed
|
|
1777
|
+
this.emitExpr(left, wType);
|
|
1778
|
+
this.emitExpr(right, wType);
|
|
1779
|
+
this.pushInstruction(divOp);
|
|
1780
|
+
if (!is64) this.emitNarrowIntWrap(goType);
|
|
1781
|
+
return;
|
|
1782
|
+
}
|
|
1783
|
+
|
|
1665
1784
|
const tmpA = this.acquireTemp(wType);
|
|
1666
1785
|
const tmpB = this.acquireTemp(wType);
|
|
1667
1786
|
|
|
@@ -1678,64 +1797,34 @@ export class ExprsEmitter {
|
|
|
1678
1797
|
this.emitPanic("runtime error: integer divide by zero");
|
|
1679
1798
|
this.pushInstruction("end");
|
|
1680
1799
|
|
|
1681
|
-
if (wType === "i32") {
|
|
1800
|
+
if (wType === "i32" || wType === "i64") {
|
|
1682
1801
|
if (signed) {
|
|
1683
|
-
|
|
1802
|
+
const minVal = is64 ? -9223372036854775808n : -2147483648;
|
|
1803
|
+
const negOne = is64 ? -1n : -1;
|
|
1804
|
+
const zeroVal = is64 ? 0n : 0;
|
|
1684
1805
|
this.pushInstruction({ op: "local.get", index: tmpA });
|
|
1685
|
-
this.pushInstruction({ op:
|
|
1686
|
-
this.pushInstruction(
|
|
1806
|
+
this.pushInstruction({ op: `${wType}.const`, value: minVal });
|
|
1807
|
+
this.pushInstruction(`${wType}.eq`);
|
|
1687
1808
|
this.pushInstruction({ op: "local.get", index: tmpB });
|
|
1688
|
-
this.pushInstruction({ op:
|
|
1689
|
-
this.pushInstruction(
|
|
1809
|
+
this.pushInstruction({ op: `${wType}.const`, value: negOne });
|
|
1810
|
+
this.pushInstruction(`${wType}.eq`);
|
|
1690
1811
|
this.pushInstruction("i32.and");
|
|
1691
|
-
this.pushInstruction({ op: "if", blockType:
|
|
1692
|
-
if (op === "/") {
|
|
1693
|
-
this.pushInstruction({ op: "i32.const", value: -2147483648 });
|
|
1694
|
-
} else {
|
|
1695
|
-
this.pushInstruction({ op: "i32.const", value: 0 });
|
|
1696
|
-
}
|
|
1697
|
-
this.pushInstruction("else");
|
|
1698
|
-
this.pushInstruction({ op: "local.get", index: tmpA });
|
|
1699
|
-
this.pushInstruction({ op: "local.get", index: tmpB });
|
|
1700
|
-
this.pushInstruction(op === "/" ? "i32.div_s" : "i32.rem_s");
|
|
1701
|
-
this.pushInstruction("end");
|
|
1702
|
-
} else {
|
|
1703
|
-
this.pushInstruction({ op: "local.get", index: tmpA });
|
|
1704
|
-
this.pushInstruction({ op: "local.get", index: tmpB });
|
|
1705
|
-
this.pushInstruction(op === "/" ? "i32.div_u" : "i32.rem_u");
|
|
1706
|
-
}
|
|
1707
|
-
this.emitNarrowIntWrap(goType);
|
|
1708
|
-
} else if (wType === "i64") {
|
|
1709
|
-
if (signed) {
|
|
1710
|
-
this.pushInstruction({ op: "local.get", index: tmpA });
|
|
1812
|
+
this.pushInstruction({ op: "if", blockType: wType });
|
|
1711
1813
|
this.pushInstruction({
|
|
1712
|
-
op:
|
|
1713
|
-
value:
|
|
1814
|
+
op: `${wType}.const`,
|
|
1815
|
+
value: op === "/" ? minVal : zeroVal,
|
|
1714
1816
|
});
|
|
1715
|
-
this.pushInstruction("i64.eq");
|
|
1716
|
-
this.pushInstruction({ op: "local.get", index: tmpB });
|
|
1717
|
-
this.pushInstruction({ op: "i64.const", value: -1n });
|
|
1718
|
-
this.pushInstruction("i64.eq");
|
|
1719
|
-
this.pushInstruction("i32.and");
|
|
1720
|
-
this.pushInstruction({ op: "if", blockType: "i64" });
|
|
1721
|
-
if (op === "/") {
|
|
1722
|
-
this.pushInstruction({
|
|
1723
|
-
op: "i64.const",
|
|
1724
|
-
value: -9223372036854775808n,
|
|
1725
|
-
});
|
|
1726
|
-
} else {
|
|
1727
|
-
this.pushInstruction({ op: "i64.const", value: 0n });
|
|
1728
|
-
}
|
|
1729
1817
|
this.pushInstruction("else");
|
|
1730
1818
|
this.pushInstruction({ op: "local.get", index: tmpA });
|
|
1731
1819
|
this.pushInstruction({ op: "local.get", index: tmpB });
|
|
1732
|
-
this.pushInstruction(
|
|
1820
|
+
this.pushInstruction(divOp);
|
|
1733
1821
|
this.pushInstruction("end");
|
|
1734
1822
|
} else {
|
|
1735
1823
|
this.pushInstruction({ op: "local.get", index: tmpA });
|
|
1736
1824
|
this.pushInstruction({ op: "local.get", index: tmpB });
|
|
1737
|
-
this.pushInstruction(
|
|
1825
|
+
this.pushInstruction(divOp);
|
|
1738
1826
|
}
|
|
1827
|
+
if (!is64) this.emitNarrowIntWrap(goType);
|
|
1739
1828
|
}
|
|
1740
1829
|
|
|
1741
1830
|
this.releaseTemp(tmpB, wType);
|
|
@@ -1747,6 +1836,10 @@ export class ExprsEmitter {
|
|
|
1747
1836
|
const wType = targetWasmType ?? toWasmType(goType, this.mod.checker);
|
|
1748
1837
|
const signed = isSigned(goType);
|
|
1749
1838
|
const rightWType = toWasmType(right._type, this.mod.checker);
|
|
1839
|
+
const is64 = wType === "i64";
|
|
1840
|
+
const zeroVal = is64 ? 0n : 0;
|
|
1841
|
+
const negOne = is64 ? -1n : -1;
|
|
1842
|
+
const widthVal = is64 ? 64n : 32;
|
|
1750
1843
|
|
|
1751
1844
|
const tmpVal = this.acquireTemp(wType);
|
|
1752
1845
|
const tmpShift = this.acquireTemp(wType);
|
|
@@ -1762,68 +1855,34 @@ export class ExprsEmitter {
|
|
|
1762
1855
|
}
|
|
1763
1856
|
this.pushInstruction({ op: "local.set", index: tmpShift });
|
|
1764
1857
|
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
this.pushInstruction({ op: "if", blockType: "i32" });
|
|
1770
|
-
|
|
1771
|
-
if (op === ">>" && signed) {
|
|
1772
|
-
this.pushInstruction({ op: "local.get", index: tmpVal });
|
|
1773
|
-
this.pushInstruction({ op: "i32.const", value: 0 });
|
|
1774
|
-
this.pushInstruction("i32.lt_s");
|
|
1775
|
-
this.pushInstruction({ op: "if", blockType: "i32" });
|
|
1776
|
-
this.pushInstruction({ op: "i32.const", value: -1 });
|
|
1777
|
-
this.pushInstruction("else");
|
|
1778
|
-
this.pushInstruction({ op: "i32.const", value: 0 });
|
|
1779
|
-
this.pushInstruction("end");
|
|
1780
|
-
} else {
|
|
1781
|
-
this.pushInstruction({ op: "i32.const", value: 0 });
|
|
1782
|
-
}
|
|
1783
|
-
|
|
1784
|
-
this.pushInstruction("else");
|
|
1858
|
+
this.pushInstruction({ op: "local.get", index: tmpShift });
|
|
1859
|
+
this.pushInstruction({ op: `${wType}.const`, value: widthVal });
|
|
1860
|
+
this.pushInstruction(`${wType}.ge_u`);
|
|
1861
|
+
this.pushInstruction({ op: "if", blockType: wType });
|
|
1785
1862
|
|
|
1863
|
+
if (op === ">>" && signed) {
|
|
1786
1864
|
this.pushInstruction({ op: "local.get", index: tmpVal });
|
|
1787
|
-
this.pushInstruction({ op:
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
}
|
|
1791
|
-
|
|
1792
|
-
}
|
|
1793
|
-
|
|
1865
|
+
this.pushInstruction({ op: `${wType}.const`, value: zeroVal });
|
|
1866
|
+
this.pushInstruction(`${wType}.lt_s`);
|
|
1867
|
+
this.pushInstruction({ op: "if", blockType: wType });
|
|
1868
|
+
this.pushInstruction({ op: `${wType}.const`, value: negOne });
|
|
1869
|
+
this.pushInstruction("else");
|
|
1870
|
+
this.pushInstruction({ op: `${wType}.const`, value: zeroVal });
|
|
1794
1871
|
this.pushInstruction("end");
|
|
1795
|
-
this.emitNarrowIntWrap(goType);
|
|
1796
1872
|
} else {
|
|
1797
|
-
this.pushInstruction({ op:
|
|
1798
|
-
|
|
1799
|
-
this.pushInstruction("i64.ge_u");
|
|
1800
|
-
this.pushInstruction({ op: "if", blockType: "i64" });
|
|
1801
|
-
|
|
1802
|
-
if (op === ">>" && signed) {
|
|
1803
|
-
this.pushInstruction({ op: "local.get", index: tmpVal });
|
|
1804
|
-
this.pushInstruction({ op: "i64.const", value: 0n });
|
|
1805
|
-
this.pushInstruction("i64.lt_s");
|
|
1806
|
-
this.pushInstruction({ op: "if", blockType: "i64" });
|
|
1807
|
-
this.pushInstruction({ op: "i64.const", value: -1n });
|
|
1808
|
-
this.pushInstruction("else");
|
|
1809
|
-
this.pushInstruction({ op: "i64.const", value: 0n });
|
|
1810
|
-
this.pushInstruction("end");
|
|
1811
|
-
} else {
|
|
1812
|
-
this.pushInstruction({ op: "i64.const", value: 0n });
|
|
1813
|
-
}
|
|
1873
|
+
this.pushInstruction({ op: `${wType}.const`, value: zeroVal });
|
|
1874
|
+
}
|
|
1814
1875
|
|
|
1815
|
-
|
|
1876
|
+
this.pushInstruction("else");
|
|
1816
1877
|
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
this.pushInstruction(signed ? "i64.shr_s" : "i64.shr_u");
|
|
1823
|
-
}
|
|
1878
|
+
this.pushInstruction({ op: "local.get", index: tmpVal });
|
|
1879
|
+
this.pushInstruction({ op: "local.get", index: tmpShift });
|
|
1880
|
+
this.pushInstruction(
|
|
1881
|
+
op === "<<" ? `${wType}.shl` : `${wType}.shr_${signed ? "s" : "u"}`,
|
|
1882
|
+
);
|
|
1824
1883
|
|
|
1825
|
-
|
|
1826
|
-
|
|
1884
|
+
this.pushInstruction("end");
|
|
1885
|
+
if (!is64) this.emitNarrowIntWrap(goType);
|
|
1827
1886
|
|
|
1828
1887
|
this.releaseTemp(tmpShift, wType);
|
|
1829
1888
|
this.releaseTemp(tmpVal, wType);
|
|
@@ -1842,6 +1901,24 @@ export class ExprsEmitter {
|
|
|
1842
1901
|
return;
|
|
1843
1902
|
}
|
|
1844
1903
|
|
|
1904
|
+
if (
|
|
1905
|
+
fromWType === "externref" &&
|
|
1906
|
+
isSliceType(targetType, this.mod.checker) &&
|
|
1907
|
+
(targetType.elem?.name === "byte" || targetType.elem?.name === "uint8")
|
|
1908
|
+
) {
|
|
1909
|
+
this._emitStringToByteSlice(targetType);
|
|
1910
|
+
return;
|
|
1911
|
+
}
|
|
1912
|
+
|
|
1913
|
+
if (
|
|
1914
|
+
toWType === "externref" &&
|
|
1915
|
+
isSliceType(fromType, this.mod.checker) &&
|
|
1916
|
+
(fromType.elem?.name === "byte" || fromType.elem?.name === "uint8")
|
|
1917
|
+
) {
|
|
1918
|
+
this._emitByteSliceToString(fromType);
|
|
1919
|
+
return;
|
|
1920
|
+
}
|
|
1921
|
+
|
|
1845
1922
|
if (toWType === "externref") {
|
|
1846
1923
|
if (fromWType === "i64") {
|
|
1847
1924
|
this.pushInstruction("i32.wrap_i64");
|
|
@@ -1858,51 +1935,173 @@ export class ExprsEmitter {
|
|
|
1858
1935
|
return;
|
|
1859
1936
|
}
|
|
1860
1937
|
|
|
1938
|
+
const srcSign = isSigned(fromType) ? "s" : "u";
|
|
1939
|
+
const dstSign = isSigned(targetType) ? "s" : "u";
|
|
1861
1940
|
if (fromWType === "i32" && toWType === "i64") {
|
|
1862
|
-
this.pushInstruction(
|
|
1863
|
-
isSigned(fromType) ? "i64.extend_i32_s" : "i64.extend_i32_u",
|
|
1864
|
-
);
|
|
1941
|
+
this.pushInstruction(`i64.extend_i32_${srcSign}`);
|
|
1865
1942
|
} else if (fromWType === "i64" && toWType === "i32") {
|
|
1866
1943
|
this.pushInstruction("i32.wrap_i64");
|
|
1867
1944
|
this.emitNarrowIntWrap(targetType);
|
|
1868
|
-
} else if (
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
this.pushInstruction(
|
|
1874
|
-
isSigned(fromType) ? "f64.convert_i32_s" : "f64.convert_i32_u",
|
|
1875
|
-
);
|
|
1876
|
-
} else if (fromWType === "i64" && toWType === "f32") {
|
|
1877
|
-
this.pushInstruction(
|
|
1878
|
-
isSigned(fromType) ? "f32.convert_i64_s" : "f32.convert_i64_u",
|
|
1879
|
-
);
|
|
1880
|
-
} else if (fromWType === "i64" && toWType === "f64") {
|
|
1881
|
-
this.pushInstruction(
|
|
1882
|
-
isSigned(fromType) ? "f64.convert_i64_s" : "f64.convert_i64_u",
|
|
1883
|
-
);
|
|
1945
|
+
} else if (
|
|
1946
|
+
(fromWType === "i32" || fromWType === "i64") &&
|
|
1947
|
+
(toWType === "f32" || toWType === "f64")
|
|
1948
|
+
) {
|
|
1949
|
+
this.pushInstruction(`${toWType}.convert_${fromWType}_${srcSign}`);
|
|
1884
1950
|
} else if (fromWType === "f32" && toWType === "f64") {
|
|
1885
1951
|
this.pushInstruction("f64.promote_f32");
|
|
1886
1952
|
} else if (fromWType === "f64" && toWType === "f32") {
|
|
1887
1953
|
this.pushInstruction("f32.demote_f64");
|
|
1888
|
-
} else if (
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
this.
|
|
1893
|
-
|
|
1894
|
-
this.pushInstruction(
|
|
1895
|
-
isSigned(targetType) ? "i32.trunc_sat_f32_s" : "i32.trunc_sat_f32_u",
|
|
1896
|
-
);
|
|
1897
|
-
this.emitNarrowIntWrap(targetType);
|
|
1898
|
-
} else if (fromWType === "f64" && toWType === "i64") {
|
|
1899
|
-
this.pushInstruction(
|
|
1900
|
-
isSigned(targetType) ? "i64.trunc_sat_f64_s" : "i64.trunc_sat_f64_u",
|
|
1901
|
-
);
|
|
1902
|
-
} else if (fromWType === "f32" && toWType === "i64") {
|
|
1903
|
-
this.pushInstruction(
|
|
1904
|
-
isSigned(targetType) ? "i64.trunc_sat_f32_s" : "i64.trunc_sat_f32_u",
|
|
1905
|
-
);
|
|
1954
|
+
} else if (
|
|
1955
|
+
(fromWType === "f32" || fromWType === "f64") &&
|
|
1956
|
+
(toWType === "i32" || toWType === "i64")
|
|
1957
|
+
) {
|
|
1958
|
+
this.pushInstruction(`${toWType}.trunc_sat_${fromWType}_${dstSign}`);
|
|
1959
|
+
if (toWType === "i32") this.emitNarrowIntWrap(targetType);
|
|
1906
1960
|
}
|
|
1907
1961
|
}
|
|
1962
|
+
|
|
1963
|
+
_emitStringToByteSlice(targetType) {
|
|
1964
|
+
const elemGo = targetType.elem;
|
|
1965
|
+
const sliceInfo = this.mod.getSliceType(elemGo);
|
|
1966
|
+
const arrInfo = sliceInfo.arrInfo;
|
|
1967
|
+
const strTmp = this.acquireTemp("externref");
|
|
1968
|
+
this.pushInstruction({ op: "local.set", index: strTmp });
|
|
1969
|
+
const lenTmp = this.acquireTemp("i32");
|
|
1970
|
+
this.pushInstruction({ op: "local.get", index: strTmp });
|
|
1971
|
+
this.pushInstruction({
|
|
1972
|
+
op: "call",
|
|
1973
|
+
funcIndex: this.mod.getStrToBytesImportIndex(),
|
|
1974
|
+
});
|
|
1975
|
+
this.pushInstruction({ op: "local.tee", index: lenTmp });
|
|
1976
|
+
this.pushInstruction({
|
|
1977
|
+
op: "array.new_default",
|
|
1978
|
+
typeIndex: arrInfo.typeIndex,
|
|
1979
|
+
});
|
|
1980
|
+
const arrTmp = this.acquireTemp({
|
|
1981
|
+
kind: "ref",
|
|
1982
|
+
nullable: true,
|
|
1983
|
+
typeIndex: arrInfo.typeIndex,
|
|
1984
|
+
});
|
|
1985
|
+
this.pushInstruction({ op: "local.set", index: arrTmp });
|
|
1986
|
+
const iTmp = this.acquireTemp("i32");
|
|
1987
|
+
this.pushInstruction({ op: "i32.const", value: 0 });
|
|
1988
|
+
this.pushInstruction({ op: "local.set", index: iTmp });
|
|
1989
|
+
|
|
1990
|
+
this.pushInstruction({ op: "block", blockType: "void" });
|
|
1991
|
+
this.pushInstruction({ op: "loop", blockType: "void" });
|
|
1992
|
+
this.pushInstruction({ op: "local.get", index: iTmp });
|
|
1993
|
+
this.pushInstruction({ op: "local.get", index: lenTmp });
|
|
1994
|
+
this.pushInstruction("i32.ge_s");
|
|
1995
|
+
this.pushInstruction({ op: "br_if", depth: 1 });
|
|
1996
|
+
|
|
1997
|
+
this.pushInstruction({ op: "local.get", index: arrTmp });
|
|
1998
|
+
this.pushInstruction({ op: "local.get", index: iTmp });
|
|
1999
|
+
this.pushInstruction({ op: "local.get", index: iTmp });
|
|
2000
|
+
this.pushInstruction({
|
|
2001
|
+
op: "call",
|
|
2002
|
+
funcIndex: this.mod.getStrByteAtImportIndex(),
|
|
2003
|
+
});
|
|
2004
|
+
this.pushInstruction({ op: "array.set", typeIndex: arrInfo.typeIndex });
|
|
2005
|
+
|
|
2006
|
+
this.pushInstruction({ op: "local.get", index: iTmp });
|
|
2007
|
+
this.pushInstruction({ op: "i32.const", value: 1 });
|
|
2008
|
+
this.pushInstruction("i32.add");
|
|
2009
|
+
this.pushInstruction({ op: "local.set", index: iTmp });
|
|
2010
|
+
this.pushInstruction({ op: "br", depth: 0 });
|
|
2011
|
+
this.pushInstruction("end");
|
|
2012
|
+
this.pushInstruction("end");
|
|
2013
|
+
|
|
2014
|
+
this.pushInstruction({ op: "local.get", index: arrTmp });
|
|
2015
|
+
this.pushInstruction({ op: "i32.const", value: 0 });
|
|
2016
|
+
this.pushInstruction({ op: "local.get", index: lenTmp });
|
|
2017
|
+
this.pushInstruction({ op: "local.get", index: lenTmp });
|
|
2018
|
+
this.pushInstruction({
|
|
2019
|
+
op: "struct.new",
|
|
2020
|
+
typeIndex: sliceInfo.typeIndex,
|
|
2021
|
+
});
|
|
2022
|
+
|
|
2023
|
+
this.releaseTemp(arrTmp, {
|
|
2024
|
+
kind: "ref",
|
|
2025
|
+
nullable: true,
|
|
2026
|
+
typeIndex: arrInfo.typeIndex,
|
|
2027
|
+
});
|
|
2028
|
+
this.releaseTemp(iTmp, "i32");
|
|
2029
|
+
this.releaseTemp(lenTmp, "i32");
|
|
2030
|
+
this.releaseTemp(strTmp, "externref");
|
|
2031
|
+
}
|
|
2032
|
+
|
|
2033
|
+
_emitByteSliceToString(fromType) {
|
|
2034
|
+
const elemGo = fromType.elem;
|
|
2035
|
+
const sliceInfo = this.mod.getSliceType(elemGo);
|
|
2036
|
+
const arrInfo = sliceInfo.arrInfo;
|
|
2037
|
+
const sliceW = {
|
|
2038
|
+
kind: "ref",
|
|
2039
|
+
nullable: true,
|
|
2040
|
+
typeIndex: sliceInfo.typeIndex,
|
|
2041
|
+
};
|
|
2042
|
+
const arrW = {
|
|
2043
|
+
kind: "ref",
|
|
2044
|
+
nullable: true,
|
|
2045
|
+
typeIndex: arrInfo.typeIndex,
|
|
2046
|
+
};
|
|
2047
|
+
const sTmp = this.acquireTemp(sliceW);
|
|
2048
|
+
this.pushInstruction({ op: "local.set", index: sTmp });
|
|
2049
|
+
const arrTmp = this.acquireTemp(arrW);
|
|
2050
|
+
const offTmp = this.acquireTemp("i32");
|
|
2051
|
+
const lenTmp = this.acquireTemp("i32");
|
|
2052
|
+
const capTmp = this.acquireTemp("i32");
|
|
2053
|
+
this._emitSliceUnpack(sTmp, sliceInfo, {
|
|
2054
|
+
arr: arrTmp,
|
|
2055
|
+
off: offTmp,
|
|
2056
|
+
len: lenTmp,
|
|
2057
|
+
cap: capTmp,
|
|
2058
|
+
});
|
|
2059
|
+
this.releaseTemp(sTmp, sliceW);
|
|
2060
|
+
this.releaseTemp(capTmp, "i32");
|
|
2061
|
+
|
|
2062
|
+
this.pushInstruction({ op: "local.get", index: lenTmp });
|
|
2063
|
+
this.pushInstruction({
|
|
2064
|
+
op: "call",
|
|
2065
|
+
funcIndex: this.mod.getBytesToStrInitImportIndex(),
|
|
2066
|
+
});
|
|
2067
|
+
|
|
2068
|
+
const iTmp = this.acquireTemp("i32");
|
|
2069
|
+
this.pushInstruction({ op: "i32.const", value: 0 });
|
|
2070
|
+
this.pushInstruction({ op: "local.set", index: iTmp });
|
|
2071
|
+
|
|
2072
|
+
this.pushInstruction({ op: "block", blockType: "void" });
|
|
2073
|
+
this.pushInstruction({ op: "loop", blockType: "void" });
|
|
2074
|
+
this.pushInstruction({ op: "local.get", index: iTmp });
|
|
2075
|
+
this.pushInstruction({ op: "local.get", index: lenTmp });
|
|
2076
|
+
this.pushInstruction("i32.ge_s");
|
|
2077
|
+
this.pushInstruction({ op: "br_if", depth: 1 });
|
|
2078
|
+
|
|
2079
|
+
this.pushInstruction({ op: "local.get", index: arrTmp });
|
|
2080
|
+
this.pushInstruction({ op: "local.get", index: offTmp });
|
|
2081
|
+
this.pushInstruction({ op: "local.get", index: iTmp });
|
|
2082
|
+
this.pushInstruction("i32.add");
|
|
2083
|
+
this.pushInstruction({ op: "array.get", typeIndex: arrInfo.typeIndex });
|
|
2084
|
+
this.pushInstruction({
|
|
2085
|
+
op: "call",
|
|
2086
|
+
funcIndex: this.mod.getBytesToStrPushImportIndex(),
|
|
2087
|
+
});
|
|
2088
|
+
|
|
2089
|
+
this.pushInstruction({ op: "local.get", index: iTmp });
|
|
2090
|
+
this.pushInstruction({ op: "i32.const", value: 1 });
|
|
2091
|
+
this.pushInstruction("i32.add");
|
|
2092
|
+
this.pushInstruction({ op: "local.set", index: iTmp });
|
|
2093
|
+
this.pushInstruction({ op: "br", depth: 0 });
|
|
2094
|
+
this.pushInstruction("end");
|
|
2095
|
+
this.pushInstruction("end");
|
|
2096
|
+
|
|
2097
|
+
this.pushInstruction({
|
|
2098
|
+
op: "call",
|
|
2099
|
+
funcIndex: this.mod.getBytesToStrFinishImportIndex(),
|
|
2100
|
+
});
|
|
2101
|
+
|
|
2102
|
+
this.releaseTemp(iTmp, "i32");
|
|
2103
|
+
this.releaseTemp(lenTmp, "i32");
|
|
2104
|
+
this.releaseTemp(offTmp, "i32");
|
|
2105
|
+
this.releaseTemp(arrTmp, arrW);
|
|
2106
|
+
}
|
|
1908
2107
|
}
|