gofront 1.6.0 → 1.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/backend/js/expressions.js +238 -109
- package/src/backend/js/index.js +38 -1
- package/src/backend/js/runtime.js +953 -53
- package/src/backend/js/statements.js +55 -67
- 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 +20 -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 +16 -0
- package/src/backend/js/stdlib/io.js +105 -3
- 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/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 +1207 -41
- package/src/backend/wasm/const-fold.js +205 -0
- package/src/backend/wasm/emit-builtins.js +203 -76
- package/src/backend/wasm/emit-exprs.js +464 -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 +115 -87
- package/src/backend/wasm/encode.js +55 -29
- package/src/backend/wasm/index.js +1001 -32
- package/src/backend/wasm/optimize.js +13 -4
- 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 +40 -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/time.js +1200 -0
- package/src/backend/wasm/types.js +153 -1
- package/src/cli-core.js +1 -1
- package/src/compiler.js +18 -4
- package/src/dts-parser.js +79 -126
- package/src/index.js +2 -6
- package/src/lexer.js +80 -29
- package/src/lower/boxing.js +1 -2
- package/src/lower/captures.js +2 -6
- 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/types.js +1 -2
- 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 +81 -13
- package/src/typechecker/expressions.js +102 -2
- package/src/typechecker/resolve.js +36 -6
- package/src/typechecker/stdlib/core.js +280 -89
- package/src/typechecker/stdlib/extended.js +453 -1
- package/src/typechecker/types.js +344 -6
|
@@ -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) {
|
|
@@ -363,7 +364,10 @@ export class ExprsEmitter {
|
|
|
363
364
|
const typeName =
|
|
364
365
|
lit.typeExpr?.name ??
|
|
365
366
|
(litType?.kind === "named" ? litType.name : litType?.name);
|
|
366
|
-
|
|
367
|
+
let structInfo = typeName ? this.mod.getStructType(typeName) : null;
|
|
368
|
+
if (!structInfo) {
|
|
369
|
+
structInfo = this._resolveStructInfo(lit);
|
|
370
|
+
}
|
|
367
371
|
if (!structInfo) {
|
|
368
372
|
throw new Error(`Unknown struct in CompositeLit: ${typeName}`);
|
|
369
373
|
}
|
|
@@ -780,6 +784,59 @@ export class ExprsEmitter {
|
|
|
780
784
|
this.pushInstruction({ op: "local.set", index: dstArrTmp });
|
|
781
785
|
|
|
782
786
|
const iTmp = this.acquireTemp("i32");
|
|
787
|
+
|
|
788
|
+
// If copying within the same array and shifting right (dstOff > srcOff),
|
|
789
|
+
// copy backwards to prevent clobbering overlapping elements.
|
|
790
|
+
this.pushInstruction({ op: "local.get", index: dstArrTmp });
|
|
791
|
+
this.pushInstruction({ op: "local.get", index: srcArrTmp });
|
|
792
|
+
this.pushInstruction("ref.eq");
|
|
793
|
+
this.pushInstruction({ op: "local.get", index: dstOffTmp });
|
|
794
|
+
this.pushInstruction({ op: "local.get", index: srcOffTmp });
|
|
795
|
+
this.pushInstruction("i32.gt_u");
|
|
796
|
+
this.pushInstruction("i32.and");
|
|
797
|
+
this.pushInstruction({ op: "if", blockType: "void" });
|
|
798
|
+
|
|
799
|
+
// Backwards copy: i from lenTmp - 1 down to 0
|
|
800
|
+
this.pushInstruction({ op: "local.get", index: lenTmp });
|
|
801
|
+
this.pushInstruction({ op: "i32.const", value: 1 });
|
|
802
|
+
this.pushInstruction("i32.sub");
|
|
803
|
+
this.pushInstruction({ op: "local.set", index: iTmp });
|
|
804
|
+
|
|
805
|
+
this.pushInstruction({ op: "block", blockType: "void" });
|
|
806
|
+
this.pushInstruction({ op: "loop", blockType: "void" });
|
|
807
|
+
this.pushInstruction({ op: "local.get", index: iTmp });
|
|
808
|
+
this.pushInstruction({ op: "i32.const", value: 0 });
|
|
809
|
+
this.pushInstruction("i32.lt_s");
|
|
810
|
+
this.pushInstruction({ op: "br_if", depth: 1 });
|
|
811
|
+
|
|
812
|
+
this.pushInstruction({ op: "local.get", index: dstArrTmp });
|
|
813
|
+
this.pushInstruction({ op: "local.get", index: dstOffTmp });
|
|
814
|
+
this.pushInstruction({ op: "local.get", index: iTmp });
|
|
815
|
+
this.pushInstruction("i32.add");
|
|
816
|
+
|
|
817
|
+
this.pushInstruction({ op: "local.get", index: srcArrTmp });
|
|
818
|
+
this.pushInstruction({ op: "local.get", index: srcOffTmp });
|
|
819
|
+
this.pushInstruction({ op: "local.get", index: iTmp });
|
|
820
|
+
this.pushInstruction("i32.add");
|
|
821
|
+
this.pushInstruction({ op: "array.get", typeIndex: arrInfo.typeIndex });
|
|
822
|
+
|
|
823
|
+
if (sInfo) {
|
|
824
|
+
this.emitCloneStruct(sInfo, arrInfo.elemWType);
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
this.pushInstruction({ op: "array.set", typeIndex: arrInfo.typeIndex });
|
|
828
|
+
|
|
829
|
+
this.pushInstruction({ op: "local.get", index: iTmp });
|
|
830
|
+
this.pushInstruction({ op: "i32.const", value: 1 });
|
|
831
|
+
this.pushInstruction("i32.sub");
|
|
832
|
+
this.pushInstruction({ op: "local.set", index: iTmp });
|
|
833
|
+
this.pushInstruction({ op: "br", depth: 0 });
|
|
834
|
+
this.pushInstruction("end");
|
|
835
|
+
this.pushInstruction("end");
|
|
836
|
+
|
|
837
|
+
this.pushInstruction("else");
|
|
838
|
+
|
|
839
|
+
// Forwards copy: i from 0 up to lenTmp - 1
|
|
783
840
|
this.pushInstruction({ op: "i32.const", value: 0 });
|
|
784
841
|
this.pushInstruction({ op: "local.set", index: iTmp });
|
|
785
842
|
|
|
@@ -815,6 +872,8 @@ export class ExprsEmitter {
|
|
|
815
872
|
this.pushInstruction("end");
|
|
816
873
|
this.pushInstruction("end");
|
|
817
874
|
|
|
875
|
+
this.pushInstruction("end");
|
|
876
|
+
|
|
818
877
|
this.releaseTemp(iTmp, "i32");
|
|
819
878
|
this.releaseTemp(dstArrTmp, {
|
|
820
879
|
kind: "ref",
|
|
@@ -964,6 +1023,31 @@ export class ExprsEmitter {
|
|
|
964
1023
|
nullable: true,
|
|
965
1024
|
typeIndex: arrInfo.typeIndex,
|
|
966
1025
|
};
|
|
1026
|
+
|
|
1027
|
+
const rawBaseType = baseNode._type ?? this._resolveExprGoType(baseNode);
|
|
1028
|
+
const baseType =
|
|
1029
|
+
rawBaseType?.kind === "pointer" ? rawBaseType.base : rawBaseType;
|
|
1030
|
+
const arrayLen =
|
|
1031
|
+
baseType?.kind === "array" ? (baseType.len ?? baseType.size) : null;
|
|
1032
|
+
let constIdx = null;
|
|
1033
|
+
if (indexNode.kind === "BasicLit" && indexNode.litKind === "INT") {
|
|
1034
|
+
try {
|
|
1035
|
+
const v = Number(indexNode.value);
|
|
1036
|
+
if (Number.isInteger(v)) constIdx = v;
|
|
1037
|
+
} catch {}
|
|
1038
|
+
}
|
|
1039
|
+
if (
|
|
1040
|
+
arrayLen !== null &&
|
|
1041
|
+
arrayLen !== undefined &&
|
|
1042
|
+
constIdx !== null &&
|
|
1043
|
+
constIdx >= 0 &&
|
|
1044
|
+
constIdx < arrayLen
|
|
1045
|
+
) {
|
|
1046
|
+
this.emitExpr(baseNode, arrWType);
|
|
1047
|
+
this.pushInstruction({ op: "i32.const", value: constIdx });
|
|
1048
|
+
return;
|
|
1049
|
+
}
|
|
1050
|
+
|
|
967
1051
|
const arrTmp = this.acquireTemp(arrWType);
|
|
968
1052
|
this.emitExpr(baseNode, arrWType);
|
|
969
1053
|
this.pushInstruction({ op: "local.tee", index: arrTmp });
|
|
@@ -998,14 +1082,16 @@ export class ExprsEmitter {
|
|
|
998
1082
|
(lit.litKind === "INT" ? "i64" : lit.litKind === "FLOAT" ? "f64" : "i32");
|
|
999
1083
|
|
|
1000
1084
|
if (lit.litKind === "INT") {
|
|
1001
|
-
const
|
|
1085
|
+
const s = String(lit.value);
|
|
1086
|
+
const clean = /^0[0-7]+$/.test(s) ? `0o${s.slice(1)}` : s;
|
|
1087
|
+
const n = Number(clean);
|
|
1002
1088
|
if (wType === "i32") {
|
|
1003
1089
|
this.pushInstruction({ op: "i32.const", value: n | 0 });
|
|
1004
1090
|
} else if (wType === "f64" || wType === "f32") {
|
|
1005
1091
|
// Untyped integer constant in a float context (`x * 2`).
|
|
1006
1092
|
this.pushInstruction({ op: `${wType}.const`, value: n });
|
|
1007
1093
|
} else {
|
|
1008
|
-
this.pushInstruction({ op: "i64.const", value: BigInt(
|
|
1094
|
+
this.pushInstruction({ op: "i64.const", value: BigInt(clean) });
|
|
1009
1095
|
}
|
|
1010
1096
|
return;
|
|
1011
1097
|
}
|
|
@@ -1029,31 +1115,7 @@ export class ExprsEmitter {
|
|
|
1029
1115
|
}
|
|
1030
1116
|
|
|
1031
1117
|
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 });
|
|
1118
|
+
this._emitNilValue(lit._type, targetWasmType);
|
|
1057
1119
|
return;
|
|
1058
1120
|
}
|
|
1059
1121
|
|
|
@@ -1068,6 +1130,42 @@ export class ExprsEmitter {
|
|
|
1068
1130
|
}
|
|
1069
1131
|
}
|
|
1070
1132
|
|
|
1133
|
+
_emitNilValue(goType, targetWasmType) {
|
|
1134
|
+
const effectiveType = targetWasmType ?? this.toWasmType(goType);
|
|
1135
|
+
if (
|
|
1136
|
+
(goType && isSliceType(goType, this.mod.checker)) ||
|
|
1137
|
+
(effectiveType &&
|
|
1138
|
+
typeof effectiveType === "object" &&
|
|
1139
|
+
typeof effectiveType.typeIndex === "number" &&
|
|
1140
|
+
this.mod.getSliceTypeByIndex(effectiveType.typeIndex))
|
|
1141
|
+
) {
|
|
1142
|
+
const elemType = goType ? this._getSliceElemType(goType) : null;
|
|
1143
|
+
const sliceInfo = elemType
|
|
1144
|
+
? this.mod.getSliceType(elemType)
|
|
1145
|
+
: this.mod.getSliceTypeByIndex(effectiveType.typeIndex);
|
|
1146
|
+
if (sliceInfo) {
|
|
1147
|
+
this.pushInstruction({
|
|
1148
|
+
op: "global.get",
|
|
1149
|
+
index: sliceInfo.emptyGlobalIndex,
|
|
1150
|
+
});
|
|
1151
|
+
return;
|
|
1152
|
+
}
|
|
1153
|
+
}
|
|
1154
|
+
const heapType =
|
|
1155
|
+
typeof effectiveType === "object" && effectiveType !== null
|
|
1156
|
+
? (effectiveType.typeIndex ?? effectiveType.heapType ?? "any")
|
|
1157
|
+
: "any";
|
|
1158
|
+
this.pushInstruction({ op: "ref.null", heapType });
|
|
1159
|
+
}
|
|
1160
|
+
|
|
1161
|
+
_coerceIntWidth(srcType, targetWasmType) {
|
|
1162
|
+
if (srcType === "i32" && targetWasmType === "i64") {
|
|
1163
|
+
this.pushInstruction("i64.extend_i32_s");
|
|
1164
|
+
} else if (srcType === "i64" && targetWasmType === "i32") {
|
|
1165
|
+
this.pushInstruction("i32.wrap_i64");
|
|
1166
|
+
}
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1071
1169
|
emitIdent(ident, targetWasmType = null) {
|
|
1072
1170
|
if (ident.name === "true") {
|
|
1073
1171
|
this.pushInstruction({ op: "i32.const", value: 1 });
|
|
@@ -1078,33 +1176,7 @@ export class ExprsEmitter {
|
|
|
1078
1176
|
return;
|
|
1079
1177
|
}
|
|
1080
1178
|
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 });
|
|
1179
|
+
this._emitNilValue(ident._type, targetWasmType);
|
|
1108
1180
|
return;
|
|
1109
1181
|
}
|
|
1110
1182
|
|
|
@@ -1120,33 +1192,21 @@ export class ExprsEmitter {
|
|
|
1120
1192
|
} else {
|
|
1121
1193
|
this.pushInstruction({ op: "local.get", index: localInfo.index });
|
|
1122
1194
|
}
|
|
1123
|
-
|
|
1124
|
-
this.pushInstruction("i64.extend_i32_s");
|
|
1125
|
-
} else if (localInfo.type === "i64" && targetWasmType === "i32") {
|
|
1126
|
-
this.pushInstruction("i32.wrap_i64");
|
|
1127
|
-
}
|
|
1195
|
+
this._coerceIntWidth(localInfo.type, targetWasmType);
|
|
1128
1196
|
return;
|
|
1129
1197
|
}
|
|
1130
1198
|
|
|
1131
1199
|
if (this.cachedGlobals.has(ident.name)) {
|
|
1132
1200
|
const cached = this.cachedGlobals.get(ident.name);
|
|
1133
1201
|
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
|
-
}
|
|
1202
|
+
this._coerceIntWidth(cached.globalInfo.type, targetWasmType);
|
|
1139
1203
|
return;
|
|
1140
1204
|
}
|
|
1141
1205
|
|
|
1142
1206
|
const globalInfo = this.mod.resolveGlobal(ident.name);
|
|
1143
1207
|
if (globalInfo) {
|
|
1144
1208
|
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
|
-
}
|
|
1209
|
+
this._coerceIntWidth(globalInfo.type, targetWasmType);
|
|
1150
1210
|
return;
|
|
1151
1211
|
}
|
|
1152
1212
|
|
|
@@ -1158,11 +1218,6 @@ export class ExprsEmitter {
|
|
|
1158
1218
|
);
|
|
1159
1219
|
return;
|
|
1160
1220
|
}
|
|
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
1221
|
|
|
1167
1222
|
const trampName = `_tramp$${ident.name}`;
|
|
1168
1223
|
const trampFuncIdx = this.mod.resolveFuncIndex(trampName);
|
|
@@ -1256,6 +1311,13 @@ export class ExprsEmitter {
|
|
|
1256
1311
|
break;
|
|
1257
1312
|
|
|
1258
1313
|
case "&": {
|
|
1314
|
+
if (operand.kind === "Ident") {
|
|
1315
|
+
const loc = this.resolveLocal(operand.name);
|
|
1316
|
+
if (loc?.isBoxed) {
|
|
1317
|
+
this.pushInstruction({ op: "local.get", index: loc.index });
|
|
1318
|
+
return;
|
|
1319
|
+
}
|
|
1320
|
+
}
|
|
1259
1321
|
if (operand.kind === "CompositeLit") {
|
|
1260
1322
|
this.emitExpr(operand);
|
|
1261
1323
|
return;
|
|
@@ -1526,6 +1588,26 @@ export class ExprsEmitter {
|
|
|
1526
1588
|
this.pushInstruction(`${wType}.mul`);
|
|
1527
1589
|
this.emitNarrowIntWrap(goType);
|
|
1528
1590
|
break;
|
|
1591
|
+
case "/":
|
|
1592
|
+
if (wType === "f32" || wType === "f64") {
|
|
1593
|
+
this.pushInstruction(`${wType}.div`);
|
|
1594
|
+
} else {
|
|
1595
|
+
this.pushInstruction(signed ? `${wType}.div_s` : `${wType}.div_u`);
|
|
1596
|
+
this.emitNarrowIntWrap(goType);
|
|
1597
|
+
}
|
|
1598
|
+
break;
|
|
1599
|
+
case "%":
|
|
1600
|
+
this.pushInstruction(signed ? `${wType}.rem_s` : `${wType}.rem_u`);
|
|
1601
|
+
this.emitNarrowIntWrap(goType);
|
|
1602
|
+
break;
|
|
1603
|
+
case "<<":
|
|
1604
|
+
this.pushInstruction(`${wType}.shl`);
|
|
1605
|
+
this.emitNarrowIntWrap(goType);
|
|
1606
|
+
break;
|
|
1607
|
+
case ">>":
|
|
1608
|
+
this.pushInstruction(signed ? `${wType}.shr_s` : `${wType}.shr_u`);
|
|
1609
|
+
this.emitNarrowIntWrap(goType);
|
|
1610
|
+
break;
|
|
1529
1611
|
|
|
1530
1612
|
case "&":
|
|
1531
1613
|
this.pushInstruction(`${wType}.and`);
|
|
@@ -1576,45 +1658,21 @@ export class ExprsEmitter {
|
|
|
1576
1658
|
}
|
|
1577
1659
|
break;
|
|
1578
1660
|
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
1661
|
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
1662
|
case ">":
|
|
1663
|
+
case ">=": {
|
|
1599
1664
|
if (isStringType(goType, this.mod.checker) || wType === "externref") {
|
|
1600
|
-
const cmpIdx = this.mod.getStringCmpImportIndex(
|
|
1665
|
+
const cmpIdx = this.mod.getStringCmpImportIndex(op);
|
|
1601
1666
|
this.pushInstruction({ op: "call", funcIndex: cmpIdx });
|
|
1602
|
-
} else if (wType === "f32" || wType === "f64") {
|
|
1603
|
-
this.pushInstruction(`${wType}.gt`);
|
|
1604
1667
|
} else {
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
const cmpIdx = this.mod.getStringCmpImportIndex(">=");
|
|
1611
|
-
this.pushInstruction({ op: "call", funcIndex: cmpIdx });
|
|
1612
|
-
} else if (wType === "f32" || wType === "f64") {
|
|
1613
|
-
this.pushInstruction(`${wType}.ge`);
|
|
1614
|
-
} else {
|
|
1615
|
-
this.pushInstruction(`${wType}.ge_${signed ? "s" : "u"}`);
|
|
1668
|
+
const name =
|
|
1669
|
+
op === "<" ? "lt" : op === "<=" ? "le" : op === ">" ? "gt" : "ge";
|
|
1670
|
+
const suffix =
|
|
1671
|
+
wType === "f32" || wType === "f64" ? "" : `_${signed ? "s" : "u"}`;
|
|
1672
|
+
this.pushInstruction(`${wType}.${name}${suffix}`);
|
|
1616
1673
|
}
|
|
1617
1674
|
break;
|
|
1675
|
+
}
|
|
1618
1676
|
|
|
1619
1677
|
default:
|
|
1620
1678
|
throw new Error(`Unsupported binary operator: ${op}`);
|
|
@@ -1662,6 +1720,56 @@ export class ExprsEmitter {
|
|
|
1662
1720
|
}
|
|
1663
1721
|
|
|
1664
1722
|
const signed = isSigned(goType);
|
|
1723
|
+
const is64 = wType === "i64";
|
|
1724
|
+
const divOp = `${wType}.${op === "/" ? "div" : "rem"}_${signed ? "s" : "u"}`;
|
|
1725
|
+
|
|
1726
|
+
let constDivisor = null;
|
|
1727
|
+
if (right.kind === "BasicLit" && right.litKind === "INT") {
|
|
1728
|
+
try {
|
|
1729
|
+
constDivisor = BigInt(right.value);
|
|
1730
|
+
} catch {}
|
|
1731
|
+
}
|
|
1732
|
+
|
|
1733
|
+
if (constDivisor !== null && constDivisor !== 0n && constDivisor !== -1n) {
|
|
1734
|
+
// Specialize unsigned powers-of-two to shifts or bitwise masks
|
|
1735
|
+
if (
|
|
1736
|
+
!signed &&
|
|
1737
|
+
constDivisor > 0n &&
|
|
1738
|
+
(constDivisor & (constDivisor - 1n)) === 0n
|
|
1739
|
+
) {
|
|
1740
|
+
let k = 0n;
|
|
1741
|
+
let temp = constDivisor;
|
|
1742
|
+
while (temp > 1n) {
|
|
1743
|
+
temp >>= 1n;
|
|
1744
|
+
k++;
|
|
1745
|
+
}
|
|
1746
|
+
if (op === "/") {
|
|
1747
|
+
this.emitExpr(left, wType);
|
|
1748
|
+
this.pushInstruction({
|
|
1749
|
+
op: `${wType}.const`,
|
|
1750
|
+
value: is64 ? k : Number(k),
|
|
1751
|
+
});
|
|
1752
|
+
this.pushInstruction(`${wType}.shr_u`);
|
|
1753
|
+
} else {
|
|
1754
|
+
this.emitExpr(left, wType);
|
|
1755
|
+
this.pushInstruction({
|
|
1756
|
+
op: `${wType}.const`,
|
|
1757
|
+
value: is64 ? constDivisor - 1n : Number(constDivisor - 1n),
|
|
1758
|
+
});
|
|
1759
|
+
this.pushInstruction(`${wType}.and`);
|
|
1760
|
+
}
|
|
1761
|
+
if (!is64) this.emitNarrowIntWrap(goType);
|
|
1762
|
+
return;
|
|
1763
|
+
}
|
|
1764
|
+
|
|
1765
|
+
// Constant divisor != 0 and != -1: no dynamic zero or overflow check needed
|
|
1766
|
+
this.emitExpr(left, wType);
|
|
1767
|
+
this.emitExpr(right, wType);
|
|
1768
|
+
this.pushInstruction(divOp);
|
|
1769
|
+
if (!is64) this.emitNarrowIntWrap(goType);
|
|
1770
|
+
return;
|
|
1771
|
+
}
|
|
1772
|
+
|
|
1665
1773
|
const tmpA = this.acquireTemp(wType);
|
|
1666
1774
|
const tmpB = this.acquireTemp(wType);
|
|
1667
1775
|
|
|
@@ -1678,64 +1786,34 @@ export class ExprsEmitter {
|
|
|
1678
1786
|
this.emitPanic("runtime error: integer divide by zero");
|
|
1679
1787
|
this.pushInstruction("end");
|
|
1680
1788
|
|
|
1681
|
-
if (wType === "i32") {
|
|
1789
|
+
if (wType === "i32" || wType === "i64") {
|
|
1682
1790
|
if (signed) {
|
|
1683
|
-
|
|
1791
|
+
const minVal = is64 ? -9223372036854775808n : -2147483648;
|
|
1792
|
+
const negOne = is64 ? -1n : -1;
|
|
1793
|
+
const zeroVal = is64 ? 0n : 0;
|
|
1684
1794
|
this.pushInstruction({ op: "local.get", index: tmpA });
|
|
1685
|
-
this.pushInstruction({ op:
|
|
1686
|
-
this.pushInstruction(
|
|
1795
|
+
this.pushInstruction({ op: `${wType}.const`, value: minVal });
|
|
1796
|
+
this.pushInstruction(`${wType}.eq`);
|
|
1687
1797
|
this.pushInstruction({ op: "local.get", index: tmpB });
|
|
1688
|
-
this.pushInstruction({ op:
|
|
1689
|
-
this.pushInstruction(
|
|
1798
|
+
this.pushInstruction({ op: `${wType}.const`, value: negOne });
|
|
1799
|
+
this.pushInstruction(`${wType}.eq`);
|
|
1690
1800
|
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 });
|
|
1801
|
+
this.pushInstruction({ op: "if", blockType: wType });
|
|
1711
1802
|
this.pushInstruction({
|
|
1712
|
-
op:
|
|
1713
|
-
value:
|
|
1803
|
+
op: `${wType}.const`,
|
|
1804
|
+
value: op === "/" ? minVal : zeroVal,
|
|
1714
1805
|
});
|
|
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
1806
|
this.pushInstruction("else");
|
|
1730
1807
|
this.pushInstruction({ op: "local.get", index: tmpA });
|
|
1731
1808
|
this.pushInstruction({ op: "local.get", index: tmpB });
|
|
1732
|
-
this.pushInstruction(
|
|
1809
|
+
this.pushInstruction(divOp);
|
|
1733
1810
|
this.pushInstruction("end");
|
|
1734
1811
|
} else {
|
|
1735
1812
|
this.pushInstruction({ op: "local.get", index: tmpA });
|
|
1736
1813
|
this.pushInstruction({ op: "local.get", index: tmpB });
|
|
1737
|
-
this.pushInstruction(
|
|
1814
|
+
this.pushInstruction(divOp);
|
|
1738
1815
|
}
|
|
1816
|
+
if (!is64) this.emitNarrowIntWrap(goType);
|
|
1739
1817
|
}
|
|
1740
1818
|
|
|
1741
1819
|
this.releaseTemp(tmpB, wType);
|
|
@@ -1747,6 +1825,10 @@ export class ExprsEmitter {
|
|
|
1747
1825
|
const wType = targetWasmType ?? toWasmType(goType, this.mod.checker);
|
|
1748
1826
|
const signed = isSigned(goType);
|
|
1749
1827
|
const rightWType = toWasmType(right._type, this.mod.checker);
|
|
1828
|
+
const is64 = wType === "i64";
|
|
1829
|
+
const zeroVal = is64 ? 0n : 0;
|
|
1830
|
+
const negOne = is64 ? -1n : -1;
|
|
1831
|
+
const widthVal = is64 ? 64n : 32;
|
|
1750
1832
|
|
|
1751
1833
|
const tmpVal = this.acquireTemp(wType);
|
|
1752
1834
|
const tmpShift = this.acquireTemp(wType);
|
|
@@ -1762,68 +1844,34 @@ export class ExprsEmitter {
|
|
|
1762
1844
|
}
|
|
1763
1845
|
this.pushInstruction({ op: "local.set", index: tmpShift });
|
|
1764
1846
|
|
|
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");
|
|
1847
|
+
this.pushInstruction({ op: "local.get", index: tmpShift });
|
|
1848
|
+
this.pushInstruction({ op: `${wType}.const`, value: widthVal });
|
|
1849
|
+
this.pushInstruction(`${wType}.ge_u`);
|
|
1850
|
+
this.pushInstruction({ op: "if", blockType: wType });
|
|
1785
1851
|
|
|
1852
|
+
if (op === ">>" && signed) {
|
|
1786
1853
|
this.pushInstruction({ op: "local.get", index: tmpVal });
|
|
1787
|
-
this.pushInstruction({ op:
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
}
|
|
1791
|
-
|
|
1792
|
-
}
|
|
1793
|
-
|
|
1854
|
+
this.pushInstruction({ op: `${wType}.const`, value: zeroVal });
|
|
1855
|
+
this.pushInstruction(`${wType}.lt_s`);
|
|
1856
|
+
this.pushInstruction({ op: "if", blockType: wType });
|
|
1857
|
+
this.pushInstruction({ op: `${wType}.const`, value: negOne });
|
|
1858
|
+
this.pushInstruction("else");
|
|
1859
|
+
this.pushInstruction({ op: `${wType}.const`, value: zeroVal });
|
|
1794
1860
|
this.pushInstruction("end");
|
|
1795
|
-
this.emitNarrowIntWrap(goType);
|
|
1796
1861
|
} 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
|
-
}
|
|
1862
|
+
this.pushInstruction({ op: `${wType}.const`, value: zeroVal });
|
|
1863
|
+
}
|
|
1814
1864
|
|
|
1815
|
-
|
|
1865
|
+
this.pushInstruction("else");
|
|
1816
1866
|
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
this.pushInstruction(signed ? "i64.shr_s" : "i64.shr_u");
|
|
1823
|
-
}
|
|
1867
|
+
this.pushInstruction({ op: "local.get", index: tmpVal });
|
|
1868
|
+
this.pushInstruction({ op: "local.get", index: tmpShift });
|
|
1869
|
+
this.pushInstruction(
|
|
1870
|
+
op === "<<" ? `${wType}.shl` : `${wType}.shr_${signed ? "s" : "u"}`,
|
|
1871
|
+
);
|
|
1824
1872
|
|
|
1825
|
-
|
|
1826
|
-
|
|
1873
|
+
this.pushInstruction("end");
|
|
1874
|
+
if (!is64) this.emitNarrowIntWrap(goType);
|
|
1827
1875
|
|
|
1828
1876
|
this.releaseTemp(tmpShift, wType);
|
|
1829
1877
|
this.releaseTemp(tmpVal, wType);
|
|
@@ -1842,6 +1890,24 @@ export class ExprsEmitter {
|
|
|
1842
1890
|
return;
|
|
1843
1891
|
}
|
|
1844
1892
|
|
|
1893
|
+
if (
|
|
1894
|
+
fromWType === "externref" &&
|
|
1895
|
+
isSliceType(targetType, this.mod.checker) &&
|
|
1896
|
+
(targetType.elem?.name === "byte" || targetType.elem?.name === "uint8")
|
|
1897
|
+
) {
|
|
1898
|
+
this._emitStringToByteSlice(targetType);
|
|
1899
|
+
return;
|
|
1900
|
+
}
|
|
1901
|
+
|
|
1902
|
+
if (
|
|
1903
|
+
toWType === "externref" &&
|
|
1904
|
+
isSliceType(fromType, this.mod.checker) &&
|
|
1905
|
+
(fromType.elem?.name === "byte" || fromType.elem?.name === "uint8")
|
|
1906
|
+
) {
|
|
1907
|
+
this._emitByteSliceToString(fromType);
|
|
1908
|
+
return;
|
|
1909
|
+
}
|
|
1910
|
+
|
|
1845
1911
|
if (toWType === "externref") {
|
|
1846
1912
|
if (fromWType === "i64") {
|
|
1847
1913
|
this.pushInstruction("i32.wrap_i64");
|
|
@@ -1858,51 +1924,173 @@ export class ExprsEmitter {
|
|
|
1858
1924
|
return;
|
|
1859
1925
|
}
|
|
1860
1926
|
|
|
1927
|
+
const srcSign = isSigned(fromType) ? "s" : "u";
|
|
1928
|
+
const dstSign = isSigned(targetType) ? "s" : "u";
|
|
1861
1929
|
if (fromWType === "i32" && toWType === "i64") {
|
|
1862
|
-
this.pushInstruction(
|
|
1863
|
-
isSigned(fromType) ? "i64.extend_i32_s" : "i64.extend_i32_u",
|
|
1864
|
-
);
|
|
1930
|
+
this.pushInstruction(`i64.extend_i32_${srcSign}`);
|
|
1865
1931
|
} else if (fromWType === "i64" && toWType === "i32") {
|
|
1866
1932
|
this.pushInstruction("i32.wrap_i64");
|
|
1867
1933
|
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
|
-
);
|
|
1934
|
+
} else if (
|
|
1935
|
+
(fromWType === "i32" || fromWType === "i64") &&
|
|
1936
|
+
(toWType === "f32" || toWType === "f64")
|
|
1937
|
+
) {
|
|
1938
|
+
this.pushInstruction(`${toWType}.convert_${fromWType}_${srcSign}`);
|
|
1884
1939
|
} else if (fromWType === "f32" && toWType === "f64") {
|
|
1885
1940
|
this.pushInstruction("f64.promote_f32");
|
|
1886
1941
|
} else if (fromWType === "f64" && toWType === "f32") {
|
|
1887
1942
|
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
|
-
);
|
|
1943
|
+
} else if (
|
|
1944
|
+
(fromWType === "f32" || fromWType === "f64") &&
|
|
1945
|
+
(toWType === "i32" || toWType === "i64")
|
|
1946
|
+
) {
|
|
1947
|
+
this.pushInstruction(`${toWType}.trunc_sat_${fromWType}_${dstSign}`);
|
|
1948
|
+
if (toWType === "i32") this.emitNarrowIntWrap(targetType);
|
|
1906
1949
|
}
|
|
1907
1950
|
}
|
|
1951
|
+
|
|
1952
|
+
_emitStringToByteSlice(targetType) {
|
|
1953
|
+
const elemGo = targetType.elem;
|
|
1954
|
+
const sliceInfo = this.mod.getSliceType(elemGo);
|
|
1955
|
+
const arrInfo = sliceInfo.arrInfo;
|
|
1956
|
+
const strTmp = this.acquireTemp("externref");
|
|
1957
|
+
this.pushInstruction({ op: "local.set", index: strTmp });
|
|
1958
|
+
const lenTmp = this.acquireTemp("i32");
|
|
1959
|
+
this.pushInstruction({ op: "local.get", index: strTmp });
|
|
1960
|
+
this.pushInstruction({
|
|
1961
|
+
op: "call",
|
|
1962
|
+
funcIndex: this.mod.getStrToBytesImportIndex(),
|
|
1963
|
+
});
|
|
1964
|
+
this.pushInstruction({ op: "local.tee", index: lenTmp });
|
|
1965
|
+
this.pushInstruction({
|
|
1966
|
+
op: "array.new_default",
|
|
1967
|
+
typeIndex: arrInfo.typeIndex,
|
|
1968
|
+
});
|
|
1969
|
+
const arrTmp = this.acquireTemp({
|
|
1970
|
+
kind: "ref",
|
|
1971
|
+
nullable: true,
|
|
1972
|
+
typeIndex: arrInfo.typeIndex,
|
|
1973
|
+
});
|
|
1974
|
+
this.pushInstruction({ op: "local.set", index: arrTmp });
|
|
1975
|
+
const iTmp = this.acquireTemp("i32");
|
|
1976
|
+
this.pushInstruction({ op: "i32.const", value: 0 });
|
|
1977
|
+
this.pushInstruction({ op: "local.set", index: iTmp });
|
|
1978
|
+
|
|
1979
|
+
this.pushInstruction({ op: "block", blockType: "void" });
|
|
1980
|
+
this.pushInstruction({ op: "loop", blockType: "void" });
|
|
1981
|
+
this.pushInstruction({ op: "local.get", index: iTmp });
|
|
1982
|
+
this.pushInstruction({ op: "local.get", index: lenTmp });
|
|
1983
|
+
this.pushInstruction("i32.ge_s");
|
|
1984
|
+
this.pushInstruction({ op: "br_if", depth: 1 });
|
|
1985
|
+
|
|
1986
|
+
this.pushInstruction({ op: "local.get", index: arrTmp });
|
|
1987
|
+
this.pushInstruction({ op: "local.get", index: iTmp });
|
|
1988
|
+
this.pushInstruction({ op: "local.get", index: iTmp });
|
|
1989
|
+
this.pushInstruction({
|
|
1990
|
+
op: "call",
|
|
1991
|
+
funcIndex: this.mod.getStrByteAtImportIndex(),
|
|
1992
|
+
});
|
|
1993
|
+
this.pushInstruction({ op: "array.set", typeIndex: arrInfo.typeIndex });
|
|
1994
|
+
|
|
1995
|
+
this.pushInstruction({ op: "local.get", index: iTmp });
|
|
1996
|
+
this.pushInstruction({ op: "i32.const", value: 1 });
|
|
1997
|
+
this.pushInstruction("i32.add");
|
|
1998
|
+
this.pushInstruction({ op: "local.set", index: iTmp });
|
|
1999
|
+
this.pushInstruction({ op: "br", depth: 0 });
|
|
2000
|
+
this.pushInstruction("end");
|
|
2001
|
+
this.pushInstruction("end");
|
|
2002
|
+
|
|
2003
|
+
this.pushInstruction({ op: "local.get", index: arrTmp });
|
|
2004
|
+
this.pushInstruction({ op: "i32.const", value: 0 });
|
|
2005
|
+
this.pushInstruction({ op: "local.get", index: lenTmp });
|
|
2006
|
+
this.pushInstruction({ op: "local.get", index: lenTmp });
|
|
2007
|
+
this.pushInstruction({
|
|
2008
|
+
op: "struct.new",
|
|
2009
|
+
typeIndex: sliceInfo.typeIndex,
|
|
2010
|
+
});
|
|
2011
|
+
|
|
2012
|
+
this.releaseTemp(arrTmp, {
|
|
2013
|
+
kind: "ref",
|
|
2014
|
+
nullable: true,
|
|
2015
|
+
typeIndex: arrInfo.typeIndex,
|
|
2016
|
+
});
|
|
2017
|
+
this.releaseTemp(iTmp, "i32");
|
|
2018
|
+
this.releaseTemp(lenTmp, "i32");
|
|
2019
|
+
this.releaseTemp(strTmp, "externref");
|
|
2020
|
+
}
|
|
2021
|
+
|
|
2022
|
+
_emitByteSliceToString(fromType) {
|
|
2023
|
+
const elemGo = fromType.elem;
|
|
2024
|
+
const sliceInfo = this.mod.getSliceType(elemGo);
|
|
2025
|
+
const arrInfo = sliceInfo.arrInfo;
|
|
2026
|
+
const sliceW = {
|
|
2027
|
+
kind: "ref",
|
|
2028
|
+
nullable: true,
|
|
2029
|
+
typeIndex: sliceInfo.typeIndex,
|
|
2030
|
+
};
|
|
2031
|
+
const arrW = {
|
|
2032
|
+
kind: "ref",
|
|
2033
|
+
nullable: true,
|
|
2034
|
+
typeIndex: arrInfo.typeIndex,
|
|
2035
|
+
};
|
|
2036
|
+
const sTmp = this.acquireTemp(sliceW);
|
|
2037
|
+
this.pushInstruction({ op: "local.set", index: sTmp });
|
|
2038
|
+
const arrTmp = this.acquireTemp(arrW);
|
|
2039
|
+
const offTmp = this.acquireTemp("i32");
|
|
2040
|
+
const lenTmp = this.acquireTemp("i32");
|
|
2041
|
+
const capTmp = this.acquireTemp("i32");
|
|
2042
|
+
this._emitSliceUnpack(sTmp, sliceInfo, {
|
|
2043
|
+
arr: arrTmp,
|
|
2044
|
+
off: offTmp,
|
|
2045
|
+
len: lenTmp,
|
|
2046
|
+
cap: capTmp,
|
|
2047
|
+
});
|
|
2048
|
+
this.releaseTemp(sTmp, sliceW);
|
|
2049
|
+
this.releaseTemp(capTmp, "i32");
|
|
2050
|
+
|
|
2051
|
+
this.pushInstruction({ op: "local.get", index: lenTmp });
|
|
2052
|
+
this.pushInstruction({
|
|
2053
|
+
op: "call",
|
|
2054
|
+
funcIndex: this.mod.getBytesToStrInitImportIndex(),
|
|
2055
|
+
});
|
|
2056
|
+
|
|
2057
|
+
const iTmp = this.acquireTemp("i32");
|
|
2058
|
+
this.pushInstruction({ op: "i32.const", value: 0 });
|
|
2059
|
+
this.pushInstruction({ op: "local.set", index: iTmp });
|
|
2060
|
+
|
|
2061
|
+
this.pushInstruction({ op: "block", blockType: "void" });
|
|
2062
|
+
this.pushInstruction({ op: "loop", blockType: "void" });
|
|
2063
|
+
this.pushInstruction({ op: "local.get", index: iTmp });
|
|
2064
|
+
this.pushInstruction({ op: "local.get", index: lenTmp });
|
|
2065
|
+
this.pushInstruction("i32.ge_s");
|
|
2066
|
+
this.pushInstruction({ op: "br_if", depth: 1 });
|
|
2067
|
+
|
|
2068
|
+
this.pushInstruction({ op: "local.get", index: arrTmp });
|
|
2069
|
+
this.pushInstruction({ op: "local.get", index: offTmp });
|
|
2070
|
+
this.pushInstruction({ op: "local.get", index: iTmp });
|
|
2071
|
+
this.pushInstruction("i32.add");
|
|
2072
|
+
this.pushInstruction({ op: "array.get", typeIndex: arrInfo.typeIndex });
|
|
2073
|
+
this.pushInstruction({
|
|
2074
|
+
op: "call",
|
|
2075
|
+
funcIndex: this.mod.getBytesToStrPushImportIndex(),
|
|
2076
|
+
});
|
|
2077
|
+
|
|
2078
|
+
this.pushInstruction({ op: "local.get", index: iTmp });
|
|
2079
|
+
this.pushInstruction({ op: "i32.const", value: 1 });
|
|
2080
|
+
this.pushInstruction("i32.add");
|
|
2081
|
+
this.pushInstruction({ op: "local.set", index: iTmp });
|
|
2082
|
+
this.pushInstruction({ op: "br", depth: 0 });
|
|
2083
|
+
this.pushInstruction("end");
|
|
2084
|
+
this.pushInstruction("end");
|
|
2085
|
+
|
|
2086
|
+
this.pushInstruction({
|
|
2087
|
+
op: "call",
|
|
2088
|
+
funcIndex: this.mod.getBytesToStrFinishImportIndex(),
|
|
2089
|
+
});
|
|
2090
|
+
|
|
2091
|
+
this.releaseTemp(iTmp, "i32");
|
|
2092
|
+
this.releaseTemp(lenTmp, "i32");
|
|
2093
|
+
this.releaseTemp(offTmp, "i32");
|
|
2094
|
+
this.releaseTemp(arrTmp, arrW);
|
|
2095
|
+
}
|
|
1908
2096
|
}
|