porffor 0.2.0-eeb45f8 → 0.2.0-f2bbe1f
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 +1 -1
- package/compiler/codeGen.js +33 -144
- package/compiler/opt.js +0 -1
- package/compiler/prototype.js +16 -171
- package/compiler/wasmSpec.js +0 -3
- package/compiler/wrap.js +1 -12
- package/package.json +1 -1
package/README.md
CHANGED
@@ -215,7 +215,7 @@ Basically none right now (other than giving people headaches). Potential ideas:
|
|
215
215
|
- More in future probably?
|
216
216
|
|
217
217
|
## Usage
|
218
|
-
Basically nothing will work :). See files in `test`
|
218
|
+
Basically nothing will work :). See files in `test` for examples.
|
219
219
|
|
220
220
|
1. Clone repo
|
221
221
|
2. `npm install`
|
package/compiler/codeGen.js
CHANGED
@@ -55,7 +55,7 @@ const todo = msg => {
|
|
55
55
|
};
|
56
56
|
|
57
57
|
const isFuncType = type => type === 'FunctionDeclaration' || type === 'FunctionExpression' || type === 'ArrowFunctionExpression';
|
58
|
-
const generate = (scope, decl, global = false, name = undefined
|
58
|
+
const generate = (scope, decl, global = false, name = undefined) => {
|
59
59
|
switch (decl.type) {
|
60
60
|
case 'BinaryExpression':
|
61
61
|
return generateBinaryExp(scope, decl, global, name);
|
@@ -86,7 +86,7 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
|
|
86
86
|
return generateExp(scope, decl);
|
87
87
|
|
88
88
|
case 'CallExpression':
|
89
|
-
return generateCall(scope, decl, global, name
|
89
|
+
return generateCall(scope, decl, global, name);
|
90
90
|
|
91
91
|
case 'NewExpression':
|
92
92
|
return generateNew(scope, decl, global, name);
|
@@ -685,15 +685,6 @@ const truthy = (scope, wasm, type, intIn = false, intOut = false) => {
|
|
685
685
|
[ Opcodes.i32_eqz ], */
|
686
686
|
...(intOut ? [] : [ Opcodes.i32_from_u ])
|
687
687
|
],
|
688
|
-
[TYPES._bytestring]: [ // duplicate of string
|
689
|
-
[ Opcodes.local_get, tmp ],
|
690
|
-
...(intIn ? [] : [ Opcodes.i32_to_u ]),
|
691
|
-
|
692
|
-
// get length
|
693
|
-
[ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
|
694
|
-
|
695
|
-
...(intOut ? [] : [ Opcodes.i32_from_u ])
|
696
|
-
],
|
697
688
|
default: def
|
698
689
|
}, intOut ? Valtype.i32 : valtypeBinary)
|
699
690
|
];
|
@@ -721,17 +712,6 @@ const falsy = (scope, wasm, type, intIn = false, intOut = false) => {
|
|
721
712
|
[ Opcodes.i32_eqz ],
|
722
713
|
...(intOut ? [] : [ Opcodes.i32_from_u ])
|
723
714
|
],
|
724
|
-
[TYPES._bytestring]: [ // duplicate of string
|
725
|
-
[ Opcodes.local_get, tmp ],
|
726
|
-
...(intIn ? [] : [ Opcodes.i32_to_u ]),
|
727
|
-
|
728
|
-
// get length
|
729
|
-
[ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
|
730
|
-
|
731
|
-
// if length == 0
|
732
|
-
[ Opcodes.i32_eqz ],
|
733
|
-
...(intOut ? [] : [ Opcodes.i32_from_u ])
|
734
|
-
],
|
735
715
|
default: [
|
736
716
|
// if value == 0
|
737
717
|
[ Opcodes.local_get, tmp ],
|
@@ -1064,8 +1044,7 @@ const TYPES = {
|
|
1064
1044
|
|
1065
1045
|
// these are not "typeof" types but tracked internally
|
1066
1046
|
_array: 0x10,
|
1067
|
-
_regexp: 0x11
|
1068
|
-
_bytestring: 0x12
|
1047
|
+
_regexp: 0x11
|
1069
1048
|
};
|
1070
1049
|
|
1071
1050
|
const TYPE_NAMES = {
|
@@ -1079,8 +1058,7 @@ const TYPE_NAMES = {
|
|
1079
1058
|
[TYPES.bigint]: 'BigInt',
|
1080
1059
|
|
1081
1060
|
[TYPES._array]: 'Array',
|
1082
|
-
[TYPES._regexp]: 'RegExp'
|
1083
|
-
[TYPES._bytestring]: 'ByteString'
|
1061
|
+
[TYPES._regexp]: 'RegExp'
|
1084
1062
|
};
|
1085
1063
|
|
1086
1064
|
const getType = (scope, _name) => {
|
@@ -1133,8 +1111,6 @@ const getNodeType = (scope, node) => {
|
|
1133
1111
|
if (node.type === 'Literal') {
|
1134
1112
|
if (node.regex) return TYPES._regexp;
|
1135
1113
|
|
1136
|
-
if (typeof node.value === 'string' && byteStringable(node.value)) return TYPES._bytestring;
|
1137
|
-
|
1138
1114
|
return TYPES[typeof node.value];
|
1139
1115
|
}
|
1140
1116
|
|
@@ -1148,15 +1124,6 @@ const getNodeType = (scope, node) => {
|
|
1148
1124
|
|
1149
1125
|
if (node.type === 'CallExpression' || node.type === 'NewExpression') {
|
1150
1126
|
const name = node.callee.name;
|
1151
|
-
if (!name) {
|
1152
|
-
// iife
|
1153
|
-
if (scope.locals['#last_type']) return [ getLastType(scope) ];
|
1154
|
-
|
1155
|
-
// presume
|
1156
|
-
// todo: warn here?
|
1157
|
-
return TYPES.number;
|
1158
|
-
}
|
1159
|
-
|
1160
1127
|
const func = funcs.find(x => x.name === name);
|
1161
1128
|
|
1162
1129
|
if (func) {
|
@@ -1251,7 +1218,7 @@ const getNodeType = (scope, node) => {
|
|
1251
1218
|
if (node.operator === '!') return TYPES.boolean;
|
1252
1219
|
if (node.operator === 'void') return TYPES.undefined;
|
1253
1220
|
if (node.operator === 'delete') return TYPES.boolean;
|
1254
|
-
if (node.operator === 'typeof') return
|
1221
|
+
if (node.operator === 'typeof') return TYPES.string;
|
1255
1222
|
|
1256
1223
|
return TYPES.number;
|
1257
1224
|
}
|
@@ -1260,9 +1227,7 @@ const getNodeType = (scope, node) => {
|
|
1260
1227
|
// hack: if something.length, number type
|
1261
1228
|
if (node.property.name === 'length') return TYPES.number;
|
1262
1229
|
|
1263
|
-
|
1264
|
-
|
1265
|
-
// presume
|
1230
|
+
// we cannot guess
|
1266
1231
|
return TYPES.number;
|
1267
1232
|
}
|
1268
1233
|
|
@@ -1334,9 +1299,9 @@ const countLeftover = wasm => {
|
|
1334
1299
|
|
1335
1300
|
if (depth === 0)
|
1336
1301
|
if ([Opcodes.throw,Opcodes.drop, Opcodes.local_set, Opcodes.global_set].includes(inst[0])) count--;
|
1337
|
-
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.
|
1302
|
+
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.memory_grow].includes(inst[0]) && (inst[0] !== 0xfc || inst[1] < 0x0a)) {}
|
1338
1303
|
else if ([Opcodes.local_get, Opcodes.global_get, Opcodes.f64_const, Opcodes.i32_const, Opcodes.i64_const, Opcodes.v128_const].includes(inst[0])) count++;
|
1339
|
-
else if ([Opcodes.i32_store, Opcodes.i64_store, Opcodes.f64_store, Opcodes.i32_store16
|
1304
|
+
else if ([Opcodes.i32_store, Opcodes.i64_store, Opcodes.f64_store, Opcodes.i32_store16].includes(inst[0])) count -= 2;
|
1340
1305
|
else if (Opcodes.memory_copy[0] === inst[0] && Opcodes.memory_copy[1] === inst[1]) count -= 3;
|
1341
1306
|
else if (inst[0] === Opcodes.return) count = 0;
|
1342
1307
|
else if (inst[0] === Opcodes.call) {
|
@@ -1362,7 +1327,7 @@ const disposeLeftover = wasm => {
|
|
1362
1327
|
const generateExp = (scope, decl) => {
|
1363
1328
|
const expression = decl.expression;
|
1364
1329
|
|
1365
|
-
const out = generate(scope, expression
|
1330
|
+
const out = generate(scope, expression);
|
1366
1331
|
disposeLeftover(out);
|
1367
1332
|
|
1368
1333
|
return out;
|
@@ -1420,7 +1385,7 @@ const RTArrayUtil = {
|
|
1420
1385
|
]
|
1421
1386
|
};
|
1422
1387
|
|
1423
|
-
const generateCall = (scope, decl, _global, _name
|
1388
|
+
const generateCall = (scope, decl, _global, _name) => {
|
1424
1389
|
/* const callee = decl.callee;
|
1425
1390
|
const args = decl.arguments;
|
1426
1391
|
|
@@ -1539,18 +1504,10 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1539
1504
|
// use local for cached i32 length as commonly used
|
1540
1505
|
const lengthLocal = localTmp(scope, '__proto_length_cache', Valtype.i32);
|
1541
1506
|
const pointerLocal = localTmp(scope, '__proto_pointer_cache', Valtype.i32);
|
1507
|
+
const getPointer = [ [ Opcodes.local_get, pointerLocal ] ];
|
1542
1508
|
|
1543
1509
|
// TODO: long-term, prototypes should be their individual separate funcs
|
1544
1510
|
|
1545
|
-
const rawPointer = [
|
1546
|
-
...generate(scope, target),
|
1547
|
-
Opcodes.i32_to_u
|
1548
|
-
];
|
1549
|
-
|
1550
|
-
const usePointerCache = !Object.values(protoCands).every(x => x.noPointerCache === true);
|
1551
|
-
const getPointer = usePointerCache ? [ [ Opcodes.local_get, pointerLocal ] ] : rawPointer;
|
1552
|
-
|
1553
|
-
let allOptUnused = true;
|
1554
1511
|
let lengthI32CacheUsed = false;
|
1555
1512
|
const protoBC = {};
|
1556
1513
|
for (const x in protoCands) {
|
@@ -1570,7 +1527,6 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1570
1527
|
const protoLocal = protoFunc.local ? localTmp(scope, `__${protoName}_tmp`, protoFunc.local) : -1;
|
1571
1528
|
const protoLocal2 = protoFunc.local2 ? localTmp(scope, `__${protoName}_tmp2`, protoFunc.local2) : -1;
|
1572
1529
|
|
1573
|
-
let optUnused = false;
|
1574
1530
|
const protoOut = protoFunc(getPointer, {
|
1575
1531
|
getCachedI32: () => {
|
1576
1532
|
lengthI32CacheUsed = true;
|
@@ -1585,15 +1541,10 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1585
1541
|
return makeArray(scope, {
|
1586
1542
|
rawElements: new Array(length)
|
1587
1543
|
}, _global, _name, true, itemType);
|
1588
|
-
}, () => {
|
1589
|
-
optUnused = true;
|
1590
|
-
return unusedValue;
|
1591
1544
|
});
|
1592
1545
|
|
1593
|
-
if (!optUnused) allOptUnused = false;
|
1594
|
-
|
1595
1546
|
protoBC[x] = [
|
1596
|
-
[ Opcodes.block,
|
1547
|
+
[ Opcodes.block, valtypeBinary ],
|
1597
1548
|
...protoOut,
|
1598
1549
|
|
1599
1550
|
...number(protoFunc.returnType ?? TYPES.number, Valtype.i32),
|
@@ -1602,13 +1553,11 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1602
1553
|
];
|
1603
1554
|
}
|
1604
1555
|
|
1605
|
-
// todo: if some cands use optUnused and some don't, we will probably crash
|
1606
|
-
|
1607
1556
|
return [
|
1608
|
-
...(
|
1609
|
-
|
1610
|
-
|
1611
|
-
|
1557
|
+
...generate(scope, target),
|
1558
|
+
|
1559
|
+
Opcodes.i32_to_u,
|
1560
|
+
[ Opcodes.local_set, pointerLocal ],
|
1612
1561
|
|
1613
1562
|
...(!lengthI32CacheUsed ? [] : [
|
1614
1563
|
...RTArrayUtil.getLengthI32(getPointer),
|
@@ -1620,7 +1569,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1620
1569
|
|
1621
1570
|
// TODO: error better
|
1622
1571
|
default: internalThrow(scope, 'TypeError', `'${protoName}' proto func tried to be called on a type without an impl`)
|
1623
|
-
},
|
1572
|
+
}, valtypeBinary),
|
1624
1573
|
];
|
1625
1574
|
}
|
1626
1575
|
}
|
@@ -1828,8 +1777,6 @@ const brTable = (input, bc, returns) => {
|
|
1828
1777
|
};
|
1829
1778
|
|
1830
1779
|
const typeSwitch = (scope, type, bc, returns = valtypeBinary) => {
|
1831
|
-
if (!process.argv.includes('-bytestring')) delete bc[TYPES._bytestring];
|
1832
|
-
|
1833
1780
|
const known = knownType(scope, type);
|
1834
1781
|
if (known != null) {
|
1835
1782
|
return bc[known] ?? bc.default;
|
@@ -2220,8 +2167,6 @@ const generateUnary = (scope, decl) => {
|
|
2220
2167
|
[TYPES.undefined]: makeString(scope, 'undefined', false, '#typeof_result'),
|
2221
2168
|
[TYPES.function]: makeString(scope, 'function', false, '#typeof_result'),
|
2222
2169
|
|
2223
|
-
[TYPES._bytestring]: makeString(scope, 'string', false, '#typeof_result'),
|
2224
|
-
|
2225
2170
|
// object and internal types
|
2226
2171
|
default: makeString(scope, 'object', false, '#typeof_result'),
|
2227
2172
|
});
|
@@ -2403,14 +2348,13 @@ const generateForOf = (scope, decl) => {
|
|
2403
2348
|
// // todo: we should only do this for strings but we don't know at compile-time :(
|
2404
2349
|
// hack: this is naughty and will break things!
|
2405
2350
|
let newOut = number(0, Valtype.f64), newPointer = -1;
|
2406
|
-
if (pages.
|
2351
|
+
if (pages.hasString) {
|
2407
2352
|
0, [ newOut, newPointer ] = makeArray(scope, {
|
2408
2353
|
rawElements: new Array(1)
|
2409
2354
|
}, isGlobal, leftName, true, 'i16');
|
2410
2355
|
}
|
2411
2356
|
|
2412
2357
|
// set type for local
|
2413
|
-
// todo: optimize away counter and use end pointer
|
2414
2358
|
out.push(...typeSwitch(scope, getNodeType(scope, decl.right), {
|
2415
2359
|
[TYPES._array]: [
|
2416
2360
|
...setType(scope, leftName, TYPES.number),
|
@@ -2596,8 +2540,6 @@ const allocPage = (reason, type) => {
|
|
2596
2540
|
|
2597
2541
|
if (reason.startsWith('array:')) pages.hasArray = true;
|
2598
2542
|
if (reason.startsWith('string:')) pages.hasString = true;
|
2599
|
-
if (reason.startsWith('bytestring:')) pages.hasByteString = true;
|
2600
|
-
if (reason.includes('string:')) pages.hasAnyString = true;
|
2601
2543
|
|
2602
2544
|
const ind = pages.size;
|
2603
2545
|
pages.set(reason, { ind, type });
|
@@ -2631,8 +2573,7 @@ const StoreOps = {
|
|
2631
2573
|
f64: Opcodes.f64_store,
|
2632
2574
|
|
2633
2575
|
// expects i32 input!
|
2634
|
-
|
2635
|
-
i16: Opcodes.i32_store16,
|
2576
|
+
i16: Opcodes.i32_store16
|
2636
2577
|
};
|
2637
2578
|
|
2638
2579
|
let data = [];
|
@@ -2651,15 +2592,6 @@ const compileBytes = (val, itemType, signed = true) => {
|
|
2651
2592
|
}
|
2652
2593
|
};
|
2653
2594
|
|
2654
|
-
const getAllocType = itemType => {
|
2655
|
-
switch (itemType) {
|
2656
|
-
case 'i8': return 'bytestring';
|
2657
|
-
case 'i16': return 'string';
|
2658
|
-
|
2659
|
-
default: return 'array';
|
2660
|
-
}
|
2661
|
-
};
|
2662
|
-
|
2663
2595
|
const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty = false, itemType = valtype) => {
|
2664
2596
|
const out = [];
|
2665
2597
|
|
@@ -2669,7 +2601,7 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
|
|
2669
2601
|
|
2670
2602
|
// todo: can we just have 1 undeclared array? probably not? but this is not really memory efficient
|
2671
2603
|
const uniqueName = name === '$undeclared' ? name + Math.random().toString().slice(2) : name;
|
2672
|
-
arrays.set(name, allocPage(`${
|
2604
|
+
arrays.set(name, allocPage(`${itemType === 'i16' ? 'string' : 'array'}: ${uniqueName}`, itemType) * pageSize);
|
2673
2605
|
}
|
2674
2606
|
|
2675
2607
|
const pointer = arrays.get(name);
|
@@ -2715,7 +2647,7 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
|
|
2715
2647
|
out.push(
|
2716
2648
|
...number(0, Valtype.i32),
|
2717
2649
|
...(useRawElements ? number(elements[i], Valtype[valtype]) : generate(scope, elements[i])),
|
2718
|
-
[ storeOp,
|
2650
|
+
[ storeOp, Math.log2(ValtypeSize[itemType]) - 1, ...unsignedLEB128(pointer + ValtypeSize.i32 + i * ValtypeSize[itemType]) ]
|
2719
2651
|
);
|
2720
2652
|
}
|
2721
2653
|
|
@@ -2725,29 +2657,15 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
|
|
2725
2657
|
return [ out, pointer ];
|
2726
2658
|
};
|
2727
2659
|
|
2728
|
-
const byteStringable = str => {
|
2729
|
-
if (!process.argv.includes('-bytestring')) return false;
|
2730
|
-
|
2731
|
-
for (let i = 0; i < str.length; i++) {
|
2732
|
-
if (str.charCodeAt(i) > 0xFF) return false;
|
2733
|
-
}
|
2734
|
-
|
2735
|
-
return true;
|
2736
|
-
};
|
2737
|
-
|
2738
2660
|
const makeString = (scope, str, global = false, name = '$undeclared') => {
|
2739
2661
|
const rawElements = new Array(str.length);
|
2740
|
-
let byteStringable = process.argv.includes('-bytestring');
|
2741
2662
|
for (let i = 0; i < str.length; i++) {
|
2742
|
-
|
2743
|
-
rawElements[i] = c;
|
2744
|
-
|
2745
|
-
if (byteStringable && c > 0xFF) byteStringable = false;
|
2663
|
+
rawElements[i] = str.charCodeAt(i);
|
2746
2664
|
}
|
2747
2665
|
|
2748
2666
|
return makeArray(scope, {
|
2749
2667
|
rawElements
|
2750
|
-
}, global, name, false,
|
2668
|
+
}, global, name, false, 'i16')[0];
|
2751
2669
|
};
|
2752
2670
|
|
2753
2671
|
let arrays = new Map();
|
@@ -2775,13 +2693,10 @@ export const generateMember = (scope, decl, _global, _name) => {
|
|
2775
2693
|
];
|
2776
2694
|
}
|
2777
2695
|
|
2778
|
-
const object = generate(scope, decl.object);
|
2779
|
-
const property = generate(scope, decl.property);
|
2780
|
-
|
2781
2696
|
// // todo: we should only do this for strings but we don't know at compile-time :(
|
2782
2697
|
// hack: this is naughty and will break things!
|
2783
2698
|
let newOut = number(0, valtypeBinary), newPointer = -1;
|
2784
|
-
if (pages.
|
2699
|
+
if (pages.hasString) {
|
2785
2700
|
0, [ newOut, newPointer ] = makeArray(scope, {
|
2786
2701
|
rawElements: new Array(1)
|
2787
2702
|
}, _global, _name, true, 'i16');
|
@@ -2790,7 +2705,7 @@ export const generateMember = (scope, decl, _global, _name) => {
|
|
2790
2705
|
return typeSwitch(scope, getNodeType(scope, decl.object), {
|
2791
2706
|
[TYPES._array]: [
|
2792
2707
|
// get index as valtype
|
2793
|
-
...property,
|
2708
|
+
...generate(scope, decl.property),
|
2794
2709
|
|
2795
2710
|
// convert to i32 and turn into byte offset by * valtypeSize (4 for i32, 8 for i64/f64)
|
2796
2711
|
Opcodes.i32_to_u,
|
@@ -2798,7 +2713,7 @@ export const generateMember = (scope, decl, _global, _name) => {
|
|
2798
2713
|
[ Opcodes.i32_mul ],
|
2799
2714
|
|
2800
2715
|
...(aotPointer ? [] : [
|
2801
|
-
...object,
|
2716
|
+
...generate(scope, decl.object),
|
2802
2717
|
Opcodes.i32_to_u,
|
2803
2718
|
[ Opcodes.i32_add ]
|
2804
2719
|
]),
|
@@ -2817,14 +2732,14 @@ export const generateMember = (scope, decl, _global, _name) => {
|
|
2817
2732
|
|
2818
2733
|
...number(0, Valtype.i32), // base 0 for store later
|
2819
2734
|
|
2820
|
-
...property,
|
2821
|
-
Opcodes.i32_to_u,
|
2735
|
+
...generate(scope, decl.property),
|
2822
2736
|
|
2737
|
+
Opcodes.i32_to_u,
|
2823
2738
|
...number(ValtypeSize.i16, Valtype.i32),
|
2824
2739
|
[ Opcodes.i32_mul ],
|
2825
2740
|
|
2826
2741
|
...(aotPointer ? [] : [
|
2827
|
-
...object,
|
2742
|
+
...generate(scope, decl.object),
|
2828
2743
|
Opcodes.i32_to_u,
|
2829
2744
|
[ Opcodes.i32_add ]
|
2830
2745
|
]),
|
@@ -2841,34 +2756,6 @@ export const generateMember = (scope, decl, _global, _name) => {
|
|
2841
2756
|
...number(TYPES.string, Valtype.i32),
|
2842
2757
|
setLastType(scope)
|
2843
2758
|
],
|
2844
|
-
[TYPES._bytestring]: [
|
2845
|
-
// setup new/out array
|
2846
|
-
...newOut,
|
2847
|
-
[ Opcodes.drop ],
|
2848
|
-
|
2849
|
-
...number(0, Valtype.i32), // base 0 for store later
|
2850
|
-
|
2851
|
-
...property,
|
2852
|
-
Opcodes.i32_to_u,
|
2853
|
-
|
2854
|
-
...(aotPointer ? [] : [
|
2855
|
-
...object,
|
2856
|
-
Opcodes.i32_to_u,
|
2857
|
-
[ Opcodes.i32_add ]
|
2858
|
-
]),
|
2859
|
-
|
2860
|
-
// load current string ind {arg}
|
2861
|
-
[ Opcodes.i32_load8_u, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ],
|
2862
|
-
|
2863
|
-
// store to new string ind 0
|
2864
|
-
[ Opcodes.i32_store8, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128(newPointer + ValtypeSize.i32) ],
|
2865
|
-
|
2866
|
-
// return new string (page)
|
2867
|
-
...number(newPointer),
|
2868
|
-
|
2869
|
-
...number(TYPES._bytestring, Valtype.i32),
|
2870
|
-
setLastType(scope)
|
2871
|
-
],
|
2872
2759
|
|
2873
2760
|
default: [ [ Opcodes.unreachable ] ]
|
2874
2761
|
});
|
@@ -2950,8 +2837,10 @@ const generateFunc = (scope, decl) => {
|
|
2950
2837
|
const func = {
|
2951
2838
|
name,
|
2952
2839
|
params: Object.values(innerScope.locals).slice(0, params.length * 2).map(x => x.type),
|
2953
|
-
|
2954
|
-
|
2840
|
+
returns: innerScope.returns,
|
2841
|
+
locals: innerScope.locals,
|
2842
|
+
throws: innerScope.throws,
|
2843
|
+
index: currentFuncIndex++
|
2955
2844
|
};
|
2956
2845
|
funcIndex[name] = func.index;
|
2957
2846
|
|
package/compiler/opt.js
CHANGED
@@ -192,7 +192,6 @@ export default (funcs, globals, pages, tags) => {
|
|
192
192
|
let missing = false;
|
193
193
|
if (type === 'Array') missing = !pages.hasArray;
|
194
194
|
if (type === 'String') missing = !pages.hasString;
|
195
|
-
if (type === 'ByteString') missing = !pages.hasByteString;
|
196
195
|
|
197
196
|
if (missing) {
|
198
197
|
let j = i, depth = 0;
|
package/compiler/prototype.js
CHANGED
@@ -16,8 +16,7 @@ const TYPES = {
|
|
16
16
|
|
17
17
|
// these are not "typeof" types but tracked internally
|
18
18
|
_array: 0x10,
|
19
|
-
_regexp: 0x11
|
20
|
-
_bytestring: 0x12
|
19
|
+
_regexp: 0x11
|
21
20
|
};
|
22
21
|
|
23
22
|
// todo: turn these into built-ins once arrays and these become less hacky
|
@@ -72,7 +71,7 @@ export const PrototypeFuncs = function() {
|
|
72
71
|
],
|
73
72
|
|
74
73
|
// todo: only for 1 argument
|
75
|
-
push: (pointer, length, wNewMember
|
74
|
+
push: (pointer, length, wNewMember) => [
|
76
75
|
// get memory offset of array at last index (length)
|
77
76
|
...length.getCachedI32(),
|
78
77
|
...number(ValtypeSize[valtype], Valtype.i32),
|
@@ -93,28 +92,22 @@ export const PrototypeFuncs = function() {
|
|
93
92
|
...number(1, Valtype.i32),
|
94
93
|
[ Opcodes.i32_add ],
|
95
94
|
|
96
|
-
...(
|
97
|
-
|
98
|
-
...length.getCachedI32(),
|
99
|
-
])
|
95
|
+
...length.setCachedI32(),
|
96
|
+
...length.getCachedI32(),
|
100
97
|
]),
|
101
98
|
|
102
|
-
...(
|
103
|
-
|
104
|
-
Opcodes.i32_from_u
|
105
|
-
])
|
99
|
+
...length.getCachedI32(),
|
100
|
+
Opcodes.i32_from_u
|
106
101
|
|
107
102
|
// ...length.get()
|
108
103
|
],
|
109
104
|
|
110
|
-
pop: (pointer, length
|
105
|
+
pop: (pointer, length) => [
|
111
106
|
// if length == 0, noop
|
112
107
|
...length.getCachedI32(),
|
113
108
|
[ Opcodes.i32_eqz ],
|
114
109
|
[ Opcodes.if, Blocktype.void ],
|
115
|
-
...(
|
116
|
-
...number(UNDEFINED),
|
117
|
-
]),
|
110
|
+
...number(UNDEFINED),
|
118
111
|
[ Opcodes.br, 1 ],
|
119
112
|
[ Opcodes.end ],
|
120
113
|
|
@@ -126,23 +119,19 @@ export const PrototypeFuncs = function() {
|
|
126
119
|
...number(1, Valtype.i32),
|
127
120
|
[ Opcodes.i32_sub ],
|
128
121
|
|
129
|
-
...(
|
130
|
-
|
131
|
-
...length.getCachedI32(),
|
132
|
-
])
|
122
|
+
...length.setCachedI32(),
|
123
|
+
...length.getCachedI32(),
|
133
124
|
]),
|
134
125
|
|
135
126
|
// load last element
|
136
|
-
...(
|
137
|
-
|
138
|
-
|
139
|
-
[ Opcodes.i32_mul ],
|
127
|
+
...length.getCachedI32(),
|
128
|
+
...number(ValtypeSize[valtype], Valtype.i32),
|
129
|
+
[ Opcodes.i32_mul ],
|
140
130
|
|
141
|
-
|
142
|
-
|
131
|
+
...pointer,
|
132
|
+
[ Opcodes.i32_add ],
|
143
133
|
|
144
|
-
|
145
|
-
])
|
134
|
+
[ Opcodes.load, Math.log2(ValtypeSize[valtype]) - 1, ...unsignedLEB128(ValtypeSize.i32) ]
|
146
135
|
],
|
147
136
|
|
148
137
|
shift: (pointer, length) => [
|
@@ -483,152 +472,8 @@ export const PrototypeFuncs = function() {
|
|
483
472
|
this[TYPES.string].at.returnType = TYPES.string;
|
484
473
|
this[TYPES.string].charAt.returnType = TYPES.string;
|
485
474
|
this[TYPES.string].charCodeAt.local = Valtype.i32;
|
486
|
-
this[TYPES.string].charCodeAt.noPointerCache = zeroChecks.charcodeat;
|
487
475
|
|
488
476
|
this[TYPES.string].isWellFormed.local = Valtype.i32;
|
489
477
|
this[TYPES.string].isWellFormed.local2 = Valtype.i32;
|
490
478
|
this[TYPES.string].isWellFormed.returnType = TYPES.boolean;
|
491
|
-
|
492
|
-
if (process.argv.includes('-bytestring')) {
|
493
|
-
this[TYPES._bytestring] = {
|
494
|
-
at: (pointer, length, wIndex, iTmp, _, arrayShell) => {
|
495
|
-
const [ newOut, newPointer ] = arrayShell(1, 'i16');
|
496
|
-
|
497
|
-
return [
|
498
|
-
// setup new/out array
|
499
|
-
...newOut,
|
500
|
-
[ Opcodes.drop ],
|
501
|
-
|
502
|
-
...number(0, Valtype.i32), // base 0 for store later
|
503
|
-
|
504
|
-
...wIndex,
|
505
|
-
Opcodes.i32_to_u,
|
506
|
-
[ Opcodes.local_tee, iTmp ],
|
507
|
-
|
508
|
-
// if index < 0: access index + array length
|
509
|
-
...number(0, Valtype.i32),
|
510
|
-
[ Opcodes.i32_lt_s ],
|
511
|
-
[ Opcodes.if, Blocktype.void ],
|
512
|
-
[ Opcodes.local_get, iTmp ],
|
513
|
-
...length.getCachedI32(),
|
514
|
-
[ Opcodes.i32_add ],
|
515
|
-
[ Opcodes.local_set, iTmp ],
|
516
|
-
[ Opcodes.end ],
|
517
|
-
|
518
|
-
// if still < 0 or >= length: return undefined
|
519
|
-
[ Opcodes.local_get, iTmp ],
|
520
|
-
...number(0, Valtype.i32),
|
521
|
-
[ Opcodes.i32_lt_s ],
|
522
|
-
|
523
|
-
[ Opcodes.local_get, iTmp ],
|
524
|
-
...length.getCachedI32(),
|
525
|
-
[ Opcodes.i32_ge_s ],
|
526
|
-
[ Opcodes.i32_or ],
|
527
|
-
|
528
|
-
[ Opcodes.if, Blocktype.void ],
|
529
|
-
...number(UNDEFINED),
|
530
|
-
[ Opcodes.br, 1 ],
|
531
|
-
[ Opcodes.end ],
|
532
|
-
|
533
|
-
[ Opcodes.local_get, iTmp ],
|
534
|
-
|
535
|
-
...pointer,
|
536
|
-
[ Opcodes.i32_add ],
|
537
|
-
|
538
|
-
// load current string ind {arg}
|
539
|
-
[ Opcodes.i32_load8_u, 0, ...unsignedLEB128(ValtypeSize.i32) ],
|
540
|
-
|
541
|
-
// store to new string ind 0
|
542
|
-
[ Opcodes.i32_store8, 0, ...unsignedLEB128(newPointer + ValtypeSize.i32) ],
|
543
|
-
|
544
|
-
// return new string (pointer)
|
545
|
-
...number(newPointer)
|
546
|
-
];
|
547
|
-
},
|
548
|
-
|
549
|
-
// todo: out of bounds properly
|
550
|
-
charAt: (pointer, length, wIndex, _1, _2, arrayShell) => {
|
551
|
-
const [ newOut, newPointer ] = arrayShell(1, 'i16');
|
552
|
-
|
553
|
-
return [
|
554
|
-
// setup new/out array
|
555
|
-
...newOut,
|
556
|
-
[ Opcodes.drop ],
|
557
|
-
|
558
|
-
...number(0, Valtype.i32), // base 0 for store later
|
559
|
-
|
560
|
-
...wIndex,
|
561
|
-
|
562
|
-
Opcodes.i32_to,
|
563
|
-
|
564
|
-
...pointer,
|
565
|
-
[ Opcodes.i32_add ],
|
566
|
-
|
567
|
-
// load current string ind {arg}
|
568
|
-
[ Opcodes.i32_load8_u, 0, ...unsignedLEB128(ValtypeSize.i32) ],
|
569
|
-
|
570
|
-
// store to new string ind 0
|
571
|
-
[ Opcodes.i32_store8, 0, ...unsignedLEB128(newPointer + ValtypeSize.i32) ],
|
572
|
-
|
573
|
-
// return new string (page)
|
574
|
-
...number(newPointer)
|
575
|
-
];
|
576
|
-
},
|
577
|
-
|
578
|
-
charCodeAt: (pointer, length, wIndex, iTmp) => {
|
579
|
-
return [
|
580
|
-
...wIndex,
|
581
|
-
Opcodes.i32_to,
|
582
|
-
|
583
|
-
...(zeroChecks.charcodeat ? [] : [
|
584
|
-
[ Opcodes.local_set, iTmp ],
|
585
|
-
|
586
|
-
// index < 0
|
587
|
-
...(noUnlikelyChecks ? [] : [
|
588
|
-
[ Opcodes.local_get, iTmp ],
|
589
|
-
...number(0, Valtype.i32),
|
590
|
-
[ Opcodes.i32_lt_s ],
|
591
|
-
]),
|
592
|
-
|
593
|
-
// index >= length
|
594
|
-
[ Opcodes.local_get, iTmp ],
|
595
|
-
...length.getCachedI32(),
|
596
|
-
[ Opcodes.i32_ge_s ],
|
597
|
-
|
598
|
-
...(noUnlikelyChecks ? [] : [ [ Opcodes.i32_or ] ]),
|
599
|
-
[ Opcodes.if, Blocktype.void ],
|
600
|
-
...number(NaN),
|
601
|
-
[ Opcodes.br, 1 ],
|
602
|
-
[ Opcodes.end ],
|
603
|
-
|
604
|
-
[ Opcodes.local_get, iTmp ],
|
605
|
-
]),
|
606
|
-
|
607
|
-
...pointer,
|
608
|
-
[ Opcodes.i32_add ],
|
609
|
-
|
610
|
-
// load current string ind {arg}
|
611
|
-
[ Opcodes.i32_load8_u, 0, ...unsignedLEB128(ValtypeSize.i32) ],
|
612
|
-
Opcodes.i32_from_u
|
613
|
-
];
|
614
|
-
},
|
615
|
-
|
616
|
-
isWellFormed: () => {
|
617
|
-
return [
|
618
|
-
// we know it must be true as it is a bytestring lol
|
619
|
-
...number(1)
|
620
|
-
]
|
621
|
-
}
|
622
|
-
};
|
623
|
-
|
624
|
-
this[TYPES._bytestring].at.local = Valtype.i32;
|
625
|
-
this[TYPES._bytestring].at.returnType = TYPES._bytestring;
|
626
|
-
this[TYPES._bytestring].charAt.returnType = TYPES._bytestring;
|
627
|
-
this[TYPES._bytestring].charCodeAt.local = Valtype.i32;
|
628
|
-
this[TYPES._bytestring].charCodeAt.noPointerCache = zeroChecks.charcodeat;
|
629
|
-
|
630
|
-
this[TYPES._bytestring].isWellFormed.local = Valtype.i32;
|
631
|
-
this[TYPES._bytestring].isWellFormed.local2 = Valtype.i32;
|
632
|
-
this[TYPES._bytestring].isWellFormed.returnType = TYPES.boolean;
|
633
|
-
}
|
634
479
|
};
|
package/compiler/wasmSpec.js
CHANGED
package/compiler/wrap.js
CHANGED
@@ -19,8 +19,7 @@ const TYPES = {
|
|
19
19
|
|
20
20
|
// internal
|
21
21
|
[internalTypeBase]: '_array',
|
22
|
-
[internalTypeBase + 1]: '_regexp'
|
23
|
-
[internalTypeBase + 2]: '_bytestring'
|
22
|
+
[internalTypeBase + 1]: '_regexp'
|
24
23
|
};
|
25
24
|
|
26
25
|
export default async (source, flags = [ 'module' ], customImports = {}, print = str => process.stdout.write(str)) => {
|
@@ -49,9 +48,6 @@ export default async (source, flags = [ 'module' ], customImports = {}, print =
|
|
49
48
|
}
|
50
49
|
});
|
51
50
|
} catch (e) {
|
52
|
-
// only backtrace for runner, not test262/etc
|
53
|
-
if (!process.argv[1].includes('/runner')) throw e;
|
54
|
-
|
55
51
|
const funcInd = parseInt(e.message.match(/function #([0-9]+) /)[1]);
|
56
52
|
const blobOffset = parseInt(e.message.split('@')[1]);
|
57
53
|
|
@@ -181,13 +177,6 @@ export default async (source, flags = [ 'module' ], customImports = {}, print =
|
|
181
177
|
return Array.from(new Uint16Array(memory.buffer, pointer + 4, length)).map(x => String.fromCharCode(x)).join('');
|
182
178
|
}
|
183
179
|
|
184
|
-
case '_bytestring': {
|
185
|
-
const pointer = ret;
|
186
|
-
const length = new Int32Array(memory.buffer, pointer, 1);
|
187
|
-
|
188
|
-
return Array.from(new Uint8Array(memory.buffer, pointer + 4, length)).map(x => String.fromCharCode(x)).join('');
|
189
|
-
}
|
190
|
-
|
191
180
|
case 'function': {
|
192
181
|
// wasm func index, including all imports
|
193
182
|
const func = funcs.find(x => (x.originalIndex ?? x.index) === ret);
|
package/package.json
CHANGED