porffor 0.17.0-589ace465 → 0.17.0-6a05ca3ad
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 +57 -9
- package/compiler/builtins/date.ts +104 -106
- package/compiler/builtins/error.js +2 -5
- package/compiler/builtins/set.ts +4 -5
- package/compiler/builtins/string_f64.ts +4 -6
- package/compiler/builtins/symbol.ts +2 -1
- package/compiler/builtins/typedarray.js +58 -6
- package/compiler/builtins/z_ecma262.ts +1 -0
- package/compiler/builtins.js +12 -1
- package/compiler/codegen.js +473 -129
- package/compiler/generated_builtins.js +2615 -714
- package/compiler/opt.js +3 -0
- package/compiler/pgo.js +9 -1
- package/compiler/precompile.js +4 -2
- package/compiler/prototype.js +0 -69
- package/compiler/wrap.js +5 -3
- 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 +2 -2
- package/runner/profile.js +1 -1
- package/runner/repl.js +5 -5
package/compiler/codegen.js
CHANGED
@@ -123,6 +123,9 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
|
|
123
123
|
case 'EmptyStatement':
|
124
124
|
return generateEmpty(scope, decl);
|
125
125
|
|
126
|
+
case 'MetaProperty':
|
127
|
+
return generateMeta(scope, decl);
|
128
|
+
|
126
129
|
case 'ConditionalExpression':
|
127
130
|
return generateConditional(scope, decl);
|
128
131
|
|
@@ -295,10 +298,10 @@ const generateIdent = (scope, decl) => {
|
|
295
298
|
}
|
296
299
|
|
297
300
|
// todo: enable this by default in future
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
301
|
+
if (!Object.hasOwn(funcIndex, name) && Object.hasOwn(builtinFuncs, name)) {
|
302
|
+
includeBuiltin(scope, name);
|
303
|
+
return number(funcIndex[name] - importedFuncs.length);
|
304
|
+
}
|
302
305
|
|
303
306
|
if (isExistingProtoFunc(name) || Object.hasOwn(internalConstrs, name) || Object.hasOwn(builtinFuncs, name)) {
|
304
307
|
// todo: return an actual something
|
@@ -619,11 +622,14 @@ const compareStrings = (scope, left, right, bytestrings = false) => {
|
|
619
622
|
};
|
620
623
|
|
621
624
|
const truthy = (scope, wasm, type, intIn = false, intOut = false, forceTruthyMode = undefined) => {
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
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
|
+
];
|
627
633
|
|
628
634
|
// todo/perf: use knownType and custom bytecode here instead of typeSwitch
|
629
635
|
|
@@ -1023,12 +1029,13 @@ const asmFuncToAsm = (func, scope) => {
|
|
1023
1029
|
idx = funcIndex[n];
|
1024
1030
|
}
|
1025
1031
|
|
1032
|
+
if (idx == null) throw new Error(`builtin('${n}') failed to find a func (inside ${scope.name})`);
|
1026
1033
|
return idx;
|
1027
1034
|
}
|
1028
1035
|
});
|
1029
1036
|
};
|
1030
1037
|
|
1031
|
-
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 }) => {
|
1032
1039
|
const existing = funcs.find(x => x.name === name);
|
1033
1040
|
if (existing) return existing;
|
1034
1041
|
|
@@ -1055,13 +1062,17 @@ const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes
|
|
1055
1062
|
returnType,
|
1056
1063
|
internal: true,
|
1057
1064
|
index: currentFuncIndex++,
|
1058
|
-
table
|
1065
|
+
table,
|
1066
|
+
constr
|
1059
1067
|
};
|
1060
1068
|
|
1061
1069
|
funcs.push(func);
|
1062
1070
|
funcIndex[name] = func.index;
|
1063
1071
|
|
1064
|
-
if (typeof wasm === 'function')
|
1072
|
+
if (typeof wasm === 'function') {
|
1073
|
+
if (globalThis.precompile) wasm = [];
|
1074
|
+
else wasm = asmFuncToAsm(wasm, func);
|
1075
|
+
}
|
1065
1076
|
|
1066
1077
|
let baseGlobalIdx, i = 0;
|
1067
1078
|
for (const type of globalTypes) {
|
@@ -1082,15 +1093,35 @@ const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes
|
|
1082
1093
|
|
1083
1094
|
if (table) {
|
1084
1095
|
for (const inst of wasm) {
|
1085
|
-
if (inst
|
1096
|
+
if (inst.at(-1) === 'read func lut') {
|
1086
1097
|
inst.splice(2, 99);
|
1087
|
-
inst.push(...unsignedLEB128(allocPage({}, 'func
|
1098
|
+
inst.push(...unsignedLEB128(allocPage({}, 'func lut') * pageSize));
|
1088
1099
|
}
|
1089
1100
|
}
|
1090
1101
|
|
1091
1102
|
funcs.table = true;
|
1092
1103
|
}
|
1093
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
|
+
|
1094
1125
|
func.wasm = wasm;
|
1095
1126
|
|
1096
1127
|
return func;
|
@@ -1217,20 +1248,7 @@ const getNodeType = (scope, node) => {
|
|
1217
1248
|
return TYPES.number;
|
1218
1249
|
}
|
1219
1250
|
|
1220
|
-
if (node.type === 'NewExpression' && builtinFuncs[name + '$constructor']) {
|
1221
|
-
if (builtinFuncs[name + '$constructor'].typedReturns) {
|
1222
|
-
if (scope.locals['#last_type']) return getLastType(scope);
|
1223
|
-
|
1224
|
-
// presume
|
1225
|
-
// todo: warn here?
|
1226
|
-
return TYPES.number;
|
1227
|
-
}
|
1228
|
-
|
1229
|
-
return builtinFuncs[name + '$constructor'].returnType ?? TYPES.number;
|
1230
|
-
}
|
1231
|
-
|
1232
1251
|
const func = funcs.find(x => x.name === name);
|
1233
|
-
|
1234
1252
|
if (func) {
|
1235
1253
|
if (func.returnType != null) return func.returnType;
|
1236
1254
|
}
|
@@ -1417,9 +1435,9 @@ const countLeftover = wasm => {
|
|
1417
1435
|
|
1418
1436
|
if (depth === 0)
|
1419
1437
|
if ([Opcodes.throw, Opcodes.drop, Opcodes.local_set, Opcodes.global_set].includes(inst[0])) count--;
|
1420
|
-
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)) {}
|
1421
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++;
|
1422
|
-
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;
|
1423
1441
|
else if (inst[0] === Opcodes.memory_copy[0] && (inst[1] === Opcodes.memory_copy[1] || inst[1] === Opcodes.memory_init[1])) count -= 3;
|
1424
1442
|
else if (inst[0] === Opcodes.return) count = 0;
|
1425
1443
|
else if (inst[0] === Opcodes.call) {
|
@@ -1528,7 +1546,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1528
1546
|
name = func.name;
|
1529
1547
|
}
|
1530
1548
|
|
1531
|
-
if (name === 'eval' && decl.arguments[0]?.type === 'Literal') {
|
1549
|
+
if (!decl._new && name === 'eval' && decl.arguments[0]?.type === 'Literal') {
|
1532
1550
|
// literal eval hack
|
1533
1551
|
const code = decl.arguments[0]?.value ?? '';
|
1534
1552
|
|
@@ -1571,7 +1589,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1571
1589
|
|
1572
1590
|
let protoName, target;
|
1573
1591
|
// ident.func()
|
1574
|
-
if (name && name.startsWith('__')) {
|
1592
|
+
if (!decl._new && name && name.startsWith('__')) {
|
1575
1593
|
const spl = name.slice(2).split('_');
|
1576
1594
|
|
1577
1595
|
protoName = spl[spl.length - 1];
|
@@ -1584,12 +1602,12 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1584
1602
|
}
|
1585
1603
|
|
1586
1604
|
// literal.func()
|
1587
|
-
if (!name && decl.callee.type === 'MemberExpression') {
|
1605
|
+
if (!decl._new && !name && decl.callee.type === 'MemberExpression') {
|
1588
1606
|
// megahack for /regex/.func()
|
1589
1607
|
const funcName = decl.callee.property.name;
|
1590
|
-
if (decl.callee.object.regex &&
|
1608
|
+
if (decl.callee.object.regex && ['test'].includes(funcName)) {
|
1591
1609
|
const regex = decl.callee.object.regex.pattern;
|
1592
|
-
const rhemynName = `regex_${funcName}_${regex}`;
|
1610
|
+
const rhemynName = `regex_${funcName}_${sanitize(regex)}`;
|
1593
1611
|
|
1594
1612
|
if (!funcIndex[rhemynName]) {
|
1595
1613
|
const func = Rhemyn[funcName](regex, currentFuncIndex++, rhemynName);
|
@@ -1610,7 +1628,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1610
1628
|
[ Opcodes.call, idx ],
|
1611
1629
|
Opcodes.i32_from_u,
|
1612
1630
|
|
1613
|
-
...setLastType(scope,
|
1631
|
+
...setLastType(scope, Rhemyn.types[funcName])
|
1614
1632
|
];
|
1615
1633
|
}
|
1616
1634
|
|
@@ -1619,27 +1637,56 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1619
1637
|
target = decl.callee.object;
|
1620
1638
|
}
|
1621
1639
|
|
1622
|
-
|
1623
|
-
|
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 ],
|
1624
1648
|
|
1625
|
-
|
1626
|
-
|
1649
|
+
...number(Rhemyn.types[protoName] === TYPES.number ? -1 : 0),
|
1650
|
+
...setLastType(scope, Rhemyn.types[protoName])
|
1651
|
+
];
|
1627
1652
|
|
1628
|
-
|
1629
|
-
// generate(scope, decl.callee.object)
|
1653
|
+
const rhemynName = `regex_${protoName}_${sanitize(regex)}`;
|
1630
1654
|
|
1631
|
-
|
1632
|
-
|
1633
|
-
|
1634
|
-
// ];
|
1635
|
-
// }
|
1655
|
+
if (!funcIndex[rhemynName]) {
|
1656
|
+
const func = Rhemyn[protoName](regex, currentFuncIndex++, rhemynName);
|
1657
|
+
func.internal = true;
|
1636
1658
|
|
1637
|
-
|
1638
|
-
|
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
|
+
}
|
1639
1677
|
|
1678
|
+
const protoBC = {};
|
1640
1679
|
const builtinProtoCands = Object.keys(builtinFuncs).filter(x => x.startsWith('__') && x.endsWith('_prototype_' + protoName));
|
1641
1680
|
|
1642
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
|
+
|
1643
1690
|
for (const x of builtinProtoCands) {
|
1644
1691
|
const type = TYPES[x.split('_prototype_')[0].slice(2).toLowerCase()];
|
1645
1692
|
if (type == null) continue;
|
@@ -1649,7 +1696,14 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1649
1696
|
type: 'Identifier',
|
1650
1697
|
name: x
|
1651
1698
|
},
|
1652
|
-
arguments: [
|
1699
|
+
arguments: [
|
1700
|
+
{
|
1701
|
+
type: 'Identifier',
|
1702
|
+
name: '#proto_target'
|
1703
|
+
},
|
1704
|
+
|
1705
|
+
...decl.arguments
|
1706
|
+
],
|
1653
1707
|
_protoInternalCall: true
|
1654
1708
|
});
|
1655
1709
|
}
|
@@ -1743,29 +1797,37 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1743
1797
|
}
|
1744
1798
|
|
1745
1799
|
if (Object.keys(protoBC).length > 0) {
|
1746
|
-
return
|
1747
|
-
...
|
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,
|
1748
1805
|
|
1749
|
-
|
1750
|
-
|
1751
|
-
|
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
|
+
];
|
1752
1810
|
}
|
1753
1811
|
}
|
1754
1812
|
|
1755
|
-
// TODO: only allows callee as
|
1756
|
-
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})`);
|
1757
1815
|
|
1758
1816
|
let idx = funcIndex[name] ?? importedFuncs[name];
|
1759
1817
|
if (idx === undefined && builtinFuncs[name]) {
|
1760
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);
|
1761
1820
|
|
1762
1821
|
includeBuiltin(scope, name);
|
1763
1822
|
idx = funcIndex[name];
|
1764
1823
|
}
|
1765
1824
|
|
1766
|
-
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
|
+
}
|
1767
1829
|
|
1768
|
-
if (idx === undefined && name.startsWith('__Porffor_wasm_')) {
|
1830
|
+
if (idx === undefined && !decl._new && name.startsWith('__Porffor_wasm_')) {
|
1769
1831
|
const wasmOps = {
|
1770
1832
|
// pointer, align, offset
|
1771
1833
|
i32_load: { imms: 2, args: [ true ], returns: 1 },
|
@@ -1820,7 +1882,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1820
1882
|
|
1821
1883
|
const indirectMode = Prefs.indirectCallMode ?? 'vararg';
|
1822
1884
|
// options: vararg, strict
|
1823
|
-
// - strict: simpler, smaller size usage, no func
|
1885
|
+
// - strict: simpler, smaller size usage, no func lut needed.
|
1824
1886
|
// ONLY works when arg count of call == arg count of function being called
|
1825
1887
|
// - vararg: large size usage, cursed.
|
1826
1888
|
// works when arg count of call != arg count of function being called*
|
@@ -1830,8 +1892,6 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1830
1892
|
scope.table = true;
|
1831
1893
|
|
1832
1894
|
let args = decl.arguments;
|
1833
|
-
let out = [];
|
1834
|
-
|
1835
1895
|
let locals = [];
|
1836
1896
|
|
1837
1897
|
if (indirectMode === 'vararg') {
|
@@ -1895,24 +1955,67 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1895
1955
|
// *for argc 0-3, in future (todo:) the max number should be
|
1896
1956
|
// dynamically changed to the max argc of any func in the js file.
|
1897
1957
|
|
1898
|
-
const funcLocal = localTmp(scope,
|
1958
|
+
const funcLocal = localTmp(scope, '#indirect_func', Valtype.i32);
|
1959
|
+
const flags = localTmp(scope, '#indirect_flags', Valtype.i32);
|
1899
1960
|
|
1900
1961
|
const gen = argc => {
|
1901
|
-
const
|
1962
|
+
const argsOut = [];
|
1902
1963
|
for (let i = 0; i < argc; i++) {
|
1903
|
-
|
1964
|
+
argsOut.push(
|
1904
1965
|
[ Opcodes.local_get, locals[i][0] ],
|
1905
1966
|
[ Opcodes.local_get, locals[i][1] ]
|
1906
1967
|
);
|
1907
1968
|
}
|
1908
1969
|
|
1909
|
-
|
1910
|
-
[ Opcodes.local_get,
|
1911
|
-
|
1912
|
-
|
1913
|
-
|
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
|
+
];
|
1914
1980
|
|
1915
|
-
|
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
|
+
);
|
1916
2019
|
};
|
1917
2020
|
|
1918
2021
|
const tableBc = {};
|
@@ -1930,13 +2033,32 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1930
2033
|
Opcodes.i32_to_u,
|
1931
2034
|
[ Opcodes.local_set, funcLocal ],
|
1932
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
|
+
|
1933
2056
|
...brTable([
|
1934
2057
|
// get argc of func we are calling
|
1935
2058
|
[ Opcodes.local_get, funcLocal ],
|
1936
|
-
...number(
|
2059
|
+
...number(3, Valtype.i32),
|
1937
2060
|
[ Opcodes.i32_mul ],
|
1938
|
-
|
1939
|
-
[ 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' ]
|
1940
2062
|
], tableBc, valtypeBinary)
|
1941
2063
|
],
|
1942
2064
|
default: internalThrow(scope, 'TypeError', `${unhackName(name)} is not a function`, true)
|
@@ -1950,7 +2072,16 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1950
2072
|
const userFunc = func && !func.internal;
|
1951
2073
|
const typedParams = userFunc || builtinFuncs[name]?.typedParams;
|
1952
2074
|
const typedReturns = (userFunc && func.returnType == null) || builtinFuncs[name]?.typedReturns;
|
1953
|
-
|
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);
|
1954
2085
|
|
1955
2086
|
let args = decl.arguments;
|
1956
2087
|
if (func && args.length < paramCount) {
|
@@ -1965,7 +2096,6 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1965
2096
|
|
1966
2097
|
if (func && func.throws) scope.throws = true;
|
1967
2098
|
|
1968
|
-
let out = [];
|
1969
2099
|
for (let i = 0; i < args.length; i++) {
|
1970
2100
|
const arg = args[i];
|
1971
2101
|
out = out.concat(generate(scope, arg));
|
@@ -1978,13 +2108,13 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1978
2108
|
}
|
1979
2109
|
|
1980
2110
|
if (valtypeBinary !== Valtype.i32 &&
|
1981
|
-
(func && func.params[i * (typedParams ? 2 : 1)] === Valtype.i32)
|
2111
|
+
(func && func.params[paramOffset + i * (typedParams ? 2 : 1)] === Valtype.i32)
|
1982
2112
|
) {
|
1983
2113
|
out.push(Opcodes.i32_to);
|
1984
2114
|
}
|
1985
2115
|
|
1986
2116
|
if (valtypeBinary === Valtype.i32 &&
|
1987
|
-
(func && func.params[i * (typedParams ? 2 : 1)] === Valtype.f64)
|
2117
|
+
(func && func.params[paramOffset + i * (typedParams ? 2 : 1)] === Valtype.f64)
|
1988
2118
|
) {
|
1989
2119
|
out.push([ Opcodes.f64_convert_i32_s ]);
|
1990
2120
|
}
|
@@ -2017,32 +2147,10 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
2017
2147
|
return out;
|
2018
2148
|
};
|
2019
2149
|
|
2020
|
-
const generateNew = (scope, decl, _global, _name) => {
|
2021
|
-
|
2022
|
-
|
2023
|
-
|
2024
|
-
if (internalConstrs[name] && !internalConstrs[name].notConstr) return internalConstrs[name].generate(scope, decl, _global, _name);
|
2025
|
-
|
2026
|
-
if (builtinFuncs[name + '$constructor']) {
|
2027
|
-
// custom ...$constructor override builtin func
|
2028
|
-
return generateCall(scope, {
|
2029
|
-
...decl,
|
2030
|
-
callee: {
|
2031
|
-
type: 'Identifier',
|
2032
|
-
name: name + '$constructor'
|
2033
|
-
}
|
2034
|
-
}, _global, _name);
|
2035
|
-
}
|
2036
|
-
|
2037
|
-
if (
|
2038
|
-
(builtinFuncs[name] && !builtinFuncs[name].constr) ||
|
2039
|
-
(internalConstrs[name] && builtinFuncs[name].notConstr)
|
2040
|
-
) return internalThrow(scope, 'TypeError', `${name} is not a constructor`, true);
|
2041
|
-
|
2042
|
-
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)})`);
|
2043
|
-
|
2044
|
-
return generateCall(scope, decl, _global, _name);
|
2045
|
-
};
|
2150
|
+
const generateNew = (scope, decl, _global, _name) => generateCall(scope, {
|
2151
|
+
...decl,
|
2152
|
+
_new: true
|
2153
|
+
}, _global, _name);
|
2046
2154
|
|
2047
2155
|
// bad hack for undefined and null working without additional logic
|
2048
2156
|
const DEFAULT_VALUE = {
|
@@ -2050,6 +2158,16 @@ const DEFAULT_VALUE = {
|
|
2050
2158
|
name: 'undefined'
|
2051
2159
|
};
|
2052
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
|
+
|
2053
2171
|
const unhackName = name => {
|
2054
2172
|
if (name.startsWith('__')) return name.slice(2).replaceAll('_', '.');
|
2055
2173
|
return name;
|
@@ -2285,9 +2403,120 @@ const generateVar = (scope, decl) => {
|
|
2285
2403
|
const global = topLevel || decl._bare;
|
2286
2404
|
|
2287
2405
|
for (const x of decl.declarations) {
|
2288
|
-
|
2406
|
+
if (x.id.type === 'ArrayPattern') {
|
2407
|
+
const decls = [];
|
2408
|
+
const tmpName = '#destructure' + randId();
|
2409
|
+
|
2410
|
+
let i = 0;
|
2411
|
+
const elements = [...x.id.elements];
|
2412
|
+
for (const e of elements) {
|
2413
|
+
switch (e?.type) {
|
2414
|
+
case 'RestElement': { // let [ ...foo ] = []
|
2415
|
+
if (e.argument.type === 'ArrayPattern') {
|
2416
|
+
// let [ ...[a, b, c] ] = []
|
2417
|
+
elements.push(...e.argument.elements);
|
2418
|
+
} else {
|
2419
|
+
decls.push({
|
2420
|
+
type: 'VariableDeclarator',
|
2421
|
+
id: { type: 'Identifier', name: e.argument.name },
|
2422
|
+
init: {
|
2423
|
+
type: 'CallExpression',
|
2424
|
+
callee: {
|
2425
|
+
type: 'Identifier',
|
2426
|
+
name: '__Array_prototype_slice'
|
2427
|
+
},
|
2428
|
+
arguments: [
|
2429
|
+
{ type: 'Identifier', name: tmpName },
|
2430
|
+
{ type: 'Literal', value: i },
|
2431
|
+
{
|
2432
|
+
type: 'MemberExpression',
|
2433
|
+
object: { type: 'Identifier', name: tmpName, },
|
2434
|
+
property: { type: 'Identifier', name: 'length', }
|
2435
|
+
}
|
2436
|
+
]
|
2437
|
+
}
|
2438
|
+
});
|
2439
|
+
}
|
2440
|
+
|
2441
|
+
continue; // skip i++
|
2442
|
+
}
|
2443
|
+
|
2444
|
+
case 'Identifier': { // let [ foo ] = []
|
2445
|
+
decls.push({
|
2446
|
+
type: 'VariableDeclarator',
|
2447
|
+
id: e,
|
2448
|
+
init: {
|
2449
|
+
type: 'MemberExpression',
|
2450
|
+
object: { type: 'Identifier', name: tmpName },
|
2451
|
+
property: { type: 'Literal', value: i }
|
2452
|
+
}
|
2453
|
+
});
|
2454
|
+
|
2455
|
+
break;
|
2456
|
+
}
|
2457
|
+
|
2458
|
+
case 'AssignmentPattern': { // let [ foo = defaultValue ] = []
|
2459
|
+
decls.push({
|
2460
|
+
type: 'VariableDeclarator',
|
2461
|
+
id: e.left,
|
2462
|
+
init: {
|
2463
|
+
type: 'LogicalExpression',
|
2464
|
+
operator: '??',
|
2465
|
+
left: {
|
2466
|
+
type: 'MemberExpression',
|
2467
|
+
object: { type: 'Identifier', name: tmpName },
|
2468
|
+
property: { type: 'Literal', value: i }
|
2469
|
+
},
|
2470
|
+
right: e.right
|
2471
|
+
}
|
2472
|
+
});
|
2473
|
+
|
2474
|
+
break;
|
2475
|
+
}
|
2476
|
+
|
2477
|
+
case 'ArrayPattern': { // let [ [ foo, bar ] ] = []
|
2478
|
+
decls.push({
|
2479
|
+
type: 'VariableDeclarator',
|
2480
|
+
id: e,
|
2481
|
+
init: {
|
2482
|
+
type: 'MemberExpression',
|
2483
|
+
object: { type: 'Identifier', name: tmpName },
|
2484
|
+
property: { type: 'Literal', value: i }
|
2485
|
+
}
|
2486
|
+
});
|
2487
|
+
|
2488
|
+
break;
|
2489
|
+
}
|
2289
2490
|
|
2290
|
-
|
2491
|
+
case 'ObjectPattern':
|
2492
|
+
return todo(scope, 'object destructuring is not supported yet')
|
2493
|
+
}
|
2494
|
+
|
2495
|
+
i++;
|
2496
|
+
}
|
2497
|
+
|
2498
|
+
out = out.concat([
|
2499
|
+
...generateVar(scope, {
|
2500
|
+
type: 'VariableDeclaration',
|
2501
|
+
declarations: [{
|
2502
|
+
type: 'VariableDeclarator',
|
2503
|
+
id: { type: 'Identifier', name: tmpName },
|
2504
|
+
init: x.init
|
2505
|
+
}],
|
2506
|
+
kind: decl.kind
|
2507
|
+
}),
|
2508
|
+
...generateVar(scope, {
|
2509
|
+
type: 'VariableDeclaration',
|
2510
|
+
declarations: decls,
|
2511
|
+
kind: decl.kind
|
2512
|
+
})
|
2513
|
+
]);
|
2514
|
+
|
2515
|
+
continue;
|
2516
|
+
}
|
2517
|
+
|
2518
|
+
const name = mapName(x.id.name);
|
2519
|
+
if (!name) return todo(scope, 'object destructuring is not supported yet')
|
2291
2520
|
|
2292
2521
|
if (x.init && isFuncType(x.init.type)) {
|
2293
2522
|
// hack for let a = function () { ... }
|
@@ -2322,7 +2551,9 @@ const generateVar = (scope, decl) => {
|
|
2322
2551
|
// hack to set local as pointer before
|
2323
2552
|
out.push(...number(scope.arrays.get(name)), [ global ? Opcodes.global_set : Opcodes.local_set, idx ]);
|
2324
2553
|
if (generated.at(-1) == Opcodes.i32_from_u) generated.pop();
|
2325
|
-
generated.pop();
|
2554
|
+
// generated.pop();
|
2555
|
+
generated.push([ Opcodes.drop ]);
|
2556
|
+
|
2326
2557
|
out = out.concat(generated);
|
2327
2558
|
} else {
|
2328
2559
|
out = out.concat(generated);
|
@@ -2389,8 +2620,8 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2389
2620
|
|
2390
2621
|
// arr[i]
|
2391
2622
|
if (decl.left.type === 'MemberExpression' && decl.left.computed) {
|
2392
|
-
const newValueTmp = localTmp(scope, '
|
2393
|
-
const pointerTmp =
|
2623
|
+
const newValueTmp = localTmp(scope, '#member_setter_val_tmp');
|
2624
|
+
const pointerTmp = localTmp(scope, '#member_setter_ptr_tmp', Valtype.i32);
|
2394
2625
|
|
2395
2626
|
return [
|
2396
2627
|
...typeSwitch(scope, getNodeType(scope, decl.left.object), {
|
@@ -2402,11 +2633,11 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2402
2633
|
...generate(scope, decl.left.property),
|
2403
2634
|
Opcodes.i32_to_u,
|
2404
2635
|
|
2405
|
-
// turn into byte offset by * valtypeSize
|
2636
|
+
// turn into byte offset by * valtypeSize + 1
|
2406
2637
|
...number(ValtypeSize[valtype] + 1, Valtype.i32),
|
2407
2638
|
[ Opcodes.i32_mul ],
|
2408
2639
|
[ Opcodes.i32_add ],
|
2409
|
-
|
2640
|
+
[ Opcodes.local_tee, pointerTmp ],
|
2410
2641
|
|
2411
2642
|
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2412
2643
|
[ Opcodes.local_get, pointerTmp ],
|
@@ -2416,7 +2647,11 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2416
2647
|
[ Opcodes.i32_load8_u, 0, ValtypeSize.i32 + ValtypeSize[valtype] ]
|
2417
2648
|
], getNodeType(scope, decl.right), false, name, true)),
|
2418
2649
|
[ Opcodes.local_tee, newValueTmp ],
|
2419
|
-
[ Opcodes.store, 0, ValtypeSize.i32 ]
|
2650
|
+
[ Opcodes.store, 0, ValtypeSize.i32 ],
|
2651
|
+
|
2652
|
+
[ Opcodes.local_get, pointerTmp ],
|
2653
|
+
...getNodeType(scope, decl),
|
2654
|
+
[ Opcodes.i32_store8, 0, ValtypeSize.i32 + ValtypeSize[valtype] ],
|
2420
2655
|
],
|
2421
2656
|
|
2422
2657
|
...wrapBC({
|
@@ -2953,7 +3188,9 @@ const generateForOf = (scope, decl) => {
|
|
2953
3188
|
// // todo: we should only do this for strings but we don't know at compile-time :(
|
2954
3189
|
// hack: this is naughty and will break things!
|
2955
3190
|
let newOut = number(0, Valtype.i32), newPointer = number(0, Valtype.i32);
|
2956
|
-
|
3191
|
+
|
3192
|
+
const known = knownType(scope, getNodeType(scope, decl.right));
|
3193
|
+
if ((known === TYPES.string || known === TYPES.bytestring) || (pages.hasAnyString && known == null)) {
|
2957
3194
|
// todo: we use i16 even for bytestrings which should not make a bad thing happen, just be confusing for debugging?
|
2958
3195
|
0, [ newOut, newPointer ] = makeArray(scope, {
|
2959
3196
|
rawElements: new Array(0)
|
@@ -3001,6 +3238,7 @@ const generateForOf = (scope, decl) => {
|
|
3001
3238
|
[ Opcodes.end ],
|
3002
3239
|
[ Opcodes.end ]
|
3003
3240
|
],
|
3241
|
+
|
3004
3242
|
[TYPES.string]: [
|
3005
3243
|
...setType(scope, leftName, TYPES.string),
|
3006
3244
|
|
@@ -3109,6 +3347,7 @@ const generateForOf = (scope, decl) => {
|
|
3109
3347
|
[ Opcodes.end ],
|
3110
3348
|
[ Opcodes.end ]
|
3111
3349
|
],
|
3350
|
+
|
3112
3351
|
[TYPES.set]: [
|
3113
3352
|
[ Opcodes.loop, Blocktype.void ],
|
3114
3353
|
|
@@ -3147,7 +3386,106 @@ const generateForOf = (scope, decl) => {
|
|
3147
3386
|
[ Opcodes.end ],
|
3148
3387
|
[ Opcodes.end ]
|
3149
3388
|
],
|
3150
|
-
|
3389
|
+
|
3390
|
+
...wrapBC({
|
3391
|
+
[TYPES.uint8array]: [
|
3392
|
+
[ Opcodes.i32_add ],
|
3393
|
+
|
3394
|
+
[ Opcodes.i32_load8_u, 0, 4 ],
|
3395
|
+
Opcodes.i32_from_u
|
3396
|
+
],
|
3397
|
+
[TYPES.uint8clampedarray]: [
|
3398
|
+
[ Opcodes.i32_add ],
|
3399
|
+
|
3400
|
+
[ Opcodes.i32_load8_u, 0, 4 ],
|
3401
|
+
Opcodes.i32_from_u
|
3402
|
+
],
|
3403
|
+
[TYPES.int8array]: [
|
3404
|
+
[ Opcodes.i32_add ],
|
3405
|
+
|
3406
|
+
[ Opcodes.i32_load8_s, 0, 4 ],
|
3407
|
+
Opcodes.i32_from
|
3408
|
+
],
|
3409
|
+
[TYPES.uint16array]: [
|
3410
|
+
...number(2, Valtype.i32),
|
3411
|
+
[ Opcodes.i32_mul ],
|
3412
|
+
[ Opcodes.i32_add ],
|
3413
|
+
|
3414
|
+
[ Opcodes.i32_load16_u, 0, 4 ],
|
3415
|
+
Opcodes.i32_from_u
|
3416
|
+
],
|
3417
|
+
[TYPES.int16array]: [
|
3418
|
+
...number(2, Valtype.i32),
|
3419
|
+
[ Opcodes.i32_mul ],
|
3420
|
+
[ Opcodes.i32_add ],
|
3421
|
+
|
3422
|
+
[ Opcodes.i32_load16_s, 0, 4 ],
|
3423
|
+
Opcodes.i32_from
|
3424
|
+
],
|
3425
|
+
[TYPES.uint32array]: [
|
3426
|
+
...number(4, Valtype.i32),
|
3427
|
+
[ Opcodes.i32_mul ],
|
3428
|
+
[ Opcodes.i32_add ],
|
3429
|
+
|
3430
|
+
[ Opcodes.i32_load, 0, 4 ],
|
3431
|
+
Opcodes.i32_from_u
|
3432
|
+
],
|
3433
|
+
[TYPES.int32array]: [
|
3434
|
+
...number(4, Valtype.i32),
|
3435
|
+
[ Opcodes.i32_mul ],
|
3436
|
+
[ Opcodes.i32_add ],
|
3437
|
+
|
3438
|
+
[ Opcodes.i32_load, 0, 4 ],
|
3439
|
+
Opcodes.i32_from
|
3440
|
+
],
|
3441
|
+
[TYPES.float32array]: [
|
3442
|
+
...number(4, Valtype.i32),
|
3443
|
+
[ Opcodes.i32_mul ],
|
3444
|
+
[ Opcodes.i32_add ],
|
3445
|
+
|
3446
|
+
[ Opcodes.f32_load, 0, 4 ],
|
3447
|
+
[ Opcodes.f64_promote_f32 ]
|
3448
|
+
],
|
3449
|
+
[TYPES.float64array]: [
|
3450
|
+
...number(8, Valtype.i32),
|
3451
|
+
[ Opcodes.i32_mul ],
|
3452
|
+
[ Opcodes.i32_add ],
|
3453
|
+
|
3454
|
+
[ Opcodes.f64_load, 0, 4 ]
|
3455
|
+
],
|
3456
|
+
}, {
|
3457
|
+
prelude: [
|
3458
|
+
...setType(scope, leftName, TYPES.number),
|
3459
|
+
|
3460
|
+
[ Opcodes.loop, Blocktype.void ],
|
3461
|
+
|
3462
|
+
[ Opcodes.local_get, pointer ],
|
3463
|
+
[ Opcodes.local_get, counter ]
|
3464
|
+
],
|
3465
|
+
postlude: [
|
3466
|
+
[ isGlobal ? Opcodes.global_set : Opcodes.local_set, local.idx ],
|
3467
|
+
|
3468
|
+
[ Opcodes.block, Blocktype.void ],
|
3469
|
+
[ Opcodes.block, Blocktype.void ],
|
3470
|
+
...generate(scope, decl.body),
|
3471
|
+
[ Opcodes.end ],
|
3472
|
+
|
3473
|
+
// increment counter by 1
|
3474
|
+
[ Opcodes.local_get, counter ],
|
3475
|
+
...number(1, Valtype.i32),
|
3476
|
+
[ Opcodes.i32_add ],
|
3477
|
+
[ Opcodes.local_tee, counter ],
|
3478
|
+
|
3479
|
+
// loop if counter != length
|
3480
|
+
[ Opcodes.local_get, length ],
|
3481
|
+
[ Opcodes.i32_ne ],
|
3482
|
+
[ Opcodes.br_if, 1 ],
|
3483
|
+
|
3484
|
+
[ Opcodes.end ],
|
3485
|
+
[ Opcodes.end ]
|
3486
|
+
]
|
3487
|
+
}),
|
3488
|
+
|
3151
3489
|
default: internalThrow(scope, 'TypeError', `Tried for..of on non-iterable type`)
|
3152
3490
|
}, Blocktype.void));
|
3153
3491
|
|
@@ -3351,6 +3689,22 @@ const generateEmpty = (scope, decl) => {
|
|
3351
3689
|
return [];
|
3352
3690
|
};
|
3353
3691
|
|
3692
|
+
const generateMeta = (scope, decl) => {
|
3693
|
+
if (decl.meta.name !== 'new') return todo(scope, `meta property object ${decl.meta.name} is not supported yet`, true);
|
3694
|
+
|
3695
|
+
switch (`${decl.meta.name}.${decl.property.name}`) {
|
3696
|
+
case 'new.target': {
|
3697
|
+
scope.constr = true;
|
3698
|
+
|
3699
|
+
return [
|
3700
|
+
[ Opcodes.local_get, -1 ],
|
3701
|
+
Opcodes.i32_from_u,
|
3702
|
+
...setLastType(scope, TYPES.boolean)
|
3703
|
+
];
|
3704
|
+
}
|
3705
|
+
}
|
3706
|
+
};
|
3707
|
+
|
3354
3708
|
let pages = new Map();
|
3355
3709
|
const allocPage = (scope, reason, type) => {
|
3356
3710
|
if (pages.has(reason)) return pages.get(reason).ind;
|
@@ -3703,20 +4057,10 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3703
4057
|
const func = funcs.find(x => x.name === name);
|
3704
4058
|
if (func) {
|
3705
4059
|
const typedParams = !func.internal || builtinFuncs[name]?.typedParams;
|
3706
|
-
return withType(scope, number(typedParams ? func.params.length / 2 : func.params.length), TYPES.number);
|
3707
|
-
}
|
3708
|
-
|
3709
|
-
if (builtinFuncs[name + '$constructor']) {
|
3710
|
-
const regularFunc = builtinFuncs[name];
|
3711
|
-
const regularParams = regularFunc.typedParams ? (regularFunc.params.length / 2) : regularFunc.params.length;
|
3712
|
-
|
3713
|
-
const constructorFunc = builtinFuncs[name + '$constructor'];
|
3714
|
-
const constructorParams = constructorFunc.typedParams ? (constructorFunc.params.length / 2) : constructorFunc.params.length;
|
3715
|
-
|
3716
|
-
return withType(scope, number(Math.max(regularParams, constructorParams)), TYPES.number);
|
4060
|
+
return withType(scope, number(typedParams ? Math.floor(func.params.length / 2) : (func.constr ? (func.params.length - 1) : func.params.length)), TYPES.number);
|
3717
4061
|
}
|
3718
4062
|
|
3719
|
-
if (builtinFuncs[name]) return withType(scope, number(builtinFuncs[name].typedParams ? (builtinFuncs[name].params.length / 2) : builtinFuncs[name].params.length), TYPES.number);
|
4063
|
+
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);
|
3720
4064
|
if (importedFuncs[name]) return withType(scope, number(importedFuncs[name].params.length ?? importedFuncs[name].params), TYPES.number);
|
3721
4065
|
if (internalConstrs[name]) return withType(scope, number(internalConstrs[name].length ?? 0), TYPES.number);
|
3722
4066
|
|
@@ -3765,7 +4109,7 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3765
4109
|
}
|
3766
4110
|
|
3767
4111
|
// todo: generate this array procedurally during builtinFuncs creation
|
3768
|
-
if (['size', 'description'].includes(decl.property.name)) {
|
4112
|
+
if (['size', 'description', 'byteLength'].includes(decl.property.name)) {
|
3769
4113
|
const bc = {};
|
3770
4114
|
const cands = Object.keys(builtinFuncs).filter(x => x.startsWith('__') && x.endsWith('_prototype_' + decl.property.name + '$get'));
|
3771
4115
|
|
@@ -3971,7 +4315,7 @@ const objectHack = node => {
|
|
3971
4315
|
if (!objectName) objectName = objectHack(node.object)?.name?.slice?.(2);
|
3972
4316
|
|
3973
4317
|
// if .name or .length, give up (hack within a hack!)
|
3974
|
-
if (['name', 'length', 'size', 'description'].includes(node.property.name)) {
|
4318
|
+
if (['name', 'length', 'size', 'description', 'byteLength'].includes(node.property.name)) {
|
3975
4319
|
node.object = objectHack(node.object);
|
3976
4320
|
return;
|
3977
4321
|
}
|
@@ -4024,8 +4368,8 @@ const generateFunc = (scope, decl) => {
|
|
4024
4368
|
|
4025
4369
|
if (typedInput && decl.returnType) {
|
4026
4370
|
const { type } = extractTypeAnnotation(decl.returnType);
|
4027
|
-
|
4028
|
-
if (type != null) {
|
4371
|
+
if (type != null && !Prefs.indirectCalls) {
|
4372
|
+
// if (type != null) {
|
4029
4373
|
func.returnType = type;
|
4030
4374
|
func.returns = [ valtypeBinary ];
|
4031
4375
|
}
|