porffor 0.28.6 → 0.28.8
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 +124 -42
- 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 ]);
|
@@ -2976,16 +3023,12 @@ const generateVar = (scope, decl) => {
|
|
2976
3023
|
type: 'VariableDeclarator',
|
2977
3024
|
id: e.left,
|
2978
3025
|
init: {
|
2979
|
-
type: '
|
2980
|
-
|
2981
|
-
|
2982
|
-
|
2983
|
-
|
2984
|
-
|
2985
|
-
computed: true
|
2986
|
-
},
|
2987
|
-
right: e.right
|
2988
|
-
}
|
3026
|
+
type: 'MemberExpression',
|
3027
|
+
object: { type: 'Identifier', name: tmpName },
|
3028
|
+
property: { type: 'Literal', value: i },
|
3029
|
+
computed: true
|
3030
|
+
},
|
3031
|
+
_default: e.right
|
2989
3032
|
});
|
2990
3033
|
|
2991
3034
|
break;
|
@@ -3018,7 +3061,8 @@ const generateVar = (scope, decl) => {
|
|
3018
3061
|
declarations: [{
|
3019
3062
|
type: 'VariableDeclarator',
|
3020
3063
|
id: { type: 'Identifier', name: tmpName },
|
3021
|
-
init: x.init
|
3064
|
+
init: x.init,
|
3065
|
+
_default: x._default
|
3022
3066
|
}],
|
3023
3067
|
kind: decl.kind,
|
3024
3068
|
_global: false
|
@@ -3063,16 +3107,12 @@ const generateVar = (scope, decl) => {
|
|
3063
3107
|
type: 'VariableDeclarator',
|
3064
3108
|
id: prop.value.left,
|
3065
3109
|
init: {
|
3066
|
-
type: '
|
3067
|
-
|
3068
|
-
|
3069
|
-
|
3070
|
-
|
3071
|
-
|
3072
|
-
computed: prop.computed
|
3073
|
-
},
|
3074
|
-
right: prop.value.right
|
3075
|
-
}
|
3110
|
+
type: 'MemberExpression',
|
3111
|
+
object: { type: 'Identifier', name: tmpName },
|
3112
|
+
property: prop.key,
|
3113
|
+
computed: prop.computed
|
3114
|
+
},
|
3115
|
+
_default: prop.value.right
|
3076
3116
|
});
|
3077
3117
|
} else {
|
3078
3118
|
decls.push({
|
@@ -3097,7 +3137,8 @@ const generateVar = (scope, decl) => {
|
|
3097
3137
|
declarations: [{
|
3098
3138
|
type: 'VariableDeclarator',
|
3099
3139
|
id: { type: 'Identifier', name: tmpName },
|
3100
|
-
init: x.init
|
3140
|
+
init: x.init,
|
3141
|
+
_default: x._default
|
3101
3142
|
}],
|
3102
3143
|
kind: decl.kind,
|
3103
3144
|
_global: false
|
@@ -3179,6 +3220,17 @@ const generateVar = (scope, decl) => {
|
|
3179
3220
|
|
3180
3221
|
out = out.concat(newOut);
|
3181
3222
|
|
3223
|
+
if (x._default) {
|
3224
|
+
out.push(
|
3225
|
+
...typeIsOneOf(getType(scope, name), [ TYPES.undefined, TYPES.empty ]),
|
3226
|
+
[ Opcodes.if, Blocktype.void ],
|
3227
|
+
...generate(scope, x._default, global, name),
|
3228
|
+
[ global ? Opcodes.global_set : Opcodes.local_set, idx ],
|
3229
|
+
...setType(scope, name, getNodeType(scope, x._default)),
|
3230
|
+
[ Opcodes.end ],
|
3231
|
+
);
|
3232
|
+
}
|
3233
|
+
|
3182
3234
|
if (globalThis.precompile && global) {
|
3183
3235
|
scope.globalInits ??= {};
|
3184
3236
|
scope.globalInits[name] = newOut;
|
@@ -5043,13 +5095,23 @@ const countParams = (func, name = undefined) => {
|
|
5043
5095
|
}
|
5044
5096
|
if (func.argc) return func.argc;
|
5045
5097
|
|
5098
|
+
name ??= func.name;
|
5046
5099
|
let params = func.params.length;
|
5047
5100
|
if (func.constr) params -= 4;
|
5048
|
-
if (!
|
5101
|
+
if (!builtinFuncs[name] || builtinFuncs[name]?.typedParams) params = Math.floor(params / 2);
|
5049
5102
|
|
5050
5103
|
return func.argc = params;
|
5051
5104
|
};
|
5052
5105
|
|
5106
|
+
const countLength = (func, name = undefined) => {
|
5107
|
+
name ??= func.name;
|
5108
|
+
|
5109
|
+
let count = countParams(func, name);
|
5110
|
+
if (builtinFuncs[name] && name.includes('_prototype_')) count--;
|
5111
|
+
|
5112
|
+
return count;
|
5113
|
+
};
|
5114
|
+
|
5053
5115
|
const generateMember = (scope, decl, _global, _name, _objectWasm = undefined) => {
|
5054
5116
|
const name = decl.object.name;
|
5055
5117
|
|
@@ -5068,9 +5130,9 @@ const generateMember = (scope, decl, _global, _name, _objectWasm = undefined) =>
|
|
5068
5130
|
// todo: support optional
|
5069
5131
|
|
5070
5132
|
const func = funcs.find(x => x.name === name);
|
5071
|
-
if (func) return withType(scope, number(
|
5133
|
+
if (func) return withType(scope, number(countLength(func, name)), TYPES.number);
|
5072
5134
|
|
5073
|
-
if (Object.hasOwn(builtinFuncs, name)) return withType(scope, number(
|
5135
|
+
if (Object.hasOwn(builtinFuncs, name)) return withType(scope, number(countLength(builtinFuncs[name], name)), TYPES.number);
|
5074
5136
|
if (Object.hasOwn(importedFuncs, name)) return withType(scope, number(importedFuncs[name].params.length ?? importedFuncs[name].params), TYPES.number);
|
5075
5137
|
if (Object.hasOwn(internalConstrs, name)) return withType(scope, number(internalConstrs[name].length ?? 0), TYPES.number);
|
5076
5138
|
|
@@ -5402,7 +5464,7 @@ const objectHack = node => {
|
|
5402
5464
|
if (node.computed || node.optional) return;
|
5403
5465
|
|
5404
5466
|
// hack: block these properties as they can be accessed on functions
|
5405
|
-
if (node.property.name == 'length' || node.property.name == 'name') return;
|
5467
|
+
if (node.property.name == 'length' || node.property.name == 'name' || node.property.name == 'call') return;
|
5406
5468
|
|
5407
5469
|
let objectName = node.object.name;
|
5408
5470
|
|
@@ -5481,6 +5543,7 @@ const generateFunc = (scope, decl) => {
|
|
5481
5543
|
}
|
5482
5544
|
}
|
5483
5545
|
|
5546
|
+
const prelude = [];
|
5484
5547
|
const defaultValues = {};
|
5485
5548
|
for (let i = 0; i < params.length; i++) {
|
5486
5549
|
let name;
|
@@ -5508,7 +5571,27 @@ const generateFunc = (scope, decl) => {
|
|
5508
5571
|
|
5509
5572
|
allocVar(func, name, false);
|
5510
5573
|
if (typedInput && params[i].typeAnnotation) {
|
5511
|
-
|
5574
|
+
const typeAnno = extractTypeAnnotation(params[i]);
|
5575
|
+
addVarMetadata(func, name, false, typeAnno);
|
5576
|
+
|
5577
|
+
// automatically add throws if unexpected this type to builtins
|
5578
|
+
if (globalThis.precompile && i === 0 && func.name.includes('_prototype_') && [
|
5579
|
+
TYPES.date, TYPES.number, TYPES.promise, TYPES.symbol,
|
5580
|
+
TYPES.set, TYPES.map,
|
5581
|
+
TYPES.weakref, TYPES.weakset, TYPES.weakmap,
|
5582
|
+
TYPES.arraybuffer, TYPES.sharedarraybuffer, TYPES.dataview
|
5583
|
+
].includes(typeAnno.type)) {
|
5584
|
+
prelude.push(
|
5585
|
+
[ Opcodes.local_get, i * 2 + 1 ],
|
5586
|
+
...number(typeAnno.type, Valtype.i32),
|
5587
|
+
[ Opcodes.i32_ne ],
|
5588
|
+
[ Opcodes.if, Blocktype.void ],
|
5589
|
+
...internalThrow(func, 'TypeError', `${unhackName(func.name)} expects 'this' to be a ${TYPE_NAMES[typeAnno.type]}`),
|
5590
|
+
[ Opcodes.end ]
|
5591
|
+
);
|
5592
|
+
}
|
5593
|
+
|
5594
|
+
// todo: if string, try converting to it to one
|
5512
5595
|
}
|
5513
5596
|
}
|
5514
5597
|
|
@@ -5523,7 +5606,6 @@ const generateFunc = (scope, decl) => {
|
|
5523
5606
|
};
|
5524
5607
|
}
|
5525
5608
|
|
5526
|
-
const prelude = [];
|
5527
5609
|
for (const x in defaultValues) {
|
5528
5610
|
prelude.push(
|
5529
5611
|
...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