porffor 0.28.6 → 0.28.7
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/assemble.js +8 -4
- package/compiler/builtins/z_weakmap.ts +10 -3
- package/compiler/builtins/z_weakset.ts +10 -3
- package/compiler/builtins.js +4 -2
- package/compiler/builtins_precompiled.js +433 -433
- package/compiler/codegen.js +97 -20
- package/compiler/precompile.js +2 -2
- package/package.json +1 -1
- package/runner/index.js +1 -1
package/compiler/codegen.js
CHANGED
@@ -1976,6 +1976,52 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1976
1976
|
|
1977
1977
|
let out = [];
|
1978
1978
|
if (protoName) {
|
1979
|
+
if (protoName === 'call') {
|
1980
|
+
const valTmp = localTmp(scope, '#call_val');
|
1981
|
+
const typeTmp = localTmp(scope, '#call_type', Valtype.i32);
|
1982
|
+
|
1983
|
+
return generateCall(scope, {
|
1984
|
+
type: 'CallExpression',
|
1985
|
+
callee: target,
|
1986
|
+
arguments: decl.arguments.slice(1),
|
1987
|
+
_thisWasm: [
|
1988
|
+
...generate(scope, decl.arguments[0] ?? DEFAULT_VALUE()),
|
1989
|
+
[ Opcodes.local_tee, valTmp ],
|
1990
|
+
...getNodeType(scope, decl.arguments[0] ?? DEFAULT_VALUE()),
|
1991
|
+
[ Opcodes.local_tee, typeTmp ],
|
1992
|
+
|
1993
|
+
// check not undefined or null
|
1994
|
+
// todo: technically this should be allowed sometimes but for now, never
|
1995
|
+
...nullish(scope,
|
1996
|
+
[ [ Opcodes.local_get, valTmp ] ],
|
1997
|
+
[ [ Opcodes.local_get, typeTmp ] ],
|
1998
|
+
false, true),
|
1999
|
+
[ Opcodes.if, Blocktype.void ],
|
2000
|
+
...internalThrow(scope, 'TypeError', `Cannot use undefined or null as 'this'`),
|
2001
|
+
[ Opcodes.end ],
|
2002
|
+
],
|
2003
|
+
_thisWasmComponents: {
|
2004
|
+
_callValue: [
|
2005
|
+
...generate(scope, decl.arguments[0] ?? DEFAULT_VALUE()),
|
2006
|
+
[ Opcodes.local_tee, valTmp ],
|
2007
|
+
...getNodeType(scope, decl.arguments[0] ?? DEFAULT_VALUE()),
|
2008
|
+
[ Opcodes.local_set, typeTmp ],
|
2009
|
+
|
2010
|
+
// check not undefined or null
|
2011
|
+
// todo: technically this should be allowed sometimes but for now, never
|
2012
|
+
...nullish(scope,
|
2013
|
+
[ [ Opcodes.local_get, valTmp ] ],
|
2014
|
+
[ [ Opcodes.local_get, typeTmp ] ],
|
2015
|
+
false, true),
|
2016
|
+
[ Opcodes.if, Blocktype.void ],
|
2017
|
+
...internalThrow(scope, 'TypeError', `Cannot use undefined or null as 'this'`),
|
2018
|
+
[ Opcodes.end ],
|
2019
|
+
],
|
2020
|
+
_callType: [ [ Opcodes.local_get, typeTmp ] ]
|
2021
|
+
}
|
2022
|
+
});
|
2023
|
+
}
|
2024
|
+
|
1979
2025
|
if (['search'].includes(protoName)) {
|
1980
2026
|
const regex = decl.arguments[0]?.regex?.pattern;
|
1981
2027
|
if (!regex) return [
|
@@ -2024,6 +2070,15 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
2024
2070
|
[ Opcodes.local_set, localTmp(scope, '#proto_target#type', Valtype.i32) ],
|
2025
2071
|
);
|
2026
2072
|
|
2073
|
+
if (decl._thisWasm) {
|
2074
|
+
// after to still generate original target
|
2075
|
+
out.push(
|
2076
|
+
...decl._thisWasm,
|
2077
|
+
[ Opcodes.local_set, localTmp(scope, '#proto_target#type', Valtype.i32) ],
|
2078
|
+
[ Opcodes.local_set, localTmp(scope, '#proto_target') ]
|
2079
|
+
);
|
2080
|
+
}
|
2081
|
+
|
2027
2082
|
for (const x of builtinProtoCands) {
|
2028
2083
|
const type = TYPES[x.split('_prototype_')[0].slice(2).toLowerCase()];
|
2029
2084
|
if (type == null) continue;
|
@@ -2137,7 +2192,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
2137
2192
|
return [
|
2138
2193
|
...out,
|
2139
2194
|
|
2140
|
-
...typeSwitch(scope,
|
2195
|
+
...typeSwitch(scope, getNodeType(scope, target), {
|
2141
2196
|
...protoBC,
|
2142
2197
|
|
2143
2198
|
// TODO: error better
|
@@ -2232,7 +2287,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
2232
2287
|
let locals = [];
|
2233
2288
|
|
2234
2289
|
if (indirectMode === 'vararg') {
|
2235
|
-
const minArgc = Prefs.indirectCallMinArgc ??
|
2290
|
+
const minArgc = Prefs.indirectCallMinArgc ?? 5;
|
2236
2291
|
|
2237
2292
|
if (args.length < minArgc) {
|
2238
2293
|
args = args.concat(new Array(minArgc - args.length).fill(DEFAULT_VALUE()));
|
@@ -2242,14 +2297,6 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
2242
2297
|
for (let i = 0; i < args.length; i++) {
|
2243
2298
|
const arg = args[i];
|
2244
2299
|
out = out.concat(generate(scope, arg));
|
2245
|
-
|
2246
|
-
if (valtypeBinary !== Valtype.i32 && (
|
2247
|
-
(builtinFuncs[name] && builtinFuncs[name].params[i * (typedParams ? 2 : 1)] === Valtype.i32) ||
|
2248
|
-
(importedFuncs[name] && name.startsWith('profile'))
|
2249
|
-
)) {
|
2250
|
-
out.push(Opcodes.i32_to);
|
2251
|
-
}
|
2252
|
-
|
2253
2300
|
out = out.concat(getNodeType(scope, arg));
|
2254
2301
|
|
2255
2302
|
if (indirectMode === 'vararg') {
|
@@ -2410,7 +2457,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
2410
2457
|
[ Opcodes.local_get, funcLocal ],
|
2411
2458
|
...number(128, Valtype.i32),
|
2412
2459
|
[ Opcodes.i32_mul ],
|
2413
|
-
...number(
|
2460
|
+
...number(4, Valtype.i32),
|
2414
2461
|
[ Opcodes.i32_add ],
|
2415
2462
|
[ Opcodes.i32_load8_u, 0, ...unsignedLEB128(allocPage(scope, 'func lut') * pageSize), 'read func lut' ],
|
2416
2463
|
[ Opcodes.local_set, flags ],
|
@@ -2479,7 +2526,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
2479
2526
|
const internalProtoFunc = func && func.internal && func.name.includes('_prototype_');
|
2480
2527
|
if (!globalThis.precompile && internalProtoFunc && !decl._protoInternalCall) {
|
2481
2528
|
// just function called, not as prototype, add this to start
|
2482
|
-
args.unshift(decl._thisWasm ?? createThisArg(scope, decl));
|
2529
|
+
args.unshift(decl._thisWasmComponents ?? decl._thisWasm ?? createThisArg(scope, decl));
|
2483
2530
|
}
|
2484
2531
|
|
2485
2532
|
if (func && func.constr) {
|
@@ -2521,7 +2568,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
2521
2568
|
continue;
|
2522
2569
|
}
|
2523
2570
|
|
2524
|
-
out = out.concat(generate(scope, arg));
|
2571
|
+
out = out.concat(arg._callValue ?? generate(scope, arg));
|
2525
2572
|
|
2526
2573
|
// todo: this should be used instead of the too many args thing above (by removing that)
|
2527
2574
|
if (i >= paramCount) {
|
@@ -2542,7 +2589,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
2542
2589
|
out.push(Opcodes.i32_from);
|
2543
2590
|
}
|
2544
2591
|
|
2545
|
-
if (typedParams) out = out.concat(getNodeType(scope, arg));
|
2592
|
+
if (typedParams) out = out.concat(arg._callType ?? getNodeType(scope, arg));
|
2546
2593
|
}
|
2547
2594
|
|
2548
2595
|
out.push([ Opcodes.call, idx ]);
|
@@ -5043,13 +5090,23 @@ const countParams = (func, name = undefined) => {
|
|
5043
5090
|
}
|
5044
5091
|
if (func.argc) return func.argc;
|
5045
5092
|
|
5093
|
+
name ??= func.name;
|
5046
5094
|
let params = func.params.length;
|
5047
5095
|
if (func.constr) params -= 4;
|
5048
|
-
if (!
|
5096
|
+
if (!builtinFuncs[name] || builtinFuncs[name]?.typedParams) params = Math.floor(params / 2);
|
5049
5097
|
|
5050
5098
|
return func.argc = params;
|
5051
5099
|
};
|
5052
5100
|
|
5101
|
+
const countLength = (func, name = undefined) => {
|
5102
|
+
name ??= func.name;
|
5103
|
+
|
5104
|
+
let count = countParams(func, name);
|
5105
|
+
if (builtinFuncs[name] && name.includes('_prototype_')) count--;
|
5106
|
+
|
5107
|
+
return count;
|
5108
|
+
};
|
5109
|
+
|
5053
5110
|
const generateMember = (scope, decl, _global, _name, _objectWasm = undefined) => {
|
5054
5111
|
const name = decl.object.name;
|
5055
5112
|
|
@@ -5068,9 +5125,9 @@ const generateMember = (scope, decl, _global, _name, _objectWasm = undefined) =>
|
|
5068
5125
|
// todo: support optional
|
5069
5126
|
|
5070
5127
|
const func = funcs.find(x => x.name === name);
|
5071
|
-
if (func) return withType(scope, number(
|
5128
|
+
if (func) return withType(scope, number(countLength(func, name)), TYPES.number);
|
5072
5129
|
|
5073
|
-
if (Object.hasOwn(builtinFuncs, name)) return withType(scope, number(
|
5130
|
+
if (Object.hasOwn(builtinFuncs, name)) return withType(scope, number(countLength(builtinFuncs[name], name)), TYPES.number);
|
5074
5131
|
if (Object.hasOwn(importedFuncs, name)) return withType(scope, number(importedFuncs[name].params.length ?? importedFuncs[name].params), TYPES.number);
|
5075
5132
|
if (Object.hasOwn(internalConstrs, name)) return withType(scope, number(internalConstrs[name].length ?? 0), TYPES.number);
|
5076
5133
|
|
@@ -5402,7 +5459,7 @@ const objectHack = node => {
|
|
5402
5459
|
if (node.computed || node.optional) return;
|
5403
5460
|
|
5404
5461
|
// hack: block these properties as they can be accessed on functions
|
5405
|
-
if (node.property.name == 'length' || node.property.name == 'name') return;
|
5462
|
+
if (node.property.name == 'length' || node.property.name == 'name' || node.property.name == 'call') return;
|
5406
5463
|
|
5407
5464
|
let objectName = node.object.name;
|
5408
5465
|
|
@@ -5481,6 +5538,7 @@ const generateFunc = (scope, decl) => {
|
|
5481
5538
|
}
|
5482
5539
|
}
|
5483
5540
|
|
5541
|
+
const prelude = [];
|
5484
5542
|
const defaultValues = {};
|
5485
5543
|
for (let i = 0; i < params.length; i++) {
|
5486
5544
|
let name;
|
@@ -5508,7 +5566,27 @@ const generateFunc = (scope, decl) => {
|
|
5508
5566
|
|
5509
5567
|
allocVar(func, name, false);
|
5510
5568
|
if (typedInput && params[i].typeAnnotation) {
|
5511
|
-
|
5569
|
+
const typeAnno = extractTypeAnnotation(params[i]);
|
5570
|
+
addVarMetadata(func, name, false, typeAnno);
|
5571
|
+
|
5572
|
+
// automatically add throws if unexpected this type to builtins
|
5573
|
+
if (globalThis.precompile && i === 0 && func.name.includes('_prototype_') && [
|
5574
|
+
TYPES.date, TYPES.number, TYPES.promise, TYPES.symbol,
|
5575
|
+
TYPES.set, TYPES.map,
|
5576
|
+
TYPES.weakref, TYPES.weakset, TYPES.weakmap,
|
5577
|
+
TYPES.arraybuffer, TYPES.sharedarraybuffer, TYPES.dataview
|
5578
|
+
].includes(typeAnno.type)) {
|
5579
|
+
prelude.push(
|
5580
|
+
[ Opcodes.local_get, i * 2 + 1 ],
|
5581
|
+
...number(typeAnno.type, Valtype.i32),
|
5582
|
+
[ Opcodes.i32_ne ],
|
5583
|
+
[ Opcodes.if, Blocktype.void ],
|
5584
|
+
...internalThrow(func, 'TypeError', `${unhackName(func.name)} expects 'this' to be a ${TYPE_NAMES[typeAnno.type]}`),
|
5585
|
+
[ Opcodes.end ]
|
5586
|
+
);
|
5587
|
+
}
|
5588
|
+
|
5589
|
+
// todo: if string, try converting to it to one
|
5512
5590
|
}
|
5513
5591
|
}
|
5514
5592
|
|
@@ -5523,7 +5601,6 @@ const generateFunc = (scope, decl) => {
|
|
5523
5601
|
};
|
5524
5602
|
}
|
5525
5603
|
|
5526
|
-
const prelude = [];
|
5527
5604
|
for (const x in defaultValues) {
|
5528
5605
|
prelude.push(
|
5529
5606
|
...getType(func, x),
|
package/compiler/precompile.js
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
import { Opcodes, Valtype } from './wasmSpec.js';
|
2
|
-
import { read_unsignedLEB128 } from './encoding.js';
|
2
|
+
import { read_signedLEB128, read_unsignedLEB128 } from './encoding.js';
|
3
3
|
import { TYPES } from './types.js';
|
4
4
|
|
5
5
|
import process from 'node:process';
|
@@ -151,7 +151,7 @@ const compile = async (file, _funcs) => {
|
|
151
151
|
|
152
152
|
|
153
153
|
if (y[0] === Opcodes.i32_const && n[0] === Opcodes.throw) {
|
154
|
-
const id = y
|
154
|
+
const id = read_signedLEB128(y.slice(1));
|
155
155
|
y.splice(0, 10, 'throw', exceptions[id].constructor, exceptions[id].message);
|
156
156
|
|
157
157
|
// remove throw inst
|
package/package.json
CHANGED