porffor 0.34.6 → 0.34.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 -12
- package/compiler/builtins/crypto.ts +12 -1
- package/compiler/builtins/promise.ts +5 -5
- package/compiler/builtins.js +9 -9
- package/compiler/builtins_objects.js +1 -2
- package/compiler/builtins_precompiled.js +238 -233
- package/compiler/codegen.js +257 -157
- package/compiler/decompile.js +1 -1
- package/compiler/precompile.js +3 -3
- package/compiler/wrap.js +3 -2
- package/package.json +1 -1
- package/runner/index.js +1 -1
- package/runner/repl.js +1 -1
- package/r.js +0 -113
package/compiler/codegen.js
CHANGED
@@ -48,12 +48,18 @@ const cacheAst = (decl, wasm) => {
|
|
48
48
|
return wasm;
|
49
49
|
};
|
50
50
|
|
51
|
-
const funcRef =
|
51
|
+
const funcRef = func => {
|
52
|
+
// generate func
|
53
|
+
func.generate?.();
|
54
|
+
|
52
55
|
if (globalThis.precompile) return [
|
53
|
-
[ Opcodes.const, 'funcref', name ]
|
56
|
+
[ Opcodes.const, 'funcref', func.name ]
|
54
57
|
];
|
55
58
|
|
56
|
-
return
|
59
|
+
return [
|
60
|
+
[ Opcodes.const, func.index - importedFuncs.length ]
|
61
|
+
// [ Opcodes.const, func.index - importedFuncs.length, 'funcref' ]
|
62
|
+
];
|
57
63
|
};
|
58
64
|
|
59
65
|
const generate = (scope, decl, global = false, name = undefined, valueUnused = false) => {
|
@@ -189,6 +195,9 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
|
|
189
195
|
|
190
196
|
for (const x of newFuncs) {
|
191
197
|
x.export = true;
|
198
|
+
|
199
|
+
// generate func
|
200
|
+
x.generate?.();
|
192
201
|
}
|
193
202
|
}
|
194
203
|
|
@@ -344,9 +353,7 @@ const generateIdent = (scope, decl) => {
|
|
344
353
|
if (Object.hasOwn(globals, name)) return [ [ Opcodes.global_get, globals[name].idx ] ];
|
345
354
|
|
346
355
|
if (Object.hasOwn(importedFuncs, name)) return number(importedFuncs[name] - importedFuncs.length);
|
347
|
-
if (Object.hasOwn(funcIndex, name))
|
348
|
-
return funcRef(funcIndex[name], name);
|
349
|
-
}
|
356
|
+
if (Object.hasOwn(funcIndex, name)) return funcRef(funcByName(name));
|
350
357
|
}
|
351
358
|
|
352
359
|
if (local?.idx === undefined && rawName.startsWith('__')) {
|
@@ -1117,6 +1124,14 @@ const asmFuncToAsm = (scope, func) => {
|
|
1117
1124
|
|
1118
1125
|
return idx;
|
1119
1126
|
},
|
1127
|
+
funcRef: name => {
|
1128
|
+
if (funcIndex[name] == null && builtinFuncs[name]) {
|
1129
|
+
includeBuiltin(scope, name);
|
1130
|
+
}
|
1131
|
+
|
1132
|
+
const func = funcByName(name);
|
1133
|
+
return funcRef(func);
|
1134
|
+
},
|
1120
1135
|
glbl: (opcode, name, type) => {
|
1121
1136
|
const globalName = '#porf#' + name; // avoid potential name clashing with user js
|
1122
1137
|
if (!globals[globalName]) {
|
@@ -1164,7 +1179,7 @@ const asmFunc = (name, { wasm, params = [], typedParams = false, locals: localTy
|
|
1164
1179
|
wasm = [];
|
1165
1180
|
}
|
1166
1181
|
|
1167
|
-
const existing =
|
1182
|
+
const existing = funcByName(name);
|
1168
1183
|
if (existing) return existing;
|
1169
1184
|
|
1170
1185
|
const nameParam = i => localNames[i] ?? (i >= params.length ? ['a', 'b', 'c'][i - params.length] : ['x', 'y', 'z'][i]);
|
@@ -1223,7 +1238,7 @@ const asmFunc = (name, { wasm, params = [], typedParams = false, locals: localTy
|
|
1223
1238
|
for (const inst of wasm) {
|
1224
1239
|
if (inst.at(-1) === 'read func lut') {
|
1225
1240
|
inst.splice(2, 99);
|
1226
|
-
inst.push(...unsignedLEB128(allocPage({}, 'func lut')
|
1241
|
+
inst.push(...unsignedLEB128(allocPage({}, 'func lut')));
|
1227
1242
|
}
|
1228
1243
|
}
|
1229
1244
|
|
@@ -1391,7 +1406,7 @@ const getNodeType = (scope, node) => {
|
|
1391
1406
|
return TYPES.number;
|
1392
1407
|
}
|
1393
1408
|
|
1394
|
-
const func =
|
1409
|
+
const func = funcByName(name);
|
1395
1410
|
if (func) {
|
1396
1411
|
if (func.returnType != null) return func.returnType;
|
1397
1412
|
}
|
@@ -1616,11 +1631,11 @@ const countLeftover = wasm => {
|
|
1616
1631
|
else if (inst[0] === Opcodes.memory_copy[0] && (inst[1] === Opcodes.memory_copy[1] || inst[1] === Opcodes.memory_init[1])) count -= 3;
|
1617
1632
|
else if (inst[0] === Opcodes.return) count = 0;
|
1618
1633
|
else if (inst[0] === Opcodes.call) {
|
1619
|
-
let func = funcs.find(x => x.index === inst[1]);
|
1620
1634
|
if (inst[1] < importedFuncs.length) {
|
1621
|
-
func = importedFuncs[inst[1]];
|
1635
|
+
const func = importedFuncs[inst[1]];
|
1622
1636
|
count = count - func.params + func.returns;
|
1623
1637
|
} else {
|
1638
|
+
const func = funcByIndex(inst[1]);
|
1624
1639
|
count = count - func.params.length + func.returns.length;
|
1625
1640
|
}
|
1626
1641
|
} else if (inst[0] === Opcodes.call_indirect) {
|
@@ -1855,7 +1870,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1855
1870
|
|
1856
1871
|
// opt: virtualize iifes
|
1857
1872
|
if (isFuncType(decl.callee.type)) {
|
1858
|
-
const [ func ] = generateFunc(scope, decl.callee);
|
1873
|
+
const [ func ] = generateFunc(scope, decl.callee, true);
|
1859
1874
|
name = func.name;
|
1860
1875
|
}
|
1861
1876
|
|
@@ -2439,19 +2454,19 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
2439
2454
|
[ Opcodes.i32_mul ],
|
2440
2455
|
...number(4, Valtype.i32),
|
2441
2456
|
[ Opcodes.i32_add ],
|
2442
|
-
[ Opcodes.i32_load8_u, 0, ...unsignedLEB128(allocPage(scope, 'func lut')
|
2457
|
+
[ Opcodes.i32_load8_u, 0, ...unsignedLEB128(allocPage(scope, 'func lut')), 'read func lut' ],
|
2443
2458
|
[ Opcodes.local_set, flags ],
|
2444
2459
|
|
2445
2460
|
// check if non-constructor was called with new, if so throw
|
2446
|
-
|
2447
|
-
|
2448
|
-
|
2449
|
-
|
2450
|
-
|
2451
|
-
|
2452
|
-
|
2453
|
-
|
2454
|
-
|
2461
|
+
...(decl._new ? [
|
2462
|
+
[ Opcodes.local_get, flags ],
|
2463
|
+
...number(0b10, Valtype.i32),
|
2464
|
+
[ Opcodes.i32_and ],
|
2465
|
+
[ Opcodes.i32_eqz ],
|
2466
|
+
[ Opcodes.if, Blocktype.void ],
|
2467
|
+
...internalThrow(scope, 'TypeError', `${unhackName(name)} is not a constructor`),
|
2468
|
+
[ Opcodes.end ],
|
2469
|
+
] : []),
|
2455
2470
|
|
2456
2471
|
// [ Opcodes.local_get, funcLocal ],
|
2457
2472
|
// Opcodes.i32_from_u,
|
@@ -2463,10 +2478,18 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
2463
2478
|
// [ Opcodes.local_get, funcLocal ],
|
2464
2479
|
// ...number(64, Valtype.i32),
|
2465
2480
|
// [ Opcodes.i32_mul ],
|
2466
|
-
// [ Opcodes.i32_load16_u, 0, ...unsignedLEB128(allocPage(scope, 'func lut')
|
2481
|
+
// [ Opcodes.i32_load16_u, 0, ...unsignedLEB128(allocPage(scope, 'func lut')), 'read func lut' ],
|
2467
2482
|
// Opcodes.i32_from_u,
|
2468
2483
|
// [ Opcodes.call, 0 ],
|
2469
2484
|
|
2485
|
+
// [ Opcodes.local_get, funcLocal ],
|
2486
|
+
// [ Opcodes.call, includeBuiltin(scope, '__Porffor_funcLut_name').index ],
|
2487
|
+
// Opcodes.i32_from_u,
|
2488
|
+
// ...number(TYPES.bytestring, Valtype.i32),
|
2489
|
+
// [ Opcodes.call, includeBuiltin(scope, '__Porffor_printString').index ],
|
2490
|
+
// [ Opcodes.drop ],
|
2491
|
+
// [ Opcodes.drop ],
|
2492
|
+
|
2470
2493
|
// ...number(10),
|
2471
2494
|
// [ Opcodes.call, 1 ],
|
2472
2495
|
|
@@ -2475,7 +2498,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
2475
2498
|
[ Opcodes.local_get, funcLocal ],
|
2476
2499
|
...number(64, Valtype.i32),
|
2477
2500
|
[ Opcodes.i32_mul ],
|
2478
|
-
[ Opcodes.i32_load16_u, 0, ...unsignedLEB128(allocPage(scope, 'func lut')
|
2501
|
+
[ Opcodes.i32_load16_u, 0, ...unsignedLEB128(allocPage(scope, 'func lut')), 'read func lut' ]
|
2479
2502
|
], tableBc, valtypeBinary)
|
2480
2503
|
],
|
2481
2504
|
|
@@ -2491,7 +2514,11 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
2491
2514
|
];
|
2492
2515
|
}
|
2493
2516
|
|
2494
|
-
const func =
|
2517
|
+
const func = funcByIndex(idx);
|
2518
|
+
|
2519
|
+
// generate func
|
2520
|
+
if (func) func.generate?.();
|
2521
|
+
|
2495
2522
|
const userFunc = func && !func.internal;
|
2496
2523
|
const typedParams = userFunc || func?.typedParams;
|
2497
2524
|
const typedReturns = (userFunc && func.returnType == null) || builtinFuncs[name]?.typedReturns;
|
@@ -2987,7 +3014,7 @@ const generateVarDstr = (scope, kind, pattern, init, defaultValue, global) => {
|
|
2987
3014
|
// hack for let a = function () { ... }
|
2988
3015
|
if (!init.id) {
|
2989
3016
|
init.id = { name };
|
2990
|
-
generateFunc(scope, init);
|
3017
|
+
generateFunc(scope, init, true);
|
2991
3018
|
return out;
|
2992
3019
|
}
|
2993
3020
|
}
|
@@ -4774,7 +4801,8 @@ const generateMeta = (scope, decl) => {
|
|
4774
4801
|
|
4775
4802
|
let pages = new Map();
|
4776
4803
|
const allocPage = (scope, reason, type) => {
|
4777
|
-
|
4804
|
+
const ptr = i => i === 0 ? 16 : (i * pageSize);
|
4805
|
+
if (pages.has(reason)) return ptr(pages.get(reason).ind);
|
4778
4806
|
|
4779
4807
|
if (reason.startsWith('array:')) pages.hasArray = true;
|
4780
4808
|
if (reason.startsWith('string:')) pages.hasString = true;
|
@@ -4787,7 +4815,7 @@ const allocPage = (scope, reason, type) => {
|
|
4787
4815
|
scope.pages ??= new Map();
|
4788
4816
|
scope.pages.set(reason, { ind, type });
|
4789
4817
|
|
4790
|
-
return ind;
|
4818
|
+
return ptr(ind);
|
4791
4819
|
};
|
4792
4820
|
|
4793
4821
|
const itemTypeToValtype = {
|
@@ -5257,7 +5285,7 @@ const generateMember = (scope, decl, _global, _name, _objectWasm = undefined) =>
|
|
5257
5285
|
// todo: support optional
|
5258
5286
|
|
5259
5287
|
if (!scope.noFastFuncMembers) {
|
5260
|
-
const func =
|
5288
|
+
const func = funcByName(name);
|
5261
5289
|
if (func) return withType(scope, number(countLength(func, name)), TYPES.number);
|
5262
5290
|
|
5263
5291
|
if (Object.hasOwn(builtinFuncs, name)) return withType(scope, number(countLength(builtinFuncs[name], name)), TYPES.number);
|
@@ -5676,6 +5704,9 @@ const generateClass = (scope, decl) => {
|
|
5676
5704
|
type: expr ? 'FunctionExpression' : 'FunctionDeclaration'
|
5677
5705
|
});
|
5678
5706
|
|
5707
|
+
// always generate class constructor funcs
|
5708
|
+
func.generate();
|
5709
|
+
|
5679
5710
|
if (decl.superClass) {
|
5680
5711
|
out.push(
|
5681
5712
|
...generateCall(scope, {
|
@@ -5808,14 +5839,25 @@ const objectHack = node => {
|
|
5808
5839
|
for (const x in node) {
|
5809
5840
|
if (node[x] != null && typeof node[x] === 'object') {
|
5810
5841
|
if (node[x].type) node[x] = objectHack(node[x]);
|
5811
|
-
if (Array.isArray(node[x])) node[x] = node[x].map(
|
5842
|
+
if (Array.isArray(node[x])) node[x] = node[x].map(objectHack);
|
5812
5843
|
}
|
5813
5844
|
}
|
5814
5845
|
|
5815
5846
|
return node;
|
5816
5847
|
};
|
5817
5848
|
|
5818
|
-
const
|
5849
|
+
const funcByIndex = idx => {
|
5850
|
+
if (idx == null ||
|
5851
|
+
idx < importedFuncs.length) return null;
|
5852
|
+
|
5853
|
+
const func = funcs[idx - importedFuncs.length];
|
5854
|
+
if (func && func.index === idx) return func;
|
5855
|
+
|
5856
|
+
return funcs.find(x => x.index === idx);
|
5857
|
+
};
|
5858
|
+
const funcByName = name => funcByIndex(funcIndex[name]);
|
5859
|
+
|
5860
|
+
const generateFunc = (scope, decl, outUnused = false) => {
|
5819
5861
|
const name = decl.id ? decl.id.name : `#anonymous${uniqId()}`;
|
5820
5862
|
if (decl.type.startsWith('Class')) {
|
5821
5863
|
const out = generateClass(scope, {
|
@@ -5823,7 +5865,7 @@ const generateFunc = (scope, decl) => {
|
|
5823
5865
|
id: { name }
|
5824
5866
|
});
|
5825
5867
|
|
5826
|
-
const func =
|
5868
|
+
const func = funcByName(name);
|
5827
5869
|
return [ func, out ];
|
5828
5870
|
}
|
5829
5871
|
|
@@ -5843,25 +5885,145 @@ const generateFunc = (scope, decl) => {
|
|
5843
5885
|
// not async or generator
|
5844
5886
|
!decl.async && !decl.generator,
|
5845
5887
|
_onlyConstr: decl._onlyConstr,
|
5846
|
-
strict: scope.strict
|
5888
|
+
strict: scope.strict,
|
5889
|
+
|
5890
|
+
generate() {
|
5891
|
+
if (func.wasm) return func.wasm;
|
5892
|
+
|
5893
|
+
// generating, stub _wasm
|
5894
|
+
func.wasm = [];
|
5895
|
+
|
5896
|
+
let body = objectHack(decl.body);
|
5897
|
+
if (decl.type === 'ArrowFunctionExpression' && decl.expression) {
|
5898
|
+
// hack: () => 0 -> () => return 0
|
5899
|
+
body = {
|
5900
|
+
type: 'ReturnStatement',
|
5901
|
+
argument: decl.body
|
5902
|
+
};
|
5903
|
+
}
|
5904
|
+
|
5905
|
+
for (const x in defaultValues) {
|
5906
|
+
prelude.push(
|
5907
|
+
...getType(func, x),
|
5908
|
+
...number(TYPES.undefined, Valtype.i32),
|
5909
|
+
[ Opcodes.i32_eq ],
|
5910
|
+
[ Opcodes.if, Blocktype.void ],
|
5911
|
+
...generate(func, defaultValues[x], false, x),
|
5912
|
+
[ Opcodes.local_set, func.locals[x].idx ],
|
5913
|
+
|
5914
|
+
...setType(func, x, getNodeType(func, defaultValues[x])),
|
5915
|
+
[ Opcodes.end ]
|
5916
|
+
);
|
5917
|
+
}
|
5918
|
+
|
5919
|
+
for (const x in destructuredArgs) {
|
5920
|
+
prelude.push(
|
5921
|
+
...generateVarDstr(func, 'var', destructuredArgs[x], { type: 'Identifier', name: x }, undefined, false)
|
5922
|
+
);
|
5923
|
+
}
|
5924
|
+
|
5925
|
+
if (decl.async) {
|
5926
|
+
// make out promise local
|
5927
|
+
allocVar(func, '#async_out_promise', false, false);
|
5928
|
+
func.async = true;
|
5929
|
+
}
|
5930
|
+
|
5931
|
+
const wasm = prelude.concat(generate(func, body));
|
5932
|
+
|
5933
|
+
if (decl.async) {
|
5934
|
+
// make promise at the start
|
5935
|
+
wasm.unshift(
|
5936
|
+
[ Opcodes.call, includeBuiltin(func, '__Porffor_promise_create').index ],
|
5937
|
+
[ Opcodes.drop ],
|
5938
|
+
[ Opcodes.local_set, func.locals['#async_out_promise'].idx ]
|
5939
|
+
);
|
5940
|
+
|
5941
|
+
// todo: wrap in try and reject thrown value once supported
|
5942
|
+
}
|
5943
|
+
|
5944
|
+
if (!globalThis.precompile && func.constr) {
|
5945
|
+
wasm.unshift(
|
5946
|
+
// opt: do not check for pure constructors
|
5947
|
+
...(func._onlyConstr ? [] : [
|
5948
|
+
// if being constructed
|
5949
|
+
[ Opcodes.local_get, func.locals['#newtarget'].idx ],
|
5950
|
+
Opcodes.i32_to_u,
|
5951
|
+
[ Opcodes.if, Blocktype.void ],
|
5952
|
+
]),
|
5953
|
+
// set prototype of this ;)
|
5954
|
+
...generate(func, setObjProp({ type: 'ThisExpression' }, '__proto__', getObjProp(func.name, 'prototype'))),
|
5955
|
+
...(func._onlyConstr ? [] : [ [ Opcodes.end ] ])
|
5956
|
+
);
|
5957
|
+
}
|
5958
|
+
|
5959
|
+
if (name === 'main') {
|
5960
|
+
func.gotLastType = true;
|
5961
|
+
func.export = true;
|
5962
|
+
func.returns = [ valtypeBinary, Valtype.i32 ];
|
5963
|
+
|
5964
|
+
let finalStatement = decl.body.body[decl.body.body.length - 1];
|
5965
|
+
if (finalStatement?.type === 'EmptyStatement') finalStatement = decl.body.body[decl.body.body.length - 2];
|
5966
|
+
|
5967
|
+
const lastInst = wasm[wasm.length - 1] ?? [ Opcodes.end ];
|
5968
|
+
if (lastInst[0] === Opcodes.drop) {
|
5969
|
+
if (finalStatement.type.endsWith('Declaration')) {
|
5970
|
+
// final statement is decl, force undefined
|
5971
|
+
disposeLeftover(wasm);
|
5972
|
+
wasm.push(
|
5973
|
+
...number(UNDEFINED),
|
5974
|
+
...number(TYPES.undefined, Valtype.i32)
|
5975
|
+
);
|
5976
|
+
} else {
|
5977
|
+
wasm.splice(wasm.length - 1, 1);
|
5978
|
+
wasm.push(...getNodeType(func, finalStatement));
|
5979
|
+
}
|
5980
|
+
}
|
5981
|
+
|
5982
|
+
if (lastInst[0] === Opcodes.end || lastInst[0] === Opcodes.local_set || lastInst[0] === Opcodes.global_set) {
|
5983
|
+
if (lastInst[0] === Opcodes.local_set && lastInst[1] === func.locals['#last_type'].idx) {
|
5984
|
+
wasm.splice(wasm.length - 1, 1);
|
5985
|
+
} else {
|
5986
|
+
func.returns = [];
|
5987
|
+
}
|
5988
|
+
}
|
5989
|
+
|
5990
|
+
if (lastInst[0] === Opcodes.call) {
|
5991
|
+
const callee = funcByIndex(lastInst[1]);
|
5992
|
+
if (callee) func.returns = callee.returns.slice();
|
5993
|
+
else func.returns = [];
|
5994
|
+
}
|
5995
|
+
|
5996
|
+
// inject promise job runner func at the end of main if job queue is used
|
5997
|
+
if (Object.hasOwn(funcIndex, '__ecma262_HostEnqueuePromiseJob')) {
|
5998
|
+
wasm.push(
|
5999
|
+
[ Opcodes.call, includeBuiltin(scope, '__Porffor_promise_runJobs').index ],
|
6000
|
+
[ Opcodes.drop ],
|
6001
|
+
[ Opcodes.drop ]
|
6002
|
+
);
|
6003
|
+
}
|
6004
|
+
} else {
|
6005
|
+
// add end return if not found
|
6006
|
+
if (wasm[wasm.length - 1]?.[0] !== Opcodes.return && countLeftover(wasm) === 0) {
|
6007
|
+
wasm.push(...generateReturn(func, {}));
|
6008
|
+
}
|
6009
|
+
}
|
6010
|
+
|
6011
|
+
return func.wasm = wasm;
|
6012
|
+
}
|
5847
6013
|
};
|
5848
6014
|
|
5849
6015
|
funcIndex[name] = func.index;
|
5850
6016
|
funcs.push(func);
|
5851
6017
|
|
5852
|
-
const out = decl.type.endsWith('Expression') ? funcRef(func.index, func.name) : [];
|
5853
|
-
|
5854
6018
|
let errorWasm = null;
|
5855
6019
|
if (decl.generator) errorWasm = todo(scope, 'generator functions are not supported');
|
5856
6020
|
|
5857
6021
|
if (errorWasm) {
|
6022
|
+
// func.params = [];
|
5858
6023
|
func.wasm = errorWasm.concat([
|
5859
6024
|
...number(UNDEFINED),
|
5860
6025
|
...number(TYPES.undefined, Valtype.i32)
|
5861
6026
|
]);
|
5862
|
-
func.params = [];
|
5863
|
-
func.constr = false;
|
5864
|
-
return [ func, out ];
|
5865
6027
|
}
|
5866
6028
|
|
5867
6029
|
if (typedInput && decl.returnType) {
|
@@ -5936,121 +6098,13 @@ const generateFunc = (scope, decl) => {
|
|
5936
6098
|
|
5937
6099
|
func.params = Object.values(func.locals).map(x => x.type);
|
5938
6100
|
|
5939
|
-
|
5940
|
-
if (
|
5941
|
-
// hack: () => 0 -> () => return 0
|
5942
|
-
body = {
|
5943
|
-
type: 'ReturnStatement',
|
5944
|
-
argument: decl.body
|
5945
|
-
};
|
5946
|
-
}
|
5947
|
-
|
5948
|
-
for (const x in defaultValues) {
|
5949
|
-
prelude.push(
|
5950
|
-
...getType(func, x),
|
5951
|
-
...number(TYPES.undefined, Valtype.i32),
|
5952
|
-
[ Opcodes.i32_eq ],
|
5953
|
-
[ Opcodes.if, Blocktype.void ],
|
5954
|
-
...generate(func, defaultValues[x], false, x),
|
5955
|
-
[ Opcodes.local_set, func.locals[x].idx ],
|
5956
|
-
|
5957
|
-
...setType(func, x, getNodeType(func, defaultValues[x])),
|
5958
|
-
[ Opcodes.end ]
|
5959
|
-
);
|
5960
|
-
}
|
5961
|
-
|
5962
|
-
for (const x in destructuredArgs) {
|
5963
|
-
prelude.push(
|
5964
|
-
...generateVarDstr(func, 'var', destructuredArgs[x], { type: 'Identifier', name: x }, undefined, false)
|
5965
|
-
);
|
5966
|
-
}
|
5967
|
-
|
5968
|
-
if (decl.async) {
|
5969
|
-
// make out promise local
|
5970
|
-
allocVar(func, '#async_out_promise', false, false);
|
5971
|
-
func.async = true;
|
5972
|
-
}
|
5973
|
-
|
5974
|
-
const wasm = func.wasm = prelude.concat(generate(func, body));
|
5975
|
-
|
5976
|
-
if (decl.async) {
|
5977
|
-
// make promise at the start
|
5978
|
-
wasm.unshift(
|
5979
|
-
[ Opcodes.call, includeBuiltin(func, '__Porffor_promise_create').index ],
|
5980
|
-
[ Opcodes.drop ],
|
5981
|
-
[ Opcodes.local_set, func.locals['#async_out_promise'].idx ]
|
5982
|
-
);
|
5983
|
-
|
5984
|
-
// todo: wrap in try and reject thrown value once supported
|
5985
|
-
}
|
5986
|
-
|
5987
|
-
if (!globalThis.precompile && func.constr) {
|
5988
|
-
wasm.unshift(
|
5989
|
-
// opt: do not check for pure constructors
|
5990
|
-
...(func._onlyConstr ? [] : [
|
5991
|
-
// if being constructed
|
5992
|
-
[ Opcodes.local_get, func.locals['#newtarget'].idx ],
|
5993
|
-
Opcodes.i32_to_u,
|
5994
|
-
[ Opcodes.if, Blocktype.void ],
|
5995
|
-
]),
|
5996
|
-
// set prototype of this ;)
|
5997
|
-
...generate(func, setObjProp({ type: 'ThisExpression' }, '__proto__', getObjProp(func.name, 'prototype'))),
|
5998
|
-
...(func._onlyConstr ? [] : [ [ Opcodes.end ] ])
|
5999
|
-
);
|
6000
|
-
}
|
6001
|
-
|
6002
|
-
if (name === 'main') {
|
6003
|
-
func.gotLastType = true;
|
6004
|
-
func.export = true;
|
6005
|
-
func.returns = [ valtypeBinary, Valtype.i32 ];
|
6006
|
-
|
6007
|
-
let finalStatement = decl.body.body[decl.body.body.length - 1];
|
6008
|
-
if (finalStatement?.type === 'EmptyStatement') finalStatement = decl.body.body[decl.body.body.length - 2];
|
6009
|
-
|
6010
|
-
const lastInst = func.wasm[func.wasm.length - 1] ?? [ Opcodes.end ];
|
6011
|
-
if (lastInst[0] === Opcodes.drop) {
|
6012
|
-
if (finalStatement.type.endsWith('Declaration')) {
|
6013
|
-
// final statement is decl, force undefined
|
6014
|
-
disposeLeftover(wasm);
|
6015
|
-
func.wasm.push(
|
6016
|
-
...number(UNDEFINED),
|
6017
|
-
...number(TYPES.undefined, Valtype.i32)
|
6018
|
-
);
|
6019
|
-
} else {
|
6020
|
-
func.wasm.splice(func.wasm.length - 1, 1);
|
6021
|
-
func.wasm.push(...getNodeType(func, finalStatement));
|
6022
|
-
}
|
6023
|
-
}
|
6024
|
-
|
6025
|
-
if (lastInst[0] === Opcodes.end || lastInst[0] === Opcodes.local_set || lastInst[0] === Opcodes.global_set) {
|
6026
|
-
if (lastInst[0] === Opcodes.local_set && lastInst[1] === func.locals['#last_type'].idx) {
|
6027
|
-
func.wasm.splice(func.wasm.length - 1, 1);
|
6028
|
-
} else {
|
6029
|
-
func.returns = [];
|
6030
|
-
}
|
6031
|
-
}
|
6032
|
-
|
6033
|
-
if (lastInst[0] === Opcodes.call) {
|
6034
|
-
const callee = funcs.find(x => x.index === lastInst[1]);
|
6035
|
-
if (callee) func.returns = callee.returns.slice();
|
6036
|
-
else func.returns = [];
|
6037
|
-
}
|
6101
|
+
// force generate for main
|
6102
|
+
if (name === 'main') func.generate();
|
6038
6103
|
|
6039
|
-
|
6040
|
-
|
6041
|
-
wasm.push(
|
6042
|
-
[ Opcodes.call, includeBuiltin(scope, '__Porffor_promise_runJobs').index ],
|
6043
|
-
[ Opcodes.drop ],
|
6044
|
-
[ Opcodes.drop ]
|
6045
|
-
);
|
6046
|
-
}
|
6047
|
-
} else {
|
6048
|
-
// add end return if not found
|
6049
|
-
if (wasm[wasm.length - 1]?.[0] !== Opcodes.return && countLeftover(wasm) === 0) {
|
6050
|
-
wasm.push(...generateReturn(func, {}));
|
6051
|
-
}
|
6052
|
-
}
|
6104
|
+
// force generate all for precompile
|
6105
|
+
if (globalThis.precompile) func.generate();
|
6053
6106
|
|
6107
|
+
const out = decl.type.endsWith('Expression') && !outUnused ? funcRef(func) : [];
|
6054
6108
|
return [ func, out ];
|
6055
6109
|
};
|
6056
6110
|
|
@@ -6255,11 +6309,6 @@ export default program => {
|
|
6255
6309
|
|
6256
6310
|
program.id = { name: 'main' };
|
6257
6311
|
|
6258
|
-
const scope = {
|
6259
|
-
locals: {},
|
6260
|
-
localInd: 0
|
6261
|
-
};
|
6262
|
-
|
6263
6312
|
program.body = {
|
6264
6313
|
type: 'BlockStatement',
|
6265
6314
|
body: program.body
|
@@ -6267,12 +6316,63 @@ export default program => {
|
|
6267
6316
|
|
6268
6317
|
if (Prefs.astLog) console.log(JSON.stringify(program.body.body, null, 2));
|
6269
6318
|
|
6270
|
-
const [ main ] = generateFunc(
|
6319
|
+
const [ main ] = generateFunc({}, program);
|
6271
6320
|
|
6272
6321
|
delete globals['#ind'];
|
6273
6322
|
|
6274
6323
|
// if blank main func and other exports, remove it
|
6275
6324
|
if (main.wasm.length === 0 && funcs.reduce((acc, x) => acc + (x.export ? 1 : 0), 0) > 1) funcs.splice(main.index - importedFuncs.length, 1);
|
6276
6325
|
|
6326
|
+
// make ~empty funcs for never generated funcs
|
6327
|
+
// todo: these should just be deleted once able
|
6328
|
+
for (let i = 0; i < funcs.length; i++) {
|
6329
|
+
const f = funcs[i];
|
6330
|
+
if (f.internal || f.wasm) {
|
6331
|
+
continue;
|
6332
|
+
}
|
6333
|
+
|
6334
|
+
// make wasm just return 0s for expected returns
|
6335
|
+
f.wasm = f.returns.map(x => number(0, x)).flat();
|
6336
|
+
|
6337
|
+
// alternative: make func empty, may break some indirect calls
|
6338
|
+
// f.wasm = [];
|
6339
|
+
// f.returns = [];
|
6340
|
+
// f.params = [];
|
6341
|
+
// f.locals = {};
|
6342
|
+
}
|
6343
|
+
|
6344
|
+
// // remove never generated functions
|
6345
|
+
// let indexDelta = 0;
|
6346
|
+
// const funcRemap = new Map();
|
6347
|
+
// for (let i = 0; i < funcs.length; i++) {
|
6348
|
+
// const f = funcs[i];
|
6349
|
+
// if (f.internal || f.wasm) {
|
6350
|
+
// if (indexDelta) {
|
6351
|
+
// funcRemap.set(f.index, f.index - indexDelta);
|
6352
|
+
// f.index -= indexDelta;
|
6353
|
+
// }
|
6354
|
+
// continue;
|
6355
|
+
// }
|
6356
|
+
|
6357
|
+
// funcs.splice(i--, 1);
|
6358
|
+
// indexDelta++;
|
6359
|
+
// }
|
6360
|
+
|
6361
|
+
// // remap call ops
|
6362
|
+
// if (indexDelta) for (let i = 0; i < funcs.length; i++) {
|
6363
|
+
// const wasm = funcs[i].wasm;
|
6364
|
+
// for (let j = 0; j < wasm.length; j++) {
|
6365
|
+
// const op = wasm[j];
|
6366
|
+
// if (op[0] === Opcodes.call) {
|
6367
|
+
// let idx = op[1];
|
6368
|
+
// wasm[j] = [ Opcodes.call, funcRemap.get(idx) ?? idx ];
|
6369
|
+
// }
|
6370
|
+
|
6371
|
+
// if (op[0] === Opcodes.const && op[2] === 'funcref') {
|
6372
|
+
// wasm[j] = [ Opcodes.const, funcRemap.get(op[1] + importedFuncs.length) - importedFuncs.length ];
|
6373
|
+
// }
|
6374
|
+
// }
|
6375
|
+
// }
|
6376
|
+
|
6277
6377
|
return { funcs, globals, tags, exceptions, pages, data };
|
6278
6378
|
};
|
package/compiler/decompile.js
CHANGED
@@ -99,7 +99,7 @@ export default (wasm, name = '', ind = 0, locals = {}, params = [], returns = []
|
|
99
99
|
|
100
100
|
if (inst[0] === Opcodes.call || inst[0] === Opcodes.return_call) {
|
101
101
|
const idx = inst[1];
|
102
|
-
const callFunc = funcs.find(x => x.index === idx);
|
102
|
+
const callFunc = funcs.find(x => (x.asmIndex ?? x.index) === idx);
|
103
103
|
if (callFunc) out += ` ;; $${callFunc.name} ${makeSignature(callFunc.params, callFunc.returns)}`;
|
104
104
|
if (globalThis.importFuncs && idx < importFuncs.length) {
|
105
105
|
const importFunc = importFuncs[idx];
|
package/compiler/precompile.js
CHANGED
@@ -203,15 +203,15 @@ ${funcs.map(x => {
|
|
203
203
|
if (Number.isNaN(v) || v === Infinity || v === -Infinity) return v.toString();
|
204
204
|
return v;
|
205
205
|
})
|
206
|
-
.replace(/\["alloc","(.*?)","(.*?)",(.*?)\]/g, (_, reason, type, valtype) => `...number(allocPage(_,'${reason}','${type}')
|
206
|
+
.replace(/\["alloc","(.*?)","(.*?)",(.*?)\]/g, (_, reason, type, valtype) => `...number(allocPage(_,'${reason}','${type}'),${valtype})`)
|
207
207
|
.replace(/\["global",(.*?),"(.*?)",(.*?)\]/g, (_, opcode, name, valtype) => `...glbl(${opcode},'${name}',${valtype})`)
|
208
208
|
.replace(/\"local","(.*?)",(.*?)\]/g, (_, name, valtype) => `loc('${name}',${valtype})]`)
|
209
209
|
.replace(/\[16,"(.*?)"]/g, (_, name) => `[16,builtin('${name}')]`)
|
210
|
-
.replace(/\[68,"funcref","(.*?)"]/g, (_, name
|
210
|
+
.replace(/\[68,"funcref","(.*?)"]/g, (_, name) => `...funcRef('${name}')`)
|
211
211
|
.replace(/\["throw","(.*?)","(.*?)"\]/g, (_, constructor, message) => `...internalThrow(_,'${constructor}',\`${message}\`)`)
|
212
212
|
.replace(/\["get object","(.*?)"\]/g, (_, objName) => `...generateIdent(_,{name:'${objName}'})`);
|
213
213
|
|
214
|
-
return `(_,{${`${str.includes('allocPage(') ? 'allocPage,' : ''}${str.includes('glbl(') ? 'glbl,' : ''}${str.includes('loc(') ? 'loc,' : ''}${str.includes('builtin(') ? 'builtin,' : ''}${str.includes('internalThrow(') ? 'internalThrow,' : ''}${str.includes('generateIdent(') ? 'generateIdent,' : ''}`.slice(0, -1)}})=>`.replace('_,{}', '') + str;
|
214
|
+
return `(_,{${`${str.includes('allocPage(') ? 'allocPage,' : ''}${str.includes('glbl(') ? 'glbl,' : ''}${str.includes('loc(') ? 'loc,' : ''}${str.includes('builtin(') ? 'builtin,' : ''}${str.includes('funcRef(') ? 'funcRef,' : ''}${str.includes('internalThrow(') ? 'internalThrow,' : ''}${str.includes('generateIdent(') ? 'generateIdent,' : ''}`.slice(0, -1)}})=>`.replace('_,{}', '') + str;
|
215
215
|
};
|
216
216
|
|
217
217
|
const locals = Object.entries(x.locals).sort((a,b) => a[1].idx - b[1].idx)
|
package/compiler/wrap.js
CHANGED
@@ -127,7 +127,8 @@ ${flags & 0b0001 ? ` get func idx: ${get}
|
|
127
127
|
if (value < 0) {
|
128
128
|
func = importedFuncs[value + importedFuncs.length];
|
129
129
|
} else {
|
130
|
-
|
130
|
+
value += importedFuncs.length;
|
131
|
+
func = funcs.find(x => x.index === value);
|
131
132
|
}
|
132
133
|
|
133
134
|
if (!func) return function () {};
|
@@ -502,7 +503,7 @@ export default (source, flags = [ 'module' ], customImports = {}, print = str =>
|
|
502
503
|
|
503
504
|
if (exceptionMode === 'stackest') {
|
504
505
|
const constructorIdx = e.getArg(exceptTag, 0);
|
505
|
-
const constructorName = constructorIdx == -1 ? null : funcs.find(x => (
|
506
|
+
const constructorName = constructorIdx == -1 ? null : funcs.find(x => (x.index - importedFuncs.length) === constructorIdx)?.name;
|
506
507
|
|
507
508
|
const value = e.getArg(exceptTag, 1);
|
508
509
|
const type = e.getArg(exceptTag, 2);
|
package/package.json
CHANGED