porffor 0.24.12 → 0.24.14
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 +4 -8
- package/compiler/builtins/_internal_object.ts +30 -1
- package/compiler/builtins/arraybuffer.ts +1 -1
- package/compiler/builtins/console.ts +3 -3
- package/compiler/builtins.js +15 -0
- package/compiler/builtins_objects.js +2 -0
- package/compiler/builtins_precompiled.js +254 -254
- package/compiler/codegen.js +217 -95
- package/compiler/precompile.js +3 -1
- package/package.json +1 -1
- package/runner/index.js +1 -1
package/compiler/codegen.js
CHANGED
@@ -91,6 +91,9 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
|
|
91
91
|
case 'NewExpression':
|
92
92
|
return cacheAst(decl, generateNew(scope, decl, global, name));
|
93
93
|
|
94
|
+
case 'ThisExpression':
|
95
|
+
return cacheAst(decl, generateThis(scope, decl, global, name));
|
96
|
+
|
94
97
|
case 'Literal':
|
95
98
|
return cacheAst(decl, generateLiteral(scope, decl, global, name));
|
96
99
|
|
@@ -351,22 +354,33 @@ const generateIdent = (scope, decl) => {
|
|
351
354
|
};
|
352
355
|
|
353
356
|
const generateReturn = (scope, decl) => {
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
357
|
+
const arg = decl.argument ?? DEFAULT_VALUE();
|
358
|
+
|
359
|
+
const out = [];
|
360
|
+
if (
|
361
|
+
scope.constr && // only do this in constructors
|
362
|
+
!globalThis.precompile // skip in precompiled built-ins, we should not require this and handle it ourselves
|
363
|
+
) {
|
364
|
+
// ignore return value and return this if being constructed
|
365
|
+
out.push(
|
366
|
+
// ...truthy(scope, [ [ Opcodes.local_get, '#newtarget' ] ], [ [ Opcodes.local_get, '#newtarget#type' ] ], false, true),
|
367
|
+
[ Opcodes.local_get, '#newtarget' ],
|
368
|
+
Opcodes.i32_to_u,
|
369
|
+
[ Opcodes.if, Blocktype.void ],
|
370
|
+
[ Opcodes.local_get, '#this' ],
|
371
|
+
...(scope.returnType != null ? [] : [ [ Opcodes.local_get, '#this#type' ] ]),
|
372
|
+
[ Opcodes.return ],
|
373
|
+
[ Opcodes.end ]
|
374
|
+
);
|
363
375
|
}
|
364
376
|
|
365
|
-
|
366
|
-
...generate(scope,
|
367
|
-
...(scope.returnType != null ? [] : getNodeType(scope,
|
377
|
+
out.push(
|
378
|
+
...generate(scope, arg),
|
379
|
+
...(scope.returnType != null ? [] : getNodeType(scope, arg)),
|
368
380
|
[ Opcodes.return ]
|
369
|
-
|
381
|
+
);
|
382
|
+
|
383
|
+
return out;
|
370
384
|
};
|
371
385
|
|
372
386
|
const localTmp = (scope, name, type = valtypeBinary) => {
|
@@ -1303,26 +1317,6 @@ const asmFunc = (name, { wasm, params = [], typedParams = false, locals: localTy
|
|
1303
1317
|
funcs.table = true;
|
1304
1318
|
}
|
1305
1319
|
|
1306
|
-
if (constr) {
|
1307
|
-
func.params = [...func.params];
|
1308
|
-
func.params.unshift(Valtype.i32);
|
1309
|
-
|
1310
|
-
// move all locals +1 idx (sigh)
|
1311
|
-
func.localInd++;
|
1312
|
-
const locals = func.locals;
|
1313
|
-
for (const x in locals) {
|
1314
|
-
locals[x].idx++;
|
1315
|
-
}
|
1316
|
-
|
1317
|
-
locals['#newtarget'] = { idx: 0, type: Valtype.i32 };
|
1318
|
-
|
1319
|
-
for (const inst of wasm) {
|
1320
|
-
if (inst[0] === Opcodes.local_get || inst[0] === Opcodes.local_set || inst[0] === Opcodes.local_tee) {
|
1321
|
-
inst[1]++;
|
1322
|
-
}
|
1323
|
-
}
|
1324
|
-
}
|
1325
|
-
|
1326
1320
|
if (hasRestArgument) func.hasRestArgument = true;
|
1327
1321
|
|
1328
1322
|
func.wasm = wasm;
|
@@ -1605,6 +1599,22 @@ const getNodeType = (scope, node) => {
|
|
1605
1599
|
}
|
1606
1600
|
}
|
1607
1601
|
|
1602
|
+
if (node.type == 'ThisExpression') {
|
1603
|
+
if (!scope.constr) return getType(scope, 'globalThis');
|
1604
|
+
return [ [ Opcodes.local_get, '#this#type' ] ];
|
1605
|
+
}
|
1606
|
+
|
1607
|
+
if (node.type == 'MetaProperty') {
|
1608
|
+
switch (`${node.meta.name}.${node.property.name}`) {
|
1609
|
+
case 'new.target': {
|
1610
|
+
return [ [ Opcodes.local_get, '#newtarget#type' ] ];
|
1611
|
+
}
|
1612
|
+
|
1613
|
+
default:
|
1614
|
+
return todo(scope, `meta property object ${node.meta.name} is not supported yet`, true);
|
1615
|
+
}
|
1616
|
+
}
|
1617
|
+
|
1608
1618
|
if (scope.locals['#last_type']) return getLastType(scope);
|
1609
1619
|
|
1610
1620
|
// presume
|
@@ -1762,6 +1772,42 @@ const RTArrayUtil = {
|
|
1762
1772
|
]
|
1763
1773
|
};
|
1764
1774
|
|
1775
|
+
const createNewTarget = (scope, decl, idx) => {
|
1776
|
+
if (decl._new) {
|
1777
|
+
return [
|
1778
|
+
...number(idx),
|
1779
|
+
...number(TYPES.function, Valtype.i32)
|
1780
|
+
];
|
1781
|
+
}
|
1782
|
+
|
1783
|
+
return [
|
1784
|
+
...number(UNDEFINED),
|
1785
|
+
...number(TYPES.undefined, Valtype.i32)
|
1786
|
+
];
|
1787
|
+
};
|
1788
|
+
|
1789
|
+
const createThisArg = (scope, decl, getFunc, knownThis = undefined) => {
|
1790
|
+
if (knownThis) {
|
1791
|
+
// todo: check compliance
|
1792
|
+
return knownThis;
|
1793
|
+
}
|
1794
|
+
|
1795
|
+
if (decl._new) {
|
1796
|
+
// todo: created object should have .prototype = func.prototype
|
1797
|
+
// todo: created object should have .constructor = func
|
1798
|
+
return [
|
1799
|
+
// create an empty object
|
1800
|
+
...generateObject(scope, { properties: [] }),
|
1801
|
+
...number(TYPES.object, Valtype.i32)
|
1802
|
+
];
|
1803
|
+
} else {
|
1804
|
+
return [
|
1805
|
+
...generate(scope, { type: 'Identifier', name: 'globalThis' }),
|
1806
|
+
...getType(scope, 'globalThis')
|
1807
|
+
];
|
1808
|
+
}
|
1809
|
+
}
|
1810
|
+
|
1765
1811
|
const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
1766
1812
|
let name = mapName(decl.callee.name);
|
1767
1813
|
if (isFuncType(decl.callee.type)) { // iife
|
@@ -1978,7 +2024,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1978
2024
|
getI32: () => RTArrayUtil.getLengthI32(getPointer),
|
1979
2025
|
set: value => RTArrayUtil.setLength(getPointer, value),
|
1980
2026
|
setI32: value => RTArrayUtil.setLengthI32(getPointer, value)
|
1981
|
-
}, generate(scope, decl.arguments[0] ?? DEFAULT_VALUE), getNodeType(scope, decl.arguments[0] ?? DEFAULT_VALUE), protoLocal, protoLocal2, (length, itemType) => {
|
2027
|
+
}, generate(scope, decl.arguments[0] ?? DEFAULT_VALUE()), getNodeType(scope, decl.arguments[0] ?? DEFAULT_VALUE()), protoLocal, protoLocal2, (length, itemType) => {
|
1982
2028
|
return makeArray(scope, {
|
1983
2029
|
rawElements: new Array(length)
|
1984
2030
|
}, _global, _name, true, itemType, true);
|
@@ -2115,7 +2161,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
2115
2161
|
const minArgc = Prefs.indirectCallMinArgc ?? 3;
|
2116
2162
|
|
2117
2163
|
if (args.length < minArgc) {
|
2118
|
-
args = args.concat(new Array(minArgc - args.length).fill(DEFAULT_VALUE));
|
2164
|
+
args = args.concat(new Array(minArgc - args.length).fill(DEFAULT_VALUE()));
|
2119
2165
|
}
|
2120
2166
|
}
|
2121
2167
|
|
@@ -2182,6 +2228,26 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
2182
2228
|
const funcLocal = localTmp(scope, '#indirect_func', Valtype.i32);
|
2183
2229
|
const flags = localTmp(scope, '#indirect_flags', Valtype.i32);
|
2184
2230
|
|
2231
|
+
let knownThis = undefined;
|
2232
|
+
let getCalleeObj = undefined;
|
2233
|
+
let initCalleeObj = undefined;
|
2234
|
+
|
2235
|
+
// hack: this should be more thorough, Function.bind, etc.
|
2236
|
+
if (decl.callee.type == 'MemberExpression') {
|
2237
|
+
const callee = localTmp(scope, '#indirect_callee_obj', Valtype.f64);
|
2238
|
+
initCalleeObj = [
|
2239
|
+
...generate(scope, decl.callee.object),
|
2240
|
+
[ Opcodes.local_set, callee ]
|
2241
|
+
];
|
2242
|
+
getCalleeObj = [
|
2243
|
+
[ Opcodes.local_get, callee ]
|
2244
|
+
];
|
2245
|
+
knownThis = [
|
2246
|
+
[ Opcodes.local_get, callee ],
|
2247
|
+
...getNodeType(scope, decl.callee.object)
|
2248
|
+
];
|
2249
|
+
}
|
2250
|
+
|
2185
2251
|
const gen = argc => {
|
2186
2252
|
const argsOut = [];
|
2187
2253
|
for (let i = 0; i < argc; i++) {
|
@@ -2202,43 +2268,39 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
2202
2268
|
[ Opcodes.end ]
|
2203
2269
|
];
|
2204
2270
|
|
2205
|
-
//
|
2206
|
-
|
2207
|
-
|
2208
|
-
|
2209
|
-
|
2210
|
-
|
2211
|
-
|
2212
|
-
// ], [
|
2213
|
-
// ...argsOut,
|
2214
|
-
// [ Opcodes.local_get, funcLocal ],
|
2215
|
-
// [ Opcodes.call_indirect, argc, 0 ],
|
2216
|
-
// ...setLastType(scope),
|
2217
|
-
// ]);
|
2218
|
-
|
2219
|
-
return checkFlag(0b1, // no type return
|
2220
|
-
checkFlag(0b10, [ // no type return & constr
|
2221
|
-
[ Opcodes.i32_const, decl._new ? 1 : 0 ],
|
2271
|
+
// todo: i'm sure this could be made better somehow, probably only with #96?
|
2272
|
+
return checkFlag(0b1,
|
2273
|
+
// no type return
|
2274
|
+
checkFlag(0b10, [
|
2275
|
+
// no type return & constr
|
2276
|
+
...createNewTarget(scope, decl),
|
2277
|
+
...createThisArg(scope, decl, [], knownThis),
|
2222
2278
|
...argsOut,
|
2223
2279
|
[ Opcodes.local_get, funcLocal ],
|
2224
|
-
[ Opcodes.call_indirect, argc, 0, 'no_type_return'
|
2280
|
+
[ Opcodes.call_indirect, argc + 2, 0, 'no_type_return' ],
|
2225
2281
|
], [
|
2282
|
+
// no type return & not constr
|
2226
2283
|
...argsOut,
|
2227
2284
|
[ Opcodes.local_get, funcLocal ],
|
2228
2285
|
[ Opcodes.call_indirect, argc, 0, 'no_type_return' ]
|
2229
2286
|
]),
|
2230
|
-
|
2231
|
-
|
2287
|
+
|
2288
|
+
// type return
|
2289
|
+
checkFlag(0b10, [
|
2290
|
+
// type return & constr
|
2291
|
+
...createNewTarget(scope, decl),
|
2292
|
+
...createThisArg(scope, decl, [], knownThis),
|
2232
2293
|
...argsOut,
|
2233
2294
|
[ Opcodes.local_get, funcLocal ],
|
2234
|
-
[ Opcodes.call_indirect, argc, 0
|
2295
|
+
[ Opcodes.call_indirect, argc + 2, 0 ],
|
2235
2296
|
...setLastType(scope),
|
2236
2297
|
], [
|
2298
|
+
// type return
|
2237
2299
|
...argsOut,
|
2238
2300
|
[ Opcodes.local_get, funcLocal ],
|
2239
2301
|
[ Opcodes.call_indirect, argc, 0 ],
|
2240
2302
|
...setLastType(scope),
|
2241
|
-
])
|
2303
|
+
])
|
2242
2304
|
);
|
2243
2305
|
};
|
2244
2306
|
|
@@ -2250,7 +2312,10 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
2250
2312
|
// todo/perf: check if we should use br_table here or just generate our own big if..elses
|
2251
2313
|
|
2252
2314
|
return [
|
2253
|
-
...
|
2315
|
+
...(getCalleeObj ? [
|
2316
|
+
...initCalleeObj,
|
2317
|
+
...generateMember(scope, decl.callee, false, undefined, getCalleeObj)
|
2318
|
+
]: generate(scope, decl.callee)),
|
2254
2319
|
[ Opcodes.local_set, localTmp(scope, '#indirect_callee') ],
|
2255
2320
|
|
2256
2321
|
...typeSwitch(scope, getNodeType(scope, decl.callee), {
|
@@ -2298,26 +2363,28 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
2298
2363
|
const userFunc = func && !func.internal;
|
2299
2364
|
const typedParams = userFunc || func?.typedParams;
|
2300
2365
|
const typedReturns = (userFunc && func.returnType == null) || builtinFuncs[name]?.typedReturns;
|
2301
|
-
let paramCount =
|
2366
|
+
let paramCount = countParams(func, name);
|
2302
2367
|
|
2303
2368
|
let paramOffset = 0;
|
2304
|
-
if (func && func.constr) {
|
2305
|
-
// new.target arg
|
2306
|
-
if (func.internal) paramOffset = 1;
|
2307
|
-
if (!typedParams) paramCount--;
|
2308
|
-
out.push([ Opcodes.i32_const, decl._new ? 1 : 0 ]);
|
2309
|
-
} else if (decl._new)
|
2369
|
+
if (decl._new && func && !func.constr) {
|
2310
2370
|
return internalThrow(scope, 'TypeError', `${unhackName(name)} is not a constructor`, true);
|
2371
|
+
}
|
2372
|
+
|
2373
|
+
if (func && func.constr) {
|
2374
|
+
out.push(...createNewTarget(scope, decl, idx - importedFuncs.length));
|
2375
|
+
out.push(...createThisArg(scope, decl, func));
|
2376
|
+
paramOffset += 4;
|
2377
|
+
}
|
2311
2378
|
|
2312
2379
|
let args = [...decl.arguments];
|
2313
2380
|
if (func && !func.hasRestArgument && args.length < paramCount) {
|
2314
2381
|
// too little args, push undefineds
|
2315
|
-
args = args.concat(new Array(paramCount - args.length).fill(DEFAULT_VALUE));
|
2382
|
+
args = args.concat(new Array(paramCount - args.length).fill(DEFAULT_VALUE()));
|
2316
2383
|
}
|
2317
2384
|
|
2318
2385
|
if (func && func.hasRestArgument) {
|
2319
2386
|
if (args.length < paramCount) {
|
2320
|
-
args = args.concat(new Array(paramCount - 1 - args.length).fill(DEFAULT_VALUE));
|
2387
|
+
args = args.concat(new Array(paramCount - 1 - args.length).fill(DEFAULT_VALUE()));
|
2321
2388
|
}
|
2322
2389
|
|
2323
2390
|
const restArgs = args.slice(paramCount - 1);
|
@@ -2391,11 +2458,26 @@ const generateNew = (scope, decl, _global, _name) => generateCall(scope, {
|
|
2391
2458
|
_new: true
|
2392
2459
|
}, _global, _name);
|
2393
2460
|
|
2461
|
+
const generateThis = (scope, decl, _global, _name) => {
|
2462
|
+
if (!scope.constr) {
|
2463
|
+
// this in a non-constructor context is a reference to globalThis
|
2464
|
+
return [
|
2465
|
+
...generate(scope, { type: 'Identifier', name: 'globalThis' }),
|
2466
|
+
...setLastType(scope, getType(scope, 'globalThis'))
|
2467
|
+
];
|
2468
|
+
}
|
2469
|
+
|
2470
|
+
return [
|
2471
|
+
[ Opcodes.local_get, '#this' ],
|
2472
|
+
...setLastType(scope, [ [ Opcodes.local_get, '#this#type' ] ])
|
2473
|
+
];
|
2474
|
+
};
|
2475
|
+
|
2394
2476
|
// bad hack for undefined and null working without additional logic
|
2395
|
-
const DEFAULT_VALUE = {
|
2477
|
+
const DEFAULT_VALUE = () => ({
|
2396
2478
|
type: 'Identifier',
|
2397
2479
|
name: 'undefined'
|
2398
|
-
};
|
2480
|
+
});
|
2399
2481
|
|
2400
2482
|
const codeToSanitizedStr = code => {
|
2401
2483
|
let out = '';
|
@@ -4128,7 +4210,7 @@ const generateThrow = (scope, decl) => {
|
|
4128
4210
|
message = decl.argument.arguments[0];
|
4129
4211
|
}
|
4130
4212
|
|
4131
|
-
message ??= DEFAULT_VALUE;
|
4213
|
+
message ??= DEFAULT_VALUE();
|
4132
4214
|
|
4133
4215
|
if (tags.length === 0) tags.push({
|
4134
4216
|
params: [ valtypeBinary, valtypeBinary, Valtype.i32 ],
|
@@ -4153,7 +4235,7 @@ const generateThrow = (scope, decl) => {
|
|
4153
4235
|
message = decl.argument.arguments[0];
|
4154
4236
|
}
|
4155
4237
|
|
4156
|
-
message ??= DEFAULT_VALUE;
|
4238
|
+
message ??= DEFAULT_VALUE();
|
4157
4239
|
|
4158
4240
|
if (tags.length === 0) tags.push({
|
4159
4241
|
params: [ Valtype.i32, valtypeBinary, Valtype.i32 ],
|
@@ -4209,18 +4291,15 @@ const generateEmpty = (scope, decl) => {
|
|
4209
4291
|
};
|
4210
4292
|
|
4211
4293
|
const generateMeta = (scope, decl) => {
|
4212
|
-
if (decl.meta.name !== 'new') return todo(scope, `meta property object ${decl.meta.name} is not supported yet`, true);
|
4213
|
-
|
4214
4294
|
switch (`${decl.meta.name}.${decl.property.name}`) {
|
4215
4295
|
case 'new.target': {
|
4216
|
-
scope.constr = true;
|
4217
|
-
|
4218
4296
|
return [
|
4219
|
-
[ Opcodes.local_get,
|
4220
|
-
Opcodes.i32_from_u,
|
4221
|
-
...setLastType(scope, TYPES.boolean)
|
4297
|
+
[ Opcodes.local_get, '#newtarget' ],
|
4222
4298
|
];
|
4223
4299
|
}
|
4300
|
+
|
4301
|
+
default:
|
4302
|
+
return todo(scope, `meta property object ${decl.meta.name} is not supported yet`, true);
|
4224
4303
|
}
|
4225
4304
|
};
|
4226
4305
|
|
@@ -4641,7 +4720,25 @@ const wrapBC = (bc, { prelude = [], postlude = [] } = {}) => {
|
|
4641
4720
|
return out;
|
4642
4721
|
};
|
4643
4722
|
|
4644
|
-
const
|
4723
|
+
const countParams = (func, name = undefined) => {
|
4724
|
+
if (!func) {
|
4725
|
+
if (Object.hasOwn(importedFuncs, name)) {
|
4726
|
+
// reverse lookup then normal lookup
|
4727
|
+
func = importedFuncs[importedFuncs[name]];
|
4728
|
+
if (func) return func.params?.length ?? func.params;
|
4729
|
+
}
|
4730
|
+
return;
|
4731
|
+
}
|
4732
|
+
if (func.argc) return func.argc;
|
4733
|
+
|
4734
|
+
let params = func.params.length;
|
4735
|
+
if (func.constr) params -= 4;
|
4736
|
+
if (!func.internal || builtinFuncs[func.name]?.typedParams) params = Math.floor(params / 2);
|
4737
|
+
|
4738
|
+
return func.argc = params;
|
4739
|
+
};
|
4740
|
+
|
4741
|
+
const generateMember = (scope, decl, _global, _name, _objectWasm = undefined) => {
|
4645
4742
|
const name = decl.object.name;
|
4646
4743
|
|
4647
4744
|
// hack: .name
|
@@ -4659,12 +4756,9 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
4659
4756
|
// todo: support optional
|
4660
4757
|
|
4661
4758
|
const func = funcs.find(x => x.name === name);
|
4662
|
-
if (func)
|
4663
|
-
const typedParams = !func.internal || func.typedParams;
|
4664
|
-
return withType(scope, number(typedParams ? Math.floor(func.params.length / 2) : (func.constr ? (func.params.length - 1) : func.params.length)), TYPES.number);
|
4665
|
-
}
|
4759
|
+
if (func) return withType(scope, number(countParams(func)), TYPES.number);
|
4666
4760
|
|
4667
|
-
if (Object.hasOwn(builtinFuncs, name)) return withType(scope, number(
|
4761
|
+
if (Object.hasOwn(builtinFuncs, name)) return withType(scope, number(countParams(builtinFuncs[name])), TYPES.number);
|
4668
4762
|
if (Object.hasOwn(importedFuncs, name)) return withType(scope, number(importedFuncs[name].params.length ?? importedFuncs[name].params), TYPES.number);
|
4669
4763
|
if (Object.hasOwn(internalConstrs, name)) return withType(scope, number(internalConstrs[name].length ?? 0), TYPES.number);
|
4670
4764
|
|
@@ -4954,7 +5048,7 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
4954
5048
|
if (decl.optional) {
|
4955
5049
|
out.unshift(
|
4956
5050
|
[ Opcodes.block, valtypeBinary ],
|
4957
|
-
...generate(scope, object),
|
5051
|
+
...(_objectWasm ? _objectWasm : generate(scope, object)),
|
4958
5052
|
[ Opcodes.local_tee, localTmp(scope, '#member_obj') ],
|
4959
5053
|
|
4960
5054
|
...nullish(scope, [], getNodeType(scope, object), false, true),
|
@@ -4973,7 +5067,7 @@ const generateMember = (scope, decl, _global, _name) => {
|
|
4973
5067
|
);
|
4974
5068
|
} else {
|
4975
5069
|
out.unshift(
|
4976
|
-
...generate(scope, object),
|
5070
|
+
...(_objectWasm ? _objectWasm : generate(scope, object)),
|
4977
5071
|
[ Opcodes.local_set, localTmp(scope, '#member_obj') ],
|
4978
5072
|
|
4979
5073
|
...generate(scope, property, false, '#member_prop'),
|
@@ -4995,7 +5089,7 @@ const objectHack = node => {
|
|
4995
5089
|
if (node.computed || node.optional) return;
|
4996
5090
|
|
4997
5091
|
// hack: block these properties as they can be accessed on functions
|
4998
|
-
if (node.property.name ==
|
5092
|
+
if (node.property.name == 'length' || node.property.name == 'name') return;
|
4999
5093
|
|
5000
5094
|
let objectName = node.object.name;
|
5001
5095
|
|
@@ -5045,7 +5139,8 @@ const generateFunc = (scope, decl) => {
|
|
5045
5139
|
returns: [ valtypeBinary, Valtype.i32 ],
|
5046
5140
|
throws: false,
|
5047
5141
|
name,
|
5048
|
-
index: currentFuncIndex
|
5142
|
+
index: currentFuncIndex++,
|
5143
|
+
constr: decl.type && decl.type !== 'ArrowFunctionExpression' && decl.type !== 'Program'
|
5049
5144
|
};
|
5050
5145
|
|
5051
5146
|
funcIndex[name] = func.index;
|
@@ -5123,11 +5218,38 @@ const generateFunc = (scope, decl) => {
|
|
5123
5218
|
|
5124
5219
|
// add end return if not found
|
5125
5220
|
if (name !== 'main' && wasm[wasm.length - 1]?.[0] !== Opcodes.return && countLeftover(wasm) === 0) {
|
5126
|
-
wasm.push(
|
5127
|
-
|
5128
|
-
|
5129
|
-
|
5130
|
-
|
5221
|
+
wasm.push(...generateReturn(func, {}));
|
5222
|
+
}
|
5223
|
+
|
5224
|
+
if (func.constr) {
|
5225
|
+
const locals = func.locals;
|
5226
|
+
let idxOffset = 4;
|
5227
|
+
func.params = [ valtypeBinary, Valtype.i32, valtypeBinary, Valtype.i32, ...func.params ];
|
5228
|
+
|
5229
|
+
// move all local indexes by idxOffset
|
5230
|
+
func.localInd += idxOffset;
|
5231
|
+
for (const x in locals) {
|
5232
|
+
locals[x].idx += idxOffset;
|
5233
|
+
}
|
5234
|
+
|
5235
|
+
let indexes = idxOffset;
|
5236
|
+
|
5237
|
+
locals['#this#type'] = { idx: --indexes, type: Valtype.i32 };
|
5238
|
+
locals['#this'] = { idx: --indexes, type: valtypeBinary };
|
5239
|
+
locals['#newtarget#type'] = { idx: --indexes, type: Valtype.i32 };
|
5240
|
+
locals['#newtarget'] = { idx: --indexes, type: valtypeBinary };
|
5241
|
+
|
5242
|
+
for (let i = 0; i < wasm.length; i++) {
|
5243
|
+
// note: these needs to be copied, even though they realistically shouldn't
|
5244
|
+
const inst = wasm[i];
|
5245
|
+
if (inst[0] === Opcodes.local_get || inst[0] === Opcodes.local_set || inst[0] === Opcodes.local_tee) {
|
5246
|
+
if (typeof inst[1] == 'string') {
|
5247
|
+
wasm[i] = [ inst[0], locals[inst[1]].idx ];
|
5248
|
+
} else {
|
5249
|
+
wasm[i] = [ inst[0], inst[1] + idxOffset ];
|
5250
|
+
}
|
5251
|
+
}
|
5252
|
+
}
|
5131
5253
|
}
|
5132
5254
|
|
5133
5255
|
return func;
|
@@ -5156,7 +5278,7 @@ const internalConstrs = {
|
|
5156
5278
|
rawElements: new Array(0)
|
5157
5279
|
}, global, name, true, undefined, true, true);
|
5158
5280
|
|
5159
|
-
const arg = decl.arguments[0] ?? DEFAULT_VALUE;
|
5281
|
+
const arg = decl.arguments[0] ?? DEFAULT_VALUE();
|
5160
5282
|
|
5161
5283
|
// todo: check in wasm instead of here
|
5162
5284
|
const literalValue = arg.value ?? 0;
|
@@ -5232,7 +5354,7 @@ const internalConstrs = {
|
|
5232
5354
|
Boolean: {
|
5233
5355
|
generate: (scope, decl) => {
|
5234
5356
|
// todo: boolean object when used as constructor
|
5235
|
-
const arg = decl.arguments[0] ?? DEFAULT_VALUE;
|
5357
|
+
const arg = decl.arguments[0] ?? DEFAULT_VALUE();
|
5236
5358
|
return truthy(scope, generate(scope, arg), getNodeType(scope, arg), false, false, 'full');
|
5237
5359
|
},
|
5238
5360
|
type: TYPES.boolean,
|
package/compiler/precompile.js
CHANGED
@@ -209,11 +209,13 @@ ${funcs.map(x => {
|
|
209
209
|
return `(scope, {${`${str.includes('allocPage(') ? 'allocPage,' : ''}${str.includes('glbl(') ? 'glbl,' : ''}${str.includes('loc(') ? 'loc,' : ''}${str.includes('builtin(') ? 'builtin,' : ''}${str.includes('internalThrow(') ? 'internalThrow,' : ''}`.slice(0, -1)}}) => ` + str;
|
210
210
|
};
|
211
211
|
|
212
|
+
const locals = Object.entries(x.locals).sort((a,b) => a[1].idx - b[1].idx)
|
213
|
+
|
212
214
|
return ` this.${x.name} = {
|
213
215
|
wasm: ${rewriteWasm(x.wasm)},
|
214
216
|
params: ${JSON.stringify(x.params)}, typedParams: 1,
|
215
217
|
returns: ${JSON.stringify(x.returns)}, ${x.returnType != null ? `returnType: ${JSON.stringify(x.returnType)}` : 'typedReturns: 1'},
|
216
|
-
locals: ${JSON.stringify(
|
218
|
+
locals: ${JSON.stringify(locals.slice(x.params.length).map(x => x[1].type))}, localNames: ${JSON.stringify(locals.map(x => x[0]))},
|
217
219
|
${x.globalInits ? ` globalInits: {${Object.keys(x.globalInits).map(y => `${y}: ${rewriteWasm(x.globalInits[y])}`).join(',')}},\n` : ''}${x.data && x.data.length > 0 ? ` data: [${x.data.map(x => `[${x.offset ?? 'null'},[${x.bytes.join(',')}]]`).join(',')}],` : ''}
|
218
220
|
${x.table ? ` table: 1,` : ''}${x.constr ? ` constr: 1,` : ''}${x.hasRestArgument ? ` hasRestArgument: 1,` : ''}
|
219
221
|
};`.replaceAll('\n\n', '\n').replaceAll('\n\n', '\n').replaceAll('\n\n', '\n');
|
package/package.json
CHANGED