porffor 0.17.0-94400a2b8 → 0.17.0-99a1a1851
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/builtins/array.ts +51 -9
- package/compiler/builtins/math.ts +6 -2
- package/compiler/builtins/set.ts +2 -9
- package/compiler/builtins/typedarray.js +96 -0
- package/compiler/builtins.js +25 -0
- package/compiler/codegen.js +437 -42
- package/compiler/generated_builtins.js +2295 -142
- package/compiler/pgo.js +9 -1
- package/compiler/precompile.js +3 -1
- 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 +139 -73
- 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';
|
@@ -72,6 +72,9 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
|
|
72
72
|
case 'ExpressionStatement':
|
73
73
|
return generateExp(scope, decl);
|
74
74
|
|
75
|
+
case 'SequenceExpression':
|
76
|
+
return generateSequence(scope, decl);
|
77
|
+
|
75
78
|
case 'CallExpression':
|
76
79
|
return generateCall(scope, decl, global, name, valueUnused);
|
77
80
|
|
@@ -616,11 +619,14 @@ const compareStrings = (scope, left, right, bytestrings = false) => {
|
|
616
619
|
};
|
617
620
|
|
618
621
|
const truthy = (scope, wasm, type, intIn = false, intOut = false, forceTruthyMode = undefined) => {
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
622
|
+
if (isIntToFloatOp(wasm[wasm.length - 1])) return [
|
623
|
+
...wasm,
|
624
|
+
...(!intIn && intOut ? [ Opcodes.i32_to_u ] : [])
|
625
|
+
];
|
626
|
+
if (isIntOp(wasm[wasm.length - 1])) return [
|
627
|
+
...wasm,
|
628
|
+
...(intOut ? [] : [ Opcodes.i32_from ]),
|
629
|
+
];
|
624
630
|
|
625
631
|
// todo/perf: use knownType and custom bytecode here instead of typeSwitch
|
626
632
|
|
@@ -1020,6 +1026,7 @@ const asmFuncToAsm = (func, scope) => {
|
|
1020
1026
|
idx = funcIndex[n];
|
1021
1027
|
}
|
1022
1028
|
|
1029
|
+
if (idx == null) throw new Error(`builtin('${n}') failed to find a func (inside ${scope.name})`);
|
1023
1030
|
return idx;
|
1024
1031
|
}
|
1025
1032
|
});
|
@@ -1058,7 +1065,10 @@ const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes
|
|
1058
1065
|
funcs.push(func);
|
1059
1066
|
funcIndex[name] = func.index;
|
1060
1067
|
|
1061
|
-
if (typeof wasm === 'function')
|
1068
|
+
if (typeof wasm === 'function') {
|
1069
|
+
if (globalThis.precompile) wasm = [];
|
1070
|
+
else wasm = asmFuncToAsm(wasm, func);
|
1071
|
+
}
|
1062
1072
|
|
1063
1073
|
let baseGlobalIdx, i = 0;
|
1064
1074
|
for (const type of globalTypes) {
|
@@ -1342,7 +1352,7 @@ const getNodeType = (scope, node) => {
|
|
1342
1352
|
const objectKnownType = knownType(scope, getNodeType(scope, node.object));
|
1343
1353
|
if (objectKnownType != null) {
|
1344
1354
|
if (name === 'length') {
|
1345
|
-
if (
|
1355
|
+
if (typeHasFlag(objectKnownType, TYPE_FLAGS.length)) return TYPES.number;
|
1346
1356
|
else return TYPES.undefined;
|
1347
1357
|
}
|
1348
1358
|
|
@@ -1414,9 +1424,9 @@ const countLeftover = wasm => {
|
|
1414
1424
|
|
1415
1425
|
if (depth === 0)
|
1416
1426
|
if ([Opcodes.throw, Opcodes.drop, Opcodes.local_set, Opcodes.global_set].includes(inst[0])) count--;
|
1417
|
-
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)) {}
|
1427
|
+
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)) {}
|
1418
1428
|
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++;
|
1419
|
-
else if ([Opcodes.i32_store, Opcodes.i64_store, Opcodes.f64_store, Opcodes.i32_store16, Opcodes.i32_store8].includes(inst[0])) count -= 2;
|
1429
|
+
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;
|
1420
1430
|
else if (inst[0] === Opcodes.memory_copy[0] && (inst[1] === Opcodes.memory_copy[1] || inst[1] === Opcodes.memory_init[1])) count -= 3;
|
1421
1431
|
else if (inst[0] === Opcodes.return) count = 0;
|
1422
1432
|
else if (inst[0] === Opcodes.call) {
|
@@ -1454,6 +1464,18 @@ const generateExp = (scope, decl) => {
|
|
1454
1464
|
return out;
|
1455
1465
|
};
|
1456
1466
|
|
1467
|
+
const generateSequence = (scope, decl) => {
|
1468
|
+
let out = [];
|
1469
|
+
|
1470
|
+
const exprs = decl.expressions;
|
1471
|
+
for (let i = 0; i < exprs.length; i++) {
|
1472
|
+
if (i > 0) disposeLeftover(out);
|
1473
|
+
out.push(...generate(scope, exprs[i]));
|
1474
|
+
}
|
1475
|
+
|
1476
|
+
return out;
|
1477
|
+
};
|
1478
|
+
|
1457
1479
|
const CTArrayUtil = {
|
1458
1480
|
getLengthI32: pointer => [
|
1459
1481
|
...number(0, Valtype.i32),
|
@@ -1572,9 +1594,9 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1572
1594
|
if (!name && decl.callee.type === 'MemberExpression') {
|
1573
1595
|
// megahack for /regex/.func()
|
1574
1596
|
const funcName = decl.callee.property.name;
|
1575
|
-
if (decl.callee.object.regex &&
|
1597
|
+
if (decl.callee.object.regex && ['test'].includes(funcName)) {
|
1576
1598
|
const regex = decl.callee.object.regex.pattern;
|
1577
|
-
const rhemynName = `regex_${funcName}_${regex}`;
|
1599
|
+
const rhemynName = `regex_${funcName}_${sanitize(regex)}`;
|
1578
1600
|
|
1579
1601
|
if (!funcIndex[rhemynName]) {
|
1580
1602
|
const func = Rhemyn[funcName](regex, currentFuncIndex++, rhemynName);
|
@@ -1595,7 +1617,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1595
1617
|
[ Opcodes.call, idx ],
|
1596
1618
|
Opcodes.i32_from_u,
|
1597
1619
|
|
1598
|
-
...setLastType(scope,
|
1620
|
+
...setLastType(scope, Rhemyn.types[funcName])
|
1599
1621
|
];
|
1600
1622
|
}
|
1601
1623
|
|
@@ -1604,24 +1626,44 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1604
1626
|
target = decl.callee.object;
|
1605
1627
|
}
|
1606
1628
|
|
1607
|
-
|
1608
|
-
|
1629
|
+
if (protoName) {
|
1630
|
+
if (['search'].includes(protoName)) {
|
1631
|
+
const regex = decl.arguments[0]?.regex?.pattern;
|
1632
|
+
if (!regex) return [
|
1633
|
+
// no/bad regex arg, return -1/0 for now
|
1634
|
+
...generate(scope, target),
|
1635
|
+
[ Opcodes.drop ],
|
1609
1636
|
|
1610
|
-
|
1611
|
-
|
1637
|
+
...number(Rhemyn.types[protoName] === TYPES.number ? -1 : 0),
|
1638
|
+
...setLastType(scope, Rhemyn.types[protoName])
|
1639
|
+
];
|
1612
1640
|
|
1613
|
-
|
1614
|
-
// generate(scope, decl.callee.object)
|
1641
|
+
const rhemynName = `regex_${protoName}_${sanitize(regex)}`;
|
1615
1642
|
|
1616
|
-
|
1617
|
-
|
1618
|
-
|
1619
|
-
// ];
|
1620
|
-
// }
|
1643
|
+
if (!funcIndex[rhemynName]) {
|
1644
|
+
const func = Rhemyn[protoName](regex, currentFuncIndex++, rhemynName);
|
1645
|
+
func.internal = true;
|
1621
1646
|
|
1622
|
-
|
1623
|
-
|
1647
|
+
funcIndex[func.name] = func.index;
|
1648
|
+
funcs.push(func);
|
1649
|
+
}
|
1650
|
+
|
1651
|
+
const idx = funcIndex[rhemynName];
|
1652
|
+
return [
|
1653
|
+
// make string arg
|
1654
|
+
...generate(scope, target),
|
1655
|
+
Opcodes.i32_to_u,
|
1656
|
+
...getNodeType(scope, target),
|
1624
1657
|
|
1658
|
+
// call regex func
|
1659
|
+
[ Opcodes.call, idx ],
|
1660
|
+
Opcodes.i32_from,
|
1661
|
+
|
1662
|
+
...setLastType(scope, Rhemyn.types[protoName])
|
1663
|
+
];
|
1664
|
+
}
|
1665
|
+
|
1666
|
+
const protoBC = {};
|
1625
1667
|
const builtinProtoCands = Object.keys(builtinFuncs).filter(x => x.startsWith('__') && x.endsWith('_prototype_' + protoName));
|
1626
1668
|
|
1627
1669
|
if (!decl._protoInternalCall && builtinProtoCands.length > 0) {
|
@@ -2035,6 +2077,16 @@ const DEFAULT_VALUE = {
|
|
2035
2077
|
name: 'undefined'
|
2036
2078
|
};
|
2037
2079
|
|
2080
|
+
const codeToSanitizedStr = code => {
|
2081
|
+
let out = '';
|
2082
|
+
while (code > 0) {
|
2083
|
+
out += String.fromCharCode(97 + code % 26);
|
2084
|
+
code -= 26;
|
2085
|
+
}
|
2086
|
+
return out;
|
2087
|
+
};
|
2088
|
+
const sanitize = str => str.replace(/[^0-9a-zA-Z_]/g, _ => codeToSanitizedStr(_.charCodeAt(0)));
|
2089
|
+
|
2038
2090
|
const unhackName = name => {
|
2039
2091
|
if (name.startsWith('__')) return name.slice(2).replaceAll('_', '.');
|
2040
2092
|
return name;
|
@@ -2042,7 +2094,7 @@ const unhackName = name => {
|
|
2042
2094
|
|
2043
2095
|
const knownType = (scope, type) => {
|
2044
2096
|
if (type.length === 1 && type[0][0] === Opcodes.i32_const) {
|
2045
|
-
return type[0]
|
2097
|
+
return read_signedLEB128(type[0].slice(1));
|
2046
2098
|
}
|
2047
2099
|
|
2048
2100
|
if (typedInput && type.length === 1 && type[0][0] === Opcodes.local_get) {
|
@@ -2329,11 +2381,6 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2329
2381
|
const { type, name } = decl.left;
|
2330
2382
|
const [ local, isGlobal ] = lookupName(scope, name);
|
2331
2383
|
|
2332
|
-
if (type === 'ObjectPattern') {
|
2333
|
-
// hack: ignore object parts of `var a = {} = 2`
|
2334
|
-
return generate(scope, decl.right);
|
2335
|
-
}
|
2336
|
-
|
2337
2384
|
if (isFuncType(decl.right.type)) {
|
2338
2385
|
// hack for a = function () { ... }
|
2339
2386
|
decl.right.id = { name };
|
@@ -2406,10 +2453,160 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2406
2453
|
[ Opcodes.i32_load8_u, 0, ValtypeSize.i32 + ValtypeSize[valtype] ]
|
2407
2454
|
], getNodeType(scope, decl.right), false, name, true)),
|
2408
2455
|
[ Opcodes.local_tee, newValueTmp ],
|
2409
|
-
|
2410
2456
|
[ Opcodes.store, 0, ValtypeSize.i32 ]
|
2411
2457
|
],
|
2412
2458
|
|
2459
|
+
...wrapBC({
|
2460
|
+
[TYPES.uint8array]: [
|
2461
|
+
[ Opcodes.i32_add ],
|
2462
|
+
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2463
|
+
|
2464
|
+
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2465
|
+
[ Opcodes.local_get, pointerTmp ],
|
2466
|
+
[ Opcodes.i32_load8_u, 0, 4 ],
|
2467
|
+
Opcodes.i32_from_u
|
2468
|
+
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
2469
|
+
[ Opcodes.local_tee, newValueTmp ],
|
2470
|
+
|
2471
|
+
Opcodes.i32_to_u,
|
2472
|
+
[ Opcodes.i32_store8, 0, 4 ]
|
2473
|
+
],
|
2474
|
+
[TYPES.uint8clampedarray]: [
|
2475
|
+
[ Opcodes.i32_add ],
|
2476
|
+
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2477
|
+
|
2478
|
+
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2479
|
+
[ Opcodes.local_get, pointerTmp ],
|
2480
|
+
[ Opcodes.i32_load8_u, 0, 4 ],
|
2481
|
+
Opcodes.i32_from_u
|
2482
|
+
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
2483
|
+
[ Opcodes.local_tee, newValueTmp ],
|
2484
|
+
|
2485
|
+
...number(0),
|
2486
|
+
[ Opcodes.f64_max ],
|
2487
|
+
...number(255),
|
2488
|
+
[ Opcodes.f64_min ],
|
2489
|
+
Opcodes.i32_to_u,
|
2490
|
+
[ Opcodes.i32_store8, 0, 4 ]
|
2491
|
+
],
|
2492
|
+
[TYPES.int8array]: [
|
2493
|
+
[ Opcodes.i32_add ],
|
2494
|
+
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2495
|
+
|
2496
|
+
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2497
|
+
[ Opcodes.local_get, pointerTmp ],
|
2498
|
+
[ Opcodes.i32_load8_s, 0, 4 ],
|
2499
|
+
Opcodes.i32_from
|
2500
|
+
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
2501
|
+
[ Opcodes.local_tee, newValueTmp ],
|
2502
|
+
|
2503
|
+
Opcodes.i32_to,
|
2504
|
+
[ Opcodes.i32_store8, 0, 4 ]
|
2505
|
+
],
|
2506
|
+
[TYPES.uint16array]: [
|
2507
|
+
...number(2, Valtype.i32),
|
2508
|
+
[ Opcodes.i32_mul ],
|
2509
|
+
[ Opcodes.i32_add ],
|
2510
|
+
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2511
|
+
|
2512
|
+
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2513
|
+
[ Opcodes.local_get, pointerTmp ],
|
2514
|
+
[ Opcodes.i32_load16_u, 0, 4 ],
|
2515
|
+
Opcodes.i32_from_u
|
2516
|
+
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
2517
|
+
[ Opcodes.local_tee, newValueTmp ],
|
2518
|
+
|
2519
|
+
Opcodes.i32_to_u,
|
2520
|
+
[ Opcodes.i32_store16, 0, 4 ]
|
2521
|
+
],
|
2522
|
+
[TYPES.int16array]: [
|
2523
|
+
...number(2, Valtype.i32),
|
2524
|
+
[ Opcodes.i32_mul ],
|
2525
|
+
[ Opcodes.i32_add ],
|
2526
|
+
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2527
|
+
|
2528
|
+
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2529
|
+
[ Opcodes.local_get, pointerTmp ],
|
2530
|
+
[ Opcodes.i32_load16_s, 0, 4 ],
|
2531
|
+
Opcodes.i32_from
|
2532
|
+
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
2533
|
+
[ Opcodes.local_tee, newValueTmp ],
|
2534
|
+
|
2535
|
+
Opcodes.i32_to,
|
2536
|
+
[ Opcodes.i32_store16, 0, 4 ]
|
2537
|
+
],
|
2538
|
+
[TYPES.uint32array]: [
|
2539
|
+
...number(4, Valtype.i32),
|
2540
|
+
[ Opcodes.i32_mul ],
|
2541
|
+
[ Opcodes.i32_add ],
|
2542
|
+
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2543
|
+
|
2544
|
+
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2545
|
+
[ Opcodes.local_get, pointerTmp ],
|
2546
|
+
[ Opcodes.i32_load, 0, 4 ],
|
2547
|
+
Opcodes.i32_from_u
|
2548
|
+
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
2549
|
+
[ Opcodes.local_tee, newValueTmp ],
|
2550
|
+
|
2551
|
+
Opcodes.i32_to_u,
|
2552
|
+
[ Opcodes.i32_store, 0, 4 ]
|
2553
|
+
],
|
2554
|
+
[TYPES.int32array]: [
|
2555
|
+
...number(4, Valtype.i32),
|
2556
|
+
[ Opcodes.i32_mul ],
|
2557
|
+
[ Opcodes.i32_add ],
|
2558
|
+
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2559
|
+
|
2560
|
+
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2561
|
+
[ Opcodes.local_get, pointerTmp ],
|
2562
|
+
[ Opcodes.i32_load, 0, 4 ],
|
2563
|
+
Opcodes.i32_from
|
2564
|
+
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
2565
|
+
[ Opcodes.local_tee, newValueTmp ],
|
2566
|
+
|
2567
|
+
Opcodes.i32_to,
|
2568
|
+
[ Opcodes.i32_store, 0, 4 ]
|
2569
|
+
],
|
2570
|
+
[TYPES.float32array]: [
|
2571
|
+
...number(4, Valtype.i32),
|
2572
|
+
[ Opcodes.i32_mul ],
|
2573
|
+
[ Opcodes.i32_add ],
|
2574
|
+
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2575
|
+
|
2576
|
+
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2577
|
+
[ Opcodes.local_get, pointerTmp ],
|
2578
|
+
[ Opcodes.f32_load, 0, 4 ],
|
2579
|
+
[ Opcodes.f64_promote_f32 ]
|
2580
|
+
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
2581
|
+
[ Opcodes.local_tee, newValueTmp ],
|
2582
|
+
|
2583
|
+
[ Opcodes.f32_demote_f64 ],
|
2584
|
+
[ Opcodes.f32_store, 0, 4 ]
|
2585
|
+
],
|
2586
|
+
[TYPES.float64array]: [
|
2587
|
+
...number(8, Valtype.i32),
|
2588
|
+
[ Opcodes.i32_mul ],
|
2589
|
+
[ Opcodes.i32_add ],
|
2590
|
+
...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
|
2591
|
+
|
2592
|
+
...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
|
2593
|
+
[ Opcodes.local_get, pointerTmp ],
|
2594
|
+
[ Opcodes.f64_load, 0, 4 ]
|
2595
|
+
], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
|
2596
|
+
[ Opcodes.local_tee, newValueTmp ],
|
2597
|
+
|
2598
|
+
[ Opcodes.f64_store, 0, 4 ]
|
2599
|
+
],
|
2600
|
+
}, {
|
2601
|
+
prelude: [
|
2602
|
+
...generate(scope, decl.left.object),
|
2603
|
+
Opcodes.i32_to_u,
|
2604
|
+
...generate(scope, decl.left.property),
|
2605
|
+
Opcodes.i32_to_u,
|
2606
|
+
],
|
2607
|
+
postlude: setLastType(scope, TYPES.number)
|
2608
|
+
}),
|
2609
|
+
|
2413
2610
|
default: internalThrow(scope, 'TypeError', `Cannot assign member with non-array`)
|
2414
2611
|
}, Blocktype.void),
|
2415
2612
|
|
@@ -2793,7 +2990,9 @@ const generateForOf = (scope, decl) => {
|
|
2793
2990
|
// // todo: we should only do this for strings but we don't know at compile-time :(
|
2794
2991
|
// hack: this is naughty and will break things!
|
2795
2992
|
let newOut = number(0, Valtype.i32), newPointer = number(0, Valtype.i32);
|
2796
|
-
|
2993
|
+
|
2994
|
+
const known = knownType(scope, getNodeType(scope, decl.right));
|
2995
|
+
if ((known === TYPES.string || known === TYPES.bytestring) || (pages.hasAnyString && known == null)) {
|
2797
2996
|
// todo: we use i16 even for bytestrings which should not make a bad thing happen, just be confusing for debugging?
|
2798
2997
|
0, [ newOut, newPointer ] = makeArray(scope, {
|
2799
2998
|
rawElements: new Array(0)
|
@@ -2841,6 +3040,7 @@ const generateForOf = (scope, decl) => {
|
|
2841
3040
|
[ Opcodes.end ],
|
2842
3041
|
[ Opcodes.end ]
|
2843
3042
|
],
|
3043
|
+
|
2844
3044
|
[TYPES.string]: [
|
2845
3045
|
...setType(scope, leftName, TYPES.string),
|
2846
3046
|
|
@@ -2949,6 +3149,7 @@ const generateForOf = (scope, decl) => {
|
|
2949
3149
|
[ Opcodes.end ],
|
2950
3150
|
[ Opcodes.end ]
|
2951
3151
|
],
|
3152
|
+
|
2952
3153
|
[TYPES.set]: [
|
2953
3154
|
[ Opcodes.loop, Blocktype.void ],
|
2954
3155
|
|
@@ -2987,6 +3188,106 @@ const generateForOf = (scope, decl) => {
|
|
2987
3188
|
[ Opcodes.end ],
|
2988
3189
|
[ Opcodes.end ]
|
2989
3190
|
],
|
3191
|
+
|
3192
|
+
...wrapBC({
|
3193
|
+
[TYPES.uint8array]: [
|
3194
|
+
[ Opcodes.i32_add ],
|
3195
|
+
|
3196
|
+
[ Opcodes.i32_load8_u, 0, 4 ],
|
3197
|
+
Opcodes.i32_from_u
|
3198
|
+
],
|
3199
|
+
[TYPES.uint8clampedarray]: [
|
3200
|
+
[ Opcodes.i32_add ],
|
3201
|
+
|
3202
|
+
[ Opcodes.i32_load8_u, 0, 4 ],
|
3203
|
+
Opcodes.i32_from_u
|
3204
|
+
],
|
3205
|
+
[TYPES.int8array]: [
|
3206
|
+
[ Opcodes.i32_add ],
|
3207
|
+
|
3208
|
+
[ Opcodes.i32_load8_s, 0, 4 ],
|
3209
|
+
Opcodes.i32_from
|
3210
|
+
],
|
3211
|
+
[TYPES.uint16array]: [
|
3212
|
+
...number(2, Valtype.i32),
|
3213
|
+
[ Opcodes.i32_mul ],
|
3214
|
+
[ Opcodes.i32_add ],
|
3215
|
+
|
3216
|
+
[ Opcodes.i32_load16_u, 0, 4 ],
|
3217
|
+
Opcodes.i32_from_u
|
3218
|
+
],
|
3219
|
+
[TYPES.int16array]: [
|
3220
|
+
...number(2, Valtype.i32),
|
3221
|
+
[ Opcodes.i32_mul ],
|
3222
|
+
[ Opcodes.i32_add ],
|
3223
|
+
|
3224
|
+
[ Opcodes.i32_load16_s, 0, 4 ],
|
3225
|
+
Opcodes.i32_from
|
3226
|
+
],
|
3227
|
+
[TYPES.uint32array]: [
|
3228
|
+
...number(4, Valtype.i32),
|
3229
|
+
[ Opcodes.i32_mul ],
|
3230
|
+
[ Opcodes.i32_add ],
|
3231
|
+
|
3232
|
+
[ Opcodes.i32_load, 0, 4 ],
|
3233
|
+
Opcodes.i32_from_u
|
3234
|
+
],
|
3235
|
+
[TYPES.int32array]: [
|
3236
|
+
...number(4, Valtype.i32),
|
3237
|
+
[ Opcodes.i32_mul ],
|
3238
|
+
[ Opcodes.i32_add ],
|
3239
|
+
|
3240
|
+
[ Opcodes.i32_load, 0, 4 ],
|
3241
|
+
Opcodes.i32_from
|
3242
|
+
],
|
3243
|
+
[TYPES.float32array]: [
|
3244
|
+
...number(4, Valtype.i32),
|
3245
|
+
[ Opcodes.i32_mul ],
|
3246
|
+
[ Opcodes.i32_add ],
|
3247
|
+
|
3248
|
+
[ Opcodes.f32_load, 0, 4 ],
|
3249
|
+
[ Opcodes.f64_promote_f32 ]
|
3250
|
+
],
|
3251
|
+
[TYPES.float64array]: [
|
3252
|
+
...number(8, Valtype.i32),
|
3253
|
+
[ Opcodes.i32_mul ],
|
3254
|
+
[ Opcodes.i32_add ],
|
3255
|
+
|
3256
|
+
[ Opcodes.f64_load, 0, 4 ]
|
3257
|
+
],
|
3258
|
+
}, {
|
3259
|
+
prelude: [
|
3260
|
+
...setType(scope, leftName, TYPES.number),
|
3261
|
+
|
3262
|
+
[ Opcodes.loop, Blocktype.void ],
|
3263
|
+
|
3264
|
+
[ Opcodes.local_get, pointer ],
|
3265
|
+
[ Opcodes.local_get, counter ]
|
3266
|
+
],
|
3267
|
+
postlude: [
|
3268
|
+
[ isGlobal ? Opcodes.global_set : Opcodes.local_set, local.idx ],
|
3269
|
+
|
3270
|
+
[ Opcodes.block, Blocktype.void ],
|
3271
|
+
[ Opcodes.block, Blocktype.void ],
|
3272
|
+
...generate(scope, decl.body),
|
3273
|
+
[ Opcodes.end ],
|
3274
|
+
|
3275
|
+
// increment counter by 1
|
3276
|
+
[ Opcodes.local_get, counter ],
|
3277
|
+
...number(1, Valtype.i32),
|
3278
|
+
[ Opcodes.i32_add ],
|
3279
|
+
[ Opcodes.local_tee, counter ],
|
3280
|
+
|
3281
|
+
// loop if counter != length
|
3282
|
+
[ Opcodes.local_get, length ],
|
3283
|
+
[ Opcodes.i32_ne ],
|
3284
|
+
[ Opcodes.br_if, 1 ],
|
3285
|
+
|
3286
|
+
[ Opcodes.end ],
|
3287
|
+
[ Opcodes.end ]
|
3288
|
+
]
|
3289
|
+
}),
|
3290
|
+
|
2990
3291
|
default: internalThrow(scope, 'TypeError', `Tried for..of on non-iterable type`)
|
2991
3292
|
}, Blocktype.void));
|
2992
3293
|
|
@@ -3075,13 +3376,14 @@ const generateThrow = (scope, decl) => {
|
|
3075
3376
|
idx: tags.length
|
3076
3377
|
});
|
3077
3378
|
|
3078
|
-
let exceptId = exceptions.
|
3379
|
+
let exceptId = exceptions.findIndex(x => x.constructor === constructor && x.message === message);
|
3380
|
+
if (exceptId === -1) exceptId = exceptions.push({ constructor, message }) - 1;
|
3079
3381
|
|
3080
3382
|
scope.exceptions ??= [];
|
3081
3383
|
scope.exceptions.push(exceptId);
|
3082
3384
|
|
3083
3385
|
return [
|
3084
|
-
|
3386
|
+
...number(exceptId, Valtype.i32),
|
3085
3387
|
[ Opcodes.throw, tags[0].idx ]
|
3086
3388
|
];
|
3087
3389
|
}
|
@@ -3148,7 +3450,7 @@ const generateThrow = (scope, decl) => {
|
|
3148
3450
|
scope.exceptions.push(exceptId);
|
3149
3451
|
|
3150
3452
|
return [
|
3151
|
-
|
3453
|
+
...number(exceptId, Valtype.i32),
|
3152
3454
|
...generate(scope, message),
|
3153
3455
|
...getNodeType(scope, message),
|
3154
3456
|
[ Opcodes.throw, tags[0].idx ]
|
@@ -3506,6 +3808,19 @@ const withType = (scope, wasm, type) => [
|
|
3506
3808
|
...setLastType(scope, type)
|
3507
3809
|
];
|
3508
3810
|
|
3811
|
+
const wrapBC = (bc, { prelude = [], postlude = [] } = {}) => {
|
3812
|
+
const out = {};
|
3813
|
+
for (const x in bc) {
|
3814
|
+
out[x] = [
|
3815
|
+
...prelude,
|
3816
|
+
...bc[x],
|
3817
|
+
...postlude
|
3818
|
+
];
|
3819
|
+
}
|
3820
|
+
|
3821
|
+
return out;
|
3822
|
+
};
|
3823
|
+
|
3509
3824
|
const generateMember = (scope, decl, _global, _name) => {
|
3510
3825
|
const name = decl.object.name;
|
3511
3826
|
|
@@ -3559,7 +3874,7 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3559
3874
|
const type = getNodeType(scope, decl.object);
|
3560
3875
|
const known = knownType(scope, type);
|
3561
3876
|
if (known != null) {
|
3562
|
-
if (
|
3877
|
+
if (typeHasFlag(known, TYPE_FLAGS.length)) return [
|
3563
3878
|
...generate(scope, decl.object),
|
3564
3879
|
Opcodes.i32_to_u,
|
3565
3880
|
|
@@ -3571,7 +3886,9 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3571
3886
|
}
|
3572
3887
|
|
3573
3888
|
return [
|
3574
|
-
...
|
3889
|
+
...getNodeType(scope, decl.object),
|
3890
|
+
...number(TYPE_FLAGS.length, Valtype.i32),
|
3891
|
+
[ Opcodes.i32_and ],
|
3575
3892
|
[ Opcodes.if, valtypeBinary ],
|
3576
3893
|
...generate(scope, decl.object),
|
3577
3894
|
Opcodes.i32_to_u,
|
@@ -3588,7 +3905,7 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3588
3905
|
}
|
3589
3906
|
|
3590
3907
|
// todo: generate this array procedurally during builtinFuncs creation
|
3591
|
-
if (['size', 'description'].includes(decl.property.name)) {
|
3908
|
+
if (['size', 'description', 'byteLength'].includes(decl.property.name)) {
|
3592
3909
|
const bc = {};
|
3593
3910
|
const cands = Object.keys(builtinFuncs).filter(x => x.startsWith('__') && x.endsWith('_prototype_' + decl.property.name + '$get'));
|
3594
3911
|
|
@@ -3620,7 +3937,9 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3620
3937
|
// // todo: we should only do this for strings but we don't know at compile-time :(
|
3621
3938
|
// hack: this is naughty and will break things!
|
3622
3939
|
let newOut = number(0, Valtype.i32), newPointer = number(0, Valtype.i32);
|
3623
|
-
|
3940
|
+
|
3941
|
+
const known = knownType(scope, getNodeType(scope, decl.object));
|
3942
|
+
if ((known === TYPES.string || known === TYPES.bytestring) || (pages.hasAnyString && known == null)) {
|
3624
3943
|
// todo: we use i16 even for bytestrings which should not make a bad thing happen, just be confusing for debugging?
|
3625
3944
|
0, [ newOut, newPointer ] = makeArray(scope, {
|
3626
3945
|
rawElements: new Array(0)
|
@@ -3694,6 +4013,82 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
3694
4013
|
...setLastType(scope, TYPES.bytestring)
|
3695
4014
|
],
|
3696
4015
|
|
4016
|
+
...wrapBC({
|
4017
|
+
[TYPES.uint8array]: [
|
4018
|
+
[ Opcodes.i32_add ],
|
4019
|
+
|
4020
|
+
[ Opcodes.i32_load8_u, 0, 4 ],
|
4021
|
+
Opcodes.i32_from_u
|
4022
|
+
],
|
4023
|
+
[TYPES.uint8clampedarray]: [
|
4024
|
+
[ Opcodes.i32_add ],
|
4025
|
+
|
4026
|
+
[ Opcodes.i32_load8_u, 0, 4 ],
|
4027
|
+
Opcodes.i32_from_u
|
4028
|
+
],
|
4029
|
+
[TYPES.int8array]: [
|
4030
|
+
[ Opcodes.i32_add ],
|
4031
|
+
|
4032
|
+
[ Opcodes.i32_load8_s, 0, 4 ],
|
4033
|
+
Opcodes.i32_from
|
4034
|
+
],
|
4035
|
+
[TYPES.uint16array]: [
|
4036
|
+
...number(2, Valtype.i32),
|
4037
|
+
[ Opcodes.i32_mul ],
|
4038
|
+
[ Opcodes.i32_add ],
|
4039
|
+
|
4040
|
+
[ Opcodes.i32_load16_u, 0, 4 ],
|
4041
|
+
Opcodes.i32_from_u
|
4042
|
+
],
|
4043
|
+
[TYPES.int16array]: [
|
4044
|
+
...number(2, Valtype.i32),
|
4045
|
+
[ Opcodes.i32_mul ],
|
4046
|
+
[ Opcodes.i32_add ],
|
4047
|
+
|
4048
|
+
[ Opcodes.i32_load16_s, 0, 4 ],
|
4049
|
+
Opcodes.i32_from
|
4050
|
+
],
|
4051
|
+
[TYPES.uint32array]: [
|
4052
|
+
...number(4, Valtype.i32),
|
4053
|
+
[ Opcodes.i32_mul ],
|
4054
|
+
[ Opcodes.i32_add ],
|
4055
|
+
|
4056
|
+
[ Opcodes.i32_load, 0, 4 ],
|
4057
|
+
Opcodes.i32_from_u
|
4058
|
+
],
|
4059
|
+
[TYPES.int32array]: [
|
4060
|
+
...number(4, Valtype.i32),
|
4061
|
+
[ Opcodes.i32_mul ],
|
4062
|
+
[ Opcodes.i32_add ],
|
4063
|
+
|
4064
|
+
[ Opcodes.i32_load, 0, 4 ],
|
4065
|
+
Opcodes.i32_from
|
4066
|
+
],
|
4067
|
+
[TYPES.float32array]: [
|
4068
|
+
...number(4, Valtype.i32),
|
4069
|
+
[ Opcodes.i32_mul ],
|
4070
|
+
[ Opcodes.i32_add ],
|
4071
|
+
|
4072
|
+
[ Opcodes.f32_load, 0, 4 ],
|
4073
|
+
[ Opcodes.f64_promote_f32 ]
|
4074
|
+
],
|
4075
|
+
[TYPES.float64array]: [
|
4076
|
+
...number(8, Valtype.i32),
|
4077
|
+
[ Opcodes.i32_mul ],
|
4078
|
+
[ Opcodes.i32_add ],
|
4079
|
+
|
4080
|
+
[ Opcodes.f64_load, 0, 4 ]
|
4081
|
+
],
|
4082
|
+
}, {
|
4083
|
+
prelude: [
|
4084
|
+
...object,
|
4085
|
+
Opcodes.i32_to_u,
|
4086
|
+
...property,
|
4087
|
+
Opcodes.i32_to_u
|
4088
|
+
],
|
4089
|
+
postlude: setLastType(scope, TYPES.number)
|
4090
|
+
}),
|
4091
|
+
|
3697
4092
|
default: internalThrow(scope, 'TypeError', 'Member expression is not supported for non-string non-array yet', true)
|
3698
4093
|
});
|
3699
4094
|
};
|
@@ -3716,7 +4111,7 @@ const objectHack = node => {
|
|
3716
4111
|
if (!objectName) objectName = objectHack(node.object)?.name?.slice?.(2);
|
3717
4112
|
|
3718
4113
|
// if .name or .length, give up (hack within a hack!)
|
3719
|
-
if (['name', 'length', 'size', 'description'].includes(node.property.name)) {
|
4114
|
+
if (['name', 'length', 'size', 'description', 'byteLength'].includes(node.property.name)) {
|
3720
4115
|
node.object = objectHack(node.object);
|
3721
4116
|
return;
|
3722
4117
|
}
|