porffor 0.28.5 → 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/2c.js +8 -3
- package/compiler/assemble.js +8 -4
- package/compiler/builtins/number.ts +26 -4
- package/compiler/builtins/stringtonumber.ts +2 -0
- 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 +435 -435
- package/compiler/codegen.js +134 -23
- package/compiler/precompile.js +2 -2
- package/package.json +1 -1
- package/runner/index.js +1 -1
package/compiler/codegen.js
CHANGED
@@ -1848,12 +1848,33 @@ const createThisArg = (scope, decl, knownThis = undefined) => {
|
|
1848
1848
|
...number(TYPES.object, Valtype.i32)
|
1849
1849
|
];
|
1850
1850
|
} else {
|
1851
|
+
const name = mapName(decl.callee?.name);
|
1852
|
+
if (name && name.startsWith('__') && name.includes('_prototype_')) {
|
1853
|
+
// todo: this should just be same as decl._new
|
1854
|
+
// but we do not support prototype, constructor, etc yet
|
1855
|
+
// so do `this` as `new Type()` instead
|
1856
|
+
const node = {
|
1857
|
+
type: 'NewExpression',
|
1858
|
+
callee: {
|
1859
|
+
type: 'Identifier',
|
1860
|
+
name: name.slice(2, name.indexOf('_', 2))
|
1861
|
+
},
|
1862
|
+
arguments: [],
|
1863
|
+
_new: true
|
1864
|
+
};
|
1865
|
+
|
1866
|
+
return [
|
1867
|
+
...generateCall(scope, node),
|
1868
|
+
...getNodeType(scope, node)
|
1869
|
+
];
|
1870
|
+
}
|
1871
|
+
|
1851
1872
|
return [
|
1852
1873
|
...generate(scope, { type: 'Identifier', name: 'globalThis' }),
|
1853
1874
|
...getType(scope, 'globalThis')
|
1854
1875
|
];
|
1855
1876
|
}
|
1856
|
-
}
|
1877
|
+
};
|
1857
1878
|
|
1858
1879
|
const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
1859
1880
|
let name = mapName(decl.callee.name);
|
@@ -1955,6 +1976,52 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1955
1976
|
|
1956
1977
|
let out = [];
|
1957
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
|
+
|
1958
2025
|
if (['search'].includes(protoName)) {
|
1959
2026
|
const regex = decl.arguments[0]?.regex?.pattern;
|
1960
2027
|
if (!regex) return [
|
@@ -2003,6 +2070,15 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
2003
2070
|
[ Opcodes.local_set, localTmp(scope, '#proto_target#type', Valtype.i32) ],
|
2004
2071
|
);
|
2005
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
|
+
|
2006
2082
|
for (const x of builtinProtoCands) {
|
2007
2083
|
const type = TYPES[x.split('_prototype_')[0].slice(2).toLowerCase()];
|
2008
2084
|
if (type == null) continue;
|
@@ -2116,7 +2192,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
2116
2192
|
return [
|
2117
2193
|
...out,
|
2118
2194
|
|
2119
|
-
...typeSwitch(scope,
|
2195
|
+
...typeSwitch(scope, getNodeType(scope, target), {
|
2120
2196
|
...protoBC,
|
2121
2197
|
|
2122
2198
|
// TODO: error better
|
@@ -2211,7 +2287,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
2211
2287
|
let locals = [];
|
2212
2288
|
|
2213
2289
|
if (indirectMode === 'vararg') {
|
2214
|
-
const minArgc = Prefs.indirectCallMinArgc ??
|
2290
|
+
const minArgc = Prefs.indirectCallMinArgc ?? 5;
|
2215
2291
|
|
2216
2292
|
if (args.length < minArgc) {
|
2217
2293
|
args = args.concat(new Array(minArgc - args.length).fill(DEFAULT_VALUE()));
|
@@ -2221,14 +2297,6 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
2221
2297
|
for (let i = 0; i < args.length; i++) {
|
2222
2298
|
const arg = args[i];
|
2223
2299
|
out = out.concat(generate(scope, arg));
|
2224
|
-
|
2225
|
-
if (valtypeBinary !== Valtype.i32 && (
|
2226
|
-
(builtinFuncs[name] && builtinFuncs[name].params[i * (typedParams ? 2 : 1)] === Valtype.i32) ||
|
2227
|
-
(importedFuncs[name] && name.startsWith('profile'))
|
2228
|
-
)) {
|
2229
|
-
out.push(Opcodes.i32_to);
|
2230
|
-
}
|
2231
|
-
|
2232
2300
|
out = out.concat(getNodeType(scope, arg));
|
2233
2301
|
|
2234
2302
|
if (indirectMode === 'vararg') {
|
@@ -2389,7 +2457,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
2389
2457
|
[ Opcodes.local_get, funcLocal ],
|
2390
2458
|
...number(128, Valtype.i32),
|
2391
2459
|
[ Opcodes.i32_mul ],
|
2392
|
-
...number(
|
2460
|
+
...number(4, Valtype.i32),
|
2393
2461
|
[ Opcodes.i32_add ],
|
2394
2462
|
[ Opcodes.i32_load8_u, 0, ...unsignedLEB128(allocPage(scope, 'func lut') * pageSize), 'read func lut' ],
|
2395
2463
|
[ Opcodes.local_set, flags ],
|
@@ -2454,13 +2522,19 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
2454
2522
|
return internalThrow(scope, 'TypeError', `${unhackName(name)} is not a constructor`, true);
|
2455
2523
|
}
|
2456
2524
|
|
2525
|
+
let args = [...decl.arguments];
|
2526
|
+
const internalProtoFunc = func && func.internal && func.name.includes('_prototype_');
|
2527
|
+
if (!globalThis.precompile && internalProtoFunc && !decl._protoInternalCall) {
|
2528
|
+
// just function called, not as prototype, add this to start
|
2529
|
+
args.unshift(decl._thisWasmComponents ?? decl._thisWasm ?? createThisArg(scope, decl));
|
2530
|
+
}
|
2531
|
+
|
2457
2532
|
if (func && func.constr) {
|
2458
2533
|
out.push(...(decl._newTargetWasm ?? createNewTarget(scope, decl, idx - importedFuncs.length)));
|
2459
2534
|
out.push(...(decl._thisWasm ?? createThisArg(scope, decl)));
|
2460
2535
|
paramOffset += 4;
|
2461
2536
|
}
|
2462
2537
|
|
2463
|
-
let args = [...decl.arguments];
|
2464
2538
|
if (func && !func.hasRestArgument && args.length < paramCount) {
|
2465
2539
|
// too little args, push undefineds
|
2466
2540
|
args = args.concat(new Array(paramCount - args.length).fill(DEFAULT_VALUE()));
|
@@ -2488,7 +2562,13 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
2488
2562
|
|
2489
2563
|
for (let i = 0; i < args.length; i++) {
|
2490
2564
|
const arg = args[i];
|
2491
|
-
|
2565
|
+
if (Array.isArray(arg)) {
|
2566
|
+
// if wasm, just append it
|
2567
|
+
out = out.concat(arg);
|
2568
|
+
continue;
|
2569
|
+
}
|
2570
|
+
|
2571
|
+
out = out.concat(arg._callValue ?? generate(scope, arg));
|
2492
2572
|
|
2493
2573
|
// todo: this should be used instead of the too many args thing above (by removing that)
|
2494
2574
|
if (i >= paramCount) {
|
@@ -2509,7 +2589,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
2509
2589
|
out.push(Opcodes.i32_from);
|
2510
2590
|
}
|
2511
2591
|
|
2512
|
-
if (typedParams) out = out.concat(getNodeType(scope, arg));
|
2592
|
+
if (typedParams) out = out.concat(arg._callType ?? getNodeType(scope, arg));
|
2513
2593
|
}
|
2514
2594
|
|
2515
2595
|
out.push([ Opcodes.call, idx ]);
|
@@ -2929,7 +3009,8 @@ const generateVar = (scope, decl) => {
|
|
2929
3009
|
object: { type: 'Identifier', name: tmpName, },
|
2930
3010
|
property: { type: 'Identifier', name: 'length', }
|
2931
3011
|
}
|
2932
|
-
]
|
3012
|
+
],
|
3013
|
+
_protoInternalCall: true
|
2933
3014
|
}
|
2934
3015
|
});
|
2935
3016
|
}
|
@@ -5009,13 +5090,23 @@ const countParams = (func, name = undefined) => {
|
|
5009
5090
|
}
|
5010
5091
|
if (func.argc) return func.argc;
|
5011
5092
|
|
5093
|
+
name ??= func.name;
|
5012
5094
|
let params = func.params.length;
|
5013
5095
|
if (func.constr) params -= 4;
|
5014
|
-
if (!
|
5096
|
+
if (!builtinFuncs[name] || builtinFuncs[name]?.typedParams) params = Math.floor(params / 2);
|
5015
5097
|
|
5016
5098
|
return func.argc = params;
|
5017
5099
|
};
|
5018
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
|
+
|
5019
5110
|
const generateMember = (scope, decl, _global, _name, _objectWasm = undefined) => {
|
5020
5111
|
const name = decl.object.name;
|
5021
5112
|
|
@@ -5034,9 +5125,9 @@ const generateMember = (scope, decl, _global, _name, _objectWasm = undefined) =>
|
|
5034
5125
|
// todo: support optional
|
5035
5126
|
|
5036
5127
|
const func = funcs.find(x => x.name === name);
|
5037
|
-
if (func) return withType(scope, number(
|
5128
|
+
if (func) return withType(scope, number(countLength(func, name)), TYPES.number);
|
5038
5129
|
|
5039
|
-
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);
|
5040
5131
|
if (Object.hasOwn(importedFuncs, name)) return withType(scope, number(importedFuncs[name].params.length ?? importedFuncs[name].params), TYPES.number);
|
5041
5132
|
if (Object.hasOwn(internalConstrs, name)) return withType(scope, number(internalConstrs[name].length ?? 0), TYPES.number);
|
5042
5133
|
|
@@ -5368,7 +5459,7 @@ const objectHack = node => {
|
|
5368
5459
|
if (node.computed || node.optional) return;
|
5369
5460
|
|
5370
5461
|
// hack: block these properties as they can be accessed on functions
|
5371
|
-
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;
|
5372
5463
|
|
5373
5464
|
let objectName = node.object.name;
|
5374
5465
|
|
@@ -5447,6 +5538,7 @@ const generateFunc = (scope, decl) => {
|
|
5447
5538
|
}
|
5448
5539
|
}
|
5449
5540
|
|
5541
|
+
const prelude = [];
|
5450
5542
|
const defaultValues = {};
|
5451
5543
|
for (let i = 0; i < params.length; i++) {
|
5452
5544
|
let name;
|
@@ -5474,7 +5566,27 @@ const generateFunc = (scope, decl) => {
|
|
5474
5566
|
|
5475
5567
|
allocVar(func, name, false);
|
5476
5568
|
if (typedInput && params[i].typeAnnotation) {
|
5477
|
-
|
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
|
5478
5590
|
}
|
5479
5591
|
}
|
5480
5592
|
|
@@ -5489,7 +5601,6 @@ const generateFunc = (scope, decl) => {
|
|
5489
5601
|
};
|
5490
5602
|
}
|
5491
5603
|
|
5492
|
-
const prelude = [];
|
5493
5604
|
for (const x in defaultValues) {
|
5494
5605
|
prelude.push(
|
5495
5606
|
...getType(func, x),
|
@@ -5539,7 +5650,7 @@ const generateFunc = (scope, decl) => {
|
|
5539
5650
|
|
5540
5651
|
if (lastInst[0] === Opcodes.end || lastInst[0] === Opcodes.local_set || lastInst[0] === Opcodes.global_set) {
|
5541
5652
|
if (lastInst[0] === Opcodes.local_set && lastInst[1] === func.locals['#last_type'].idx) {
|
5542
|
-
func.wasm.splice(
|
5653
|
+
func.wasm.splice(func.wasm.length - 1, 1);
|
5543
5654
|
} else {
|
5544
5655
|
func.returns = [];
|
5545
5656
|
}
|
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