porffor 0.60.8 → 0.60.10
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/compiler/2c.js +2 -2
- package/compiler/assemble.js +13 -0
- package/compiler/builtins/regexp.ts +180 -36
- package/compiler/builtins.js +79 -69
- package/compiler/builtins_precompiled.js +2160 -2160
- package/compiler/codegen.js +73 -63
- package/compiler/cyclone.js +2 -2
- package/compiler/disassemble.js +2 -2
- package/compiler/encoding.js +22 -4
- package/compiler/expression.js +0 -25
- package/compiler/opt.js +15 -15
- package/compiler/precompile.js +4 -4
- package/compiler/wrap.js +4 -1
- package/foo.js +34 -0
- package/package.json +2 -2
- package/runtime/index.js +1 -1
package/compiler/codegen.js
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
import { Blocktype, Opcodes, Valtype, ValtypeSize } from './wasmSpec.js';
|
2
|
-
import { number, ieee754_binary64, signedLEB128, unsignedLEB128, encodeVector
|
2
|
+
import { number, ieee754_binary64, signedLEB128, unsignedLEB128, encodeVector } from './encoding.js';
|
3
3
|
import { operatorOpcode } from './expression.js';
|
4
4
|
import { BuiltinFuncs, BuiltinVars, importedFuncs, NULL, UNDEFINED } from './builtins.js';
|
5
5
|
import { TYPES, TYPE_FLAGS, TYPE_NAMES } from './types.js';
|
@@ -41,24 +41,30 @@ const allocBytes = (scope, reason, bytes) => {
|
|
41
41
|
return allocs.get(reason);
|
42
42
|
}
|
43
43
|
|
44
|
-
let
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
bin = {
|
49
|
-
used: 0,
|
50
|
-
page
|
51
|
-
};
|
44
|
+
let startingPtr = 0;
|
45
|
+
while (bytes > 0) {
|
46
|
+
const alloc = Math.min(bytes, pageSize);
|
47
|
+
bytes -= alloc;
|
52
48
|
|
53
|
-
|
54
|
-
|
55
|
-
|
49
|
+
let bin = bins.find(x => (pageSize - x.used) >= alloc);
|
50
|
+
if (!bin) {
|
51
|
+
// new bin
|
52
|
+
const page = pages.size;
|
53
|
+
bin = {
|
54
|
+
used: 0,
|
55
|
+
page
|
56
|
+
};
|
56
57
|
|
57
|
-
|
58
|
-
|
58
|
+
const id = bins.push(bin);
|
59
|
+
pages.set(`#bin: ${id}`, page);
|
60
|
+
}
|
61
|
+
|
62
|
+
if (!startingPtr) startingPtr = pagePtr(bin.page) + bin.used;
|
63
|
+
bin.used += alloc;
|
64
|
+
}
|
59
65
|
|
60
|
-
allocs.set(reason,
|
61
|
-
return
|
66
|
+
allocs.set(reason, startingPtr);
|
67
|
+
return startingPtr;
|
62
68
|
};
|
63
69
|
|
64
70
|
export const allocStr = (scope, str, bytestring) => {
|
@@ -83,7 +89,7 @@ const isFuncType = type =>
|
|
83
89
|
type === 'FunctionDeclaration' || type === 'FunctionExpression' || type === 'ArrowFunctionExpression' ||
|
84
90
|
type === 'ClassDeclaration' || type === 'ClassExpression';
|
85
91
|
const hasFuncWithName = name =>
|
86
|
-
|
92
|
+
name in funcIndex || name in builtinFuncs || name in importedFuncs || name in internalConstrs;
|
87
93
|
|
88
94
|
const astCache = new WeakMap();
|
89
95
|
const cacheAst = (decl, wasm) => {
|
@@ -535,8 +541,8 @@ const generateEnum = (scope, decl) => {
|
|
535
541
|
const optional = (op, clause = op.at(-1)) => clause || clause === 0 ? (Array.isArray(op[0]) ? op : [ op ]) : [];
|
536
542
|
|
537
543
|
const lookupName = (scope, name) => {
|
538
|
-
if (
|
539
|
-
if (
|
544
|
+
if (name in scope.locals) return [ scope.locals[name], false ];
|
545
|
+
if (name in globals) return [ globals[name], true ];
|
540
546
|
|
541
547
|
return [ undefined, undefined ];
|
542
548
|
};
|
@@ -602,7 +608,7 @@ const hoistLookupType = (scope, name) => {
|
|
602
608
|
const lookup = (scope, name, failEarly = false) => {
|
603
609
|
let local = scope.locals[name];
|
604
610
|
|
605
|
-
if (
|
611
|
+
if (name in builtinVars) {
|
606
612
|
let wasm = builtinVars[name];
|
607
613
|
if (wasm.usesImports) scope.usesImports = true;
|
608
614
|
|
@@ -610,9 +616,9 @@ const lookup = (scope, name, failEarly = false) => {
|
|
610
616
|
return wasm.slice();
|
611
617
|
}
|
612
618
|
|
613
|
-
if (!
|
619
|
+
if (!(name in funcIndex) && name in builtinFuncs) {
|
614
620
|
includeBuiltin(scope, name);
|
615
|
-
} else if (
|
621
|
+
} else if (name in internalConstrs) {
|
616
622
|
// todo: return an actual something
|
617
623
|
return [ number(1) ];
|
618
624
|
}
|
@@ -656,16 +662,16 @@ const lookup = (scope, name, failEarly = false) => {
|
|
656
662
|
}
|
657
663
|
|
658
664
|
// no local var with name
|
659
|
-
if (
|
660
|
-
if (
|
661
|
-
if (
|
665
|
+
if (name in globals) return [ [ Opcodes.global_get, globals[name].idx ] ];
|
666
|
+
if (name in funcIndex) return funcRef(funcByName(name));
|
667
|
+
if (name in importedFuncs) return [ number(importedFuncs[name] - importedFuncs.length) ];
|
662
668
|
|
663
669
|
if (name.startsWith('__')) {
|
664
670
|
// return undefined if unknown key in already known var
|
665
671
|
let parent = name.slice(2).split('_').slice(0, -1).join('_');
|
666
672
|
if (parent.includes('_')) parent = '__' + parent;
|
667
673
|
|
668
|
-
if (
|
674
|
+
if ((name + '$get') in builtinFuncs) {
|
669
675
|
// hack: force error as accessors should only be used with objects anyway
|
670
676
|
return internalThrow(scope, 'TypeError', 'Accessor called without object');
|
671
677
|
}
|
@@ -1468,7 +1474,7 @@ const asmFuncToAsm = (scope, func, extra) => func(scope, {
|
|
1468
1474
|
},
|
1469
1475
|
glbl: (opcode, name, type) => {
|
1470
1476
|
const globalName = '#porf#' + name; // avoid potential name clashing with user js
|
1471
|
-
if (!
|
1477
|
+
if (!(globalName in globals)) {
|
1472
1478
|
const idx = globals['#ind']++;
|
1473
1479
|
globals[globalName] = { idx, type };
|
1474
1480
|
|
@@ -1503,7 +1509,7 @@ const asmFuncToAsm = (scope, func, extra) => func(scope, {
|
|
1503
1509
|
return out;
|
1504
1510
|
},
|
1505
1511
|
loc: (name, type) => {
|
1506
|
-
if (!
|
1512
|
+
if (!(name in scope.locals)) {
|
1507
1513
|
const idx = scope.localInd++;
|
1508
1514
|
scope.locals[name] = { idx, type };
|
1509
1515
|
}
|
@@ -1545,7 +1551,7 @@ const asmFunc = (name, func) => {
|
|
1545
1551
|
if (existing) return existing;
|
1546
1552
|
|
1547
1553
|
const allLocals = params.concat(localTypes);
|
1548
|
-
const locals =
|
1554
|
+
const locals = Object.create(null);
|
1549
1555
|
for (let i = 0; i < allLocals.length; i++) {
|
1550
1556
|
locals[localNames[i] ?? `l${i}`] = { idx: i, type: allLocals[i] };
|
1551
1557
|
}
|
@@ -1640,14 +1646,14 @@ const getType = (scope, name, failEarly = false) => {
|
|
1640
1646
|
[ null, () => hoistLookupType(scope, name) ]
|
1641
1647
|
];
|
1642
1648
|
|
1643
|
-
if (
|
1649
|
+
if (name in builtinVars) return [ number(builtinVars[name].type ?? TYPES.number, Valtype.i32) ];
|
1644
1650
|
|
1645
1651
|
let metadata, typeLocal, global = null;
|
1646
|
-
if (
|
1652
|
+
if (name in scope.locals) {
|
1647
1653
|
metadata = scope.locals[name].metadata;
|
1648
1654
|
typeLocal = scope.locals[name + '#type'];
|
1649
1655
|
global = false;
|
1650
|
-
} else if (
|
1656
|
+
} else if (name in globals) {
|
1651
1657
|
metadata = globals[name].metadata;
|
1652
1658
|
typeLocal = globals[name + '#type'];
|
1653
1659
|
global = true;
|
@@ -1681,10 +1687,10 @@ const setType = (scope, name, type, noInfer = false) => {
|
|
1681
1687
|
const out = typeof type === 'number' ? [ number(type, Valtype.i32) ] : type;
|
1682
1688
|
|
1683
1689
|
let metadata, typeLocal, global = false;
|
1684
|
-
if (
|
1690
|
+
if (name in scope.locals) {
|
1685
1691
|
metadata = scope.locals[name].metadata;
|
1686
1692
|
typeLocal = scope.locals[name + '#type'];
|
1687
|
-
} else if (
|
1693
|
+
} else if (name in globals) {
|
1688
1694
|
metadata = globals[name].metadata;
|
1689
1695
|
typeLocal = globals[name + '#type'];
|
1690
1696
|
global = true;
|
@@ -1791,8 +1797,8 @@ const getNodeType = (scope, node) => {
|
|
1791
1797
|
if (func.returnType != null) return func.returnType;
|
1792
1798
|
}
|
1793
1799
|
|
1794
|
-
if (
|
1795
|
-
if (
|
1800
|
+
if (name in builtinFuncs && builtinFuncs[name].returnType != null) return builtinFuncs[name].returnType;
|
1801
|
+
if (name in internalConstrs && internalConstrs[name].type != null) return internalConstrs[name].type;
|
1796
1802
|
|
1797
1803
|
if (name.startsWith('__Porffor_wasm_')) {
|
1798
1804
|
// todo: return undefined for non-returning ops
|
@@ -2165,7 +2171,7 @@ const createThisArg = (scope, decl) => {
|
|
2165
2171
|
const name = decl.callee?.name;
|
2166
2172
|
if (decl._new) {
|
2167
2173
|
// if precompiling or builtin func, just make it null as unused
|
2168
|
-
if (!decl._forceCreateThis && (globalThis.precompile ||
|
2174
|
+
if (!decl._forceCreateThis && (globalThis.precompile || name in builtinFuncs)) return [
|
2169
2175
|
number(NULL),
|
2170
2176
|
number(TYPES.object, Valtype.i32)
|
2171
2177
|
];
|
@@ -2332,7 +2338,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
2332
2338
|
target.name = spl.slice(0, -1).join('_');
|
2333
2339
|
|
2334
2340
|
if (builtinFuncs['__' + target.name + '_' + protoName]) protoName = null;
|
2335
|
-
else if (lookupName(scope, target.name)[0] == null && !
|
2341
|
+
else if (lookupName(scope, target.name)[0] == null && !(target.name in builtinFuncs)) {
|
2336
2342
|
if (lookupName(scope, '__' + target.name)[0] != null || builtinFuncs['__' + target.name]) target.name = '__' + target.name;
|
2337
2343
|
else protoName = null;
|
2338
2344
|
}
|
@@ -2472,18 +2478,18 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
2472
2478
|
let idx;
|
2473
2479
|
if (decl._funcIdx) {
|
2474
2480
|
idx = decl._funcIdx;
|
2475
|
-
} else if (
|
2481
|
+
} else if (name in internalConstrs && !decl._noInternalConstr) {
|
2476
2482
|
if (decl._new && internalConstrs[name].notConstr) return internalThrow(scope, 'TypeError', `${unhackName(name)} is not a constructor`, true);
|
2477
2483
|
return internalConstrs[name].generate(scope, decl, _global, _name);
|
2478
|
-
} else if (
|
2484
|
+
} else if (name in funcIndex) {
|
2479
2485
|
idx = funcIndex[name];
|
2480
2486
|
} else if (scope.name === name) {
|
2481
2487
|
// fallback for own func but with a different var/id name
|
2482
2488
|
idx = scope.index;
|
2483
|
-
} else if (
|
2489
|
+
} else if (name in importedFuncs) {
|
2484
2490
|
idx = importedFuncs[name];
|
2485
2491
|
scope.usesImports = true;
|
2486
|
-
} else if (
|
2492
|
+
} else if (name in builtinFuncs) {
|
2487
2493
|
if (decl._new && !builtinFuncs[name].constr) return internalThrow(scope, 'TypeError', `${unhackName(name)} is not a constructor`, true);
|
2488
2494
|
|
2489
2495
|
includeBuiltin(scope, name);
|
@@ -2840,7 +2846,7 @@ const knownType = (scope, type) => {
|
|
2840
2846
|
if (typeof type === 'number') return type;
|
2841
2847
|
|
2842
2848
|
if (type.length === 1 && type[0][0] === Opcodes.i32_const) {
|
2843
|
-
return
|
2849
|
+
return type[0][1];
|
2844
2850
|
}
|
2845
2851
|
|
2846
2852
|
if (typedInput && type.length === 1 && type[0][0] === Opcodes.local_get) {
|
@@ -3130,7 +3136,7 @@ const allocVar = (scope, name, global = false, type = true, redecl = false, i32
|
|
3130
3136
|
const target = global ? globals : scope.locals;
|
3131
3137
|
|
3132
3138
|
// already declared
|
3133
|
-
if (
|
3139
|
+
if (name in target) {
|
3134
3140
|
if (redecl) {
|
3135
3141
|
// force change old local name(s)
|
3136
3142
|
target['#redecl_' + name + uniqId()] = target[name];
|
@@ -3326,7 +3332,7 @@ const generateVarDstr = (scope, kind, pattern, init, defaultValue, global) => {
|
|
3326
3332
|
const [ _func, out ] = generateFunc(scope, init, true);
|
3327
3333
|
|
3328
3334
|
const funcName = init.id?.name;
|
3329
|
-
if (name !== funcName &&
|
3335
|
+
if (name !== funcName && funcName in funcIndex) {
|
3330
3336
|
funcIndex[name] = funcIndex[funcName];
|
3331
3337
|
delete funcIndex[funcName];
|
3332
3338
|
}
|
@@ -3341,7 +3347,7 @@ const generateVarDstr = (scope, kind, pattern, init, defaultValue, global) => {
|
|
3341
3347
|
}
|
3342
3348
|
|
3343
3349
|
let out = [];
|
3344
|
-
if (topLevel &&
|
3350
|
+
if (topLevel && name in builtinVars) {
|
3345
3351
|
// cannot redeclare
|
3346
3352
|
if (kind !== 'var') return internalThrow(scope, 'SyntaxError', `Identifier '${unhackName(name)}' has already been declared`);
|
3347
3353
|
|
@@ -3389,7 +3395,7 @@ const generateVarDstr = (scope, kind, pattern, init, defaultValue, global) => {
|
|
3389
3395
|
}
|
3390
3396
|
|
3391
3397
|
if (globalThis.precompile && global) {
|
3392
|
-
scope.globalInits ??=
|
3398
|
+
scope.globalInits ??= Object.create(null);
|
3393
3399
|
scope.globalInits[name] = newOut;
|
3394
3400
|
}
|
3395
3401
|
} else {
|
@@ -4208,7 +4214,7 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
4208
4214
|
];
|
4209
4215
|
}
|
4210
4216
|
|
4211
|
-
if (
|
4217
|
+
if (name in builtinVars) {
|
4212
4218
|
if (scope.strict) return internalThrow(scope, 'TypeError', `Cannot assign to non-writable global ${name}`, true);
|
4213
4219
|
|
4214
4220
|
// just return rhs (eg `NaN = 2`)
|
@@ -4319,7 +4325,7 @@ const generateUnary = (scope, decl) => {
|
|
4319
4325
|
return [
|
4320
4326
|
...toNumeric(),
|
4321
4327
|
Opcodes.i32_to,
|
4322
|
-
[ Opcodes.i32_const,
|
4328
|
+
[ Opcodes.i32_const, -1 ],
|
4323
4329
|
[ Opcodes.i32_xor ],
|
4324
4330
|
Opcodes.i32_from
|
4325
4331
|
];
|
@@ -5118,14 +5124,14 @@ const generateForIn = (scope, decl) => {
|
|
5118
5124
|
[ Opcodes.local_set, tmp ],
|
5119
5125
|
|
5120
5126
|
// symbol is MSB 2 is set
|
5121
|
-
[ Opcodes.i32_const,
|
5122
|
-
[ Opcodes.i32_const,
|
5127
|
+
[ Opcodes.i32_const, TYPES.string ],
|
5128
|
+
[ Opcodes.i32_const, TYPES.symbol ],
|
5123
5129
|
[ Opcodes.local_get, tmp ],
|
5124
5130
|
number(0x40000000, Valtype.i32),
|
5125
5131
|
[ Opcodes.i32_and ],
|
5126
5132
|
[ Opcodes.select ],
|
5127
5133
|
[ Opcodes.else ], // bytestring
|
5128
|
-
[ Opcodes.i32_const,
|
5134
|
+
[ Opcodes.i32_const, TYPES.bytestring ],
|
5129
5135
|
[ Opcodes.end ]
|
5130
5136
|
]),
|
5131
5137
|
|
@@ -5839,7 +5845,7 @@ const wrapBC = (bc, { prelude = [], postlude = [] } = {}) => {
|
|
5839
5845
|
|
5840
5846
|
const countParams = (func, name = undefined) => {
|
5841
5847
|
if (!func) {
|
5842
|
-
if (
|
5848
|
+
if (name in importedFuncs) {
|
5843
5849
|
// reverse lookup then normal lookup
|
5844
5850
|
func = importedFuncs[importedFuncs[name]];
|
5845
5851
|
if (func) return func.params?.length ?? func.params;
|
@@ -6571,6 +6577,7 @@ const generateTemplate = (scope, decl) => {
|
|
6571
6577
|
|
6572
6578
|
const generateTaggedTemplate = (scope, decl, global = false, name = undefined, valueUnused = false) => {
|
6573
6579
|
const intrinsics = {
|
6580
|
+
__proto__: null,
|
6574
6581
|
__Porffor_wasm: str => {
|
6575
6582
|
let out = [];
|
6576
6583
|
|
@@ -6597,12 +6604,12 @@ const generateTaggedTemplate = (scope, decl, global = false, name = undefined, v
|
|
6597
6604
|
const immediates = asm.slice(1).map(x => {
|
6598
6605
|
const n = parseFloat(x);
|
6599
6606
|
if (Number.isNaN(n) && x !== 'NaN') {
|
6600
|
-
if (
|
6607
|
+
if (x in builtinFuncs) {
|
6601
6608
|
if (funcIndex[x] == null) includeBuiltin(scope, x);
|
6602
6609
|
return funcIndex[x];
|
6603
6610
|
}
|
6604
6611
|
|
6605
|
-
if (
|
6612
|
+
if (x in importedFuncs) {
|
6606
6613
|
scope.usesImports = true;
|
6607
6614
|
return importedFuncs[x];
|
6608
6615
|
}
|
@@ -6615,6 +6622,7 @@ const generateTaggedTemplate = (scope, decl, global = false, name = undefined, v
|
|
6615
6622
|
|
6616
6623
|
const encodeFunc = ({
|
6617
6624
|
[Opcodes.f64_const]: x => x,
|
6625
|
+
[Opcodes.i32_const]: x => x,
|
6618
6626
|
[Opcodes.if]: unsignedLEB128,
|
6619
6627
|
[Opcodes.loop]: unsignedLEB128
|
6620
6628
|
})[inst[0]] ?? signedLEB128;
|
@@ -6641,7 +6649,7 @@ const generateTaggedTemplate = (scope, decl, global = false, name = undefined, v
|
|
6641
6649
|
};
|
6642
6650
|
|
6643
6651
|
const { quasis, expressions } = decl.quasi;
|
6644
|
-
if (
|
6652
|
+
if (decl.tag.name in intrinsics) {
|
6645
6653
|
let str = quasis[0].value.raw;
|
6646
6654
|
|
6647
6655
|
for (let i = 0; i < expressions.length; i++) {
|
@@ -6725,7 +6733,7 @@ const objectHack = node => {
|
|
6725
6733
|
if (objectName !== 'Object_prototype' && (node.property.name === 'propertyIsEnumerable' || node.property.name === 'hasOwnProperty' || node.property.name === 'isPrototypeOf')) return abortOut;
|
6726
6734
|
|
6727
6735
|
const name = '__' + objectName + '_' + node.property.name;
|
6728
|
-
if ((!hasFuncWithName(name) && !
|
6736
|
+
if ((!hasFuncWithName(name) && !(name in builtinVars) && !hasFuncWithName(name + '$get')) && (hasFuncWithName(objectName) || objectName in builtinVars || hasFuncWithName('__' + objectName) || ('__' + objectName) in builtinVars)) return abortOut;
|
6729
6737
|
|
6730
6738
|
if (Prefs.codeLog) log('codegen', `object hack! ${node.object.name}.${node.property.name} -> ${name}`);
|
6731
6739
|
|
@@ -6788,7 +6796,7 @@ const generateFunc = (scope, decl, forceNoExpr = false) => {
|
|
6788
6796
|
const arrow = decl.type === 'ArrowFunctionExpression' || decl.type === 'Program';
|
6789
6797
|
const func = {
|
6790
6798
|
start: decl.start,
|
6791
|
-
locals:
|
6799
|
+
locals: Object.create(null),
|
6792
6800
|
localInd: 0,
|
6793
6801
|
returns: [ valtypeBinary, Valtype.i32 ], // value, type
|
6794
6802
|
name,
|
@@ -6998,7 +7006,7 @@ const generateFunc = (scope, decl, forceNoExpr = false) => {
|
|
6998
7006
|
wasm.push(...getNodeType(func, getLastNode(decl.body.body)));
|
6999
7007
|
|
7000
7008
|
// inject promise job runner func at the end of main if promises are made
|
7001
|
-
if (
|
7009
|
+
if (('Promise' in funcIndex) || ('__Promise_resolve' in funcIndex) || ('__Promise_reject' in funcIndex)) {
|
7002
7010
|
wasm.push(
|
7003
7011
|
[ Opcodes.call, includeBuiltin(func, '__Porffor_promise_runJobs').index ]
|
7004
7012
|
);
|
@@ -7173,6 +7181,7 @@ const generateBlock = (scope, decl) => {
|
|
7173
7181
|
};
|
7174
7182
|
|
7175
7183
|
const internalConstrs = {
|
7184
|
+
__proto__: null,
|
7176
7185
|
__Array_of: {
|
7177
7186
|
// this is not a constructor but best fits internal structure here
|
7178
7187
|
generate: (scope, decl, global, name) => {
|
@@ -7362,7 +7371,8 @@ const internalConstrs = {
|
|
7362
7371
|
|
7363
7372
|
let globals, tags, exceptions, funcs, indirectFuncs, funcIndex, currentFuncIndex, depth, pages, data, typeswitchDepth, usedTypes, coctc, globalInfer, builtinFuncs, builtinVars, lastValtype;
|
7364
7373
|
export default program => {
|
7365
|
-
globals =
|
7374
|
+
globals = Object.create(null);
|
7375
|
+
globals['#ind'] = 0;
|
7366
7376
|
tags = [];
|
7367
7377
|
exceptions = [];
|
7368
7378
|
funcs = []; indirectFuncs = [];
|
@@ -7370,7 +7380,7 @@ export default program => {
|
|
7370
7380
|
return indirectFuncs._bytesPerFuncLut ??=
|
7371
7381
|
Math.min(Math.floor((pageSize * 2) / indirectFuncs.length), indirectFuncs.reduce((acc, x) => x.name.length > acc ? x.name.length : acc, 0) + 8);
|
7372
7382
|
};
|
7373
|
-
funcIndex =
|
7383
|
+
funcIndex = Object.create(null);
|
7374
7384
|
depth = [];
|
7375
7385
|
pages = new Map();
|
7376
7386
|
data = [];
|
@@ -7397,8 +7407,8 @@ export default program => {
|
|
7397
7407
|
// keep builtins between compiles as much as possible
|
7398
7408
|
if (lastValtype !== valtypeBinary) {
|
7399
7409
|
lastValtype = valtypeBinary;
|
7400
|
-
builtinFuncs =
|
7401
|
-
builtinVars =
|
7410
|
+
builtinFuncs = BuiltinFuncs();
|
7411
|
+
builtinVars = BuiltinVars({ builtinFuncs });
|
7402
7412
|
|
7403
7413
|
const getObjectName = x => x.startsWith('__') && x.slice(2, x.indexOf('_', 2));
|
7404
7414
|
objectHackers = ['assert', 'compareArray', 'Test262Error', ...new Set(Object.keys(builtinFuncs).map(getObjectName).concat(Object.keys(builtinVars).map(getObjectName)).filter(x => x))];
|
package/compiler/cyclone.js
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
// cyclone: wasm partial constant evaluator (it is fast and dangerous hence "cyclone")
|
2
|
-
import { number
|
2
|
+
import { number } from './encoding.js';
|
3
3
|
import { Opcodes, Valtype } from './wasmSpec.js';
|
4
4
|
import './prefs.js';
|
5
5
|
|
@@ -123,7 +123,7 @@ export default ({ name, wasm, locals: _locals, params }) => {
|
|
123
123
|
}
|
124
124
|
|
125
125
|
case Opcodes.i32_const: {
|
126
|
-
const n =
|
126
|
+
const n = op[1];
|
127
127
|
push(n);
|
128
128
|
break;
|
129
129
|
}
|
package/compiler/disassemble.js
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
import { Blocktype, Opcodes, Valtype } from './wasmSpec.js';
|
2
|
-
import {
|
2
|
+
import { read_unsignedLEB128 } from './encoding.js';
|
3
3
|
import { importedFuncs } from './builtins.js';
|
4
4
|
|
5
5
|
const inv = (obj, keyMap = x => x) => Object.keys(obj).reduce((acc, x) => { acc[keyMap(obj[x])] = x; return acc; }, {});
|
@@ -74,7 +74,7 @@ export default (wasm, name = '', ind = 0, locals = {}, params = [], returns = []
|
|
74
74
|
if (inst[0] === Opcodes.f64_const) {
|
75
75
|
out += ` ${inst[1]}`;
|
76
76
|
} else if (inst[0] === Opcodes.i32_const || inst[0] === Opcodes.i64_const) {
|
77
|
-
out += ` ${
|
77
|
+
out += ` ${inst[1]}`;
|
78
78
|
} else if (inst[0] === Opcodes.i32_load || inst[0] === Opcodes.i64_load || inst[0] === Opcodes.f64_load || inst[0] === Opcodes.i32_store || inst[0] === Opcodes.i64_store || inst[0] === Opcodes.f64_store || inst[0] === Opcodes.i32_store16 || inst[0] === Opcodes.i32_load16_u) {
|
79
79
|
out += ` ${inst[1]} ${read_unsignedLEB128(inst.slice(2))}`;
|
80
80
|
} else for (const operand of inst.slice(1)) {
|
package/compiler/encoding.js
CHANGED
@@ -3,10 +3,10 @@ import { Opcodes, Valtype } from './wasmSpec.js';
|
|
3
3
|
export const number = (n, valtype = valtypeBinary) => {
|
4
4
|
if (valtype === Valtype.f64) return [ Opcodes.f64_const, n ];
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
6
|
+
return [
|
7
|
+
valtype === Valtype.i32 ? Opcodes.i32_const : Opcodes.i64_const,
|
8
|
+
n
|
9
|
+
];
|
10
10
|
};
|
11
11
|
|
12
12
|
export const codifyString = str => {
|
@@ -23,6 +23,9 @@ export const encodeVector = data => unsignedLEB128(data.length).concat(data.flat
|
|
23
23
|
|
24
24
|
// todo: this only works with integers within 32 bit range
|
25
25
|
export const signedLEB128 = n => {
|
26
|
+
if (n === Infinity) return signedLEB128(2147483647);
|
27
|
+
if (n === -Infinity) return signedLEB128(-2147483648);
|
28
|
+
|
26
29
|
n |= 0;
|
27
30
|
|
28
31
|
// just input for small numbers (for perf as common)
|
@@ -49,6 +52,9 @@ export const signedLEB128 = n => {
|
|
49
52
|
};
|
50
53
|
|
51
54
|
export const unsignedLEB128 = n => {
|
55
|
+
if (n === Infinity) return unsignedLEB128(4294967295);
|
56
|
+
if (n === -Infinity) return unsignedLEB128(0);
|
57
|
+
|
52
58
|
n |= 0;
|
53
59
|
|
54
60
|
// just input for small numbers (for perf as common)
|
@@ -69,6 +75,9 @@ export const unsignedLEB128 = n => {
|
|
69
75
|
};
|
70
76
|
|
71
77
|
export const unsignedLEB128_length = n => {
|
78
|
+
if (n === Infinity) return unsignedLEB128_length(4294967295);
|
79
|
+
if (n === -Infinity) return unsignedLEB128_length(0);
|
80
|
+
|
72
81
|
if (n < 0) n = n >>> 0;
|
73
82
|
if (n <= 127) return 1;
|
74
83
|
if (n <= 16383) return 2;
|
@@ -85,6 +94,9 @@ export const unsignedLEB128_length = n => {
|
|
85
94
|
};
|
86
95
|
|
87
96
|
export const signedLEB128_length = n => {
|
97
|
+
if (n === Infinity) return signedLEB128_length(2147483647);
|
98
|
+
if (n === -Infinity) return signedLEB128_length(-2147483648);
|
99
|
+
|
88
100
|
if (n >= -64 && n <= 63) return 1;
|
89
101
|
if (n >= -8192 && n <= 8191) return 2;
|
90
102
|
if (n >= -1048576 && n <= 1048575) return 3;
|
@@ -201,6 +213,9 @@ export const read_ieee754_binary64 = buffer => new Float64Array(new Uint8Array(b
|
|
201
213
|
|
202
214
|
// into funcs append to a given existing buffer instead of creating our own for perf
|
203
215
|
export const signedLEB128_into = (n, buffer) => {
|
216
|
+
if (n === Infinity) return signedLEB128_into(2147483647, buffer);
|
217
|
+
if (n === -Infinity) return signedLEB128_into(-2147483648, buffer);
|
218
|
+
|
204
219
|
n |= 0;
|
205
220
|
|
206
221
|
// just input for small numbers (for perf as common)
|
@@ -224,6 +239,9 @@ export const signedLEB128_into = (n, buffer) => {
|
|
224
239
|
};
|
225
240
|
|
226
241
|
export const unsignedLEB128_into = (n, buffer) => {
|
242
|
+
if (n === Infinity) return unsignedLEB128_into(4294967295, buffer);
|
243
|
+
if (n === -Infinity) return unsignedLEB128_into(0, buffer);
|
244
|
+
|
227
245
|
n |= 0;
|
228
246
|
|
229
247
|
// just input for small numbers (for perf as common)
|
package/compiler/expression.js
CHANGED
@@ -46,31 +46,6 @@ export const operatorOpcode = {
|
|
46
46
|
]
|
47
47
|
},
|
48
48
|
|
49
|
-
i64: {
|
50
|
-
'+': Opcodes.i64_add,
|
51
|
-
'-': Opcodes.i64_sub,
|
52
|
-
'*': Opcodes.i64_mul,
|
53
|
-
'/': Opcodes.i64_div_s,
|
54
|
-
'%': Opcodes.i64_rem_s,
|
55
|
-
|
56
|
-
'&': Opcodes.i64_and,
|
57
|
-
'|': Opcodes.i64_or,
|
58
|
-
'^': Opcodes.i64_xor,
|
59
|
-
'<<': Opcodes.i64_shl,
|
60
|
-
'>>': Opcodes.i64_shr_s,
|
61
|
-
'>>>': Opcodes.i64_shr_u,
|
62
|
-
|
63
|
-
'==': Opcodes.i64_eq,
|
64
|
-
'===': Opcodes.i64_eq,
|
65
|
-
'!=': Opcodes.i64_ne,
|
66
|
-
'!==': Opcodes.i64_ne,
|
67
|
-
|
68
|
-
'>': Opcodes.i64_gt_s,
|
69
|
-
'>=': Opcodes.i64_ge_s,
|
70
|
-
'<': Opcodes.i64_lt_s,
|
71
|
-
'<=': Opcodes.i64_le_s
|
72
|
-
},
|
73
|
-
|
74
49
|
f64: {
|
75
50
|
'+': Opcodes.f64_add,
|
76
51
|
'-': Opcodes.f64_sub,
|
package/compiler/opt.js
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
import { Opcodes, Valtype } from './wasmSpec.js';
|
2
|
-
import { number
|
2
|
+
import { number } from './encoding.js';
|
3
3
|
import { log } from './log.js';
|
4
4
|
import './prefs.js';
|
5
5
|
|
@@ -177,7 +177,7 @@ export default (funcs, globals, pages, tags, exceptions) => {
|
|
177
177
|
// -->
|
178
178
|
// i32.const 0
|
179
179
|
|
180
|
-
wasm[i - 1] = number(
|
180
|
+
wasm[i - 1] = number(lastInst[1], Valtype.i32); // f64.const -> i32.const
|
181
181
|
|
182
182
|
wasm.splice(i, 1); // remove this inst
|
183
183
|
i--;
|
@@ -192,7 +192,7 @@ export default (funcs, globals, pages, tags, exceptions) => {
|
|
192
192
|
// -->
|
193
193
|
// f64.const 0
|
194
194
|
|
195
|
-
wasm[i - 1] = number(
|
195
|
+
wasm[i - 1] = number(lastInst[1], Valtype.f64); // i32.const -> f64.const
|
196
196
|
|
197
197
|
wasm.splice(i, 1); // remove this inst
|
198
198
|
i--;
|
@@ -215,18 +215,18 @@ export default (funcs, globals, pages, tags, exceptions) => {
|
|
215
215
|
continue;
|
216
216
|
}
|
217
217
|
|
218
|
-
if (
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
}
|
218
|
+
// if (i === wasm.length - 1 && inst[0] === Opcodes.return) {
|
219
|
+
// // replace final return, end -> end (wasm has implicit return)
|
220
|
+
// // return
|
221
|
+
// // end
|
222
|
+
// // -->
|
223
|
+
// // end
|
224
|
+
|
225
|
+
// wasm.splice(i, 1); // remove this inst (return)
|
226
|
+
// i--;
|
227
|
+
// // if (Prefs.optLog) log('opt', `removed redundant return at end`);
|
228
|
+
// continue;
|
229
|
+
// }
|
230
230
|
|
231
231
|
// remove unneeded before get with update exprs (n++, etc) when value is unused
|
232
232
|
if (i < wasm.length - 4 && lastInst[1] === inst[1] && lastInst[0] === Opcodes.local_get && inst[0] === Opcodes.local_get && wasm[i + 1][0] === Opcodes.const && [Opcodes.add, Opcodes.sub].includes(wasm[i + 2][0]) && wasm[i + 3][0] === Opcodes.local_set && wasm[i + 3][1] === inst[1] && (wasm[i + 4][0] === Opcodes.drop || wasm[i + 4][0] === Opcodes.br)) {
|
package/compiler/precompile.js
CHANGED
@@ -176,7 +176,7 @@ const compile = async (file, _funcs) => {
|
|
176
176
|
x.usesTag = true;
|
177
177
|
let id;
|
178
178
|
if (y[0] === Opcodes.i32_const && n[1] === 0) {
|
179
|
-
id =
|
179
|
+
id = y[1];
|
180
180
|
wasm[i] = [ 'throw', exceptions[id].constructor, exceptions[id].message ];
|
181
181
|
|
182
182
|
// remove throw inst
|
@@ -237,14 +237,14 @@ const precompile = async () => {
|
|
237
237
|
return `// autogenerated by compiler/precompile.js
|
238
238
|
import { number } from './encoding.js';
|
239
239
|
|
240
|
-
export const BuiltinFuncs =
|
240
|
+
export const BuiltinFuncs = x => {
|
241
241
|
${funcs.map(x => {
|
242
242
|
const rewriteWasm = wasm => {
|
243
243
|
const str = JSON.stringify(wasm.filter(x => x.length && (x[0] != null || typeof x[1] === 'string')), (k, v) => {
|
244
244
|
if (Number.isNaN(v) || v === Infinity || v === -Infinity) return v.toString();
|
245
245
|
return v;
|
246
246
|
})
|
247
|
-
.replace(/\["alloc","(.*?)",(.*?)\]/g, (_, reason, valtype) => `
|
247
|
+
.replace(/\["alloc","(.*?)",(.*?)\]/g, (_, reason, valtype) => `[${valtype === Valtype.i32 ? Opcodes.i32_const : Opcodes.f64_const},allocPage(_,'${reason}')]`)
|
248
248
|
.replace(/\["global",(.*?),"(.*?)",(.*?)\]/g, (_, opcode, name, valtype) => `...glbl(${opcode},'${name}',${valtype})`)
|
249
249
|
.replace(/\"local","(.*?)",(.*?)\]/g, (_, name, valtype) => `loc('${name}',${valtype})]`)
|
250
250
|
.replace(/\[16,"(.*?)"]/g, (_, name) => `[16,builtin('${name}')]`)
|
@@ -278,7 +278,7 @@ ${funcs.map(x => {
|
|
278
278
|
const name = x.name.includes('#') ? `['${x.name}']` : `.${x.name}`;
|
279
279
|
|
280
280
|
const returnTypes = [...(x.returnTypes ?? [])].filter(x => ![ TYPES.undefined, TYPES.number, TYPES.boolean, TYPES.function ].includes(x));
|
281
|
-
return `
|
281
|
+
return `x${name} = {
|
282
282
|
wasm:${rewriteWasm(x.wasm)},
|
283
283
|
params:${JSON.stringify(x.params)},typedParams:1,returns:${JSON.stringify(x.returns)},${x.returnType != null ? `returnType:${JSON.stringify(x.returnType)},` : ''}${returnTypes.length > 0 ? `returnTypes:${JSON.stringify(returnTypes)},` : ''}jsLength:${x.jsLength},
|
284
284
|
locals:${JSON.stringify(locals.slice(x.params.length).map(x => x[1].type))},localNames:${JSON.stringify(locals.map(x => x[0]))},
|
package/compiler/wrap.js
CHANGED
@@ -586,7 +586,10 @@ export default (source, module = undefined, print = str => process.stdout.write(
|
|
586
586
|
}
|
587
587
|
|
588
588
|
times.push(performance.now() - t2);
|
589
|
-
if (Prefs.profileCompiler
|
589
|
+
if (Prefs.profileCompiler) {
|
590
|
+
if (globalThis.onProgress) globalThis.onProgress('instantiated', times[1]);
|
591
|
+
else console.log(`instantiated in ${times[1].toFixed(2)}ms`);
|
592
|
+
}
|
590
593
|
|
591
594
|
const exports = {};
|
592
595
|
const rawValues = Prefs.d;
|