porffor 0.17.0-bf4206d7b → 0.17.0-c2dd8f88f
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 +6 -4
- package/compiler/2c.js +28 -11
- package/compiler/assemble.js +19 -4
- package/compiler/builtins/array.ts +79 -9
- package/compiler/builtins/date.ts +104 -106
- package/compiler/builtins/error.js +2 -5
- package/compiler/builtins/math.ts +6 -2
- package/compiler/builtins/set.ts +11 -14
- package/compiler/builtins/string_f64.ts +4 -6
- package/compiler/builtins/symbol.ts +2 -1
- package/compiler/builtins/typedarray.js +94 -0
- package/compiler/builtins/z_ecma262.ts +1 -0
- package/compiler/builtins.js +25 -0
- package/compiler/codegen.js +742 -157
- package/compiler/generated_builtins.js +2761 -668
- package/compiler/pgo.js +9 -1
- package/compiler/precompile.js +4 -2
- package/compiler/prototype.js +0 -69
- package/compiler/types.js +31 -5
- package/compiler/wasmSpec.js +2 -0
- package/compiler/wrap.js +69 -12
- package/package.json +1 -1
- package/rhemyn/README.md +7 -4
- package/rhemyn/compile.js +170 -76
- package/runner/debug.js +1 -1
- package/runner/index.js +5 -3
- package/runner/profile.js +1 -1
- package/runner/repl.js +16 -11
package/compiler/codegen.js
CHANGED
@@ -4,7 +4,7 @@ import { operatorOpcode } from './expression.js';
|
|
4
4
|
import { BuiltinFuncs, BuiltinVars, importedFuncs, NULL, UNDEFINED } from './builtins.js';
|
5
5
|
import { PrototypeFuncs } from './prototype.js';
|
6
6
|
import { number } from './embedding.js';
|
7
|
-
import { TYPES, TYPE_NAMES } from './types.js';
|
7
|
+
import { TYPES, TYPE_FLAGS, TYPE_NAMES, typeHasFlag } from './types.js';
|
8
8
|
import * as Rhemyn from '../rhemyn/compile.js';
|
9
9
|
import parse from './parse.js';
|
10
10
|
import { log } from './log.js';
|
@@ -72,6 +72,9 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
|
|
72
72
|
case 'ExpressionStatement':
|
73
73
|
return generateExp(scope, decl);
|
74
74
|
|
75
|
+
case 'SequenceExpression':
|
76
|
+
return generateSequence(scope, decl);
|
77
|
+
|
75
78
|
case 'CallExpression':
|
76
79
|
return generateCall(scope, decl, global, name, valueUnused);
|
77
80
|
|
@@ -120,6 +123,9 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
|
|
120
123
|
case 'EmptyStatement':
|
121
124
|
return generateEmpty(scope, decl);
|
122
125
|
|
126
|
+
case 'MetaProperty':
|
127
|
+
return generateMeta(scope, decl);
|
128
|
+
|
123
129
|
case 'ConditionalExpression':
|
124
130
|
return generateConditional(scope, decl);
|
125
131
|
|
@@ -264,10 +270,12 @@ const internalThrow = (scope, constructor, message, expectsValue = Prefs.alwaysV
|
|
264
270
|
argument: {
|
265
271
|
type: 'NewExpression',
|
266
272
|
callee: {
|
273
|
+
type: 'Identifier',
|
267
274
|
name: constructor
|
268
275
|
},
|
269
276
|
arguments: [
|
270
277
|
{
|
278
|
+
type: 'Literal',
|
271
279
|
value: message
|
272
280
|
}
|
273
281
|
]
|
@@ -289,12 +297,13 @@ const generateIdent = (scope, decl) => {
|
|
289
297
|
return wasm.slice();
|
290
298
|
}
|
291
299
|
|
292
|
-
|
293
|
-
|
294
|
-
|
300
|
+
// todo: enable this by default in future
|
301
|
+
if (!Object.hasOwn(funcIndex, name) && Object.hasOwn(builtinFuncs, name)) {
|
302
|
+
includeBuiltin(scope, name);
|
303
|
+
return number(funcIndex[name] - importedFuncs.length);
|
295
304
|
}
|
296
305
|
|
297
|
-
if (isExistingProtoFunc(name)) {
|
306
|
+
if (isExistingProtoFunc(name) || Object.hasOwn(internalConstrs, name) || Object.hasOwn(builtinFuncs, name)) {
|
298
307
|
// todo: return an actual something
|
299
308
|
return number(1);
|
300
309
|
}
|
@@ -613,11 +622,14 @@ const compareStrings = (scope, left, right, bytestrings = false) => {
|
|
613
622
|
};
|
614
623
|
|
615
624
|
const truthy = (scope, wasm, type, intIn = false, intOut = false, forceTruthyMode = undefined) => {
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
625
|
+
if (isIntToFloatOp(wasm[wasm.length - 1])) return [
|
626
|
+
...wasm,
|
627
|
+
...(!intIn && intOut ? [ Opcodes.i32_to_u ] : [])
|
628
|
+
];
|
629
|
+
if (isIntOp(wasm[wasm.length - 1])) return [
|
630
|
+
...wasm,
|
631
|
+
...(intOut ? [] : [ Opcodes.i32_from ]),
|
632
|
+
];
|
621
633
|
|
622
634
|
// todo/perf: use knownType and custom bytecode here instead of typeSwitch
|
623
635
|
|
@@ -973,6 +985,33 @@ const performOp = (scope, op, left, right, leftType, rightType, _global = false,
|
|
973
985
|
};
|
974
986
|
|
975
987
|
const generateBinaryExp = (scope, decl, _global, _name) => {
|
988
|
+
if (decl.operator === 'instanceof') {
|
989
|
+
// very hacky basic instanceof
|
990
|
+
// todo: support dynamic right-hand side
|
991
|
+
|
992
|
+
const out = generate(scope, decl.left);
|
993
|
+
disposeLeftover(out);
|
994
|
+
|
995
|
+
const rightName = decl.right.name;
|
996
|
+
if (!rightName) return todo(scope, 'instanceof dynamic right-hand side is not supported yet', true);
|
997
|
+
|
998
|
+
const checkType = TYPES[rightName.toLowerCase()];
|
999
|
+
if (checkType == null || rightName !== TYPE_NAMES[checkType] || checkType === TYPES.undefined) return todo(scope, 'instanceof right-hand side type unsupported', true);
|
1000
|
+
|
1001
|
+
if ([TYPES.number, TYPES.boolean, TYPES.string, TYPES.symbol, TYPES.object].includes(checkType)) {
|
1002
|
+
out.push(...number(0));
|
1003
|
+
} else {
|
1004
|
+
out.push(
|
1005
|
+
...getNodeType(scope, decl.left),
|
1006
|
+
...number(checkType, Valtype.i32),
|
1007
|
+
[ Opcodes.i32_eq ],
|
1008
|
+
Opcodes.i32_from_u
|
1009
|
+
);
|
1010
|
+
}
|
1011
|
+
|
1012
|
+
return out;
|
1013
|
+
}
|
1014
|
+
|
976
1015
|
const out = performOp(scope, decl.operator, generate(scope, decl.left), generate(scope, decl.right), getNodeType(scope, decl.left), getNodeType(scope, decl.right), _global, _name);
|
977
1016
|
|
978
1017
|
if (valtype !== 'i32' && ['==', '===', '!=', '!==', '>', '>=', '<', '<='].includes(decl.operator)) out.push(Opcodes.i32_from_u);
|
@@ -990,12 +1029,13 @@ const asmFuncToAsm = (func, scope) => {
|
|
990
1029
|
idx = funcIndex[n];
|
991
1030
|
}
|
992
1031
|
|
1032
|
+
if (idx == null) throw new Error(`builtin('${n}') failed to find a func (inside ${scope.name})`);
|
993
1033
|
return idx;
|
994
1034
|
}
|
995
1035
|
});
|
996
1036
|
};
|
997
1037
|
|
998
|
-
const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes = [], globalInits = [], returns, returnType, localNames = [], globalNames = [], data: _data = [], table = false }) => {
|
1038
|
+
const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes = [], globalInits = [], returns, returnType, localNames = [], globalNames = [], data: _data = [], table = false, constr = false }) => {
|
999
1039
|
const existing = funcs.find(x => x.name === name);
|
1000
1040
|
if (existing) return existing;
|
1001
1041
|
|
@@ -1022,13 +1062,17 @@ const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes
|
|
1022
1062
|
returnType,
|
1023
1063
|
internal: true,
|
1024
1064
|
index: currentFuncIndex++,
|
1025
|
-
table
|
1065
|
+
table,
|
1066
|
+
constr
|
1026
1067
|
};
|
1027
1068
|
|
1028
1069
|
funcs.push(func);
|
1029
1070
|
funcIndex[name] = func.index;
|
1030
1071
|
|
1031
|
-
if (typeof wasm === 'function')
|
1072
|
+
if (typeof wasm === 'function') {
|
1073
|
+
if (globalThis.precompile) wasm = [];
|
1074
|
+
else wasm = asmFuncToAsm(wasm, func);
|
1075
|
+
}
|
1032
1076
|
|
1033
1077
|
let baseGlobalIdx, i = 0;
|
1034
1078
|
for (const type of globalTypes) {
|
@@ -1049,15 +1093,35 @@ const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes
|
|
1049
1093
|
|
1050
1094
|
if (table) {
|
1051
1095
|
for (const inst of wasm) {
|
1052
|
-
if (inst
|
1096
|
+
if (inst.at(-1) === 'read func lut') {
|
1053
1097
|
inst.splice(2, 99);
|
1054
|
-
inst.push(...unsignedLEB128(allocPage({}, 'func
|
1098
|
+
inst.push(...unsignedLEB128(allocPage({}, 'func lut') * pageSize));
|
1055
1099
|
}
|
1056
1100
|
}
|
1057
1101
|
|
1058
1102
|
funcs.table = true;
|
1059
1103
|
}
|
1060
1104
|
|
1105
|
+
if (constr) {
|
1106
|
+
func.params = [...func.params];
|
1107
|
+
func.params.unshift(Valtype.i32);
|
1108
|
+
|
1109
|
+
// move all locals +1 idx (sigh)
|
1110
|
+
func.localInd++;
|
1111
|
+
const locals = func.locals;
|
1112
|
+
for (const x in locals) {
|
1113
|
+
locals[x].idx++;
|
1114
|
+
}
|
1115
|
+
|
1116
|
+
locals['#newtarget'] = { idx: 0, type: Valtype.i32 };
|
1117
|
+
|
1118
|
+
for (const inst of wasm) {
|
1119
|
+
if (inst[0] === Opcodes.local_get || inst[0] === Opcodes.local_set || inst[0] === Opcodes.local_tee) {
|
1120
|
+
inst[1]++;
|
1121
|
+
}
|
1122
|
+
}
|
1123
|
+
}
|
1124
|
+
|
1061
1125
|
func.wasm = wasm;
|
1062
1126
|
|
1063
1127
|
return func;
|
@@ -1184,20 +1248,7 @@ const getNodeType = (scope, node) => {
|
|
1184
1248
|
return TYPES.number;
|
1185
1249
|
}
|
1186
1250
|
|
1187
|
-
if (node.type === 'NewExpression' && builtinFuncs[name + '$constructor']) {
|
1188
|
-
if (builtinFuncs[name + '$constructor'].typedReturns) {
|
1189
|
-
if (scope.locals['#last_type']) return getLastType(scope);
|
1190
|
-
|
1191
|
-
// presume
|
1192
|
-
// todo: warn here?
|
1193
|
-
return TYPES.number;
|
1194
|
-
}
|
1195
|
-
|
1196
|
-
return builtinFuncs[name + '$constructor'].returnType ?? TYPES.number;
|
1197
|
-
}
|
1198
|
-
|
1199
1251
|
const func = funcs.find(x => x.name === name);
|
1200
|
-
|
1201
1252
|
if (func) {
|
1202
1253
|
if (func.returnType != null) return func.returnType;
|
1203
1254
|
}
|
@@ -1279,7 +1330,7 @@ const getNodeType = (scope, node) => {
|
|
1279
1330
|
}
|
1280
1331
|
|
1281
1332
|
if (node.type === 'BinaryExpression') {
|
1282
|
-
if (['==', '===', '!=', '!==', '>', '>=', '<', '<='].includes(node.operator)) return TYPES.boolean;
|
1333
|
+
if (['==', '===', '!=', '!==', '>', '>=', '<', '<=', 'instanceof'].includes(node.operator)) return TYPES.boolean;
|
1283
1334
|
if (node.operator !== '+') return TYPES.number;
|
1284
1335
|
|
1285
1336
|
const knownLeft = knownType(scope, getNodeType(scope, node.left));
|
@@ -1312,7 +1363,7 @@ const getNodeType = (scope, node) => {
|
|
1312
1363
|
const objectKnownType = knownType(scope, getNodeType(scope, node.object));
|
1313
1364
|
if (objectKnownType != null) {
|
1314
1365
|
if (name === 'length') {
|
1315
|
-
if (
|
1366
|
+
if (typeHasFlag(objectKnownType, TYPE_FLAGS.length)) return TYPES.number;
|
1316
1367
|
else return TYPES.undefined;
|
1317
1368
|
}
|
1318
1369
|
|
@@ -1384,9 +1435,9 @@ const countLeftover = wasm => {
|
|
1384
1435
|
|
1385
1436
|
if (depth === 0)
|
1386
1437
|
if ([Opcodes.throw, Opcodes.drop, Opcodes.local_set, Opcodes.global_set].includes(inst[0])) count--;
|
1387
|
-
else if ([null, Opcodes.i32_eqz, Opcodes.i64_eqz, Opcodes.f64_ceil, Opcodes.f64_floor, Opcodes.f64_trunc, Opcodes.f64_nearest, Opcodes.f64_sqrt, Opcodes.local_tee, Opcodes.i32_wrap_i64, Opcodes.i64_extend_i32_s, Opcodes.i64_extend_i32_u, Opcodes.f32_demote_f64, Opcodes.f64_promote_f32, Opcodes.f64_convert_i32_s, Opcodes.f64_convert_i32_u, Opcodes.i32_clz, Opcodes.i32_ctz, Opcodes.i32_popcnt, Opcodes.f64_neg, Opcodes.end, Opcodes.i32_trunc_sat_f64_s[0], Opcodes.i32x4_extract_lane, Opcodes.i16x8_extract_lane, Opcodes.i32_load, Opcodes.i64_load, Opcodes.f64_load, Opcodes.v128_load, Opcodes.i32_load16_u, Opcodes.i32_load16_s, Opcodes.i32_load8_u, Opcodes.i32_load8_s, Opcodes.memory_grow].includes(inst[0]) && (inst[0] !== 0xfc || inst[1] < 0x04)) {}
|
1438
|
+
else if ([null, Opcodes.i32_eqz, Opcodes.i64_eqz, Opcodes.f64_ceil, Opcodes.f64_floor, Opcodes.f64_trunc, Opcodes.f64_nearest, Opcodes.f64_sqrt, Opcodes.local_tee, Opcodes.i32_wrap_i64, Opcodes.i64_extend_i32_s, Opcodes.i64_extend_i32_u, Opcodes.f32_demote_f64, Opcodes.f64_promote_f32, Opcodes.f64_convert_i32_s, Opcodes.f64_convert_i32_u, Opcodes.i32_clz, Opcodes.i32_ctz, Opcodes.i32_popcnt, Opcodes.f64_neg, Opcodes.end, Opcodes.i32_trunc_sat_f64_s[0], Opcodes.i32x4_extract_lane, Opcodes.i16x8_extract_lane, Opcodes.i32_load, Opcodes.i64_load, Opcodes.f64_load, Opcodes.f32_load, Opcodes.v128_load, Opcodes.i32_load16_u, Opcodes.i32_load16_s, Opcodes.i32_load8_u, Opcodes.i32_load8_s, Opcodes.memory_grow].includes(inst[0]) && (inst[0] !== 0xfc || inst[1] < 0x04)) {}
|
1388
1439
|
else if ([Opcodes.local_get, Opcodes.global_get, Opcodes.f64_const, Opcodes.i32_const, Opcodes.i64_const, Opcodes.v128_const, Opcodes.memory_size].includes(inst[0])) count++;
|
1389
|
-
else if ([Opcodes.i32_store, Opcodes.i64_store, Opcodes.f64_store, Opcodes.i32_store16, Opcodes.i32_store8].includes(inst[0])) count -= 2;
|
1440
|
+
else if ([Opcodes.i32_store, Opcodes.i64_store, Opcodes.f64_store, Opcodes.f32_store, Opcodes.i32_store16, Opcodes.i32_store8].includes(inst[0])) count -= 2;
|
1390
1441
|
else if (inst[0] === Opcodes.memory_copy[0] && (inst[1] === Opcodes.memory_copy[1] || inst[1] === Opcodes.memory_init[1])) count -= 3;
|
1391
1442
|
else if (inst[0] === Opcodes.return) count = 0;
|
1392
1443
|
else if (inst[0] === Opcodes.call) {
|
@@ -1424,6 +1475,18 @@ const generateExp = (scope, decl) => {
|
|
1424
1475
|
return out;
|
1425
1476
|
};
|
1426
1477
|
|
1478
|
+
const generateSequence = (scope, decl) => {
|
1479
|
+
let out = [];
|
1480
|
+
|
1481
|
+
const exprs = decl.expressions;
|
1482
|
+
for (let i = 0; i < exprs.length; i++) {
|
1483
|
+
if (i > 0) disposeLeftover(out);
|
1484
|
+
out.push(...generate(scope, exprs[i]));
|
1485
|
+
}
|
1486
|
+
|
1487
|
+
return out;
|
1488
|
+
};
|
1489
|
+
|
1427
1490
|
const CTArrayUtil = {
|
1428
1491
|
getLengthI32: pointer => [
|
1429
1492
|
...number(0, Valtype.i32),
|
@@ -1483,7 +1546,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1483
1546
|
name = func.name;
|
1484
1547
|
}
|
1485
1548
|
|
1486
|
-
if (name === 'eval' && decl.arguments[0]?.type === 'Literal') {
|
1549
|
+
if (!decl._new && name === 'eval' && decl.arguments[0]?.type === 'Literal') {
|
1487
1550
|
// literal eval hack
|
1488
1551
|
const code = decl.arguments[0]?.value ?? '';
|
1489
1552
|
|
@@ -1526,7 +1589,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1526
1589
|
|
1527
1590
|
let protoName, target;
|
1528
1591
|
// ident.func()
|
1529
|
-
if (name && name.startsWith('__')) {
|
1592
|
+
if (!decl._new && name && name.startsWith('__')) {
|
1530
1593
|
const spl = name.slice(2).split('_');
|
1531
1594
|
|
1532
1595
|
protoName = spl[spl.length - 1];
|
@@ -1539,12 +1602,12 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1539
1602
|
}
|
1540
1603
|
|
1541
1604
|
// literal.func()
|
1542
|
-
if (!name && decl.callee.type === 'MemberExpression') {
|
1605
|
+
if (!decl._new && !name && decl.callee.type === 'MemberExpression') {
|
1543
1606
|
// megahack for /regex/.func()
|
1544
1607
|
const funcName = decl.callee.property.name;
|
1545
|
-
if (decl.callee.object.regex &&
|
1608
|
+
if (decl.callee.object.regex && ['test'].includes(funcName)) {
|
1546
1609
|
const regex = decl.callee.object.regex.pattern;
|
1547
|
-
const rhemynName = `regex_${funcName}_${regex}`;
|
1610
|
+
const rhemynName = `regex_${funcName}_${sanitize(regex)}`;
|
1548
1611
|
|
1549
1612
|
if (!funcIndex[rhemynName]) {
|
1550
1613
|
const func = Rhemyn[funcName](regex, currentFuncIndex++, rhemynName);
|
@@ -1565,7 +1628,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1565
1628
|
[ Opcodes.call, idx ],
|
1566
1629
|
Opcodes.i32_from_u,
|
1567
1630
|
|
1568
|
-
...setLastType(scope,
|
1631
|
+
...setLastType(scope, Rhemyn.types[funcName])
|
1569
1632
|
];
|
1570
1633
|
}
|
1571
1634
|
|
@@ -1574,27 +1637,56 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1574
1637
|
target = decl.callee.object;
|
1575
1638
|
}
|
1576
1639
|
|
1577
|
-
|
1578
|
-
|
1640
|
+
let out = [];
|
1641
|
+
if (protoName) {
|
1642
|
+
if (['search'].includes(protoName)) {
|
1643
|
+
const regex = decl.arguments[0]?.regex?.pattern;
|
1644
|
+
if (!regex) return [
|
1645
|
+
// no/bad regex arg, return -1/0 for now
|
1646
|
+
...generate(scope, target),
|
1647
|
+
[ Opcodes.drop ],
|
1579
1648
|
|
1580
|
-
|
1581
|
-
|
1649
|
+
...number(Rhemyn.types[protoName] === TYPES.number ? -1 : 0),
|
1650
|
+
...setLastType(scope, Rhemyn.types[protoName])
|
1651
|
+
];
|
1582
1652
|
|
1583
|
-
|
1584
|
-
// generate(scope, decl.callee.object)
|
1653
|
+
const rhemynName = `regex_${protoName}_${sanitize(regex)}`;
|
1585
1654
|
|
1586
|
-
|
1587
|
-
|
1588
|
-
|
1589
|
-
// ];
|
1590
|
-
// }
|
1655
|
+
if (!funcIndex[rhemynName]) {
|
1656
|
+
const func = Rhemyn[protoName](regex, currentFuncIndex++, rhemynName);
|
1657
|
+
func.internal = true;
|
1591
1658
|
|
1592
|
-
|
1593
|
-
|
1659
|
+
funcIndex[func.name] = func.index;
|
1660
|
+
funcs.push(func);
|
1661
|
+
}
|
1662
|
+
|
1663
|
+
const idx = funcIndex[rhemynName];
|
1664
|
+
return [
|
1665
|
+
// make string arg
|
1666
|
+
...generate(scope, target),
|
1667
|
+
Opcodes.i32_to_u,
|
1668
|
+
...getNodeType(scope, target),
|
1669
|
+
|
1670
|
+
// call regex func
|
1671
|
+
[ Opcodes.call, idx ],
|
1672
|
+
Opcodes.i32_from,
|
1673
|
+
|
1674
|
+
...setLastType(scope, Rhemyn.types[protoName])
|
1675
|
+
];
|
1676
|
+
}
|
1594
1677
|
|
1678
|
+
const protoBC = {};
|
1595
1679
|
const builtinProtoCands = Object.keys(builtinFuncs).filter(x => x.startsWith('__') && x.endsWith('_prototype_' + protoName));
|
1596
1680
|
|
1597
1681
|
if (!decl._protoInternalCall && builtinProtoCands.length > 0) {
|
1682
|
+
out.push(
|
1683
|
+
...generate(scope, target),
|
1684
|
+
[ Opcodes.local_set, localTmp(scope, '#proto_target') ],
|
1685
|
+
|
1686
|
+
...getNodeType(scope, target),
|
1687
|
+
[ Opcodes.local_set, localTmp(scope, '#proto_target#type', Valtype.i32) ],
|
1688
|
+
);
|
1689
|
+
|
1598
1690
|
for (const x of builtinProtoCands) {
|
1599
1691
|
const type = TYPES[x.split('_prototype_')[0].slice(2).toLowerCase()];
|
1600
1692
|
if (type == null) continue;
|
@@ -1604,7 +1696,14 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1604
1696
|
type: 'Identifier',
|
1605
1697
|
name: x
|
1606
1698
|
},
|
1607
|
-
arguments: [
|
1699
|
+
arguments: [
|
1700
|
+
{
|
1701
|
+
type: 'Identifier',
|
1702
|
+
name: '#proto_target'
|
1703
|
+
},
|
1704
|
+
|
1705
|
+
...decl.arguments
|
1706
|
+
],
|
1608
1707
|
_protoInternalCall: true
|
1609
1708
|
});
|
1610
1709
|
}
|
@@ -1698,29 +1797,37 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1698
1797
|
}
|
1699
1798
|
|
1700
1799
|
if (Object.keys(protoBC).length > 0) {
|
1701
|
-
return
|
1702
|
-
...
|
1800
|
+
return [
|
1801
|
+
...out,
|
1802
|
+
|
1803
|
+
...typeSwitch(scope, builtinProtoCands.length > 0 ? [ [ Opcodes.local_get, localTmp(scope, '#proto_target#type', Valtype.i32) ] ] : getNodeType(scope, target), {
|
1804
|
+
...protoBC,
|
1703
1805
|
|
1704
|
-
|
1705
|
-
|
1706
|
-
|
1806
|
+
// TODO: error better
|
1807
|
+
default: internalThrow(scope, 'TypeError', `'${protoName}' proto func tried to be called on a type without an impl`)
|
1808
|
+
}, valtypeBinary)
|
1809
|
+
];
|
1707
1810
|
}
|
1708
1811
|
}
|
1709
1812
|
|
1710
|
-
// TODO: only allows callee as
|
1711
|
-
if (!name) return todo(scope, `only
|
1813
|
+
// TODO: only allows callee as identifier
|
1814
|
+
if (!name) return todo(scope, `only identifier callees (got ${decl.callee.type})`);
|
1712
1815
|
|
1713
1816
|
let idx = funcIndex[name] ?? importedFuncs[name];
|
1714
1817
|
if (idx === undefined && builtinFuncs[name]) {
|
1715
1818
|
if (builtinFuncs[name].floatOnly && valtype !== 'f64') throw new Error(`Cannot use built-in ${unhackName(name)} with integer valtype`);
|
1819
|
+
if (decl._new && !builtinFuncs[name].constr) return internalThrow(scope, 'TypeError', `${unhackName(name)} is not a constructor`, true);
|
1716
1820
|
|
1717
1821
|
includeBuiltin(scope, name);
|
1718
1822
|
idx = funcIndex[name];
|
1719
1823
|
}
|
1720
1824
|
|
1721
|
-
if (idx === undefined && internalConstrs[name])
|
1825
|
+
if (idx === undefined && internalConstrs[name]) {
|
1826
|
+
if (decl._new && internalConstrs[name].notConstr) return internalThrow(scope, 'TypeError', `${unhackName(name)} is not a constructor`, true);
|
1827
|
+
return internalConstrs[name].generate(scope, decl, _global, _name);
|
1828
|
+
}
|
1722
1829
|
|
1723
|
-
if (idx === undefined && name.startsWith('__Porffor_wasm_')) {
|
1830
|
+
if (idx === undefined && !decl._new && name.startsWith('__Porffor_wasm_')) {
|
1724
1831
|
const wasmOps = {
|
1725
1832
|
// pointer, align, offset
|
1726
1833
|
i32_load: { imms: 2, args: [ true ], returns: 1 },
|
@@ -1775,7 +1882,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1775
1882
|
|
1776
1883
|
const indirectMode = Prefs.indirectCallMode ?? 'vararg';
|
1777
1884
|
// options: vararg, strict
|
1778
|
-
// - strict: simpler, smaller size usage, no func
|
1885
|
+
// - strict: simpler, smaller size usage, no func lut needed.
|
1779
1886
|
// ONLY works when arg count of call == arg count of function being called
|
1780
1887
|
// - vararg: large size usage, cursed.
|
1781
1888
|
// works when arg count of call != arg count of function being called*
|
@@ -1785,8 +1892,6 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1785
1892
|
scope.table = true;
|
1786
1893
|
|
1787
1894
|
let args = decl.arguments;
|
1788
|
-
let out = [];
|
1789
|
-
|
1790
1895
|
let locals = [];
|
1791
1896
|
|
1792
1897
|
if (indirectMode === 'vararg') {
|
@@ -1850,24 +1955,67 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1850
1955
|
// *for argc 0-3, in future (todo:) the max number should be
|
1851
1956
|
// dynamically changed to the max argc of any func in the js file.
|
1852
1957
|
|
1853
|
-
const funcLocal = localTmp(scope,
|
1958
|
+
const funcLocal = localTmp(scope, '#indirect_func', Valtype.i32);
|
1959
|
+
const flags = localTmp(scope, '#indirect_flags', Valtype.i32);
|
1854
1960
|
|
1855
1961
|
const gen = argc => {
|
1856
|
-
const
|
1962
|
+
const argsOut = [];
|
1857
1963
|
for (let i = 0; i < argc; i++) {
|
1858
|
-
|
1964
|
+
argsOut.push(
|
1859
1965
|
[ Opcodes.local_get, locals[i][0] ],
|
1860
1966
|
[ Opcodes.local_get, locals[i][1] ]
|
1861
1967
|
);
|
1862
1968
|
}
|
1863
1969
|
|
1864
|
-
|
1865
|
-
[ Opcodes.local_get,
|
1866
|
-
|
1867
|
-
|
1868
|
-
|
1970
|
+
const checkFlag = (flag, pass, fail) => [
|
1971
|
+
[ Opcodes.local_get, flags ],
|
1972
|
+
...number(flag, Valtype.i32),
|
1973
|
+
[ Opcodes.i32_and ],
|
1974
|
+
[ Opcodes.if, valtypeBinary ],
|
1975
|
+
...pass,
|
1976
|
+
[ Opcodes.else ],
|
1977
|
+
...fail,
|
1978
|
+
[ Opcodes.end ]
|
1979
|
+
];
|
1869
1980
|
|
1870
|
-
|
1981
|
+
// pain.
|
1982
|
+
// return checkFlag(0b10, [ // constr
|
1983
|
+
// [ Opcodes.i32_const, decl._new ? 1 : 0 ],
|
1984
|
+
// ...argsOut,
|
1985
|
+
// [ Opcodes.local_get, funcLocal ],
|
1986
|
+
// [ Opcodes.call_indirect, argc, 0, 'constr' ],
|
1987
|
+
// ...setLastType(scope),
|
1988
|
+
// ], [
|
1989
|
+
// ...argsOut,
|
1990
|
+
// [ Opcodes.local_get, funcLocal ],
|
1991
|
+
// [ Opcodes.call_indirect, argc, 0 ],
|
1992
|
+
// ...setLastType(scope),
|
1993
|
+
// ]);
|
1994
|
+
|
1995
|
+
return checkFlag(0b1, // no type return
|
1996
|
+
checkFlag(0b10, [ // no type return & constr
|
1997
|
+
[ Opcodes.i32_const, decl._new ? 1 : 0 ],
|
1998
|
+
...argsOut,
|
1999
|
+
[ Opcodes.local_get, funcLocal ],
|
2000
|
+
[ Opcodes.call_indirect, argc, 0, 'no_type_return', 'constr' ],
|
2001
|
+
], [
|
2002
|
+
...argsOut,
|
2003
|
+
[ Opcodes.local_get, funcLocal ],
|
2004
|
+
[ Opcodes.call_indirect, argc, 0, 'no_type_return' ]
|
2005
|
+
]),
|
2006
|
+
checkFlag(0b10, [ // type return & constr
|
2007
|
+
[ Opcodes.i32_const, decl._new ? 1 : 0 ],
|
2008
|
+
...argsOut,
|
2009
|
+
[ Opcodes.local_get, funcLocal ],
|
2010
|
+
[ Opcodes.call_indirect, argc, 0, 'constr' ],
|
2011
|
+
...setLastType(scope),
|
2012
|
+
], [
|
2013
|
+
...argsOut,
|
2014
|
+
[ Opcodes.local_get, funcLocal ],
|
2015
|
+
[ Opcodes.call_indirect, argc, 0 ],
|
2016
|
+
...setLastType(scope),
|
2017
|
+
]),
|
2018
|
+
);
|
1871
2019
|
};
|
1872
2020
|
|
1873
2021
|
const tableBc = {};
|
@@ -1885,13 +2033,32 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1885
2033
|
Opcodes.i32_to_u,
|
1886
2034
|
[ Opcodes.local_set, funcLocal ],
|
1887
2035
|
|
2036
|
+
// get if func we are calling is a constructor or not
|
2037
|
+
[ Opcodes.local_get, funcLocal ],
|
2038
|
+
...number(3, Valtype.i32),
|
2039
|
+
[ Opcodes.i32_mul ],
|
2040
|
+
...number(2, Valtype.i32),
|
2041
|
+
[ Opcodes.i32_add ],
|
2042
|
+
[ Opcodes.i32_load8_u, 0, ...unsignedLEB128(allocPage(scope, 'func lut') * pageSize), 'read func lut' ],
|
2043
|
+
[ Opcodes.local_set, flags ],
|
2044
|
+
|
2045
|
+
// check if non-constructor was called with new, if so throw
|
2046
|
+
[ Opcodes.local_get, flags ],
|
2047
|
+
...number(0b10, Valtype.i32),
|
2048
|
+
[ Opcodes.i32_and ],
|
2049
|
+
[ Opcodes.i32_eqz ],
|
2050
|
+
[ Opcodes.i32_const, decl._new ? 1 : 0 ],
|
2051
|
+
[ Opcodes.i32_and ],
|
2052
|
+
[ Opcodes.if, Blocktype.void ],
|
2053
|
+
...internalThrow(scope, 'TypeError', `${unhackName(name)} is not a constructor`),
|
2054
|
+
[ Opcodes.end ],
|
2055
|
+
|
1888
2056
|
...brTable([
|
1889
2057
|
// get argc of func we are calling
|
1890
2058
|
[ Opcodes.local_get, funcLocal ],
|
1891
|
-
...number(
|
2059
|
+
...number(3, Valtype.i32),
|
1892
2060
|
[ Opcodes.i32_mul ],
|
1893
|
-
|
1894
|
-
[ Opcodes.i32_load16_u, 0, ...unsignedLEB128(allocPage(scope, 'func argc lut') * pageSize), 'read_argc' ]
|
2061
|
+
[ Opcodes.i32_load16_u, 0, ...unsignedLEB128(allocPage(scope, 'func lut') * pageSize), 'read func lut' ]
|
1895
2062
|
], tableBc, valtypeBinary)
|
1896
2063
|
],
|
1897
2064
|
default: internalThrow(scope, 'TypeError', `${unhackName(name)} is not a function`, true)
|
@@ -1905,7 +2072,16 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1905
2072
|
const userFunc = func && !func.internal;
|
1906
2073
|
const typedParams = userFunc || builtinFuncs[name]?.typedParams;
|
1907
2074
|
const typedReturns = (userFunc && func.returnType == null) || builtinFuncs[name]?.typedReturns;
|
1908
|
-
|
2075
|
+
let paramCount = func && (typedParams ? Math.floor(func.params.length / 2) : func.params.length);
|
2076
|
+
|
2077
|
+
let paramOffset = 0;
|
2078
|
+
if (func && func.constr) {
|
2079
|
+
// new.target arg
|
2080
|
+
if (func.internal) paramOffset = 1;
|
2081
|
+
if (!typedParams) paramCount--;
|
2082
|
+
out.push([ Opcodes.i32_const, decl._new ? 1 : 0 ]);
|
2083
|
+
} else if (decl._new)
|
2084
|
+
return internalThrow(scope, 'TypeError', `${unhackName(name)} is not a constructor`, true);
|
1909
2085
|
|
1910
2086
|
let args = decl.arguments;
|
1911
2087
|
if (func && args.length < paramCount) {
|
@@ -1920,7 +2096,6 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1920
2096
|
|
1921
2097
|
if (func && func.throws) scope.throws = true;
|
1922
2098
|
|
1923
|
-
let out = [];
|
1924
2099
|
for (let i = 0; i < args.length; i++) {
|
1925
2100
|
const arg = args[i];
|
1926
2101
|
out = out.concat(generate(scope, arg));
|
@@ -1933,13 +2108,13 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1933
2108
|
}
|
1934
2109
|
|
1935
2110
|
if (valtypeBinary !== Valtype.i32 &&
|
1936
|
-
(func && func.params[i * (typedParams ? 2 : 1)] === Valtype.i32)
|
2111
|
+
(func && func.params[paramOffset + i * (typedParams ? 2 : 1)] === Valtype.i32)
|
1937
2112
|
) {
|
1938
2113
|
out.push(Opcodes.i32_to);
|
1939
2114
|
}
|
1940
2115
|
|
1941
2116
|
if (valtypeBinary === Valtype.i32 &&
|
1942
|
-
(func && func.params[i * (typedParams ? 2 : 1)] === Valtype.f64)
|
2117
|
+
(func && func.params[paramOffset + i * (typedParams ? 2 : 1)] === Valtype.f64)
|
1943
2118
|
) {
|
1944
2119
|
out.push([ Opcodes.f64_convert_i32_s ]);
|
1945
2120
|
}
|
@@ -1972,32 +2147,10 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1972
2147
|
return out;
|
1973
2148
|
};
|
1974
2149
|
|
1975
|
-
const generateNew = (scope, decl, _global, _name) => {
|
1976
|
-
|
1977
|
-
|
1978
|
-
|
1979
|
-
if (internalConstrs[name] && !internalConstrs[name].notConstr) return internalConstrs[name].generate(scope, decl, _global, _name);
|
1980
|
-
|
1981
|
-
if (builtinFuncs[name + '$constructor']) {
|
1982
|
-
// custom ...$constructor override builtin func
|
1983
|
-
return generateCall(scope, {
|
1984
|
-
...decl,
|
1985
|
-
callee: {
|
1986
|
-
type: 'Identifier',
|
1987
|
-
name: name + '$constructor'
|
1988
|
-
}
|
1989
|
-
}, _global, _name);
|
1990
|
-
}
|
1991
|
-
|
1992
|
-
if (
|
1993
|
-
(builtinFuncs[name] && !builtinFuncs[name].constr) ||
|
1994
|
-
(internalConstrs[name] && builtinFuncs[name].notConstr)
|
1995
|
-
) return internalThrow(scope, 'TypeError', `${name} is not a constructor`, true);
|
1996
|
-
|
1997
|
-
if (!builtinFuncs[name]) return todo(scope, `new statement is not supported yet`, true); // return todo(scope, `new statement is not supported yet (new ${unhackName(name)})`);
|
1998
|
-
|
1999
|
-
return generateCall(scope, decl, _global, _name);
|
2000
|
-
};
|
2150
|
+
const generateNew = (scope, decl, _global, _name) => generateCall(scope, {
|
2151
|
+
...decl,
|
2152
|
+
_new: true
|
2153
|
+
}, _global, _name);
|
2001
2154
|
|
2002
2155
|
// bad hack for undefined and null working without additional logic
|
2003
2156
|
const DEFAULT_VALUE = {
|
@@ -2005,6 +2158,16 @@ const DEFAULT_VALUE = {
|
|
2005
2158
|
name: 'undefined'
|
2006
2159
|
};
|
2007
2160
|
|
2161
|
+
const codeToSanitizedStr = code => {
|
2162
|
+
let out = '';
|
2163
|
+
while (code > 0) {
|
2164
|
+
out += String.fromCharCode(97 + code % 26);
|
2165
|
+
code -= 26;
|
2166
|
+
}
|
2167
|
+
return out;
|
2168
|
+
};
|
2169
|
+
const sanitize = str => str.replace(/[^0-9a-zA-Z_]/g, _ => codeToSanitizedStr(_.charCodeAt(0)));
|
2170
|
+
|
2008
2171
|
const unhackName = name => {
|
2009
2172
|
if (name.startsWith('__')) return name.slice(2).replaceAll('_', '.');
|
2010
2173
|
return name;
|
@@ -2012,7 +2175,7 @@ const unhackName = name => {
|
|
2012
2175
|
|
2013
2176
|
const knownType = (scope, type) => {
|
2014
2177
|
if (type.length === 1 && type[0][0] === Opcodes.i32_const) {
|
2015
|
-
return type[0]
|
2178
|
+
return read_signedLEB128(type[0].slice(1));
|
2016
2179
|
}
|
2017
2180
|
|
2018
2181
|
if (typedInput && type.length === 1 && type[0][0] === Opcodes.local_get) {
|
@@ -2299,11 +2462,6 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2299
2462
|
const { type, name } = decl.left;
|
2300
2463
|
const [ local, isGlobal ] = lookupName(scope, name);
|
2301
2464
|
|
2302
|
-
if (type === 'ObjectPattern') {
|
2303
|
-
// hack: ignore object parts of `var a = {} = 2`
|
2304
|
-
return generate(scope, decl.right);
|
2305
|
-
}
|
2306
|
-
|
2307
2465
|
if (isFuncType(decl.right.type)) {
|
2308
2466
|
// hack for a = function () { ... }
|
2309
2467
|
decl.right.id = { name };
|
@@ -2349,8 +2507,8 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2349
2507
|
|
2350
2508
|
// arr[i]
|
2351
2509
|
if (decl.left.type === 'MemberExpression' && decl.left.computed) {
|
2352
|
-
const newValueTmp = localTmp(scope, '
|
2353
|
-
const pointerTmp =
|
2510
|
+
const newValueTmp = localTmp(scope, '#member_setter_val_tmp');
|
2511
|
+
const pointerTmp = localTmp(scope, '#member_setter_ptr_tmp', Valtype.i32);
|
2354
2512
|
|
2355
2513
|
return [
|
2356
2514
|
...typeSwitch(scope, getNodeType(scope, decl.left.object), {
|
@@ -2362,11 +2520,11 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2362
2520
|
...generate(scope, decl.left.property),
|
2363
2521
|
Opcodes.i32_to_u,
|
2364
2522
|
|
2365
|
-
// turn into byte offset by * valtypeSize
|
2523
|
+
// turn into byte offset by * valtypeSize + 1
|
2366
2524
|
...number(ValtypeSize[valtype] + 1, Valtype.i32),
|
2367
2525
|
[ Opcodes.i32_mul ],
|
2368
2526
|
[ Opcodes.i32_add ],
|
2369
|
-
|
2527
|
+
[ Opcodes.local_tee, pointerTmp ],
|
2370
2528
|
|
2371
2529
|
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2372
2530
|
[ Opcodes.local_get, pointerTmp ],
|
@@ -2376,10 +2534,164 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2376
2534
|
[ Opcodes.i32_load8_u, 0, ValtypeSize.i32 + ValtypeSize[valtype] ]
|
2377
2535
|
], getNodeType(scope, decl.right), false, name, true)),
|
2378
2536
|
[ Opcodes.local_tee, newValueTmp ],
|
2537
|
+
[ Opcodes.store, 0, ValtypeSize.i32 ],
|
2379
2538
|
|
2380
|
-
[ Opcodes.
|
2539
|
+
[ Opcodes.local_get, pointerTmp ],
|
2540
|
+
...getNodeType(scope, decl),
|
2541
|
+
[ Opcodes.i32_store8, 0, ValtypeSize.i32 + ValtypeSize[valtype] ],
|
2381
2542
|
],
|
2382
2543
|
|
2544
|
+
...wrapBC({
|
2545
|
+
[TYPES.uint8array]: [
|
2546
|
+
[ Opcodes.i32_add ],
|
2547
|
+
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2548
|
+
|
2549
|
+
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2550
|
+
[ Opcodes.local_get, pointerTmp ],
|
2551
|
+
[ Opcodes.i32_load8_u, 0, 4 ],
|
2552
|
+
Opcodes.i32_from_u
|
2553
|
+
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
2554
|
+
[ Opcodes.local_tee, newValueTmp ],
|
2555
|
+
|
2556
|
+
Opcodes.i32_to_u,
|
2557
|
+
[ Opcodes.i32_store8, 0, 4 ]
|
2558
|
+
],
|
2559
|
+
[TYPES.uint8clampedarray]: [
|
2560
|
+
[ Opcodes.i32_add ],
|
2561
|
+
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2562
|
+
|
2563
|
+
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2564
|
+
[ Opcodes.local_get, pointerTmp ],
|
2565
|
+
[ Opcodes.i32_load8_u, 0, 4 ],
|
2566
|
+
Opcodes.i32_from_u
|
2567
|
+
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
2568
|
+
[ Opcodes.local_tee, newValueTmp ],
|
2569
|
+
|
2570
|
+
...number(0),
|
2571
|
+
[ Opcodes.f64_max ],
|
2572
|
+
...number(255),
|
2573
|
+
[ Opcodes.f64_min ],
|
2574
|
+
Opcodes.i32_to_u,
|
2575
|
+
[ Opcodes.i32_store8, 0, 4 ]
|
2576
|
+
],
|
2577
|
+
[TYPES.int8array]: [
|
2578
|
+
[ Opcodes.i32_add ],
|
2579
|
+
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2580
|
+
|
2581
|
+
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2582
|
+
[ Opcodes.local_get, pointerTmp ],
|
2583
|
+
[ Opcodes.i32_load8_s, 0, 4 ],
|
2584
|
+
Opcodes.i32_from
|
2585
|
+
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
2586
|
+
[ Opcodes.local_tee, newValueTmp ],
|
2587
|
+
|
2588
|
+
Opcodes.i32_to,
|
2589
|
+
[ Opcodes.i32_store8, 0, 4 ]
|
2590
|
+
],
|
2591
|
+
[TYPES.uint16array]: [
|
2592
|
+
...number(2, Valtype.i32),
|
2593
|
+
[ Opcodes.i32_mul ],
|
2594
|
+
[ Opcodes.i32_add ],
|
2595
|
+
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2596
|
+
|
2597
|
+
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2598
|
+
[ Opcodes.local_get, pointerTmp ],
|
2599
|
+
[ Opcodes.i32_load16_u, 0, 4 ],
|
2600
|
+
Opcodes.i32_from_u
|
2601
|
+
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
2602
|
+
[ Opcodes.local_tee, newValueTmp ],
|
2603
|
+
|
2604
|
+
Opcodes.i32_to_u,
|
2605
|
+
[ Opcodes.i32_store16, 0, 4 ]
|
2606
|
+
],
|
2607
|
+
[TYPES.int16array]: [
|
2608
|
+
...number(2, Valtype.i32),
|
2609
|
+
[ Opcodes.i32_mul ],
|
2610
|
+
[ Opcodes.i32_add ],
|
2611
|
+
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2612
|
+
|
2613
|
+
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2614
|
+
[ Opcodes.local_get, pointerTmp ],
|
2615
|
+
[ Opcodes.i32_load16_s, 0, 4 ],
|
2616
|
+
Opcodes.i32_from
|
2617
|
+
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
2618
|
+
[ Opcodes.local_tee, newValueTmp ],
|
2619
|
+
|
2620
|
+
Opcodes.i32_to,
|
2621
|
+
[ Opcodes.i32_store16, 0, 4 ]
|
2622
|
+
],
|
2623
|
+
[TYPES.uint32array]: [
|
2624
|
+
...number(4, Valtype.i32),
|
2625
|
+
[ Opcodes.i32_mul ],
|
2626
|
+
[ Opcodes.i32_add ],
|
2627
|
+
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2628
|
+
|
2629
|
+
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2630
|
+
[ Opcodes.local_get, pointerTmp ],
|
2631
|
+
[ Opcodes.i32_load, 0, 4 ],
|
2632
|
+
Opcodes.i32_from_u
|
2633
|
+
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
2634
|
+
[ Opcodes.local_tee, newValueTmp ],
|
2635
|
+
|
2636
|
+
Opcodes.i32_to_u,
|
2637
|
+
[ Opcodes.i32_store, 0, 4 ]
|
2638
|
+
],
|
2639
|
+
[TYPES.int32array]: [
|
2640
|
+
...number(4, Valtype.i32),
|
2641
|
+
[ Opcodes.i32_mul ],
|
2642
|
+
[ Opcodes.i32_add ],
|
2643
|
+
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2644
|
+
|
2645
|
+
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2646
|
+
[ Opcodes.local_get, pointerTmp ],
|
2647
|
+
[ Opcodes.i32_load, 0, 4 ],
|
2648
|
+
Opcodes.i32_from
|
2649
|
+
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
2650
|
+
[ Opcodes.local_tee, newValueTmp ],
|
2651
|
+
|
2652
|
+
Opcodes.i32_to,
|
2653
|
+
[ Opcodes.i32_store, 0, 4 ]
|
2654
|
+
],
|
2655
|
+
[TYPES.float32array]: [
|
2656
|
+
...number(4, Valtype.i32),
|
2657
|
+
[ Opcodes.i32_mul ],
|
2658
|
+
[ Opcodes.i32_add ],
|
2659
|
+
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2660
|
+
|
2661
|
+
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2662
|
+
[ Opcodes.local_get, pointerTmp ],
|
2663
|
+
[ Opcodes.f32_load, 0, 4 ],
|
2664
|
+
[ Opcodes.f64_promote_f32 ]
|
2665
|
+
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
2666
|
+
[ Opcodes.local_tee, newValueTmp ],
|
2667
|
+
|
2668
|
+
[ Opcodes.f32_demote_f64 ],
|
2669
|
+
[ Opcodes.f32_store, 0, 4 ]
|
2670
|
+
],
|
2671
|
+
[TYPES.float64array]: [
|
2672
|
+
...number(8, Valtype.i32),
|
2673
|
+
[ Opcodes.i32_mul ],
|
2674
|
+
[ Opcodes.i32_add ],
|
2675
|
+
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2676
|
+
|
2677
|
+
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2678
|
+
[ Opcodes.local_get, pointerTmp ],
|
2679
|
+
[ Opcodes.f64_load, 0, 4 ]
|
2680
|
+
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
2681
|
+
[ Opcodes.local_tee, newValueTmp ],
|
2682
|
+
|
2683
|
+
[ Opcodes.f64_store, 0, 4 ]
|
2684
|
+
],
|
2685
|
+
}, {
|
2686
|
+
prelude: [
|
2687
|
+
...generate(scope, decl.left.object),
|
2688
|
+
Opcodes.i32_to_u,
|
2689
|
+
...generate(scope, decl.left.property),
|
2690
|
+
Opcodes.i32_to_u,
|
2691
|
+
],
|
2692
|
+
postlude: setLastType(scope, TYPES.number)
|
2693
|
+
}),
|
2694
|
+
|
2383
2695
|
default: internalThrow(scope, 'TypeError', `Cannot assign member with non-array`)
|
2384
2696
|
}, Blocktype.void),
|
2385
2697
|
|
@@ -2763,7 +3075,9 @@ const generateForOf = (scope, decl) => {
|
|
2763
3075
|
// // todo: we should only do this for strings but we don't know at compile-time :(
|
2764
3076
|
// hack: this is naughty and will break things!
|
2765
3077
|
let newOut = number(0, Valtype.i32), newPointer = number(0, Valtype.i32);
|
2766
|
-
|
3078
|
+
|
3079
|
+
const known = knownType(scope, getNodeType(scope, decl.right));
|
3080
|
+
if ((known === TYPES.string || known === TYPES.bytestring) || (pages.hasAnyString && known == null)) {
|
2767
3081
|
// todo: we use i16 even for bytestrings which should not make a bad thing happen, just be confusing for debugging?
|
2768
3082
|
0, [ newOut, newPointer ] = makeArray(scope, {
|
2769
3083
|
rawElements: new Array(0)
|
@@ -2811,6 +3125,7 @@ const generateForOf = (scope, decl) => {
|
|
2811
3125
|
[ Opcodes.end ],
|
2812
3126
|
[ Opcodes.end ]
|
2813
3127
|
],
|
3128
|
+
|
2814
3129
|
[TYPES.string]: [
|
2815
3130
|
...setType(scope, leftName, TYPES.string),
|
2816
3131
|
|
@@ -2919,6 +3234,7 @@ const generateForOf = (scope, decl) => {
|
|
2919
3234
|
[ Opcodes.end ],
|
2920
3235
|
[ Opcodes.end ]
|
2921
3236
|
],
|
3237
|
+
|
2922
3238
|
[TYPES.set]: [
|
2923
3239
|
[ Opcodes.loop, Blocktype.void ],
|
2924
3240
|
|
@@ -2957,6 +3273,106 @@ const generateForOf = (scope, decl) => {
|
|
2957
3273
|
[ Opcodes.end ],
|
2958
3274
|
[ Opcodes.end ]
|
2959
3275
|
],
|
3276
|
+
|
3277
|
+
...wrapBC({
|
3278
|
+
[TYPES.uint8array]: [
|
3279
|
+
[ Opcodes.i32_add ],
|
3280
|
+
|
3281
|
+
[ Opcodes.i32_load8_u, 0, 4 ],
|
3282
|
+
Opcodes.i32_from_u
|
3283
|
+
],
|
3284
|
+
[TYPES.uint8clampedarray]: [
|
3285
|
+
[ Opcodes.i32_add ],
|
3286
|
+
|
3287
|
+
[ Opcodes.i32_load8_u, 0, 4 ],
|
3288
|
+
Opcodes.i32_from_u
|
3289
|
+
],
|
3290
|
+
[TYPES.int8array]: [
|
3291
|
+
[ Opcodes.i32_add ],
|
3292
|
+
|
3293
|
+
[ Opcodes.i32_load8_s, 0, 4 ],
|
3294
|
+
Opcodes.i32_from
|
3295
|
+
],
|
3296
|
+
[TYPES.uint16array]: [
|
3297
|
+
...number(2, Valtype.i32),
|
3298
|
+
[ Opcodes.i32_mul ],
|
3299
|
+
[ Opcodes.i32_add ],
|
3300
|
+
|
3301
|
+
[ Opcodes.i32_load16_u, 0, 4 ],
|
3302
|
+
Opcodes.i32_from_u
|
3303
|
+
],
|
3304
|
+
[TYPES.int16array]: [
|
3305
|
+
...number(2, Valtype.i32),
|
3306
|
+
[ Opcodes.i32_mul ],
|
3307
|
+
[ Opcodes.i32_add ],
|
3308
|
+
|
3309
|
+
[ Opcodes.i32_load16_s, 0, 4 ],
|
3310
|
+
Opcodes.i32_from
|
3311
|
+
],
|
3312
|
+
[TYPES.uint32array]: [
|
3313
|
+
...number(4, Valtype.i32),
|
3314
|
+
[ Opcodes.i32_mul ],
|
3315
|
+
[ Opcodes.i32_add ],
|
3316
|
+
|
3317
|
+
[ Opcodes.i32_load, 0, 4 ],
|
3318
|
+
Opcodes.i32_from_u
|
3319
|
+
],
|
3320
|
+
[TYPES.int32array]: [
|
3321
|
+
...number(4, Valtype.i32),
|
3322
|
+
[ Opcodes.i32_mul ],
|
3323
|
+
[ Opcodes.i32_add ],
|
3324
|
+
|
3325
|
+
[ Opcodes.i32_load, 0, 4 ],
|
3326
|
+
Opcodes.i32_from
|
3327
|
+
],
|
3328
|
+
[TYPES.float32array]: [
|
3329
|
+
...number(4, Valtype.i32),
|
3330
|
+
[ Opcodes.i32_mul ],
|
3331
|
+
[ Opcodes.i32_add ],
|
3332
|
+
|
3333
|
+
[ Opcodes.f32_load, 0, 4 ],
|
3334
|
+
[ Opcodes.f64_promote_f32 ]
|
3335
|
+
],
|
3336
|
+
[TYPES.float64array]: [
|
3337
|
+
...number(8, Valtype.i32),
|
3338
|
+
[ Opcodes.i32_mul ],
|
3339
|
+
[ Opcodes.i32_add ],
|
3340
|
+
|
3341
|
+
[ Opcodes.f64_load, 0, 4 ]
|
3342
|
+
],
|
3343
|
+
}, {
|
3344
|
+
prelude: [
|
3345
|
+
...setType(scope, leftName, TYPES.number),
|
3346
|
+
|
3347
|
+
[ Opcodes.loop, Blocktype.void ],
|
3348
|
+
|
3349
|
+
[ Opcodes.local_get, pointer ],
|
3350
|
+
[ Opcodes.local_get, counter ]
|
3351
|
+
],
|
3352
|
+
postlude: [
|
3353
|
+
[ isGlobal ? Opcodes.global_set : Opcodes.local_set, local.idx ],
|
3354
|
+
|
3355
|
+
[ Opcodes.block, Blocktype.void ],
|
3356
|
+
[ Opcodes.block, Blocktype.void ],
|
3357
|
+
...generate(scope, decl.body),
|
3358
|
+
[ Opcodes.end ],
|
3359
|
+
|
3360
|
+
// increment counter by 1
|
3361
|
+
[ Opcodes.local_get, counter ],
|
3362
|
+
...number(1, Valtype.i32),
|
3363
|
+
[ Opcodes.i32_add ],
|
3364
|
+
[ Opcodes.local_tee, counter ],
|
3365
|
+
|
3366
|
+
// loop if counter != length
|
3367
|
+
[ Opcodes.local_get, length ],
|
3368
|
+
[ Opcodes.i32_ne ],
|
3369
|
+
[ Opcodes.br_if, 1 ],
|
3370
|
+
|
3371
|
+
[ Opcodes.end ],
|
3372
|
+
[ Opcodes.end ]
|
3373
|
+
]
|
3374
|
+
}),
|
3375
|
+
|
2960
3376
|
default: internalThrow(scope, 'TypeError', `Tried for..of on non-iterable type`)
|
2961
3377
|
}, Blocktype.void));
|
2962
3378
|
|
@@ -3029,32 +3445,102 @@ const generateLabel = (scope, decl) => {
|
|
3029
3445
|
const generateThrow = (scope, decl) => {
|
3030
3446
|
scope.throws = true;
|
3031
3447
|
|
3032
|
-
|
3448
|
+
const exceptionMode = Prefs.exceptionMode ?? 'lut';
|
3449
|
+
if (exceptionMode === 'lut') {
|
3450
|
+
let message = decl.argument.value, constructor = null;
|
3033
3451
|
|
3034
|
-
|
3035
|
-
|
3036
|
-
|
3037
|
-
|
3452
|
+
// support `throw (new)? Error(...)`
|
3453
|
+
if (!message && (decl.argument.type === 'NewExpression' || decl.argument.type === 'CallExpression')) {
|
3454
|
+
constructor = decl.argument.callee.name;
|
3455
|
+
message = decl.argument.arguments[0]?.value ?? '';
|
3456
|
+
}
|
3457
|
+
|
3458
|
+
if (tags.length === 0) tags.push({
|
3459
|
+
params: [ Valtype.i32 ],
|
3460
|
+
results: [],
|
3461
|
+
idx: tags.length
|
3462
|
+
});
|
3463
|
+
|
3464
|
+
let exceptId = exceptions.findIndex(x => x.constructor === constructor && x.message === message);
|
3465
|
+
if (exceptId === -1) exceptId = exceptions.push({ constructor, message }) - 1;
|
3466
|
+
|
3467
|
+
scope.exceptions ??= [];
|
3468
|
+
scope.exceptions.push(exceptId);
|
3469
|
+
|
3470
|
+
return [
|
3471
|
+
...number(exceptId, Valtype.i32),
|
3472
|
+
[ Opcodes.throw, tags[0].idx ]
|
3473
|
+
];
|
3038
3474
|
}
|
3039
3475
|
|
3040
|
-
if (
|
3041
|
-
|
3042
|
-
|
3043
|
-
|
3044
|
-
|
3476
|
+
if (exceptionMode === 'stack') {
|
3477
|
+
if (tags.length === 0) tags.push({
|
3478
|
+
params: [ valtypeBinary, Valtype.i32 ],
|
3479
|
+
results: [],
|
3480
|
+
idx: tags.length
|
3481
|
+
});
|
3482
|
+
|
3483
|
+
return [
|
3484
|
+
...generate(scope, decl.argument),
|
3485
|
+
...getNodeType(scope, decl.argument),
|
3486
|
+
[ Opcodes.throw, tags[0].idx ]
|
3487
|
+
];
|
3488
|
+
}
|
3045
3489
|
|
3046
|
-
|
3047
|
-
|
3490
|
+
if (exceptionMode === 'stackest') {
|
3491
|
+
let message = decl.argument, constructor = null;
|
3048
3492
|
|
3049
|
-
|
3050
|
-
|
3493
|
+
// support `throw (new)? Error(...)`
|
3494
|
+
if (message.type === 'NewExpression' || message.type === 'CallExpression') {
|
3495
|
+
constructor = decl.argument.callee;
|
3496
|
+
message = decl.argument.arguments[0];
|
3497
|
+
}
|
3051
3498
|
|
3052
|
-
|
3499
|
+
message ??= DEFAULT_VALUE;
|
3053
3500
|
|
3054
|
-
|
3055
|
-
|
3056
|
-
|
3057
|
-
|
3501
|
+
if (tags.length === 0) tags.push({
|
3502
|
+
params: [ valtypeBinary, valtypeBinary, Valtype.i32 ],
|
3503
|
+
results: [],
|
3504
|
+
idx: tags.length
|
3505
|
+
});
|
3506
|
+
|
3507
|
+
return [
|
3508
|
+
...(constructor == null ? number(-1) : generate(scope, constructor)),
|
3509
|
+
...generate(scope, message),
|
3510
|
+
...getNodeType(scope, message),
|
3511
|
+
[ Opcodes.throw, tags[0].idx ]
|
3512
|
+
];
|
3513
|
+
}
|
3514
|
+
|
3515
|
+
if (exceptionMode === 'partial') {
|
3516
|
+
let message = decl.argument, constructor = null;
|
3517
|
+
|
3518
|
+
// support `throw (new)? Error(...)`
|
3519
|
+
if (message.type === 'NewExpression' || message.type === 'CallExpression') {
|
3520
|
+
constructor = decl.argument.callee.name;
|
3521
|
+
message = decl.argument.arguments[0];
|
3522
|
+
}
|
3523
|
+
|
3524
|
+
message ??= DEFAULT_VALUE;
|
3525
|
+
|
3526
|
+
if (tags.length === 0) tags.push({
|
3527
|
+
params: [ Valtype.i32, valtypeBinary, Valtype.i32 ],
|
3528
|
+
results: [],
|
3529
|
+
idx: tags.length
|
3530
|
+
});
|
3531
|
+
|
3532
|
+
let exceptId = exceptions.push({ constructor }) - 1;
|
3533
|
+
|
3534
|
+
scope.exceptions ??= [];
|
3535
|
+
scope.exceptions.push(exceptId);
|
3536
|
+
|
3537
|
+
return [
|
3538
|
+
...number(exceptId, Valtype.i32),
|
3539
|
+
...generate(scope, message),
|
3540
|
+
...getNodeType(scope, message),
|
3541
|
+
[ Opcodes.throw, tags[0].idx ]
|
3542
|
+
];
|
3543
|
+
}
|
3058
3544
|
};
|
3059
3545
|
|
3060
3546
|
const generateTry = (scope, decl) => {
|
@@ -3090,6 +3576,22 @@ const generateEmpty = (scope, decl) => {
|
|
3090
3576
|
return [];
|
3091
3577
|
};
|
3092
3578
|
|
3579
|
+
const generateMeta = (scope, decl) => {
|
3580
|
+
if (decl.meta.name !== 'new') return todo(scope, `meta property object ${decl.meta.name} is not supported yet`, true);
|
3581
|
+
|
3582
|
+
switch (`${decl.meta.name}.${decl.property.name}`) {
|
3583
|
+
case 'new.target': {
|
3584
|
+
scope.constr = true;
|
3585
|
+
|
3586
|
+
return [
|
3587
|
+
[ Opcodes.local_get, -1 ],
|
3588
|
+
Opcodes.i32_from_u,
|
3589
|
+
...setLastType(scope, TYPES.boolean)
|
3590
|
+
];
|
3591
|
+
}
|
3592
|
+
}
|
3593
|
+
};
|
3594
|
+
|
3093
3595
|
let pages = new Map();
|
3094
3596
|
const allocPage = (scope, reason, type) => {
|
3095
3597
|
if (pages.has(reason)) return pages.get(reason).ind;
|
@@ -3407,6 +3909,19 @@ const withType = (scope, wasm, type) => [
|
|
3407
3909
|
...setLastType(scope, type)
|
3408
3910
|
];
|
3409
3911
|
|
3912
|
+
const wrapBC = (bc, { prelude = [], postlude = [] } = {}) => {
|
3913
|
+
const out = {};
|
3914
|
+
for (const x in bc) {
|
3915
|
+
out[x] = [
|
3916
|
+
...prelude,
|
3917
|
+
...bc[x],
|
3918
|
+
...postlude
|
3919
|
+
];
|
3920
|
+
}
|
3921
|
+
|
3922
|
+
return out;
|
3923
|
+
};
|
3924
|
+
|
3410
3925
|
const generateMember = (scope, decl, _global, _name) => {
|
3411
3926
|
const name = decl.object.name;
|
3412
3927
|
|
@@ -3429,20 +3944,10 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3429
3944
|
const func = funcs.find(x => x.name === name);
|
3430
3945
|
if (func) {
|
3431
3946
|
const typedParams = !func.internal || builtinFuncs[name]?.typedParams;
|
3432
|
-
return withType(scope, number(typedParams ? func.params.length / 2 : func.params.length), TYPES.number);
|
3947
|
+
return withType(scope, number(typedParams ? Math.floor(func.params.length / 2) : (func.constr ? (func.params.length - 1) : func.params.length)), TYPES.number);
|
3433
3948
|
}
|
3434
3949
|
|
3435
|
-
if (builtinFuncs[name
|
3436
|
-
const regularFunc = builtinFuncs[name];
|
3437
|
-
const regularParams = regularFunc.typedParams ? (regularFunc.params.length / 2) : regularFunc.params.length;
|
3438
|
-
|
3439
|
-
const constructorFunc = builtinFuncs[name + '$constructor'];
|
3440
|
-
const constructorParams = constructorFunc.typedParams ? (constructorFunc.params.length / 2) : constructorFunc.params.length;
|
3441
|
-
|
3442
|
-
return withType(scope, number(Math.max(regularParams, constructorParams)), TYPES.number);
|
3443
|
-
}
|
3444
|
-
|
3445
|
-
if (builtinFuncs[name]) return withType(scope, number(builtinFuncs[name].typedParams ? (builtinFuncs[name].params.length / 2) : builtinFuncs[name].params.length), TYPES.number);
|
3950
|
+
if (builtinFuncs[name]) return withType(scope, number(builtinFuncs[name].typedParams ? Math.floor(builtinFuncs[name].params.length / 2) : (builtinFuncs[name].constr ? (builtinFuncs[name].params.length - 1) : builtinFuncs[name].params.length)), TYPES.number);
|
3446
3951
|
if (importedFuncs[name]) return withType(scope, number(importedFuncs[name].params.length ?? importedFuncs[name].params), TYPES.number);
|
3447
3952
|
if (internalConstrs[name]) return withType(scope, number(internalConstrs[name].length ?? 0), TYPES.number);
|
3448
3953
|
|
@@ -3460,7 +3965,7 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3460
3965
|
const type = getNodeType(scope, decl.object);
|
3461
3966
|
const known = knownType(scope, type);
|
3462
3967
|
if (known != null) {
|
3463
|
-
if (
|
3968
|
+
if (typeHasFlag(known, TYPE_FLAGS.length)) return [
|
3464
3969
|
...generate(scope, decl.object),
|
3465
3970
|
Opcodes.i32_to_u,
|
3466
3971
|
|
@@ -3472,7 +3977,9 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3472
3977
|
}
|
3473
3978
|
|
3474
3979
|
return [
|
3475
|
-
...
|
3980
|
+
...getNodeType(scope, decl.object),
|
3981
|
+
...number(TYPE_FLAGS.length, Valtype.i32),
|
3982
|
+
[ Opcodes.i32_and ],
|
3476
3983
|
[ Opcodes.if, valtypeBinary ],
|
3477
3984
|
...generate(scope, decl.object),
|
3478
3985
|
Opcodes.i32_to_u,
|
@@ -3489,7 +3996,7 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3489
3996
|
}
|
3490
3997
|
|
3491
3998
|
// todo: generate this array procedurally during builtinFuncs creation
|
3492
|
-
if (['size', 'description'].includes(decl.property.name)) {
|
3999
|
+
if (['size', 'description', 'byteLength'].includes(decl.property.name)) {
|
3493
4000
|
const bc = {};
|
3494
4001
|
const cands = Object.keys(builtinFuncs).filter(x => x.startsWith('__') && x.endsWith('_prototype_' + decl.property.name + '$get'));
|
3495
4002
|
|
@@ -3521,7 +4028,9 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3521
4028
|
// // todo: we should only do this for strings but we don't know at compile-time :(
|
3522
4029
|
// hack: this is naughty and will break things!
|
3523
4030
|
let newOut = number(0, Valtype.i32), newPointer = number(0, Valtype.i32);
|
3524
|
-
|
4031
|
+
|
4032
|
+
const known = knownType(scope, getNodeType(scope, decl.object));
|
4033
|
+
if ((known === TYPES.string || known === TYPES.bytestring) || (pages.hasAnyString && known == null)) {
|
3525
4034
|
// todo: we use i16 even for bytestrings which should not make a bad thing happen, just be confusing for debugging?
|
3526
4035
|
0, [ newOut, newPointer ] = makeArray(scope, {
|
3527
4036
|
rawElements: new Array(0)
|
@@ -3595,6 +4104,82 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3595
4104
|
...setLastType(scope, TYPES.bytestring)
|
3596
4105
|
],
|
3597
4106
|
|
4107
|
+
...wrapBC({
|
4108
|
+
[TYPES.uint8array]: [
|
4109
|
+
[ Opcodes.i32_add ],
|
4110
|
+
|
4111
|
+
[ Opcodes.i32_load8_u, 0, 4 ],
|
4112
|
+
Opcodes.i32_from_u
|
4113
|
+
],
|
4114
|
+
[TYPES.uint8clampedarray]: [
|
4115
|
+
[ Opcodes.i32_add ],
|
4116
|
+
|
4117
|
+
[ Opcodes.i32_load8_u, 0, 4 ],
|
4118
|
+
Opcodes.i32_from_u
|
4119
|
+
],
|
4120
|
+
[TYPES.int8array]: [
|
4121
|
+
[ Opcodes.i32_add ],
|
4122
|
+
|
4123
|
+
[ Opcodes.i32_load8_s, 0, 4 ],
|
4124
|
+
Opcodes.i32_from
|
4125
|
+
],
|
4126
|
+
[TYPES.uint16array]: [
|
4127
|
+
...number(2, Valtype.i32),
|
4128
|
+
[ Opcodes.i32_mul ],
|
4129
|
+
[ Opcodes.i32_add ],
|
4130
|
+
|
4131
|
+
[ Opcodes.i32_load16_u, 0, 4 ],
|
4132
|
+
Opcodes.i32_from_u
|
4133
|
+
],
|
4134
|
+
[TYPES.int16array]: [
|
4135
|
+
...number(2, Valtype.i32),
|
4136
|
+
[ Opcodes.i32_mul ],
|
4137
|
+
[ Opcodes.i32_add ],
|
4138
|
+
|
4139
|
+
[ Opcodes.i32_load16_s, 0, 4 ],
|
4140
|
+
Opcodes.i32_from
|
4141
|
+
],
|
4142
|
+
[TYPES.uint32array]: [
|
4143
|
+
...number(4, Valtype.i32),
|
4144
|
+
[ Opcodes.i32_mul ],
|
4145
|
+
[ Opcodes.i32_add ],
|
4146
|
+
|
4147
|
+
[ Opcodes.i32_load, 0, 4 ],
|
4148
|
+
Opcodes.i32_from_u
|
4149
|
+
],
|
4150
|
+
[TYPES.int32array]: [
|
4151
|
+
...number(4, Valtype.i32),
|
4152
|
+
[ Opcodes.i32_mul ],
|
4153
|
+
[ Opcodes.i32_add ],
|
4154
|
+
|
4155
|
+
[ Opcodes.i32_load, 0, 4 ],
|
4156
|
+
Opcodes.i32_from
|
4157
|
+
],
|
4158
|
+
[TYPES.float32array]: [
|
4159
|
+
...number(4, Valtype.i32),
|
4160
|
+
[ Opcodes.i32_mul ],
|
4161
|
+
[ Opcodes.i32_add ],
|
4162
|
+
|
4163
|
+
[ Opcodes.f32_load, 0, 4 ],
|
4164
|
+
[ Opcodes.f64_promote_f32 ]
|
4165
|
+
],
|
4166
|
+
[TYPES.float64array]: [
|
4167
|
+
...number(8, Valtype.i32),
|
4168
|
+
[ Opcodes.i32_mul ],
|
4169
|
+
[ Opcodes.i32_add ],
|
4170
|
+
|
4171
|
+
[ Opcodes.f64_load, 0, 4 ]
|
4172
|
+
],
|
4173
|
+
}, {
|
4174
|
+
prelude: [
|
4175
|
+
...object,
|
4176
|
+
Opcodes.i32_to_u,
|
4177
|
+
...property,
|
4178
|
+
Opcodes.i32_to_u
|
4179
|
+
],
|
4180
|
+
postlude: setLastType(scope, TYPES.number)
|
4181
|
+
}),
|
4182
|
+
|
3598
4183
|
default: internalThrow(scope, 'TypeError', 'Member expression is not supported for non-string non-array yet', true)
|
3599
4184
|
});
|
3600
4185
|
};
|
@@ -3617,7 +4202,7 @@ const objectHack = node => {
|
|
3617
4202
|
if (!objectName) objectName = objectHack(node.object)?.name?.slice?.(2);
|
3618
4203
|
|
3619
4204
|
// if .name or .length, give up (hack within a hack!)
|
3620
|
-
if (['name', 'length', 'size', 'description'].includes(node.property.name)) {
|
4205
|
+
if (['name', 'length', 'size', 'description', 'byteLength'].includes(node.property.name)) {
|
3621
4206
|
node.object = objectHack(node.object);
|
3622
4207
|
return;
|
3623
4208
|
}
|
@@ -3670,8 +4255,8 @@ const generateFunc = (scope, decl) => {
|
|
3670
4255
|
|
3671
4256
|
if (typedInput && decl.returnType) {
|
3672
4257
|
const { type } = extractTypeAnnotation(decl.returnType);
|
3673
|
-
|
3674
|
-
if (type != null) {
|
4258
|
+
if (type != null && !Prefs.indirectCalls) {
|
4259
|
+
// if (type != null) {
|
3675
4260
|
func.returnType = type;
|
3676
4261
|
func.returns = [ valtypeBinary ];
|
3677
4262
|
}
|
@@ -3772,7 +4357,7 @@ const internalConstrs = {
|
|
3772
4357
|
|
3773
4358
|
// todo: check in wasm instead of here
|
3774
4359
|
const literalValue = arg.value ?? 0;
|
3775
|
-
if (literalValue < 0 || !Number.isFinite(literalValue) || literalValue > 4294967295) return internalThrow(scope, '
|
4360
|
+
if (literalValue < 0 || !Number.isFinite(literalValue) || literalValue > 4294967295) return internalThrow(scope, 'RangeError', 'Invalid array length', true);
|
3776
4361
|
|
3777
4362
|
return [
|
3778
4363
|
...out,
|