porffor 0.17.0-a1f691e30 → 0.17.0-a23029b3a
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -4
- package/compiler/2c.js +28 -11
- package/compiler/assemble.js +19 -4
- package/compiler/builtins/array.ts +79 -9
- package/compiler/builtins/date.ts +104 -106
- package/compiler/builtins/error.js +2 -5
- package/compiler/builtins/math.ts +6 -2
- package/compiler/builtins/set.ts +6 -14
- package/compiler/builtins/string_f64.ts +4 -6
- package/compiler/builtins/symbol.ts +2 -1
- package/compiler/builtins/typedarray.js +94 -0
- package/compiler/builtins/z_ecma262.ts +1 -0
- package/compiler/builtins.js +25 -0
- package/compiler/codegen.js +726 -137
- package/compiler/generated_builtins.js +2752 -669
- 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,
|
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,
|
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,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;
|
@@ -2057,7 +2175,7 @@ const unhackName = name => {
|
|
2057
2175
|
|
2058
2176
|
const knownType = (scope, type) => {
|
2059
2177
|
if (type.length === 1 && type[0][0] === Opcodes.i32_const) {
|
2060
|
-
return type[0]
|
2178
|
+
return read_signedLEB128(type[0].slice(1));
|
2061
2179
|
}
|
2062
2180
|
|
2063
2181
|
if (typedInput && type.length === 1 && type[0][0] === Opcodes.local_get) {
|
@@ -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
|
+
}
|
2289
2443
|
|
2290
|
-
|
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
|
+
}
|
2490
|
+
|
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,10 +2647,164 @@ 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 ],
|
2650
|
+
[ Opcodes.store, 0, ValtypeSize.i32 ],
|
2419
2651
|
|
2420
|
-
[ Opcodes.
|
2652
|
+
[ Opcodes.local_get, pointerTmp ],
|
2653
|
+
...getNodeType(scope, decl),
|
2654
|
+
[ Opcodes.i32_store8, 0, ValtypeSize.i32 + ValtypeSize[valtype] ],
|
2421
2655
|
],
|
2422
2656
|
|
2657
|
+
...wrapBC({
|
2658
|
+
[TYPES.uint8array]: [
|
2659
|
+
[ Opcodes.i32_add ],
|
2660
|
+
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2661
|
+
|
2662
|
+
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2663
|
+
[ Opcodes.local_get, pointerTmp ],
|
2664
|
+
[ Opcodes.i32_load8_u, 0, 4 ],
|
2665
|
+
Opcodes.i32_from_u
|
2666
|
+
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
2667
|
+
[ Opcodes.local_tee, newValueTmp ],
|
2668
|
+
|
2669
|
+
Opcodes.i32_to_u,
|
2670
|
+
[ Opcodes.i32_store8, 0, 4 ]
|
2671
|
+
],
|
2672
|
+
[TYPES.uint8clampedarray]: [
|
2673
|
+
[ Opcodes.i32_add ],
|
2674
|
+
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2675
|
+
|
2676
|
+
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2677
|
+
[ Opcodes.local_get, pointerTmp ],
|
2678
|
+
[ Opcodes.i32_load8_u, 0, 4 ],
|
2679
|
+
Opcodes.i32_from_u
|
2680
|
+
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
2681
|
+
[ Opcodes.local_tee, newValueTmp ],
|
2682
|
+
|
2683
|
+
...number(0),
|
2684
|
+
[ Opcodes.f64_max ],
|
2685
|
+
...number(255),
|
2686
|
+
[ Opcodes.f64_min ],
|
2687
|
+
Opcodes.i32_to_u,
|
2688
|
+
[ Opcodes.i32_store8, 0, 4 ]
|
2689
|
+
],
|
2690
|
+
[TYPES.int8array]: [
|
2691
|
+
[ Opcodes.i32_add ],
|
2692
|
+
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2693
|
+
|
2694
|
+
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2695
|
+
[ Opcodes.local_get, pointerTmp ],
|
2696
|
+
[ Opcodes.i32_load8_s, 0, 4 ],
|
2697
|
+
Opcodes.i32_from
|
2698
|
+
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
2699
|
+
[ Opcodes.local_tee, newValueTmp ],
|
2700
|
+
|
2701
|
+
Opcodes.i32_to,
|
2702
|
+
[ Opcodes.i32_store8, 0, 4 ]
|
2703
|
+
],
|
2704
|
+
[TYPES.uint16array]: [
|
2705
|
+
...number(2, Valtype.i32),
|
2706
|
+
[ Opcodes.i32_mul ],
|
2707
|
+
[ Opcodes.i32_add ],
|
2708
|
+
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2709
|
+
|
2710
|
+
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2711
|
+
[ Opcodes.local_get, pointerTmp ],
|
2712
|
+
[ Opcodes.i32_load16_u, 0, 4 ],
|
2713
|
+
Opcodes.i32_from_u
|
2714
|
+
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
2715
|
+
[ Opcodes.local_tee, newValueTmp ],
|
2716
|
+
|
2717
|
+
Opcodes.i32_to_u,
|
2718
|
+
[ Opcodes.i32_store16, 0, 4 ]
|
2719
|
+
],
|
2720
|
+
[TYPES.int16array]: [
|
2721
|
+
...number(2, Valtype.i32),
|
2722
|
+
[ Opcodes.i32_mul ],
|
2723
|
+
[ Opcodes.i32_add ],
|
2724
|
+
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2725
|
+
|
2726
|
+
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2727
|
+
[ Opcodes.local_get, pointerTmp ],
|
2728
|
+
[ Opcodes.i32_load16_s, 0, 4 ],
|
2729
|
+
Opcodes.i32_from
|
2730
|
+
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
2731
|
+
[ Opcodes.local_tee, newValueTmp ],
|
2732
|
+
|
2733
|
+
Opcodes.i32_to,
|
2734
|
+
[ Opcodes.i32_store16, 0, 4 ]
|
2735
|
+
],
|
2736
|
+
[TYPES.uint32array]: [
|
2737
|
+
...number(4, Valtype.i32),
|
2738
|
+
[ Opcodes.i32_mul ],
|
2739
|
+
[ Opcodes.i32_add ],
|
2740
|
+
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2741
|
+
|
2742
|
+
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2743
|
+
[ Opcodes.local_get, pointerTmp ],
|
2744
|
+
[ Opcodes.i32_load, 0, 4 ],
|
2745
|
+
Opcodes.i32_from_u
|
2746
|
+
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
2747
|
+
[ Opcodes.local_tee, newValueTmp ],
|
2748
|
+
|
2749
|
+
Opcodes.i32_to_u,
|
2750
|
+
[ Opcodes.i32_store, 0, 4 ]
|
2751
|
+
],
|
2752
|
+
[TYPES.int32array]: [
|
2753
|
+
...number(4, Valtype.i32),
|
2754
|
+
[ Opcodes.i32_mul ],
|
2755
|
+
[ Opcodes.i32_add ],
|
2756
|
+
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2757
|
+
|
2758
|
+
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2759
|
+
[ Opcodes.local_get, pointerTmp ],
|
2760
|
+
[ Opcodes.i32_load, 0, 4 ],
|
2761
|
+
Opcodes.i32_from
|
2762
|
+
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
2763
|
+
[ Opcodes.local_tee, newValueTmp ],
|
2764
|
+
|
2765
|
+
Opcodes.i32_to,
|
2766
|
+
[ Opcodes.i32_store, 0, 4 ]
|
2767
|
+
],
|
2768
|
+
[TYPES.float32array]: [
|
2769
|
+
...number(4, Valtype.i32),
|
2770
|
+
[ Opcodes.i32_mul ],
|
2771
|
+
[ Opcodes.i32_add ],
|
2772
|
+
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2773
|
+
|
2774
|
+
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2775
|
+
[ Opcodes.local_get, pointerTmp ],
|
2776
|
+
[ Opcodes.f32_load, 0, 4 ],
|
2777
|
+
[ Opcodes.f64_promote_f32 ]
|
2778
|
+
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
2779
|
+
[ Opcodes.local_tee, newValueTmp ],
|
2780
|
+
|
2781
|
+
[ Opcodes.f32_demote_f64 ],
|
2782
|
+
[ Opcodes.f32_store, 0, 4 ]
|
2783
|
+
],
|
2784
|
+
[TYPES.float64array]: [
|
2785
|
+
...number(8, Valtype.i32),
|
2786
|
+
[ Opcodes.i32_mul ],
|
2787
|
+
[ Opcodes.i32_add ],
|
2788
|
+
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2789
|
+
|
2790
|
+
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2791
|
+
[ Opcodes.local_get, pointerTmp ],
|
2792
|
+
[ Opcodes.f64_load, 0, 4 ]
|
2793
|
+
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
2794
|
+
[ Opcodes.local_tee, newValueTmp ],
|
2795
|
+
|
2796
|
+
[ Opcodes.f64_store, 0, 4 ]
|
2797
|
+
],
|
2798
|
+
}, {
|
2799
|
+
prelude: [
|
2800
|
+
...generate(scope, decl.left.object),
|
2801
|
+
Opcodes.i32_to_u,
|
2802
|
+
...generate(scope, decl.left.property),
|
2803
|
+
Opcodes.i32_to_u,
|
2804
|
+
],
|
2805
|
+
postlude: setLastType(scope, TYPES.number)
|
2806
|
+
}),
|
2807
|
+
|
2423
2808
|
default: internalThrow(scope, 'TypeError', `Cannot assign member with non-array`)
|
2424
2809
|
}, Blocktype.void),
|
2425
2810
|
|
@@ -2803,7 +3188,9 @@ const generateForOf = (scope, decl) => {
|
|
2803
3188
|
// // todo: we should only do this for strings but we don't know at compile-time :(
|
2804
3189
|
// hack: this is naughty and will break things!
|
2805
3190
|
let newOut = number(0, Valtype.i32), newPointer = number(0, Valtype.i32);
|
2806
|
-
|
3191
|
+
|
3192
|
+
const known = knownType(scope, getNodeType(scope, decl.right));
|
3193
|
+
if ((known === TYPES.string || known === TYPES.bytestring) || (pages.hasAnyString && known == null)) {
|
2807
3194
|
// todo: we use i16 even for bytestrings which should not make a bad thing happen, just be confusing for debugging?
|
2808
3195
|
0, [ newOut, newPointer ] = makeArray(scope, {
|
2809
3196
|
rawElements: new Array(0)
|
@@ -2851,6 +3238,7 @@ const generateForOf = (scope, decl) => {
|
|
2851
3238
|
[ Opcodes.end ],
|
2852
3239
|
[ Opcodes.end ]
|
2853
3240
|
],
|
3241
|
+
|
2854
3242
|
[TYPES.string]: [
|
2855
3243
|
...setType(scope, leftName, TYPES.string),
|
2856
3244
|
|
@@ -2959,6 +3347,7 @@ const generateForOf = (scope, decl) => {
|
|
2959
3347
|
[ Opcodes.end ],
|
2960
3348
|
[ Opcodes.end ]
|
2961
3349
|
],
|
3350
|
+
|
2962
3351
|
[TYPES.set]: [
|
2963
3352
|
[ Opcodes.loop, Blocktype.void ],
|
2964
3353
|
|
@@ -2997,6 +3386,106 @@ const generateForOf = (scope, decl) => {
|
|
2997
3386
|
[ Opcodes.end ],
|
2998
3387
|
[ Opcodes.end ]
|
2999
3388
|
],
|
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
|
+
|
3000
3489
|
default: internalThrow(scope, 'TypeError', `Tried for..of on non-iterable type`)
|
3001
3490
|
}, Blocktype.void));
|
3002
3491
|
|
@@ -3085,13 +3574,14 @@ const generateThrow = (scope, decl) => {
|
|
3085
3574
|
idx: tags.length
|
3086
3575
|
});
|
3087
3576
|
|
3088
|
-
let exceptId = exceptions.
|
3577
|
+
let exceptId = exceptions.findIndex(x => x.constructor === constructor && x.message === message);
|
3578
|
+
if (exceptId === -1) exceptId = exceptions.push({ constructor, message }) - 1;
|
3089
3579
|
|
3090
3580
|
scope.exceptions ??= [];
|
3091
3581
|
scope.exceptions.push(exceptId);
|
3092
3582
|
|
3093
3583
|
return [
|
3094
|
-
|
3584
|
+
...number(exceptId, Valtype.i32),
|
3095
3585
|
[ Opcodes.throw, tags[0].idx ]
|
3096
3586
|
];
|
3097
3587
|
}
|
@@ -3158,7 +3648,7 @@ const generateThrow = (scope, decl) => {
|
|
3158
3648
|
scope.exceptions.push(exceptId);
|
3159
3649
|
|
3160
3650
|
return [
|
3161
|
-
|
3651
|
+
...number(exceptId, Valtype.i32),
|
3162
3652
|
...generate(scope, message),
|
3163
3653
|
...getNodeType(scope, message),
|
3164
3654
|
[ Opcodes.throw, tags[0].idx ]
|
@@ -3199,6 +3689,22 @@ const generateEmpty = (scope, decl) => {
|
|
3199
3689
|
return [];
|
3200
3690
|
};
|
3201
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
|
+
|
3202
3708
|
let pages = new Map();
|
3203
3709
|
const allocPage = (scope, reason, type) => {
|
3204
3710
|
if (pages.has(reason)) return pages.get(reason).ind;
|
@@ -3516,6 +4022,19 @@ const withType = (scope, wasm, type) => [
|
|
3516
4022
|
...setLastType(scope, type)
|
3517
4023
|
];
|
3518
4024
|
|
4025
|
+
const wrapBC = (bc, { prelude = [], postlude = [] } = {}) => {
|
4026
|
+
const out = {};
|
4027
|
+
for (const x in bc) {
|
4028
|
+
out[x] = [
|
4029
|
+
...prelude,
|
4030
|
+
...bc[x],
|
4031
|
+
...postlude
|
4032
|
+
];
|
4033
|
+
}
|
4034
|
+
|
4035
|
+
return out;
|
4036
|
+
};
|
4037
|
+
|
3519
4038
|
const generateMember = (scope, decl, _global, _name) => {
|
3520
4039
|
const name = decl.object.name;
|
3521
4040
|
|
@@ -3538,20 +4057,10 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3538
4057
|
const func = funcs.find(x => x.name === name);
|
3539
4058
|
if (func) {
|
3540
4059
|
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);
|
4060
|
+
return withType(scope, number(typedParams ? Math.floor(func.params.length / 2) : (func.constr ? (func.params.length - 1) : func.params.length)), TYPES.number);
|
3552
4061
|
}
|
3553
4062
|
|
3554
|
-
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);
|
3555
4064
|
if (importedFuncs[name]) return withType(scope, number(importedFuncs[name].params.length ?? importedFuncs[name].params), TYPES.number);
|
3556
4065
|
if (internalConstrs[name]) return withType(scope, number(internalConstrs[name].length ?? 0), TYPES.number);
|
3557
4066
|
|
@@ -3569,7 +4078,7 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3569
4078
|
const type = getNodeType(scope, decl.object);
|
3570
4079
|
const known = knownType(scope, type);
|
3571
4080
|
if (known != null) {
|
3572
|
-
if (
|
4081
|
+
if (typeHasFlag(known, TYPE_FLAGS.length)) return [
|
3573
4082
|
...generate(scope, decl.object),
|
3574
4083
|
Opcodes.i32_to_u,
|
3575
4084
|
|
@@ -3581,7 +4090,9 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3581
4090
|
}
|
3582
4091
|
|
3583
4092
|
return [
|
3584
|
-
...
|
4093
|
+
...getNodeType(scope, decl.object),
|
4094
|
+
...number(TYPE_FLAGS.length, Valtype.i32),
|
4095
|
+
[ Opcodes.i32_and ],
|
3585
4096
|
[ Opcodes.if, valtypeBinary ],
|
3586
4097
|
...generate(scope, decl.object),
|
3587
4098
|
Opcodes.i32_to_u,
|
@@ -3598,7 +4109,7 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3598
4109
|
}
|
3599
4110
|
|
3600
4111
|
// todo: generate this array procedurally during builtinFuncs creation
|
3601
|
-
if (['size', 'description'].includes(decl.property.name)) {
|
4112
|
+
if (['size', 'description', 'byteLength'].includes(decl.property.name)) {
|
3602
4113
|
const bc = {};
|
3603
4114
|
const cands = Object.keys(builtinFuncs).filter(x => x.startsWith('__') && x.endsWith('_prototype_' + decl.property.name + '$get'));
|
3604
4115
|
|
@@ -3630,7 +4141,9 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3630
4141
|
// // todo: we should only do this for strings but we don't know at compile-time :(
|
3631
4142
|
// hack: this is naughty and will break things!
|
3632
4143
|
let newOut = number(0, Valtype.i32), newPointer = number(0, Valtype.i32);
|
3633
|
-
|
4144
|
+
|
4145
|
+
const known = knownType(scope, getNodeType(scope, decl.object));
|
4146
|
+
if ((known === TYPES.string || known === TYPES.bytestring) || (pages.hasAnyString && known == null)) {
|
3634
4147
|
// todo: we use i16 even for bytestrings which should not make a bad thing happen, just be confusing for debugging?
|
3635
4148
|
0, [ newOut, newPointer ] = makeArray(scope, {
|
3636
4149
|
rawElements: new Array(0)
|
@@ -3704,6 +4217,82 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3704
4217
|
...setLastType(scope, TYPES.bytestring)
|
3705
4218
|
],
|
3706
4219
|
|
4220
|
+
...wrapBC({
|
4221
|
+
[TYPES.uint8array]: [
|
4222
|
+
[ Opcodes.i32_add ],
|
4223
|
+
|
4224
|
+
[ Opcodes.i32_load8_u, 0, 4 ],
|
4225
|
+
Opcodes.i32_from_u
|
4226
|
+
],
|
4227
|
+
[TYPES.uint8clampedarray]: [
|
4228
|
+
[ Opcodes.i32_add ],
|
4229
|
+
|
4230
|
+
[ Opcodes.i32_load8_u, 0, 4 ],
|
4231
|
+
Opcodes.i32_from_u
|
4232
|
+
],
|
4233
|
+
[TYPES.int8array]: [
|
4234
|
+
[ Opcodes.i32_add ],
|
4235
|
+
|
4236
|
+
[ Opcodes.i32_load8_s, 0, 4 ],
|
4237
|
+
Opcodes.i32_from
|
4238
|
+
],
|
4239
|
+
[TYPES.uint16array]: [
|
4240
|
+
...number(2, Valtype.i32),
|
4241
|
+
[ Opcodes.i32_mul ],
|
4242
|
+
[ Opcodes.i32_add ],
|
4243
|
+
|
4244
|
+
[ Opcodes.i32_load16_u, 0, 4 ],
|
4245
|
+
Opcodes.i32_from_u
|
4246
|
+
],
|
4247
|
+
[TYPES.int16array]: [
|
4248
|
+
...number(2, Valtype.i32),
|
4249
|
+
[ Opcodes.i32_mul ],
|
4250
|
+
[ Opcodes.i32_add ],
|
4251
|
+
|
4252
|
+
[ Opcodes.i32_load16_s, 0, 4 ],
|
4253
|
+
Opcodes.i32_from
|
4254
|
+
],
|
4255
|
+
[TYPES.uint32array]: [
|
4256
|
+
...number(4, Valtype.i32),
|
4257
|
+
[ Opcodes.i32_mul ],
|
4258
|
+
[ Opcodes.i32_add ],
|
4259
|
+
|
4260
|
+
[ Opcodes.i32_load, 0, 4 ],
|
4261
|
+
Opcodes.i32_from_u
|
4262
|
+
],
|
4263
|
+
[TYPES.int32array]: [
|
4264
|
+
...number(4, Valtype.i32),
|
4265
|
+
[ Opcodes.i32_mul ],
|
4266
|
+
[ Opcodes.i32_add ],
|
4267
|
+
|
4268
|
+
[ Opcodes.i32_load, 0, 4 ],
|
4269
|
+
Opcodes.i32_from
|
4270
|
+
],
|
4271
|
+
[TYPES.float32array]: [
|
4272
|
+
...number(4, Valtype.i32),
|
4273
|
+
[ Opcodes.i32_mul ],
|
4274
|
+
[ Opcodes.i32_add ],
|
4275
|
+
|
4276
|
+
[ Opcodes.f32_load, 0, 4 ],
|
4277
|
+
[ Opcodes.f64_promote_f32 ]
|
4278
|
+
],
|
4279
|
+
[TYPES.float64array]: [
|
4280
|
+
...number(8, Valtype.i32),
|
4281
|
+
[ Opcodes.i32_mul ],
|
4282
|
+
[ Opcodes.i32_add ],
|
4283
|
+
|
4284
|
+
[ Opcodes.f64_load, 0, 4 ]
|
4285
|
+
],
|
4286
|
+
}, {
|
4287
|
+
prelude: [
|
4288
|
+
...object,
|
4289
|
+
Opcodes.i32_to_u,
|
4290
|
+
...property,
|
4291
|
+
Opcodes.i32_to_u
|
4292
|
+
],
|
4293
|
+
postlude: setLastType(scope, TYPES.number)
|
4294
|
+
}),
|
4295
|
+
|
3707
4296
|
default: internalThrow(scope, 'TypeError', 'Member expression is not supported for non-string non-array yet', true)
|
3708
4297
|
});
|
3709
4298
|
};
|
@@ -3726,7 +4315,7 @@ const objectHack = node => {
|
|
3726
4315
|
if (!objectName) objectName = objectHack(node.object)?.name?.slice?.(2);
|
3727
4316
|
|
3728
4317
|
// if .name or .length, give up (hack within a hack!)
|
3729
|
-
if (['name', 'length', 'size', 'description'].includes(node.property.name)) {
|
4318
|
+
if (['name', 'length', 'size', 'description', 'byteLength'].includes(node.property.name)) {
|
3730
4319
|
node.object = objectHack(node.object);
|
3731
4320
|
return;
|
3732
4321
|
}
|
@@ -3779,8 +4368,8 @@ const generateFunc = (scope, decl) => {
|
|
3779
4368
|
|
3780
4369
|
if (typedInput && decl.returnType) {
|
3781
4370
|
const { type } = extractTypeAnnotation(decl.returnType);
|
3782
|
-
|
3783
|
-
if (type != null) {
|
4371
|
+
if (type != null && !Prefs.indirectCalls) {
|
4372
|
+
// if (type != null) {
|
3784
4373
|
func.returnType = type;
|
3785
4374
|
func.returns = [ valtypeBinary ];
|
3786
4375
|
}
|