porffor 0.17.0-048c6f2ee → 0.17.0-0564424f4
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 +51 -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 +6 -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 +701 -136
- package/compiler/generated_builtins.js +2660 -667
- package/compiler/pgo.js +9 -1
- package/compiler/precompile.js +4 -2
- package/compiler/types.js +31 -5
- package/compiler/wasmSpec.js +2 -0
- package/compiler/wrap.js +52 -5
- 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
|
|
@@ -291,12 +297,13 @@ const generateIdent = (scope, decl) => {
|
|
291
297
|
return wasm.slice();
|
292
298
|
}
|
293
299
|
|
294
|
-
|
295
|
-
|
296
|
-
|
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);
|
297
304
|
}
|
298
305
|
|
299
|
-
if (isExistingProtoFunc(name)) {
|
306
|
+
if (isExistingProtoFunc(name) || Object.hasOwn(internalConstrs, name) || Object.hasOwn(builtinFuncs, name)) {
|
300
307
|
// todo: return an actual something
|
301
308
|
return number(1);
|
302
309
|
}
|
@@ -615,11 +622,14 @@ const compareStrings = (scope, left, right, bytestrings = false) => {
|
|
615
622
|
};
|
616
623
|
|
617
624
|
const truthy = (scope, wasm, type, intIn = false, intOut = false, forceTruthyMode = undefined) => {
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
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
|
+
];
|
623
633
|
|
624
634
|
// todo/perf: use knownType and custom bytecode here instead of typeSwitch
|
625
635
|
|
@@ -975,6 +985,33 @@ const performOp = (scope, op, left, right, leftType, rightType, _global = false,
|
|
975
985
|
};
|
976
986
|
|
977
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
|
+
|
978
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);
|
979
1016
|
|
980
1017
|
if (valtype !== 'i32' && ['==', '===', '!=', '!==', '>', '>=', '<', '<='].includes(decl.operator)) out.push(Opcodes.i32_from_u);
|
@@ -992,12 +1029,13 @@ const asmFuncToAsm = (func, scope) => {
|
|
992
1029
|
idx = funcIndex[n];
|
993
1030
|
}
|
994
1031
|
|
1032
|
+
if (idx == null) throw new Error(`builtin('${n}') failed to find a func (inside ${scope.name})`);
|
995
1033
|
return idx;
|
996
1034
|
}
|
997
1035
|
});
|
998
1036
|
};
|
999
1037
|
|
1000
|
-
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 }) => {
|
1001
1039
|
const existing = funcs.find(x => x.name === name);
|
1002
1040
|
if (existing) return existing;
|
1003
1041
|
|
@@ -1024,13 +1062,17 @@ const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes
|
|
1024
1062
|
returnType,
|
1025
1063
|
internal: true,
|
1026
1064
|
index: currentFuncIndex++,
|
1027
|
-
table
|
1065
|
+
table,
|
1066
|
+
constr
|
1028
1067
|
};
|
1029
1068
|
|
1030
1069
|
funcs.push(func);
|
1031
1070
|
funcIndex[name] = func.index;
|
1032
1071
|
|
1033
|
-
if (typeof wasm === 'function')
|
1072
|
+
if (typeof wasm === 'function') {
|
1073
|
+
if (globalThis.precompile) wasm = [];
|
1074
|
+
else wasm = asmFuncToAsm(wasm, func);
|
1075
|
+
}
|
1034
1076
|
|
1035
1077
|
let baseGlobalIdx, i = 0;
|
1036
1078
|
for (const type of globalTypes) {
|
@@ -1051,15 +1093,35 @@ const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes
|
|
1051
1093
|
|
1052
1094
|
if (table) {
|
1053
1095
|
for (const inst of wasm) {
|
1054
|
-
if (inst
|
1096
|
+
if (inst.at(-1) === 'read func lut') {
|
1055
1097
|
inst.splice(2, 99);
|
1056
|
-
inst.push(...unsignedLEB128(allocPage({}, 'func
|
1098
|
+
inst.push(...unsignedLEB128(allocPage({}, 'func lut') * pageSize));
|
1057
1099
|
}
|
1058
1100
|
}
|
1059
1101
|
|
1060
1102
|
funcs.table = true;
|
1061
1103
|
}
|
1062
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
|
+
|
1063
1125
|
func.wasm = wasm;
|
1064
1126
|
|
1065
1127
|
return func;
|
@@ -1186,20 +1248,7 @@ const getNodeType = (scope, node) => {
|
|
1186
1248
|
return TYPES.number;
|
1187
1249
|
}
|
1188
1250
|
|
1189
|
-
if (node.type === 'NewExpression' && builtinFuncs[name + '$constructor']) {
|
1190
|
-
if (builtinFuncs[name + '$constructor'].typedReturns) {
|
1191
|
-
if (scope.locals['#last_type']) return getLastType(scope);
|
1192
|
-
|
1193
|
-
// presume
|
1194
|
-
// todo: warn here?
|
1195
|
-
return TYPES.number;
|
1196
|
-
}
|
1197
|
-
|
1198
|
-
return builtinFuncs[name + '$constructor'].returnType ?? TYPES.number;
|
1199
|
-
}
|
1200
|
-
|
1201
1251
|
const func = funcs.find(x => x.name === name);
|
1202
|
-
|
1203
1252
|
if (func) {
|
1204
1253
|
if (func.returnType != null) return func.returnType;
|
1205
1254
|
}
|
@@ -1281,7 +1330,7 @@ const getNodeType = (scope, node) => {
|
|
1281
1330
|
}
|
1282
1331
|
|
1283
1332
|
if (node.type === 'BinaryExpression') {
|
1284
|
-
if (['==', '===', '!=', '!==', '>', '>=', '<', '<='].includes(node.operator)) return TYPES.boolean;
|
1333
|
+
if (['==', '===', '!=', '!==', '>', '>=', '<', '<=', 'instanceof'].includes(node.operator)) return TYPES.boolean;
|
1285
1334
|
if (node.operator !== '+') return TYPES.number;
|
1286
1335
|
|
1287
1336
|
const knownLeft = knownType(scope, getNodeType(scope, node.left));
|
@@ -1314,7 +1363,7 @@ const getNodeType = (scope, node) => {
|
|
1314
1363
|
const objectKnownType = knownType(scope, getNodeType(scope, node.object));
|
1315
1364
|
if (objectKnownType != null) {
|
1316
1365
|
if (name === 'length') {
|
1317
|
-
if (
|
1366
|
+
if (typeHasFlag(objectKnownType, TYPE_FLAGS.length)) return TYPES.number;
|
1318
1367
|
else return TYPES.undefined;
|
1319
1368
|
}
|
1320
1369
|
|
@@ -1386,9 +1435,9 @@ const countLeftover = wasm => {
|
|
1386
1435
|
|
1387
1436
|
if (depth === 0)
|
1388
1437
|
if ([Opcodes.throw, Opcodes.drop, Opcodes.local_set, Opcodes.global_set].includes(inst[0])) count--;
|
1389
|
-
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)) {}
|
1390
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++;
|
1391
|
-
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;
|
1392
1441
|
else if (inst[0] === Opcodes.memory_copy[0] && (inst[1] === Opcodes.memory_copy[1] || inst[1] === Opcodes.memory_init[1])) count -= 3;
|
1393
1442
|
else if (inst[0] === Opcodes.return) count = 0;
|
1394
1443
|
else if (inst[0] === Opcodes.call) {
|
@@ -1426,6 +1475,18 @@ const generateExp = (scope, decl) => {
|
|
1426
1475
|
return out;
|
1427
1476
|
};
|
1428
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
|
+
|
1429
1490
|
const CTArrayUtil = {
|
1430
1491
|
getLengthI32: pointer => [
|
1431
1492
|
...number(0, Valtype.i32),
|
@@ -1485,7 +1546,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1485
1546
|
name = func.name;
|
1486
1547
|
}
|
1487
1548
|
|
1488
|
-
if (name === 'eval' && decl.arguments[0]?.type === 'Literal') {
|
1549
|
+
if (!decl._new && name === 'eval' && decl.arguments[0]?.type === 'Literal') {
|
1489
1550
|
// literal eval hack
|
1490
1551
|
const code = decl.arguments[0]?.value ?? '';
|
1491
1552
|
|
@@ -1528,7 +1589,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1528
1589
|
|
1529
1590
|
let protoName, target;
|
1530
1591
|
// ident.func()
|
1531
|
-
if (name && name.startsWith('__')) {
|
1592
|
+
if (!decl._new && name && name.startsWith('__')) {
|
1532
1593
|
const spl = name.slice(2).split('_');
|
1533
1594
|
|
1534
1595
|
protoName = spl[spl.length - 1];
|
@@ -1541,12 +1602,12 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1541
1602
|
}
|
1542
1603
|
|
1543
1604
|
// literal.func()
|
1544
|
-
if (!name && decl.callee.type === 'MemberExpression') {
|
1605
|
+
if (!decl._new && !name && decl.callee.type === 'MemberExpression') {
|
1545
1606
|
// megahack for /regex/.func()
|
1546
1607
|
const funcName = decl.callee.property.name;
|
1547
|
-
if (decl.callee.object.regex &&
|
1608
|
+
if (decl.callee.object.regex && ['test'].includes(funcName)) {
|
1548
1609
|
const regex = decl.callee.object.regex.pattern;
|
1549
|
-
const rhemynName = `regex_${funcName}_${regex}`;
|
1610
|
+
const rhemynName = `regex_${funcName}_${sanitize(regex)}`;
|
1550
1611
|
|
1551
1612
|
if (!funcIndex[rhemynName]) {
|
1552
1613
|
const func = Rhemyn[funcName](regex, currentFuncIndex++, rhemynName);
|
@@ -1567,7 +1628,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1567
1628
|
[ Opcodes.call, idx ],
|
1568
1629
|
Opcodes.i32_from_u,
|
1569
1630
|
|
1570
|
-
...setLastType(scope,
|
1631
|
+
...setLastType(scope, Rhemyn.types[funcName])
|
1571
1632
|
];
|
1572
1633
|
}
|
1573
1634
|
|
@@ -1576,27 +1637,56 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1576
1637
|
target = decl.callee.object;
|
1577
1638
|
}
|
1578
1639
|
|
1579
|
-
|
1580
|
-
|
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 ],
|
1581
1648
|
|
1582
|
-
|
1583
|
-
|
1649
|
+
...number(Rhemyn.types[protoName] === TYPES.number ? -1 : 0),
|
1650
|
+
...setLastType(scope, Rhemyn.types[protoName])
|
1651
|
+
];
|
1584
1652
|
|
1585
|
-
|
1586
|
-
// generate(scope, decl.callee.object)
|
1653
|
+
const rhemynName = `regex_${protoName}_${sanitize(regex)}`;
|
1587
1654
|
|
1588
|
-
|
1589
|
-
|
1590
|
-
|
1591
|
-
// ];
|
1592
|
-
// }
|
1655
|
+
if (!funcIndex[rhemynName]) {
|
1656
|
+
const func = Rhemyn[protoName](regex, currentFuncIndex++, rhemynName);
|
1657
|
+
func.internal = true;
|
1593
1658
|
|
1594
|
-
|
1595
|
-
|
1659
|
+
funcIndex[func.name] = func.index;
|
1660
|
+
funcs.push(func);
|
1661
|
+
}
|
1596
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
|
+
}
|
1677
|
+
|
1678
|
+
const protoBC = {};
|
1597
1679
|
const builtinProtoCands = Object.keys(builtinFuncs).filter(x => x.startsWith('__') && x.endsWith('_prototype_' + protoName));
|
1598
1680
|
|
1599
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
|
+
|
1600
1690
|
for (const x of builtinProtoCands) {
|
1601
1691
|
const type = TYPES[x.split('_prototype_')[0].slice(2).toLowerCase()];
|
1602
1692
|
if (type == null) continue;
|
@@ -1606,7 +1696,14 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1606
1696
|
type: 'Identifier',
|
1607
1697
|
name: x
|
1608
1698
|
},
|
1609
|
-
arguments: [
|
1699
|
+
arguments: [
|
1700
|
+
{
|
1701
|
+
type: 'Identifier',
|
1702
|
+
name: '#proto_target'
|
1703
|
+
},
|
1704
|
+
|
1705
|
+
...decl.arguments
|
1706
|
+
],
|
1610
1707
|
_protoInternalCall: true
|
1611
1708
|
});
|
1612
1709
|
}
|
@@ -1700,29 +1797,37 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1700
1797
|
}
|
1701
1798
|
|
1702
1799
|
if (Object.keys(protoBC).length > 0) {
|
1703
|
-
return
|
1704
|
-
...
|
1800
|
+
return [
|
1801
|
+
...out,
|
1705
1802
|
|
1706
|
-
|
1707
|
-
|
1708
|
-
|
1803
|
+
...typeSwitch(scope, builtinProtoCands.length > 0 ? [ [ Opcodes.local_get, localTmp(scope, '#proto_target#type', Valtype.i32) ] ] : getNodeType(scope, target), {
|
1804
|
+
...protoBC,
|
1805
|
+
|
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
|
+
];
|
1709
1810
|
}
|
1710
1811
|
}
|
1711
1812
|
|
1712
|
-
// TODO: only allows callee as
|
1713
|
-
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})`);
|
1714
1815
|
|
1715
1816
|
let idx = funcIndex[name] ?? importedFuncs[name];
|
1716
1817
|
if (idx === undefined && builtinFuncs[name]) {
|
1717
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);
|
1718
1820
|
|
1719
1821
|
includeBuiltin(scope, name);
|
1720
1822
|
idx = funcIndex[name];
|
1721
1823
|
}
|
1722
1824
|
|
1723
|
-
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
|
+
}
|
1724
1829
|
|
1725
|
-
if (idx === undefined && name.startsWith('__Porffor_wasm_')) {
|
1830
|
+
if (idx === undefined && !decl._new && name.startsWith('__Porffor_wasm_')) {
|
1726
1831
|
const wasmOps = {
|
1727
1832
|
// pointer, align, offset
|
1728
1833
|
i32_load: { imms: 2, args: [ true ], returns: 1 },
|
@@ -1777,7 +1882,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1777
1882
|
|
1778
1883
|
const indirectMode = Prefs.indirectCallMode ?? 'vararg';
|
1779
1884
|
// options: vararg, strict
|
1780
|
-
// - strict: simpler, smaller size usage, no func
|
1885
|
+
// - strict: simpler, smaller size usage, no func lut needed.
|
1781
1886
|
// ONLY works when arg count of call == arg count of function being called
|
1782
1887
|
// - vararg: large size usage, cursed.
|
1783
1888
|
// works when arg count of call != arg count of function being called*
|
@@ -1787,8 +1892,6 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1787
1892
|
scope.table = true;
|
1788
1893
|
|
1789
1894
|
let args = decl.arguments;
|
1790
|
-
let out = [];
|
1791
|
-
|
1792
1895
|
let locals = [];
|
1793
1896
|
|
1794
1897
|
if (indirectMode === 'vararg') {
|
@@ -1852,24 +1955,67 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1852
1955
|
// *for argc 0-3, in future (todo:) the max number should be
|
1853
1956
|
// dynamically changed to the max argc of any func in the js file.
|
1854
1957
|
|
1855
|
-
const funcLocal = localTmp(scope,
|
1958
|
+
const funcLocal = localTmp(scope, '#indirect_func', Valtype.i32);
|
1959
|
+
const flags = localTmp(scope, '#indirect_flags', Valtype.i32);
|
1856
1960
|
|
1857
1961
|
const gen = argc => {
|
1858
|
-
const
|
1962
|
+
const argsOut = [];
|
1859
1963
|
for (let i = 0; i < argc; i++) {
|
1860
|
-
|
1964
|
+
argsOut.push(
|
1861
1965
|
[ Opcodes.local_get, locals[i][0] ],
|
1862
1966
|
[ Opcodes.local_get, locals[i][1] ]
|
1863
1967
|
);
|
1864
1968
|
}
|
1865
1969
|
|
1866
|
-
|
1867
|
-
[ Opcodes.local_get,
|
1868
|
-
|
1869
|
-
|
1870
|
-
|
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
|
+
];
|
1871
1980
|
|
1872
|
-
|
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
|
+
);
|
1873
2019
|
};
|
1874
2020
|
|
1875
2021
|
const tableBc = {};
|
@@ -1887,13 +2033,32 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1887
2033
|
Opcodes.i32_to_u,
|
1888
2034
|
[ Opcodes.local_set, funcLocal ],
|
1889
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
|
+
|
1890
2056
|
...brTable([
|
1891
2057
|
// get argc of func we are calling
|
1892
2058
|
[ Opcodes.local_get, funcLocal ],
|
1893
|
-
...number(
|
2059
|
+
...number(3, Valtype.i32),
|
1894
2060
|
[ Opcodes.i32_mul ],
|
1895
|
-
|
1896
|
-
[ 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' ]
|
1897
2062
|
], tableBc, valtypeBinary)
|
1898
2063
|
],
|
1899
2064
|
default: internalThrow(scope, 'TypeError', `${unhackName(name)} is not a function`, true)
|
@@ -1907,7 +2072,16 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1907
2072
|
const userFunc = func && !func.internal;
|
1908
2073
|
const typedParams = userFunc || builtinFuncs[name]?.typedParams;
|
1909
2074
|
const typedReturns = (userFunc && func.returnType == null) || builtinFuncs[name]?.typedReturns;
|
1910
|
-
|
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);
|
1911
2085
|
|
1912
2086
|
let args = decl.arguments;
|
1913
2087
|
if (func && args.length < paramCount) {
|
@@ -1922,7 +2096,6 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1922
2096
|
|
1923
2097
|
if (func && func.throws) scope.throws = true;
|
1924
2098
|
|
1925
|
-
let out = [];
|
1926
2099
|
for (let i = 0; i < args.length; i++) {
|
1927
2100
|
const arg = args[i];
|
1928
2101
|
out = out.concat(generate(scope, arg));
|
@@ -1935,13 +2108,13 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1935
2108
|
}
|
1936
2109
|
|
1937
2110
|
if (valtypeBinary !== Valtype.i32 &&
|
1938
|
-
(func && func.params[i * (typedParams ? 2 : 1)] === Valtype.i32)
|
2111
|
+
(func && func.params[paramOffset + i * (typedParams ? 2 : 1)] === Valtype.i32)
|
1939
2112
|
) {
|
1940
2113
|
out.push(Opcodes.i32_to);
|
1941
2114
|
}
|
1942
2115
|
|
1943
2116
|
if (valtypeBinary === Valtype.i32 &&
|
1944
|
-
(func && func.params[i * (typedParams ? 2 : 1)] === Valtype.f64)
|
2117
|
+
(func && func.params[paramOffset + i * (typedParams ? 2 : 1)] === Valtype.f64)
|
1945
2118
|
) {
|
1946
2119
|
out.push([ Opcodes.f64_convert_i32_s ]);
|
1947
2120
|
}
|
@@ -1974,32 +2147,10 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1974
2147
|
return out;
|
1975
2148
|
};
|
1976
2149
|
|
1977
|
-
const generateNew = (scope, decl, _global, _name) => {
|
1978
|
-
|
1979
|
-
|
1980
|
-
|
1981
|
-
if (internalConstrs[name] && !internalConstrs[name].notConstr) return internalConstrs[name].generate(scope, decl, _global, _name);
|
1982
|
-
|
1983
|
-
if (builtinFuncs[name + '$constructor']) {
|
1984
|
-
// custom ...$constructor override builtin func
|
1985
|
-
return generateCall(scope, {
|
1986
|
-
...decl,
|
1987
|
-
callee: {
|
1988
|
-
type: 'Identifier',
|
1989
|
-
name: name + '$constructor'
|
1990
|
-
}
|
1991
|
-
}, _global, _name);
|
1992
|
-
}
|
1993
|
-
|
1994
|
-
if (
|
1995
|
-
(builtinFuncs[name] && !builtinFuncs[name].constr) ||
|
1996
|
-
(internalConstrs[name] && builtinFuncs[name].notConstr)
|
1997
|
-
) return internalThrow(scope, 'TypeError', `${name} is not a constructor`, true);
|
1998
|
-
|
1999
|
-
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)})`);
|
2000
|
-
|
2001
|
-
return generateCall(scope, decl, _global, _name);
|
2002
|
-
};
|
2150
|
+
const generateNew = (scope, decl, _global, _name) => generateCall(scope, {
|
2151
|
+
...decl,
|
2152
|
+
_new: true
|
2153
|
+
}, _global, _name);
|
2003
2154
|
|
2004
2155
|
// bad hack for undefined and null working without additional logic
|
2005
2156
|
const DEFAULT_VALUE = {
|
@@ -2007,6 +2158,16 @@ const DEFAULT_VALUE = {
|
|
2007
2158
|
name: 'undefined'
|
2008
2159
|
};
|
2009
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
|
+
|
2010
2171
|
const unhackName = name => {
|
2011
2172
|
if (name.startsWith('__')) return name.slice(2).replaceAll('_', '.');
|
2012
2173
|
return name;
|
@@ -2014,7 +2175,7 @@ const unhackName = name => {
|
|
2014
2175
|
|
2015
2176
|
const knownType = (scope, type) => {
|
2016
2177
|
if (type.length === 1 && type[0][0] === Opcodes.i32_const) {
|
2017
|
-
return type[0]
|
2178
|
+
return read_signedLEB128(type[0].slice(1));
|
2018
2179
|
}
|
2019
2180
|
|
2020
2181
|
if (typedInput && type.length === 1 && type[0][0] === Opcodes.local_get) {
|
@@ -2301,11 +2462,6 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2301
2462
|
const { type, name } = decl.left;
|
2302
2463
|
const [ local, isGlobal ] = lookupName(scope, name);
|
2303
2464
|
|
2304
|
-
if (type === 'ObjectPattern') {
|
2305
|
-
// hack: ignore object parts of `var a = {} = 2`
|
2306
|
-
return generate(scope, decl.right);
|
2307
|
-
}
|
2308
|
-
|
2309
2465
|
if (isFuncType(decl.right.type)) {
|
2310
2466
|
// hack for a = function () { ... }
|
2311
2467
|
decl.right.id = { name };
|
@@ -2378,10 +2534,160 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2378
2534
|
[ Opcodes.i32_load8_u, 0, ValtypeSize.i32 + ValtypeSize[valtype] ]
|
2379
2535
|
], getNodeType(scope, decl.right), false, name, true)),
|
2380
2536
|
[ Opcodes.local_tee, newValueTmp ],
|
2381
|
-
|
2382
2537
|
[ Opcodes.store, 0, ValtypeSize.i32 ]
|
2383
2538
|
],
|
2384
2539
|
|
2540
|
+
...wrapBC({
|
2541
|
+
[TYPES.uint8array]: [
|
2542
|
+
[ Opcodes.i32_add ],
|
2543
|
+
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2544
|
+
|
2545
|
+
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2546
|
+
[ Opcodes.local_get, pointerTmp ],
|
2547
|
+
[ Opcodes.i32_load8_u, 0, 4 ],
|
2548
|
+
Opcodes.i32_from_u
|
2549
|
+
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
2550
|
+
[ Opcodes.local_tee, newValueTmp ],
|
2551
|
+
|
2552
|
+
Opcodes.i32_to_u,
|
2553
|
+
[ Opcodes.i32_store8, 0, 4 ]
|
2554
|
+
],
|
2555
|
+
[TYPES.uint8clampedarray]: [
|
2556
|
+
[ Opcodes.i32_add ],
|
2557
|
+
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2558
|
+
|
2559
|
+
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2560
|
+
[ Opcodes.local_get, pointerTmp ],
|
2561
|
+
[ Opcodes.i32_load8_u, 0, 4 ],
|
2562
|
+
Opcodes.i32_from_u
|
2563
|
+
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
2564
|
+
[ Opcodes.local_tee, newValueTmp ],
|
2565
|
+
|
2566
|
+
...number(0),
|
2567
|
+
[ Opcodes.f64_max ],
|
2568
|
+
...number(255),
|
2569
|
+
[ Opcodes.f64_min ],
|
2570
|
+
Opcodes.i32_to_u,
|
2571
|
+
[ Opcodes.i32_store8, 0, 4 ]
|
2572
|
+
],
|
2573
|
+
[TYPES.int8array]: [
|
2574
|
+
[ Opcodes.i32_add ],
|
2575
|
+
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2576
|
+
|
2577
|
+
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2578
|
+
[ Opcodes.local_get, pointerTmp ],
|
2579
|
+
[ Opcodes.i32_load8_s, 0, 4 ],
|
2580
|
+
Opcodes.i32_from
|
2581
|
+
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
2582
|
+
[ Opcodes.local_tee, newValueTmp ],
|
2583
|
+
|
2584
|
+
Opcodes.i32_to,
|
2585
|
+
[ Opcodes.i32_store8, 0, 4 ]
|
2586
|
+
],
|
2587
|
+
[TYPES.uint16array]: [
|
2588
|
+
...number(2, Valtype.i32),
|
2589
|
+
[ Opcodes.i32_mul ],
|
2590
|
+
[ Opcodes.i32_add ],
|
2591
|
+
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2592
|
+
|
2593
|
+
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2594
|
+
[ Opcodes.local_get, pointerTmp ],
|
2595
|
+
[ Opcodes.i32_load16_u, 0, 4 ],
|
2596
|
+
Opcodes.i32_from_u
|
2597
|
+
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
2598
|
+
[ Opcodes.local_tee, newValueTmp ],
|
2599
|
+
|
2600
|
+
Opcodes.i32_to_u,
|
2601
|
+
[ Opcodes.i32_store16, 0, 4 ]
|
2602
|
+
],
|
2603
|
+
[TYPES.int16array]: [
|
2604
|
+
...number(2, Valtype.i32),
|
2605
|
+
[ Opcodes.i32_mul ],
|
2606
|
+
[ Opcodes.i32_add ],
|
2607
|
+
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2608
|
+
|
2609
|
+
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2610
|
+
[ Opcodes.local_get, pointerTmp ],
|
2611
|
+
[ Opcodes.i32_load16_s, 0, 4 ],
|
2612
|
+
Opcodes.i32_from
|
2613
|
+
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
2614
|
+
[ Opcodes.local_tee, newValueTmp ],
|
2615
|
+
|
2616
|
+
Opcodes.i32_to,
|
2617
|
+
[ Opcodes.i32_store16, 0, 4 ]
|
2618
|
+
],
|
2619
|
+
[TYPES.uint32array]: [
|
2620
|
+
...number(4, Valtype.i32),
|
2621
|
+
[ Opcodes.i32_mul ],
|
2622
|
+
[ Opcodes.i32_add ],
|
2623
|
+
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2624
|
+
|
2625
|
+
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2626
|
+
[ Opcodes.local_get, pointerTmp ],
|
2627
|
+
[ Opcodes.i32_load, 0, 4 ],
|
2628
|
+
Opcodes.i32_from_u
|
2629
|
+
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
2630
|
+
[ Opcodes.local_tee, newValueTmp ],
|
2631
|
+
|
2632
|
+
Opcodes.i32_to_u,
|
2633
|
+
[ Opcodes.i32_store, 0, 4 ]
|
2634
|
+
],
|
2635
|
+
[TYPES.int32array]: [
|
2636
|
+
...number(4, Valtype.i32),
|
2637
|
+
[ Opcodes.i32_mul ],
|
2638
|
+
[ Opcodes.i32_add ],
|
2639
|
+
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2640
|
+
|
2641
|
+
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2642
|
+
[ Opcodes.local_get, pointerTmp ],
|
2643
|
+
[ Opcodes.i32_load, 0, 4 ],
|
2644
|
+
Opcodes.i32_from
|
2645
|
+
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
2646
|
+
[ Opcodes.local_tee, newValueTmp ],
|
2647
|
+
|
2648
|
+
Opcodes.i32_to,
|
2649
|
+
[ Opcodes.i32_store, 0, 4 ]
|
2650
|
+
],
|
2651
|
+
[TYPES.float32array]: [
|
2652
|
+
...number(4, Valtype.i32),
|
2653
|
+
[ Opcodes.i32_mul ],
|
2654
|
+
[ Opcodes.i32_add ],
|
2655
|
+
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2656
|
+
|
2657
|
+
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2658
|
+
[ Opcodes.local_get, pointerTmp ],
|
2659
|
+
[ Opcodes.f32_load, 0, 4 ],
|
2660
|
+
[ Opcodes.f64_promote_f32 ]
|
2661
|
+
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
2662
|
+
[ Opcodes.local_tee, newValueTmp ],
|
2663
|
+
|
2664
|
+
[ Opcodes.f32_demote_f64 ],
|
2665
|
+
[ Opcodes.f32_store, 0, 4 ]
|
2666
|
+
],
|
2667
|
+
[TYPES.float64array]: [
|
2668
|
+
...number(8, Valtype.i32),
|
2669
|
+
[ Opcodes.i32_mul ],
|
2670
|
+
[ Opcodes.i32_add ],
|
2671
|
+
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2672
|
+
|
2673
|
+
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2674
|
+
[ Opcodes.local_get, pointerTmp ],
|
2675
|
+
[ Opcodes.f64_load, 0, 4 ]
|
2676
|
+
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
2677
|
+
[ Opcodes.local_tee, newValueTmp ],
|
2678
|
+
|
2679
|
+
[ Opcodes.f64_store, 0, 4 ]
|
2680
|
+
],
|
2681
|
+
}, {
|
2682
|
+
prelude: [
|
2683
|
+
...generate(scope, decl.left.object),
|
2684
|
+
Opcodes.i32_to_u,
|
2685
|
+
...generate(scope, decl.left.property),
|
2686
|
+
Opcodes.i32_to_u,
|
2687
|
+
],
|
2688
|
+
postlude: setLastType(scope, TYPES.number)
|
2689
|
+
}),
|
2690
|
+
|
2385
2691
|
default: internalThrow(scope, 'TypeError', `Cannot assign member with non-array`)
|
2386
2692
|
}, Blocktype.void),
|
2387
2693
|
|
@@ -2765,7 +3071,9 @@ const generateForOf = (scope, decl) => {
|
|
2765
3071
|
// // todo: we should only do this for strings but we don't know at compile-time :(
|
2766
3072
|
// hack: this is naughty and will break things!
|
2767
3073
|
let newOut = number(0, Valtype.i32), newPointer = number(0, Valtype.i32);
|
2768
|
-
|
3074
|
+
|
3075
|
+
const known = knownType(scope, getNodeType(scope, decl.right));
|
3076
|
+
if ((known === TYPES.string || known === TYPES.bytestring) || (pages.hasAnyString && known == null)) {
|
2769
3077
|
// todo: we use i16 even for bytestrings which should not make a bad thing happen, just be confusing for debugging?
|
2770
3078
|
0, [ newOut, newPointer ] = makeArray(scope, {
|
2771
3079
|
rawElements: new Array(0)
|
@@ -2813,6 +3121,7 @@ const generateForOf = (scope, decl) => {
|
|
2813
3121
|
[ Opcodes.end ],
|
2814
3122
|
[ Opcodes.end ]
|
2815
3123
|
],
|
3124
|
+
|
2816
3125
|
[TYPES.string]: [
|
2817
3126
|
...setType(scope, leftName, TYPES.string),
|
2818
3127
|
|
@@ -2921,6 +3230,7 @@ const generateForOf = (scope, decl) => {
|
|
2921
3230
|
[ Opcodes.end ],
|
2922
3231
|
[ Opcodes.end ]
|
2923
3232
|
],
|
3233
|
+
|
2924
3234
|
[TYPES.set]: [
|
2925
3235
|
[ Opcodes.loop, Blocktype.void ],
|
2926
3236
|
|
@@ -2959,6 +3269,106 @@ const generateForOf = (scope, decl) => {
|
|
2959
3269
|
[ Opcodes.end ],
|
2960
3270
|
[ Opcodes.end ]
|
2961
3271
|
],
|
3272
|
+
|
3273
|
+
...wrapBC({
|
3274
|
+
[TYPES.uint8array]: [
|
3275
|
+
[ Opcodes.i32_add ],
|
3276
|
+
|
3277
|
+
[ Opcodes.i32_load8_u, 0, 4 ],
|
3278
|
+
Opcodes.i32_from_u
|
3279
|
+
],
|
3280
|
+
[TYPES.uint8clampedarray]: [
|
3281
|
+
[ Opcodes.i32_add ],
|
3282
|
+
|
3283
|
+
[ Opcodes.i32_load8_u, 0, 4 ],
|
3284
|
+
Opcodes.i32_from_u
|
3285
|
+
],
|
3286
|
+
[TYPES.int8array]: [
|
3287
|
+
[ Opcodes.i32_add ],
|
3288
|
+
|
3289
|
+
[ Opcodes.i32_load8_s, 0, 4 ],
|
3290
|
+
Opcodes.i32_from
|
3291
|
+
],
|
3292
|
+
[TYPES.uint16array]: [
|
3293
|
+
...number(2, Valtype.i32),
|
3294
|
+
[ Opcodes.i32_mul ],
|
3295
|
+
[ Opcodes.i32_add ],
|
3296
|
+
|
3297
|
+
[ Opcodes.i32_load16_u, 0, 4 ],
|
3298
|
+
Opcodes.i32_from_u
|
3299
|
+
],
|
3300
|
+
[TYPES.int16array]: [
|
3301
|
+
...number(2, Valtype.i32),
|
3302
|
+
[ Opcodes.i32_mul ],
|
3303
|
+
[ Opcodes.i32_add ],
|
3304
|
+
|
3305
|
+
[ Opcodes.i32_load16_s, 0, 4 ],
|
3306
|
+
Opcodes.i32_from
|
3307
|
+
],
|
3308
|
+
[TYPES.uint32array]: [
|
3309
|
+
...number(4, Valtype.i32),
|
3310
|
+
[ Opcodes.i32_mul ],
|
3311
|
+
[ Opcodes.i32_add ],
|
3312
|
+
|
3313
|
+
[ Opcodes.i32_load, 0, 4 ],
|
3314
|
+
Opcodes.i32_from_u
|
3315
|
+
],
|
3316
|
+
[TYPES.int32array]: [
|
3317
|
+
...number(4, Valtype.i32),
|
3318
|
+
[ Opcodes.i32_mul ],
|
3319
|
+
[ Opcodes.i32_add ],
|
3320
|
+
|
3321
|
+
[ Opcodes.i32_load, 0, 4 ],
|
3322
|
+
Opcodes.i32_from
|
3323
|
+
],
|
3324
|
+
[TYPES.float32array]: [
|
3325
|
+
...number(4, Valtype.i32),
|
3326
|
+
[ Opcodes.i32_mul ],
|
3327
|
+
[ Opcodes.i32_add ],
|
3328
|
+
|
3329
|
+
[ Opcodes.f32_load, 0, 4 ],
|
3330
|
+
[ Opcodes.f64_promote_f32 ]
|
3331
|
+
],
|
3332
|
+
[TYPES.float64array]: [
|
3333
|
+
...number(8, Valtype.i32),
|
3334
|
+
[ Opcodes.i32_mul ],
|
3335
|
+
[ Opcodes.i32_add ],
|
3336
|
+
|
3337
|
+
[ Opcodes.f64_load, 0, 4 ]
|
3338
|
+
],
|
3339
|
+
}, {
|
3340
|
+
prelude: [
|
3341
|
+
...setType(scope, leftName, TYPES.number),
|
3342
|
+
|
3343
|
+
[ Opcodes.loop, Blocktype.void ],
|
3344
|
+
|
3345
|
+
[ Opcodes.local_get, pointer ],
|
3346
|
+
[ Opcodes.local_get, counter ]
|
3347
|
+
],
|
3348
|
+
postlude: [
|
3349
|
+
[ isGlobal ? Opcodes.global_set : Opcodes.local_set, local.idx ],
|
3350
|
+
|
3351
|
+
[ Opcodes.block, Blocktype.void ],
|
3352
|
+
[ Opcodes.block, Blocktype.void ],
|
3353
|
+
...generate(scope, decl.body),
|
3354
|
+
[ Opcodes.end ],
|
3355
|
+
|
3356
|
+
// increment counter by 1
|
3357
|
+
[ Opcodes.local_get, counter ],
|
3358
|
+
...number(1, Valtype.i32),
|
3359
|
+
[ Opcodes.i32_add ],
|
3360
|
+
[ Opcodes.local_tee, counter ],
|
3361
|
+
|
3362
|
+
// loop if counter != length
|
3363
|
+
[ Opcodes.local_get, length ],
|
3364
|
+
[ Opcodes.i32_ne ],
|
3365
|
+
[ Opcodes.br_if, 1 ],
|
3366
|
+
|
3367
|
+
[ Opcodes.end ],
|
3368
|
+
[ Opcodes.end ]
|
3369
|
+
]
|
3370
|
+
}),
|
3371
|
+
|
2962
3372
|
default: internalThrow(scope, 'TypeError', `Tried for..of on non-iterable type`)
|
2963
3373
|
}, Blocktype.void));
|
2964
3374
|
|
@@ -3047,13 +3457,14 @@ const generateThrow = (scope, decl) => {
|
|
3047
3457
|
idx: tags.length
|
3048
3458
|
});
|
3049
3459
|
|
3050
|
-
let exceptId = exceptions.
|
3460
|
+
let exceptId = exceptions.findIndex(x => x.constructor === constructor && x.message === message);
|
3461
|
+
if (exceptId === -1) exceptId = exceptions.push({ constructor, message }) - 1;
|
3051
3462
|
|
3052
3463
|
scope.exceptions ??= [];
|
3053
3464
|
scope.exceptions.push(exceptId);
|
3054
3465
|
|
3055
3466
|
return [
|
3056
|
-
|
3467
|
+
...number(exceptId, Valtype.i32),
|
3057
3468
|
[ Opcodes.throw, tags[0].idx ]
|
3058
3469
|
];
|
3059
3470
|
}
|
@@ -3071,6 +3482,61 @@ const generateThrow = (scope, decl) => {
|
|
3071
3482
|
[ Opcodes.throw, tags[0].idx ]
|
3072
3483
|
];
|
3073
3484
|
}
|
3485
|
+
|
3486
|
+
if (exceptionMode === 'stackest') {
|
3487
|
+
let message = decl.argument, constructor = null;
|
3488
|
+
|
3489
|
+
// support `throw (new)? Error(...)`
|
3490
|
+
if (message.type === 'NewExpression' || message.type === 'CallExpression') {
|
3491
|
+
constructor = decl.argument.callee;
|
3492
|
+
message = decl.argument.arguments[0];
|
3493
|
+
}
|
3494
|
+
|
3495
|
+
message ??= DEFAULT_VALUE;
|
3496
|
+
|
3497
|
+
if (tags.length === 0) tags.push({
|
3498
|
+
params: [ valtypeBinary, valtypeBinary, Valtype.i32 ],
|
3499
|
+
results: [],
|
3500
|
+
idx: tags.length
|
3501
|
+
});
|
3502
|
+
|
3503
|
+
return [
|
3504
|
+
...(constructor == null ? number(-1) : generate(scope, constructor)),
|
3505
|
+
...generate(scope, message),
|
3506
|
+
...getNodeType(scope, message),
|
3507
|
+
[ Opcodes.throw, tags[0].idx ]
|
3508
|
+
];
|
3509
|
+
}
|
3510
|
+
|
3511
|
+
if (exceptionMode === 'partial') {
|
3512
|
+
let message = decl.argument, constructor = null;
|
3513
|
+
|
3514
|
+
// support `throw (new)? Error(...)`
|
3515
|
+
if (message.type === 'NewExpression' || message.type === 'CallExpression') {
|
3516
|
+
constructor = decl.argument.callee.name;
|
3517
|
+
message = decl.argument.arguments[0];
|
3518
|
+
}
|
3519
|
+
|
3520
|
+
message ??= DEFAULT_VALUE;
|
3521
|
+
|
3522
|
+
if (tags.length === 0) tags.push({
|
3523
|
+
params: [ Valtype.i32, valtypeBinary, Valtype.i32 ],
|
3524
|
+
results: [],
|
3525
|
+
idx: tags.length
|
3526
|
+
});
|
3527
|
+
|
3528
|
+
let exceptId = exceptions.push({ constructor }) - 1;
|
3529
|
+
|
3530
|
+
scope.exceptions ??= [];
|
3531
|
+
scope.exceptions.push(exceptId);
|
3532
|
+
|
3533
|
+
return [
|
3534
|
+
...number(exceptId, Valtype.i32),
|
3535
|
+
...generate(scope, message),
|
3536
|
+
...getNodeType(scope, message),
|
3537
|
+
[ Opcodes.throw, tags[0].idx ]
|
3538
|
+
];
|
3539
|
+
}
|
3074
3540
|
};
|
3075
3541
|
|
3076
3542
|
const generateTry = (scope, decl) => {
|
@@ -3106,6 +3572,22 @@ const generateEmpty = (scope, decl) => {
|
|
3106
3572
|
return [];
|
3107
3573
|
};
|
3108
3574
|
|
3575
|
+
const generateMeta = (scope, decl) => {
|
3576
|
+
if (decl.meta.name !== 'new') return todo(scope, `meta property object ${decl.meta.name} is not supported yet`, true);
|
3577
|
+
|
3578
|
+
switch (`${decl.meta.name}.${decl.property.name}`) {
|
3579
|
+
case 'new.target': {
|
3580
|
+
scope.constr = true;
|
3581
|
+
|
3582
|
+
return [
|
3583
|
+
[ Opcodes.local_get, -1 ],
|
3584
|
+
Opcodes.i32_from_u,
|
3585
|
+
...setLastType(scope, TYPES.boolean)
|
3586
|
+
];
|
3587
|
+
}
|
3588
|
+
}
|
3589
|
+
};
|
3590
|
+
|
3109
3591
|
let pages = new Map();
|
3110
3592
|
const allocPage = (scope, reason, type) => {
|
3111
3593
|
if (pages.has(reason)) return pages.get(reason).ind;
|
@@ -3423,6 +3905,19 @@ const withType = (scope, wasm, type) => [
|
|
3423
3905
|
...setLastType(scope, type)
|
3424
3906
|
];
|
3425
3907
|
|
3908
|
+
const wrapBC = (bc, { prelude = [], postlude = [] } = {}) => {
|
3909
|
+
const out = {};
|
3910
|
+
for (const x in bc) {
|
3911
|
+
out[x] = [
|
3912
|
+
...prelude,
|
3913
|
+
...bc[x],
|
3914
|
+
...postlude
|
3915
|
+
];
|
3916
|
+
}
|
3917
|
+
|
3918
|
+
return out;
|
3919
|
+
};
|
3920
|
+
|
3426
3921
|
const generateMember = (scope, decl, _global, _name) => {
|
3427
3922
|
const name = decl.object.name;
|
3428
3923
|
|
@@ -3445,20 +3940,10 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3445
3940
|
const func = funcs.find(x => x.name === name);
|
3446
3941
|
if (func) {
|
3447
3942
|
const typedParams = !func.internal || builtinFuncs[name]?.typedParams;
|
3448
|
-
return withType(scope, number(typedParams ? func.params.length / 2 : func.params.length), TYPES.number);
|
3943
|
+
return withType(scope, number(typedParams ? Math.floor(func.params.length / 2) : (func.constr ? (func.params.length - 1) : func.params.length)), TYPES.number);
|
3449
3944
|
}
|
3450
3945
|
|
3451
|
-
if (builtinFuncs[name
|
3452
|
-
const regularFunc = builtinFuncs[name];
|
3453
|
-
const regularParams = regularFunc.typedParams ? (regularFunc.params.length / 2) : regularFunc.params.length;
|
3454
|
-
|
3455
|
-
const constructorFunc = builtinFuncs[name + '$constructor'];
|
3456
|
-
const constructorParams = constructorFunc.typedParams ? (constructorFunc.params.length / 2) : constructorFunc.params.length;
|
3457
|
-
|
3458
|
-
return withType(scope, number(Math.max(regularParams, constructorParams)), TYPES.number);
|
3459
|
-
}
|
3460
|
-
|
3461
|
-
if (builtinFuncs[name]) return withType(scope, number(builtinFuncs[name].typedParams ? (builtinFuncs[name].params.length / 2) : builtinFuncs[name].params.length), TYPES.number);
|
3946
|
+
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);
|
3462
3947
|
if (importedFuncs[name]) return withType(scope, number(importedFuncs[name].params.length ?? importedFuncs[name].params), TYPES.number);
|
3463
3948
|
if (internalConstrs[name]) return withType(scope, number(internalConstrs[name].length ?? 0), TYPES.number);
|
3464
3949
|
|
@@ -3476,7 +3961,7 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3476
3961
|
const type = getNodeType(scope, decl.object);
|
3477
3962
|
const known = knownType(scope, type);
|
3478
3963
|
if (known != null) {
|
3479
|
-
if (
|
3964
|
+
if (typeHasFlag(known, TYPE_FLAGS.length)) return [
|
3480
3965
|
...generate(scope, decl.object),
|
3481
3966
|
Opcodes.i32_to_u,
|
3482
3967
|
|
@@ -3488,7 +3973,9 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3488
3973
|
}
|
3489
3974
|
|
3490
3975
|
return [
|
3491
|
-
...
|
3976
|
+
...getNodeType(scope, decl.object),
|
3977
|
+
...number(TYPE_FLAGS.length, Valtype.i32),
|
3978
|
+
[ Opcodes.i32_and ],
|
3492
3979
|
[ Opcodes.if, valtypeBinary ],
|
3493
3980
|
...generate(scope, decl.object),
|
3494
3981
|
Opcodes.i32_to_u,
|
@@ -3505,7 +3992,7 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3505
3992
|
}
|
3506
3993
|
|
3507
3994
|
// todo: generate this array procedurally during builtinFuncs creation
|
3508
|
-
if (['size', 'description'].includes(decl.property.name)) {
|
3995
|
+
if (['size', 'description', 'byteLength'].includes(decl.property.name)) {
|
3509
3996
|
const bc = {};
|
3510
3997
|
const cands = Object.keys(builtinFuncs).filter(x => x.startsWith('__') && x.endsWith('_prototype_' + decl.property.name + '$get'));
|
3511
3998
|
|
@@ -3537,7 +4024,9 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3537
4024
|
// // todo: we should only do this for strings but we don't know at compile-time :(
|
3538
4025
|
// hack: this is naughty and will break things!
|
3539
4026
|
let newOut = number(0, Valtype.i32), newPointer = number(0, Valtype.i32);
|
3540
|
-
|
4027
|
+
|
4028
|
+
const known = knownType(scope, getNodeType(scope, decl.object));
|
4029
|
+
if ((known === TYPES.string || known === TYPES.bytestring) || (pages.hasAnyString && known == null)) {
|
3541
4030
|
// todo: we use i16 even for bytestrings which should not make a bad thing happen, just be confusing for debugging?
|
3542
4031
|
0, [ newOut, newPointer ] = makeArray(scope, {
|
3543
4032
|
rawElements: new Array(0)
|
@@ -3611,6 +4100,82 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3611
4100
|
...setLastType(scope, TYPES.bytestring)
|
3612
4101
|
],
|
3613
4102
|
|
4103
|
+
...wrapBC({
|
4104
|
+
[TYPES.uint8array]: [
|
4105
|
+
[ Opcodes.i32_add ],
|
4106
|
+
|
4107
|
+
[ Opcodes.i32_load8_u, 0, 4 ],
|
4108
|
+
Opcodes.i32_from_u
|
4109
|
+
],
|
4110
|
+
[TYPES.uint8clampedarray]: [
|
4111
|
+
[ Opcodes.i32_add ],
|
4112
|
+
|
4113
|
+
[ Opcodes.i32_load8_u, 0, 4 ],
|
4114
|
+
Opcodes.i32_from_u
|
4115
|
+
],
|
4116
|
+
[TYPES.int8array]: [
|
4117
|
+
[ Opcodes.i32_add ],
|
4118
|
+
|
4119
|
+
[ Opcodes.i32_load8_s, 0, 4 ],
|
4120
|
+
Opcodes.i32_from
|
4121
|
+
],
|
4122
|
+
[TYPES.uint16array]: [
|
4123
|
+
...number(2, Valtype.i32),
|
4124
|
+
[ Opcodes.i32_mul ],
|
4125
|
+
[ Opcodes.i32_add ],
|
4126
|
+
|
4127
|
+
[ Opcodes.i32_load16_u, 0, 4 ],
|
4128
|
+
Opcodes.i32_from_u
|
4129
|
+
],
|
4130
|
+
[TYPES.int16array]: [
|
4131
|
+
...number(2, Valtype.i32),
|
4132
|
+
[ Opcodes.i32_mul ],
|
4133
|
+
[ Opcodes.i32_add ],
|
4134
|
+
|
4135
|
+
[ Opcodes.i32_load16_s, 0, 4 ],
|
4136
|
+
Opcodes.i32_from
|
4137
|
+
],
|
4138
|
+
[TYPES.uint32array]: [
|
4139
|
+
...number(4, Valtype.i32),
|
4140
|
+
[ Opcodes.i32_mul ],
|
4141
|
+
[ Opcodes.i32_add ],
|
4142
|
+
|
4143
|
+
[ Opcodes.i32_load, 0, 4 ],
|
4144
|
+
Opcodes.i32_from_u
|
4145
|
+
],
|
4146
|
+
[TYPES.int32array]: [
|
4147
|
+
...number(4, Valtype.i32),
|
4148
|
+
[ Opcodes.i32_mul ],
|
4149
|
+
[ Opcodes.i32_add ],
|
4150
|
+
|
4151
|
+
[ Opcodes.i32_load, 0, 4 ],
|
4152
|
+
Opcodes.i32_from
|
4153
|
+
],
|
4154
|
+
[TYPES.float32array]: [
|
4155
|
+
...number(4, Valtype.i32),
|
4156
|
+
[ Opcodes.i32_mul ],
|
4157
|
+
[ Opcodes.i32_add ],
|
4158
|
+
|
4159
|
+
[ Opcodes.f32_load, 0, 4 ],
|
4160
|
+
[ Opcodes.f64_promote_f32 ]
|
4161
|
+
],
|
4162
|
+
[TYPES.float64array]: [
|
4163
|
+
...number(8, Valtype.i32),
|
4164
|
+
[ Opcodes.i32_mul ],
|
4165
|
+
[ Opcodes.i32_add ],
|
4166
|
+
|
4167
|
+
[ Opcodes.f64_load, 0, 4 ]
|
4168
|
+
],
|
4169
|
+
}, {
|
4170
|
+
prelude: [
|
4171
|
+
...object,
|
4172
|
+
Opcodes.i32_to_u,
|
4173
|
+
...property,
|
4174
|
+
Opcodes.i32_to_u
|
4175
|
+
],
|
4176
|
+
postlude: setLastType(scope, TYPES.number)
|
4177
|
+
}),
|
4178
|
+
|
3614
4179
|
default: internalThrow(scope, 'TypeError', 'Member expression is not supported for non-string non-array yet', true)
|
3615
4180
|
});
|
3616
4181
|
};
|
@@ -3633,7 +4198,7 @@ const objectHack = node => {
|
|
3633
4198
|
if (!objectName) objectName = objectHack(node.object)?.name?.slice?.(2);
|
3634
4199
|
|
3635
4200
|
// if .name or .length, give up (hack within a hack!)
|
3636
|
-
if (['name', 'length', 'size', 'description'].includes(node.property.name)) {
|
4201
|
+
if (['name', 'length', 'size', 'description', 'byteLength'].includes(node.property.name)) {
|
3637
4202
|
node.object = objectHack(node.object);
|
3638
4203
|
return;
|
3639
4204
|
}
|
@@ -3686,8 +4251,8 @@ const generateFunc = (scope, decl) => {
|
|
3686
4251
|
|
3687
4252
|
if (typedInput && decl.returnType) {
|
3688
4253
|
const { type } = extractTypeAnnotation(decl.returnType);
|
3689
|
-
|
3690
|
-
if (type != null) {
|
4254
|
+
if (type != null && !Prefs.indirectCalls) {
|
4255
|
+
// if (type != null) {
|
3691
4256
|
func.returnType = type;
|
3692
4257
|
func.returns = [ valtypeBinary ];
|
3693
4258
|
}
|
@@ -3788,7 +4353,7 @@ const internalConstrs = {
|
|
3788
4353
|
|
3789
4354
|
// todo: check in wasm instead of here
|
3790
4355
|
const literalValue = arg.value ?? 0;
|
3791
|
-
if (literalValue < 0 || !Number.isFinite(literalValue) || literalValue > 4294967295) return internalThrow(scope, '
|
4356
|
+
if (literalValue < 0 || !Number.isFinite(literalValue) || literalValue > 4294967295) return internalThrow(scope, 'RangeError', 'Invalid array length', true);
|
3792
4357
|
|
3793
4358
|
return [
|
3794
4359
|
...out,
|