porffor 0.17.0-cab4904b8 → 0.17.0-cbb73d209
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -4
- package/compiler/2c.js +28 -11
- package/compiler/assemble.js +19 -4
- package/compiler/builtins/array.ts +79 -9
- package/compiler/builtins/date.ts +104 -106
- package/compiler/builtins/error.js +2 -5
- package/compiler/builtins/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 +12 -1
- package/compiler/codegen.js +747 -140
- package/compiler/generated_builtins.js +2752 -669
- 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/types.js +31 -5
- package/compiler/wasmSpec.js +2 -0
- package/compiler/wrap.js +20 -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 +3 -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';
|
@@ -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
|
}
|
@@ -1345,7 +1363,7 @@ const getNodeType = (scope, node) => {
|
|
1345
1363
|
const objectKnownType = knownType(scope, getNodeType(scope, node.object));
|
1346
1364
|
if (objectKnownType != null) {
|
1347
1365
|
if (name === 'length') {
|
1348
|
-
if (
|
1366
|
+
if (typeHasFlag(objectKnownType, TYPE_FLAGS.length)) return TYPES.number;
|
1349
1367
|
else return TYPES.undefined;
|
1350
1368
|
}
|
1351
1369
|
|
@@ -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,
|
1639
1673
|
|
1674
|
+
...setLastType(scope, Rhemyn.types[protoName])
|
1675
|
+
];
|
1676
|
+
}
|
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,
|
1748
1802
|
|
1749
|
-
|
1750
|
-
|
1751
|
-
|
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
|
+
];
|
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,14 +2072,35 @@ 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
|
-
|
1954
|
-
|
1955
|
-
let
|
1956
|
-
if (func &&
|
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);
|
2085
|
+
|
2086
|
+
let args = [...decl.arguments];
|
2087
|
+
if (func && !func.hasRestArgument && args.length < paramCount) {
|
1957
2088
|
// too little args, push undefineds
|
1958
2089
|
args = args.concat(new Array(paramCount - args.length).fill(DEFAULT_VALUE));
|
1959
2090
|
}
|
1960
2091
|
|
2092
|
+
if (func && func.hasRestArgument) {
|
2093
|
+
if (args.length < paramCount) {
|
2094
|
+
args = args.concat(new Array(paramCount - 1 - args.length).fill(DEFAULT_VALUE));
|
2095
|
+
}
|
2096
|
+
const restArgs = args.slice(paramCount - 1);
|
2097
|
+
args = args.slice(0, paramCount - 1);
|
2098
|
+
args.push({
|
2099
|
+
type: 'ArrayExpression',
|
2100
|
+
elements: restArgs
|
2101
|
+
})
|
2102
|
+
}
|
2103
|
+
|
1961
2104
|
if (func && args.length > paramCount) {
|
1962
2105
|
// too many args, slice extras off
|
1963
2106
|
args = args.slice(0, paramCount);
|
@@ -1965,7 +2108,6 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1965
2108
|
|
1966
2109
|
if (func && func.throws) scope.throws = true;
|
1967
2110
|
|
1968
|
-
let out = [];
|
1969
2111
|
for (let i = 0; i < args.length; i++) {
|
1970
2112
|
const arg = args[i];
|
1971
2113
|
out = out.concat(generate(scope, arg));
|
@@ -1978,13 +2120,13 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1978
2120
|
}
|
1979
2121
|
|
1980
2122
|
if (valtypeBinary !== Valtype.i32 &&
|
1981
|
-
(func && func.params[i * (typedParams ? 2 : 1)] === Valtype.i32)
|
2123
|
+
(func && func.params[paramOffset + i * (typedParams ? 2 : 1)] === Valtype.i32)
|
1982
2124
|
) {
|
1983
2125
|
out.push(Opcodes.i32_to);
|
1984
2126
|
}
|
1985
2127
|
|
1986
2128
|
if (valtypeBinary === Valtype.i32 &&
|
1987
|
-
(func && func.params[i * (typedParams ? 2 : 1)] === Valtype.f64)
|
2129
|
+
(func && func.params[paramOffset + i * (typedParams ? 2 : 1)] === Valtype.f64)
|
1988
2130
|
) {
|
1989
2131
|
out.push([ Opcodes.f64_convert_i32_s ]);
|
1990
2132
|
}
|
@@ -2017,32 +2159,10 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
2017
2159
|
return out;
|
2018
2160
|
};
|
2019
2161
|
|
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
|
-
};
|
2162
|
+
const generateNew = (scope, decl, _global, _name) => generateCall(scope, {
|
2163
|
+
...decl,
|
2164
|
+
_new: true
|
2165
|
+
}, _global, _name);
|
2046
2166
|
|
2047
2167
|
// bad hack for undefined and null working without additional logic
|
2048
2168
|
const DEFAULT_VALUE = {
|
@@ -2050,6 +2170,16 @@ const DEFAULT_VALUE = {
|
|
2050
2170
|
name: 'undefined'
|
2051
2171
|
};
|
2052
2172
|
|
2173
|
+
const codeToSanitizedStr = code => {
|
2174
|
+
let out = '';
|
2175
|
+
while (code > 0) {
|
2176
|
+
out += String.fromCharCode(97 + code % 26);
|
2177
|
+
code -= 26;
|
2178
|
+
}
|
2179
|
+
return out;
|
2180
|
+
};
|
2181
|
+
const sanitize = str => str.replace(/[^0-9a-zA-Z_]/g, _ => codeToSanitizedStr(_.charCodeAt(0)));
|
2182
|
+
|
2053
2183
|
const unhackName = name => {
|
2054
2184
|
if (name.startsWith('__')) return name.slice(2).replaceAll('_', '.');
|
2055
2185
|
return name;
|
@@ -2057,7 +2187,7 @@ const unhackName = name => {
|
|
2057
2187
|
|
2058
2188
|
const knownType = (scope, type) => {
|
2059
2189
|
if (type.length === 1 && type[0][0] === Opcodes.i32_const) {
|
2060
|
-
return type[0]
|
2190
|
+
return read_signedLEB128(type[0].slice(1));
|
2061
2191
|
}
|
2062
2192
|
|
2063
2193
|
if (typedInput && type.length === 1 && type[0][0] === Opcodes.local_get) {
|
@@ -2285,9 +2415,120 @@ const generateVar = (scope, decl) => {
|
|
2285
2415
|
const global = topLevel || decl._bare;
|
2286
2416
|
|
2287
2417
|
for (const x of decl.declarations) {
|
2288
|
-
|
2418
|
+
if (x.id.type === 'ArrayPattern') {
|
2419
|
+
const decls = [];
|
2420
|
+
const tmpName = '#destructure' + randId();
|
2421
|
+
|
2422
|
+
let i = 0;
|
2423
|
+
const elements = [...x.id.elements];
|
2424
|
+
for (const e of elements) {
|
2425
|
+
switch (e?.type) {
|
2426
|
+
case 'RestElement': { // let [ ...foo ] = []
|
2427
|
+
if (e.argument.type === 'ArrayPattern') {
|
2428
|
+
// let [ ...[a, b, c] ] = []
|
2429
|
+
elements.push(...e.argument.elements);
|
2430
|
+
} else {
|
2431
|
+
decls.push({
|
2432
|
+
type: 'VariableDeclarator',
|
2433
|
+
id: { type: 'Identifier', name: e.argument.name },
|
2434
|
+
init: {
|
2435
|
+
type: 'CallExpression',
|
2436
|
+
callee: {
|
2437
|
+
type: 'Identifier',
|
2438
|
+
name: '__Array_prototype_slice'
|
2439
|
+
},
|
2440
|
+
arguments: [
|
2441
|
+
{ type: 'Identifier', name: tmpName },
|
2442
|
+
{ type: 'Literal', value: i },
|
2443
|
+
{
|
2444
|
+
type: 'MemberExpression',
|
2445
|
+
object: { type: 'Identifier', name: tmpName, },
|
2446
|
+
property: { type: 'Identifier', name: 'length', }
|
2447
|
+
}
|
2448
|
+
]
|
2449
|
+
}
|
2450
|
+
});
|
2451
|
+
}
|
2452
|
+
|
2453
|
+
continue; // skip i++
|
2454
|
+
}
|
2289
2455
|
|
2290
|
-
|
2456
|
+
case 'Identifier': { // let [ foo ] = []
|
2457
|
+
decls.push({
|
2458
|
+
type: 'VariableDeclarator',
|
2459
|
+
id: e,
|
2460
|
+
init: {
|
2461
|
+
type: 'MemberExpression',
|
2462
|
+
object: { type: 'Identifier', name: tmpName },
|
2463
|
+
property: { type: 'Literal', value: i }
|
2464
|
+
}
|
2465
|
+
});
|
2466
|
+
|
2467
|
+
break;
|
2468
|
+
}
|
2469
|
+
|
2470
|
+
case 'AssignmentPattern': { // let [ foo = defaultValue ] = []
|
2471
|
+
decls.push({
|
2472
|
+
type: 'VariableDeclarator',
|
2473
|
+
id: e.left,
|
2474
|
+
init: {
|
2475
|
+
type: 'LogicalExpression',
|
2476
|
+
operator: '??',
|
2477
|
+
left: {
|
2478
|
+
type: 'MemberExpression',
|
2479
|
+
object: { type: 'Identifier', name: tmpName },
|
2480
|
+
property: { type: 'Literal', value: i }
|
2481
|
+
},
|
2482
|
+
right: e.right
|
2483
|
+
}
|
2484
|
+
});
|
2485
|
+
|
2486
|
+
break;
|
2487
|
+
}
|
2488
|
+
|
2489
|
+
case 'ArrayPattern': { // let [ [ foo, bar ] ] = []
|
2490
|
+
decls.push({
|
2491
|
+
type: 'VariableDeclarator',
|
2492
|
+
id: e,
|
2493
|
+
init: {
|
2494
|
+
type: 'MemberExpression',
|
2495
|
+
object: { type: 'Identifier', name: tmpName },
|
2496
|
+
property: { type: 'Literal', value: i }
|
2497
|
+
}
|
2498
|
+
});
|
2499
|
+
|
2500
|
+
break;
|
2501
|
+
}
|
2502
|
+
|
2503
|
+
case 'ObjectPattern':
|
2504
|
+
return todo(scope, 'object destructuring is not supported yet')
|
2505
|
+
}
|
2506
|
+
|
2507
|
+
i++;
|
2508
|
+
}
|
2509
|
+
|
2510
|
+
out = out.concat([
|
2511
|
+
...generateVar(scope, {
|
2512
|
+
type: 'VariableDeclaration',
|
2513
|
+
declarations: [{
|
2514
|
+
type: 'VariableDeclarator',
|
2515
|
+
id: { type: 'Identifier', name: tmpName },
|
2516
|
+
init: x.init
|
2517
|
+
}],
|
2518
|
+
kind: decl.kind
|
2519
|
+
}),
|
2520
|
+
...generateVar(scope, {
|
2521
|
+
type: 'VariableDeclaration',
|
2522
|
+
declarations: decls,
|
2523
|
+
kind: decl.kind
|
2524
|
+
})
|
2525
|
+
]);
|
2526
|
+
|
2527
|
+
continue;
|
2528
|
+
}
|
2529
|
+
|
2530
|
+
const name = mapName(x.id.name);
|
2531
|
+
if (!name) return todo(scope, 'object destructuring is not supported yet')
|
2291
2532
|
|
2292
2533
|
if (x.init && isFuncType(x.init.type)) {
|
2293
2534
|
// hack for let a = function () { ... }
|
@@ -2322,7 +2563,9 @@ const generateVar = (scope, decl) => {
|
|
2322
2563
|
// hack to set local as pointer before
|
2323
2564
|
out.push(...number(scope.arrays.get(name)), [ global ? Opcodes.global_set : Opcodes.local_set, idx ]);
|
2324
2565
|
if (generated.at(-1) == Opcodes.i32_from_u) generated.pop();
|
2325
|
-
generated.pop();
|
2566
|
+
// generated.pop();
|
2567
|
+
generated.push([ Opcodes.drop ]);
|
2568
|
+
|
2326
2569
|
out = out.concat(generated);
|
2327
2570
|
} else {
|
2328
2571
|
out = out.concat(generated);
|
@@ -2389,8 +2632,8 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2389
2632
|
|
2390
2633
|
// arr[i]
|
2391
2634
|
if (decl.left.type === 'MemberExpression' && decl.left.computed) {
|
2392
|
-
const newValueTmp = localTmp(scope, '
|
2393
|
-
const pointerTmp =
|
2635
|
+
const newValueTmp = localTmp(scope, '#member_setter_val_tmp');
|
2636
|
+
const pointerTmp = localTmp(scope, '#member_setter_ptr_tmp', Valtype.i32);
|
2394
2637
|
|
2395
2638
|
return [
|
2396
2639
|
...typeSwitch(scope, getNodeType(scope, decl.left.object), {
|
@@ -2402,11 +2645,11 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2402
2645
|
...generate(scope, decl.left.property),
|
2403
2646
|
Opcodes.i32_to_u,
|
2404
2647
|
|
2405
|
-
// turn into byte offset by * valtypeSize
|
2648
|
+
// turn into byte offset by * valtypeSize + 1
|
2406
2649
|
...number(ValtypeSize[valtype] + 1, Valtype.i32),
|
2407
2650
|
[ Opcodes.i32_mul ],
|
2408
2651
|
[ Opcodes.i32_add ],
|
2409
|
-
|
2652
|
+
[ Opcodes.local_tee, pointerTmp ],
|
2410
2653
|
|
2411
2654
|
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2412
2655
|
[ Opcodes.local_get, pointerTmp ],
|
@@ -2416,10 +2659,164 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2416
2659
|
[ Opcodes.i32_load8_u, 0, ValtypeSize.i32 + ValtypeSize[valtype] ]
|
2417
2660
|
], getNodeType(scope, decl.right), false, name, true)),
|
2418
2661
|
[ Opcodes.local_tee, newValueTmp ],
|
2662
|
+
[ Opcodes.store, 0, ValtypeSize.i32 ],
|
2419
2663
|
|
2420
|
-
[ Opcodes.
|
2664
|
+
[ Opcodes.local_get, pointerTmp ],
|
2665
|
+
...getNodeType(scope, decl),
|
2666
|
+
[ Opcodes.i32_store8, 0, ValtypeSize.i32 + ValtypeSize[valtype] ],
|
2421
2667
|
],
|
2422
2668
|
|
2669
|
+
...wrapBC({
|
2670
|
+
[TYPES.uint8array]: [
|
2671
|
+
[ Opcodes.i32_add ],
|
2672
|
+
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2673
|
+
|
2674
|
+
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2675
|
+
[ Opcodes.local_get, pointerTmp ],
|
2676
|
+
[ Opcodes.i32_load8_u, 0, 4 ],
|
2677
|
+
Opcodes.i32_from_u
|
2678
|
+
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
2679
|
+
[ Opcodes.local_tee, newValueTmp ],
|
2680
|
+
|
2681
|
+
Opcodes.i32_to_u,
|
2682
|
+
[ Opcodes.i32_store8, 0, 4 ]
|
2683
|
+
],
|
2684
|
+
[TYPES.uint8clampedarray]: [
|
2685
|
+
[ Opcodes.i32_add ],
|
2686
|
+
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2687
|
+
|
2688
|
+
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2689
|
+
[ Opcodes.local_get, pointerTmp ],
|
2690
|
+
[ Opcodes.i32_load8_u, 0, 4 ],
|
2691
|
+
Opcodes.i32_from_u
|
2692
|
+
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
2693
|
+
[ Opcodes.local_tee, newValueTmp ],
|
2694
|
+
|
2695
|
+
...number(0),
|
2696
|
+
[ Opcodes.f64_max ],
|
2697
|
+
...number(255),
|
2698
|
+
[ Opcodes.f64_min ],
|
2699
|
+
Opcodes.i32_to_u,
|
2700
|
+
[ Opcodes.i32_store8, 0, 4 ]
|
2701
|
+
],
|
2702
|
+
[TYPES.int8array]: [
|
2703
|
+
[ Opcodes.i32_add ],
|
2704
|
+
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2705
|
+
|
2706
|
+
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2707
|
+
[ Opcodes.local_get, pointerTmp ],
|
2708
|
+
[ Opcodes.i32_load8_s, 0, 4 ],
|
2709
|
+
Opcodes.i32_from
|
2710
|
+
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
2711
|
+
[ Opcodes.local_tee, newValueTmp ],
|
2712
|
+
|
2713
|
+
Opcodes.i32_to,
|
2714
|
+
[ Opcodes.i32_store8, 0, 4 ]
|
2715
|
+
],
|
2716
|
+
[TYPES.uint16array]: [
|
2717
|
+
...number(2, Valtype.i32),
|
2718
|
+
[ Opcodes.i32_mul ],
|
2719
|
+
[ Opcodes.i32_add ],
|
2720
|
+
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2721
|
+
|
2722
|
+
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2723
|
+
[ Opcodes.local_get, pointerTmp ],
|
2724
|
+
[ Opcodes.i32_load16_u, 0, 4 ],
|
2725
|
+
Opcodes.i32_from_u
|
2726
|
+
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
2727
|
+
[ Opcodes.local_tee, newValueTmp ],
|
2728
|
+
|
2729
|
+
Opcodes.i32_to_u,
|
2730
|
+
[ Opcodes.i32_store16, 0, 4 ]
|
2731
|
+
],
|
2732
|
+
[TYPES.int16array]: [
|
2733
|
+
...number(2, Valtype.i32),
|
2734
|
+
[ Opcodes.i32_mul ],
|
2735
|
+
[ Opcodes.i32_add ],
|
2736
|
+
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2737
|
+
|
2738
|
+
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2739
|
+
[ Opcodes.local_get, pointerTmp ],
|
2740
|
+
[ Opcodes.i32_load16_s, 0, 4 ],
|
2741
|
+
Opcodes.i32_from
|
2742
|
+
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
2743
|
+
[ Opcodes.local_tee, newValueTmp ],
|
2744
|
+
|
2745
|
+
Opcodes.i32_to,
|
2746
|
+
[ Opcodes.i32_store16, 0, 4 ]
|
2747
|
+
],
|
2748
|
+
[TYPES.uint32array]: [
|
2749
|
+
...number(4, Valtype.i32),
|
2750
|
+
[ Opcodes.i32_mul ],
|
2751
|
+
[ Opcodes.i32_add ],
|
2752
|
+
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2753
|
+
|
2754
|
+
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2755
|
+
[ Opcodes.local_get, pointerTmp ],
|
2756
|
+
[ Opcodes.i32_load, 0, 4 ],
|
2757
|
+
Opcodes.i32_from_u
|
2758
|
+
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
2759
|
+
[ Opcodes.local_tee, newValueTmp ],
|
2760
|
+
|
2761
|
+
Opcodes.i32_to_u,
|
2762
|
+
[ Opcodes.i32_store, 0, 4 ]
|
2763
|
+
],
|
2764
|
+
[TYPES.int32array]: [
|
2765
|
+
...number(4, Valtype.i32),
|
2766
|
+
[ Opcodes.i32_mul ],
|
2767
|
+
[ Opcodes.i32_add ],
|
2768
|
+
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2769
|
+
|
2770
|
+
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2771
|
+
[ Opcodes.local_get, pointerTmp ],
|
2772
|
+
[ Opcodes.i32_load, 0, 4 ],
|
2773
|
+
Opcodes.i32_from
|
2774
|
+
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
2775
|
+
[ Opcodes.local_tee, newValueTmp ],
|
2776
|
+
|
2777
|
+
Opcodes.i32_to,
|
2778
|
+
[ Opcodes.i32_store, 0, 4 ]
|
2779
|
+
],
|
2780
|
+
[TYPES.float32array]: [
|
2781
|
+
...number(4, Valtype.i32),
|
2782
|
+
[ Opcodes.i32_mul ],
|
2783
|
+
[ Opcodes.i32_add ],
|
2784
|
+
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2785
|
+
|
2786
|
+
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2787
|
+
[ Opcodes.local_get, pointerTmp ],
|
2788
|
+
[ Opcodes.f32_load, 0, 4 ],
|
2789
|
+
[ Opcodes.f64_promote_f32 ]
|
2790
|
+
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
2791
|
+
[ Opcodes.local_tee, newValueTmp ],
|
2792
|
+
|
2793
|
+
[ Opcodes.f32_demote_f64 ],
|
2794
|
+
[ Opcodes.f32_store, 0, 4 ]
|
2795
|
+
],
|
2796
|
+
[TYPES.float64array]: [
|
2797
|
+
...number(8, Valtype.i32),
|
2798
|
+
[ Opcodes.i32_mul ],
|
2799
|
+
[ Opcodes.i32_add ],
|
2800
|
+
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2801
|
+
|
2802
|
+
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2803
|
+
[ Opcodes.local_get, pointerTmp ],
|
2804
|
+
[ Opcodes.f64_load, 0, 4 ]
|
2805
|
+
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
2806
|
+
[ Opcodes.local_tee, newValueTmp ],
|
2807
|
+
|
2808
|
+
[ Opcodes.f64_store, 0, 4 ]
|
2809
|
+
],
|
2810
|
+
}, {
|
2811
|
+
prelude: [
|
2812
|
+
...generate(scope, decl.left.object),
|
2813
|
+
Opcodes.i32_to_u,
|
2814
|
+
...generate(scope, decl.left.property),
|
2815
|
+
Opcodes.i32_to_u,
|
2816
|
+
],
|
2817
|
+
postlude: setLastType(scope, TYPES.number)
|
2818
|
+
}),
|
2819
|
+
|
2423
2820
|
default: internalThrow(scope, 'TypeError', `Cannot assign member with non-array`)
|
2424
2821
|
}, Blocktype.void),
|
2425
2822
|
|
@@ -2803,7 +3200,9 @@ const generateForOf = (scope, decl) => {
|
|
2803
3200
|
// // todo: we should only do this for strings but we don't know at compile-time :(
|
2804
3201
|
// hack: this is naughty and will break things!
|
2805
3202
|
let newOut = number(0, Valtype.i32), newPointer = number(0, Valtype.i32);
|
2806
|
-
|
3203
|
+
|
3204
|
+
const known = knownType(scope, getNodeType(scope, decl.right));
|
3205
|
+
if ((known === TYPES.string || known === TYPES.bytestring) || (pages.hasAnyString && known == null)) {
|
2807
3206
|
// todo: we use i16 even for bytestrings which should not make a bad thing happen, just be confusing for debugging?
|
2808
3207
|
0, [ newOut, newPointer ] = makeArray(scope, {
|
2809
3208
|
rawElements: new Array(0)
|
@@ -2851,6 +3250,7 @@ const generateForOf = (scope, decl) => {
|
|
2851
3250
|
[ Opcodes.end ],
|
2852
3251
|
[ Opcodes.end ]
|
2853
3252
|
],
|
3253
|
+
|
2854
3254
|
[TYPES.string]: [
|
2855
3255
|
...setType(scope, leftName, TYPES.string),
|
2856
3256
|
|
@@ -2959,6 +3359,7 @@ const generateForOf = (scope, decl) => {
|
|
2959
3359
|
[ Opcodes.end ],
|
2960
3360
|
[ Opcodes.end ]
|
2961
3361
|
],
|
3362
|
+
|
2962
3363
|
[TYPES.set]: [
|
2963
3364
|
[ Opcodes.loop, Blocktype.void ],
|
2964
3365
|
|
@@ -2997,6 +3398,106 @@ const generateForOf = (scope, decl) => {
|
|
2997
3398
|
[ Opcodes.end ],
|
2998
3399
|
[ Opcodes.end ]
|
2999
3400
|
],
|
3401
|
+
|
3402
|
+
...wrapBC({
|
3403
|
+
[TYPES.uint8array]: [
|
3404
|
+
[ Opcodes.i32_add ],
|
3405
|
+
|
3406
|
+
[ Opcodes.i32_load8_u, 0, 4 ],
|
3407
|
+
Opcodes.i32_from_u
|
3408
|
+
],
|
3409
|
+
[TYPES.uint8clampedarray]: [
|
3410
|
+
[ Opcodes.i32_add ],
|
3411
|
+
|
3412
|
+
[ Opcodes.i32_load8_u, 0, 4 ],
|
3413
|
+
Opcodes.i32_from_u
|
3414
|
+
],
|
3415
|
+
[TYPES.int8array]: [
|
3416
|
+
[ Opcodes.i32_add ],
|
3417
|
+
|
3418
|
+
[ Opcodes.i32_load8_s, 0, 4 ],
|
3419
|
+
Opcodes.i32_from
|
3420
|
+
],
|
3421
|
+
[TYPES.uint16array]: [
|
3422
|
+
...number(2, Valtype.i32),
|
3423
|
+
[ Opcodes.i32_mul ],
|
3424
|
+
[ Opcodes.i32_add ],
|
3425
|
+
|
3426
|
+
[ Opcodes.i32_load16_u, 0, 4 ],
|
3427
|
+
Opcodes.i32_from_u
|
3428
|
+
],
|
3429
|
+
[TYPES.int16array]: [
|
3430
|
+
...number(2, Valtype.i32),
|
3431
|
+
[ Opcodes.i32_mul ],
|
3432
|
+
[ Opcodes.i32_add ],
|
3433
|
+
|
3434
|
+
[ Opcodes.i32_load16_s, 0, 4 ],
|
3435
|
+
Opcodes.i32_from
|
3436
|
+
],
|
3437
|
+
[TYPES.uint32array]: [
|
3438
|
+
...number(4, Valtype.i32),
|
3439
|
+
[ Opcodes.i32_mul ],
|
3440
|
+
[ Opcodes.i32_add ],
|
3441
|
+
|
3442
|
+
[ Opcodes.i32_load, 0, 4 ],
|
3443
|
+
Opcodes.i32_from_u
|
3444
|
+
],
|
3445
|
+
[TYPES.int32array]: [
|
3446
|
+
...number(4, Valtype.i32),
|
3447
|
+
[ Opcodes.i32_mul ],
|
3448
|
+
[ Opcodes.i32_add ],
|
3449
|
+
|
3450
|
+
[ Opcodes.i32_load, 0, 4 ],
|
3451
|
+
Opcodes.i32_from
|
3452
|
+
],
|
3453
|
+
[TYPES.float32array]: [
|
3454
|
+
...number(4, Valtype.i32),
|
3455
|
+
[ Opcodes.i32_mul ],
|
3456
|
+
[ Opcodes.i32_add ],
|
3457
|
+
|
3458
|
+
[ Opcodes.f32_load, 0, 4 ],
|
3459
|
+
[ Opcodes.f64_promote_f32 ]
|
3460
|
+
],
|
3461
|
+
[TYPES.float64array]: [
|
3462
|
+
...number(8, Valtype.i32),
|
3463
|
+
[ Opcodes.i32_mul ],
|
3464
|
+
[ Opcodes.i32_add ],
|
3465
|
+
|
3466
|
+
[ Opcodes.f64_load, 0, 4 ]
|
3467
|
+
],
|
3468
|
+
}, {
|
3469
|
+
prelude: [
|
3470
|
+
...setType(scope, leftName, TYPES.number),
|
3471
|
+
|
3472
|
+
[ Opcodes.loop, Blocktype.void ],
|
3473
|
+
|
3474
|
+
[ Opcodes.local_get, pointer ],
|
3475
|
+
[ Opcodes.local_get, counter ]
|
3476
|
+
],
|
3477
|
+
postlude: [
|
3478
|
+
[ isGlobal ? Opcodes.global_set : Opcodes.local_set, local.idx ],
|
3479
|
+
|
3480
|
+
[ Opcodes.block, Blocktype.void ],
|
3481
|
+
[ Opcodes.block, Blocktype.void ],
|
3482
|
+
...generate(scope, decl.body),
|
3483
|
+
[ Opcodes.end ],
|
3484
|
+
|
3485
|
+
// increment counter by 1
|
3486
|
+
[ Opcodes.local_get, counter ],
|
3487
|
+
...number(1, Valtype.i32),
|
3488
|
+
[ Opcodes.i32_add ],
|
3489
|
+
[ Opcodes.local_tee, counter ],
|
3490
|
+
|
3491
|
+
// loop if counter != length
|
3492
|
+
[ Opcodes.local_get, length ],
|
3493
|
+
[ Opcodes.i32_ne ],
|
3494
|
+
[ Opcodes.br_if, 1 ],
|
3495
|
+
|
3496
|
+
[ Opcodes.end ],
|
3497
|
+
[ Opcodes.end ]
|
3498
|
+
]
|
3499
|
+
}),
|
3500
|
+
|
3000
3501
|
default: internalThrow(scope, 'TypeError', `Tried for..of on non-iterable type`)
|
3001
3502
|
}, Blocktype.void));
|
3002
3503
|
|
@@ -3085,13 +3586,14 @@ const generateThrow = (scope, decl) => {
|
|
3085
3586
|
idx: tags.length
|
3086
3587
|
});
|
3087
3588
|
|
3088
|
-
let exceptId = exceptions.
|
3589
|
+
let exceptId = exceptions.findIndex(x => x.constructor === constructor && x.message === message);
|
3590
|
+
if (exceptId === -1) exceptId = exceptions.push({ constructor, message }) - 1;
|
3089
3591
|
|
3090
3592
|
scope.exceptions ??= [];
|
3091
3593
|
scope.exceptions.push(exceptId);
|
3092
3594
|
|
3093
3595
|
return [
|
3094
|
-
|
3596
|
+
...number(exceptId, Valtype.i32),
|
3095
3597
|
[ Opcodes.throw, tags[0].idx ]
|
3096
3598
|
];
|
3097
3599
|
}
|
@@ -3158,7 +3660,7 @@ const generateThrow = (scope, decl) => {
|
|
3158
3660
|
scope.exceptions.push(exceptId);
|
3159
3661
|
|
3160
3662
|
return [
|
3161
|
-
|
3663
|
+
...number(exceptId, Valtype.i32),
|
3162
3664
|
...generate(scope, message),
|
3163
3665
|
...getNodeType(scope, message),
|
3164
3666
|
[ Opcodes.throw, tags[0].idx ]
|
@@ -3199,6 +3701,22 @@ const generateEmpty = (scope, decl) => {
|
|
3199
3701
|
return [];
|
3200
3702
|
};
|
3201
3703
|
|
3704
|
+
const generateMeta = (scope, decl) => {
|
3705
|
+
if (decl.meta.name !== 'new') return todo(scope, `meta property object ${decl.meta.name} is not supported yet`, true);
|
3706
|
+
|
3707
|
+
switch (`${decl.meta.name}.${decl.property.name}`) {
|
3708
|
+
case 'new.target': {
|
3709
|
+
scope.constr = true;
|
3710
|
+
|
3711
|
+
return [
|
3712
|
+
[ Opcodes.local_get, -1 ],
|
3713
|
+
Opcodes.i32_from_u,
|
3714
|
+
...setLastType(scope, TYPES.boolean)
|
3715
|
+
];
|
3716
|
+
}
|
3717
|
+
}
|
3718
|
+
};
|
3719
|
+
|
3202
3720
|
let pages = new Map();
|
3203
3721
|
const allocPage = (scope, reason, type) => {
|
3204
3722
|
if (pages.has(reason)) return pages.get(reason).ind;
|
@@ -3516,6 +4034,19 @@ const withType = (scope, wasm, type) => [
|
|
3516
4034
|
...setLastType(scope, type)
|
3517
4035
|
];
|
3518
4036
|
|
4037
|
+
const wrapBC = (bc, { prelude = [], postlude = [] } = {}) => {
|
4038
|
+
const out = {};
|
4039
|
+
for (const x in bc) {
|
4040
|
+
out[x] = [
|
4041
|
+
...prelude,
|
4042
|
+
...bc[x],
|
4043
|
+
...postlude
|
4044
|
+
];
|
4045
|
+
}
|
4046
|
+
|
4047
|
+
return out;
|
4048
|
+
};
|
4049
|
+
|
3519
4050
|
const generateMember = (scope, decl, _global, _name) => {
|
3520
4051
|
const name = decl.object.name;
|
3521
4052
|
|
@@ -3538,20 +4069,10 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3538
4069
|
const func = funcs.find(x => x.name === name);
|
3539
4070
|
if (func) {
|
3540
4071
|
const typedParams = !func.internal || builtinFuncs[name]?.typedParams;
|
3541
|
-
return withType(scope, number(typedParams ? func.params.length / 2 : func.params.length), TYPES.number);
|
3542
|
-
}
|
3543
|
-
|
3544
|
-
if (builtinFuncs[name + '$constructor']) {
|
3545
|
-
const regularFunc = builtinFuncs[name];
|
3546
|
-
const regularParams = regularFunc.typedParams ? (regularFunc.params.length / 2) : regularFunc.params.length;
|
3547
|
-
|
3548
|
-
const constructorFunc = builtinFuncs[name + '$constructor'];
|
3549
|
-
const constructorParams = constructorFunc.typedParams ? (constructorFunc.params.length / 2) : constructorFunc.params.length;
|
3550
|
-
|
3551
|
-
return withType(scope, number(Math.max(regularParams, constructorParams)), TYPES.number);
|
4072
|
+
return withType(scope, number(typedParams ? Math.floor(func.params.length / 2) : (func.constr ? (func.params.length - 1) : func.params.length)), TYPES.number);
|
3552
4073
|
}
|
3553
4074
|
|
3554
|
-
if (builtinFuncs[name]) return withType(scope, number(builtinFuncs[name].typedParams ? (builtinFuncs[name].params.length / 2) : builtinFuncs[name].params.length), TYPES.number);
|
4075
|
+
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);
|
3555
4076
|
if (importedFuncs[name]) return withType(scope, number(importedFuncs[name].params.length ?? importedFuncs[name].params), TYPES.number);
|
3556
4077
|
if (internalConstrs[name]) return withType(scope, number(internalConstrs[name].length ?? 0), TYPES.number);
|
3557
4078
|
|
@@ -3569,7 +4090,7 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3569
4090
|
const type = getNodeType(scope, decl.object);
|
3570
4091
|
const known = knownType(scope, type);
|
3571
4092
|
if (known != null) {
|
3572
|
-
if (
|
4093
|
+
if (typeHasFlag(known, TYPE_FLAGS.length)) return [
|
3573
4094
|
...generate(scope, decl.object),
|
3574
4095
|
Opcodes.i32_to_u,
|
3575
4096
|
|
@@ -3581,7 +4102,9 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3581
4102
|
}
|
3582
4103
|
|
3583
4104
|
return [
|
3584
|
-
...
|
4105
|
+
...getNodeType(scope, decl.object),
|
4106
|
+
...number(TYPE_FLAGS.length, Valtype.i32),
|
4107
|
+
[ Opcodes.i32_and ],
|
3585
4108
|
[ Opcodes.if, valtypeBinary ],
|
3586
4109
|
...generate(scope, decl.object),
|
3587
4110
|
Opcodes.i32_to_u,
|
@@ -3598,7 +4121,7 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3598
4121
|
}
|
3599
4122
|
|
3600
4123
|
// todo: generate this array procedurally during builtinFuncs creation
|
3601
|
-
if (['size', 'description'].includes(decl.property.name)) {
|
4124
|
+
if (['size', 'description', 'byteLength'].includes(decl.property.name)) {
|
3602
4125
|
const bc = {};
|
3603
4126
|
const cands = Object.keys(builtinFuncs).filter(x => x.startsWith('__') && x.endsWith('_prototype_' + decl.property.name + '$get'));
|
3604
4127
|
|
@@ -3630,7 +4153,9 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3630
4153
|
// // todo: we should only do this for strings but we don't know at compile-time :(
|
3631
4154
|
// hack: this is naughty and will break things!
|
3632
4155
|
let newOut = number(0, Valtype.i32), newPointer = number(0, Valtype.i32);
|
3633
|
-
|
4156
|
+
|
4157
|
+
const known = knownType(scope, getNodeType(scope, decl.object));
|
4158
|
+
if ((known === TYPES.string || known === TYPES.bytestring) || (pages.hasAnyString && known == null)) {
|
3634
4159
|
// todo: we use i16 even for bytestrings which should not make a bad thing happen, just be confusing for debugging?
|
3635
4160
|
0, [ newOut, newPointer ] = makeArray(scope, {
|
3636
4161
|
rawElements: new Array(0)
|
@@ -3704,6 +4229,82 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3704
4229
|
...setLastType(scope, TYPES.bytestring)
|
3705
4230
|
],
|
3706
4231
|
|
4232
|
+
...wrapBC({
|
4233
|
+
[TYPES.uint8array]: [
|
4234
|
+
[ Opcodes.i32_add ],
|
4235
|
+
|
4236
|
+
[ Opcodes.i32_load8_u, 0, 4 ],
|
4237
|
+
Opcodes.i32_from_u
|
4238
|
+
],
|
4239
|
+
[TYPES.uint8clampedarray]: [
|
4240
|
+
[ Opcodes.i32_add ],
|
4241
|
+
|
4242
|
+
[ Opcodes.i32_load8_u, 0, 4 ],
|
4243
|
+
Opcodes.i32_from_u
|
4244
|
+
],
|
4245
|
+
[TYPES.int8array]: [
|
4246
|
+
[ Opcodes.i32_add ],
|
4247
|
+
|
4248
|
+
[ Opcodes.i32_load8_s, 0, 4 ],
|
4249
|
+
Opcodes.i32_from
|
4250
|
+
],
|
4251
|
+
[TYPES.uint16array]: [
|
4252
|
+
...number(2, Valtype.i32),
|
4253
|
+
[ Opcodes.i32_mul ],
|
4254
|
+
[ Opcodes.i32_add ],
|
4255
|
+
|
4256
|
+
[ Opcodes.i32_load16_u, 0, 4 ],
|
4257
|
+
Opcodes.i32_from_u
|
4258
|
+
],
|
4259
|
+
[TYPES.int16array]: [
|
4260
|
+
...number(2, Valtype.i32),
|
4261
|
+
[ Opcodes.i32_mul ],
|
4262
|
+
[ Opcodes.i32_add ],
|
4263
|
+
|
4264
|
+
[ Opcodes.i32_load16_s, 0, 4 ],
|
4265
|
+
Opcodes.i32_from
|
4266
|
+
],
|
4267
|
+
[TYPES.uint32array]: [
|
4268
|
+
...number(4, Valtype.i32),
|
4269
|
+
[ Opcodes.i32_mul ],
|
4270
|
+
[ Opcodes.i32_add ],
|
4271
|
+
|
4272
|
+
[ Opcodes.i32_load, 0, 4 ],
|
4273
|
+
Opcodes.i32_from_u
|
4274
|
+
],
|
4275
|
+
[TYPES.int32array]: [
|
4276
|
+
...number(4, Valtype.i32),
|
4277
|
+
[ Opcodes.i32_mul ],
|
4278
|
+
[ Opcodes.i32_add ],
|
4279
|
+
|
4280
|
+
[ Opcodes.i32_load, 0, 4 ],
|
4281
|
+
Opcodes.i32_from
|
4282
|
+
],
|
4283
|
+
[TYPES.float32array]: [
|
4284
|
+
...number(4, Valtype.i32),
|
4285
|
+
[ Opcodes.i32_mul ],
|
4286
|
+
[ Opcodes.i32_add ],
|
4287
|
+
|
4288
|
+
[ Opcodes.f32_load, 0, 4 ],
|
4289
|
+
[ Opcodes.f64_promote_f32 ]
|
4290
|
+
],
|
4291
|
+
[TYPES.float64array]: [
|
4292
|
+
...number(8, Valtype.i32),
|
4293
|
+
[ Opcodes.i32_mul ],
|
4294
|
+
[ Opcodes.i32_add ],
|
4295
|
+
|
4296
|
+
[ Opcodes.f64_load, 0, 4 ]
|
4297
|
+
],
|
4298
|
+
}, {
|
4299
|
+
prelude: [
|
4300
|
+
...object,
|
4301
|
+
Opcodes.i32_to_u,
|
4302
|
+
...property,
|
4303
|
+
Opcodes.i32_to_u
|
4304
|
+
],
|
4305
|
+
postlude: setLastType(scope, TYPES.number)
|
4306
|
+
}),
|
4307
|
+
|
3707
4308
|
default: internalThrow(scope, 'TypeError', 'Member expression is not supported for non-string non-array yet', true)
|
3708
4309
|
});
|
3709
4310
|
};
|
@@ -3726,7 +4327,7 @@ const objectHack = node => {
|
|
3726
4327
|
if (!objectName) objectName = objectHack(node.object)?.name?.slice?.(2);
|
3727
4328
|
|
3728
4329
|
// if .name or .length, give up (hack within a hack!)
|
3729
|
-
if (['name', 'length', 'size', 'description'].includes(node.property.name)) {
|
4330
|
+
if (['name', 'length', 'size', 'description', 'byteLength'].includes(node.property.name)) {
|
3730
4331
|
node.object = objectHack(node.object);
|
3731
4332
|
return;
|
3732
4333
|
}
|
@@ -3779,8 +4380,8 @@ const generateFunc = (scope, decl) => {
|
|
3779
4380
|
|
3780
4381
|
if (typedInput && decl.returnType) {
|
3781
4382
|
const { type } = extractTypeAnnotation(decl.returnType);
|
3782
|
-
|
3783
|
-
if (type != null) {
|
4383
|
+
if (type != null && !Prefs.indirectCalls) {
|
4384
|
+
// if (type != null) {
|
3784
4385
|
func.returnType = type;
|
3785
4386
|
func.returns = [ valtypeBinary ];
|
3786
4387
|
}
|
@@ -3801,6 +4402,12 @@ const generateFunc = (scope, decl) => {
|
|
3801
4402
|
defaultValues[name] = x.right;
|
3802
4403
|
break;
|
3803
4404
|
}
|
4405
|
+
|
4406
|
+
case 'RestElement': {
|
4407
|
+
name = x.argument.name;
|
4408
|
+
func.hasRestArgument = true;
|
4409
|
+
break;
|
4410
|
+
}
|
3804
4411
|
}
|
3805
4412
|
|
3806
4413
|
// if (name == null) return todo('non-identifier args are not supported');
|