porffor 0.14.0-7bef6473d → 0.14.0-a24ac8cf2
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 +12 -1
- package/compiler/codegen.js +91 -21
- package/compiler/index.js +3 -8
- package/compiler/precompile.js +1 -1
- package/compiler/prefs.js +1 -1
- package/compiler/wrap.js +10 -5
- package/package.json +1 -1
package/compiler/assemble.js
CHANGED
@@ -65,6 +65,7 @@ export default (funcs, globals, tags, pages, data, flags) => {
|
|
65
65
|
importFuncs = [...imports.values()];
|
66
66
|
|
67
67
|
// fix call indexes for non-imports
|
68
|
+
// also fix call_indirect types
|
68
69
|
const delta = importedFuncs.length - importFuncs.length;
|
69
70
|
for (const f of funcs) {
|
70
71
|
f.originalIndex = f.index;
|
@@ -74,6 +75,16 @@ export default (funcs, globals, tags, pages, data, flags) => {
|
|
74
75
|
if ((inst[0] === Opcodes.call || inst[0] === Opcodes.return_call) && inst[1] >= importedFuncs.length) {
|
75
76
|
inst[1] -= delta;
|
76
77
|
}
|
78
|
+
|
79
|
+
if (inst[0] === Opcodes.call_indirect) {
|
80
|
+
const params = [];
|
81
|
+
for (let i = 0; i < inst[1]; i++) {
|
82
|
+
params.push(valtypeBinary, Valtype.i32);
|
83
|
+
}
|
84
|
+
|
85
|
+
const returns = [ valtypeBinary, Valtype.i32 ];
|
86
|
+
inst[1] = getType(params, returns);
|
87
|
+
}
|
77
88
|
}
|
78
89
|
}
|
79
90
|
}
|
@@ -101,7 +112,7 @@ export default (funcs, globals, tags, pages, data, flags) => {
|
|
101
112
|
encodeVector([ [
|
102
113
|
0x00,
|
103
114
|
Opcodes.i32_const, 0, Opcodes.end,
|
104
|
-
encodeVector(funcs.map(x => x.index))
|
115
|
+
...encodeVector(funcs.map(x => x.index))
|
105
116
|
] ])
|
106
117
|
);
|
107
118
|
|
package/compiler/codegen.js
CHANGED
@@ -58,10 +58,11 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
|
|
58
58
|
|
59
59
|
case 'ArrowFunctionExpression':
|
60
60
|
case 'FunctionDeclaration':
|
61
|
+
case 'FunctionExpression':
|
61
62
|
const func = generateFunc(scope, decl);
|
62
63
|
|
63
64
|
if (decl.type.endsWith('Expression')) {
|
64
|
-
return number(func.index);
|
65
|
+
return number(func.index - importedFuncs.length);
|
65
66
|
}
|
66
67
|
|
67
68
|
return [];
|
@@ -187,7 +188,7 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
|
|
187
188
|
if (!Array.isArray(inst)) inst = [ inst ];
|
188
189
|
const immediates = asm.slice(1).map(x => {
|
189
190
|
const int = parseInt(x);
|
190
|
-
if (Number.isNaN(int)) return scope.locals[x]?.idx;
|
191
|
+
if (Number.isNaN(int)) return scope.locals[x]?.idx ?? globals[x].idx;
|
191
192
|
return int;
|
192
193
|
});
|
193
194
|
|
@@ -313,10 +314,10 @@ const generateIdent = (scope, decl) => {
|
|
313
314
|
|
314
315
|
if (local?.idx === undefined) {
|
315
316
|
// no local var with name
|
316
|
-
if (Object.hasOwn(importedFuncs, name)) return number(importedFuncs[name]);
|
317
|
-
if (Object.hasOwn(funcIndex, name)) return number(funcIndex[name]);
|
318
|
-
|
319
317
|
if (Object.hasOwn(globals, name)) return [ [ Opcodes.global_get, globals[name].idx ] ];
|
318
|
+
|
319
|
+
if (Object.hasOwn(importedFuncs, name)) return number(importedFuncs[name] - importedFuncs.length);
|
320
|
+
if (Object.hasOwn(funcIndex, name)) return number(funcIndex[name] - importedFuncs.length);
|
320
321
|
}
|
321
322
|
|
322
323
|
if (local?.idx === undefined && rawName.startsWith('__')) {
|
@@ -350,9 +351,7 @@ const generateReturn = (scope, decl) => {
|
|
350
351
|
|
351
352
|
return [
|
352
353
|
...generate(scope, decl.argument),
|
353
|
-
...(scope.returnType != null ? [] :
|
354
|
-
...getNodeType(scope, decl.argument)
|
355
|
-
]),
|
354
|
+
...(scope.returnType != null ? [] : getNodeType(scope, decl.argument)),
|
356
355
|
[ Opcodes.return ]
|
357
356
|
];
|
358
357
|
};
|
@@ -1450,6 +1449,10 @@ const countLeftover = wasm => {
|
|
1450
1449
|
} else count--;
|
1451
1450
|
if (func) count += func.returns.length;
|
1452
1451
|
}
|
1452
|
+
} else if (inst[0] === Opcodes.call_indirect) {
|
1453
|
+
count--; // funcidx
|
1454
|
+
count -= inst[1] * 2; // params * 2 (typed)
|
1455
|
+
count += 2; // fixed return (value, type)
|
1453
1456
|
} else count--;
|
1454
1457
|
|
1455
1458
|
// console.log(count, decompile([ inst ]).slice(0, -1));
|
@@ -1831,7 +1834,45 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1831
1834
|
}
|
1832
1835
|
|
1833
1836
|
if (idx === undefined) {
|
1834
|
-
if (scope.locals[name] !== undefined || globals[name] !== undefined || builtinVars[name] !== undefined)
|
1837
|
+
if (scope.locals[name] !== undefined || globals[name] !== undefined || builtinVars[name] !== undefined) {
|
1838
|
+
const [ local, global ] = lookupName(scope, name);
|
1839
|
+
if (!Prefs.indirectCalls || local == null) return internalThrow(scope, 'TypeError', `${unhackName(name)} is not a function`, true);
|
1840
|
+
|
1841
|
+
// todo: only works when:
|
1842
|
+
// 1. arg count matches arg count of function
|
1843
|
+
// 2. function uses typedParams and typedReturns
|
1844
|
+
|
1845
|
+
funcs.table = true;
|
1846
|
+
|
1847
|
+
let args = decl.arguments;
|
1848
|
+
let argWasm = [];
|
1849
|
+
|
1850
|
+
for (let i = 0; i < args.length; i++) {
|
1851
|
+
const arg = args[i];
|
1852
|
+
argWasm = argWasm.concat(generate(scope, arg));
|
1853
|
+
|
1854
|
+
if (valtypeBinary !== Valtype.i32 && (
|
1855
|
+
(builtinFuncs[name] && builtinFuncs[name].params[i * (typedParams ? 2 : 1)] === Valtype.i32) ||
|
1856
|
+
(importedFuncs[name] && name.startsWith('profile'))
|
1857
|
+
)) {
|
1858
|
+
argWasm.push(Opcodes.i32_to);
|
1859
|
+
}
|
1860
|
+
|
1861
|
+
argWasm = argWasm.concat(getNodeType(scope, arg));
|
1862
|
+
}
|
1863
|
+
|
1864
|
+
return typeSwitch(scope, getNodeType(scope, decl.callee), {
|
1865
|
+
[TYPES.function]: [
|
1866
|
+
...argWasm,
|
1867
|
+
[ global ? Opcodes.global_get : Opcodes.local_get, local.idx ],
|
1868
|
+
Opcodes.i32_to_u,
|
1869
|
+
[ Opcodes.call_indirect, args.length, 0 ],
|
1870
|
+
...setLastType(scope)
|
1871
|
+
],
|
1872
|
+
default: internalThrow(scope, 'TypeError', `${unhackName(name)} is not a function`, true)
|
1873
|
+
});
|
1874
|
+
}
|
1875
|
+
|
1835
1876
|
return internalThrow(scope, 'ReferenceError', `${unhackName(name)} is not defined`, true);
|
1836
1877
|
}
|
1837
1878
|
|
@@ -1860,11 +1901,10 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
1860
1901
|
const arg = args[i];
|
1861
1902
|
out = out.concat(generate(scope, arg));
|
1862
1903
|
|
1863
|
-
if (
|
1864
|
-
|
1865
|
-
|
1866
|
-
|
1867
|
-
if (importedFuncs[name] && name.startsWith('profile')) {
|
1904
|
+
if (valtypeBinary !== Valtype.i32 && (
|
1905
|
+
(builtinFuncs[name] && builtinFuncs[name].params[i * (typedParams ? 2 : 1)] === Valtype.i32) ||
|
1906
|
+
(importedFuncs[name] && name.startsWith('profile'))
|
1907
|
+
)) {
|
1868
1908
|
out.push(Opcodes.i32_to);
|
1869
1909
|
}
|
1870
1910
|
|
@@ -2174,6 +2214,22 @@ const generateVar = (scope, decl) => {
|
|
2174
2214
|
}
|
2175
2215
|
|
2176
2216
|
if (x.init) {
|
2217
|
+
// if (isFuncType(x.init.type)) {
|
2218
|
+
// // let a = function () { ... }
|
2219
|
+
// x.init.id = { name };
|
2220
|
+
|
2221
|
+
// const func = generateFunc(scope, x.init);
|
2222
|
+
|
2223
|
+
// out.push(
|
2224
|
+
// ...number(func.index - importedFuncs.length),
|
2225
|
+
// [ global ? Opcodes.global_set : Opcodes.local_set, idx ],
|
2226
|
+
|
2227
|
+
// ...setType(scope, name, TYPES.function)
|
2228
|
+
// );
|
2229
|
+
|
2230
|
+
// continue;
|
2231
|
+
// }
|
2232
|
+
|
2177
2233
|
const generated = generate(scope, x.init, global, name);
|
2178
2234
|
if (scope.arrays?.get(name) != null) {
|
2179
2235
|
// hack to set local as pointer before
|
@@ -2185,6 +2241,7 @@ const generateVar = (scope, decl) => {
|
|
2185
2241
|
out = out.concat(generated);
|
2186
2242
|
out.push([ global ? Opcodes.global_set : Opcodes.local_set, idx ]);
|
2187
2243
|
}
|
2244
|
+
|
2188
2245
|
out.push(...setType(scope, name, getNodeType(scope, x.init)));
|
2189
2246
|
}
|
2190
2247
|
|
@@ -2198,6 +2255,7 @@ const generateVar = (scope, decl) => {
|
|
2198
2255
|
// todo: optimize this func for valueUnused
|
2199
2256
|
const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
2200
2257
|
const { type, name } = decl.left;
|
2258
|
+
const [ local, isGlobal ] = lookupName(scope, name);
|
2201
2259
|
|
2202
2260
|
if (type === 'ObjectPattern') {
|
2203
2261
|
// hack: ignore object parts of `var a = {} = 2`
|
@@ -2207,8 +2265,18 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2207
2265
|
if (isFuncType(decl.right.type)) {
|
2208
2266
|
// hack for a = function () { ... }
|
2209
2267
|
decl.right.id = { name };
|
2210
|
-
|
2211
|
-
|
2268
|
+
|
2269
|
+
const func = generateFunc(scope, decl.right);
|
2270
|
+
|
2271
|
+
return [
|
2272
|
+
...number(func.index - importedFuncs.length),
|
2273
|
+
...(local != null ? [
|
2274
|
+
[ isGlobal ? Opcodes.global_set : Opcodes.local_set, local.idx ],
|
2275
|
+
[ isGlobal ? Opcodes.global_get : Opcodes.local_get, local.idx ],
|
2276
|
+
|
2277
|
+
...setType(scope, name, TYPES.function)
|
2278
|
+
] : [])
|
2279
|
+
];
|
2212
2280
|
}
|
2213
2281
|
|
2214
2282
|
const op = decl.operator.slice(0, -1) || '=';
|
@@ -2307,8 +2375,6 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
2307
2375
|
|
2308
2376
|
if (!name) return todo(scope, 'destructuring is not supported yet', true);
|
2309
2377
|
|
2310
|
-
const [ local, isGlobal ] = lookupName(scope, name);
|
2311
|
-
|
2312
2378
|
if (local === undefined) {
|
2313
2379
|
// todo: this should be a sloppy mode only thing
|
2314
2380
|
|
@@ -3368,7 +3434,7 @@ const generateFunc = (scope, decl) => {
|
|
3368
3434
|
|
3369
3435
|
if (typedInput && decl.returnType) {
|
3370
3436
|
const { type } = extractTypeAnnotation(decl.returnType);
|
3371
|
-
if (type != null) {
|
3437
|
+
if (type != null && !Prefs.indirectCalls) {
|
3372
3438
|
innerScope.returnType = type;
|
3373
3439
|
innerScope.returns = [ valtypeBinary ];
|
3374
3440
|
}
|
@@ -3586,8 +3652,10 @@ const internalConstrs = {
|
|
3586
3652
|
}),
|
3587
3653
|
|
3588
3654
|
// print space
|
3589
|
-
...
|
3590
|
-
|
3655
|
+
...(i !== decl.arguments.length - 1 ? [
|
3656
|
+
...number(32),
|
3657
|
+
[ Opcodes.call, importedFuncs.printChar ]
|
3658
|
+
] : [])
|
3591
3659
|
);
|
3592
3660
|
}
|
3593
3661
|
|
@@ -3597,6 +3665,8 @@ const internalConstrs = {
|
|
3597
3665
|
[ Opcodes.call, importedFuncs.printChar ]
|
3598
3666
|
);
|
3599
3667
|
|
3668
|
+
out.push(...number(UNDEFINED));
|
3669
|
+
|
3600
3670
|
return out;
|
3601
3671
|
},
|
3602
3672
|
type: TYPES.undefined,
|
package/compiler/index.js
CHANGED
@@ -12,14 +12,7 @@ globalThis.decompile = decompile;
|
|
12
12
|
const logFuncs = (funcs, globals, exceptions) => {
|
13
13
|
console.log('\n' + underline(bold('funcs')));
|
14
14
|
|
15
|
-
const startIndex = funcs.sort((a, b) => a.index - b.index)[0].index;
|
16
15
|
for (const f of funcs) {
|
17
|
-
console.log(`${underline(f.name)} (${f.index - startIndex})`);
|
18
|
-
|
19
|
-
console.log(`params: ${f.params.map((_, i) => Object.keys(f.locals)[Object.values(f.locals).indexOf(Object.values(f.locals).find(x => x.idx === i))]).join(', ')}`);
|
20
|
-
console.log(`returns: ${f.returns.length > 0 ? true : false}`);
|
21
|
-
console.log(`locals: ${Object.keys(f.locals).sort((a, b) => f.locals[a].idx - f.locals[b].idx).map(x => `${x} (${f.locals[x].idx})`).join(', ')}`);
|
22
|
-
console.log();
|
23
16
|
console.log(decompile(f.wasm, f.name, f.index, f.locals, f.params, f.returns, funcs, globals, exceptions));
|
24
17
|
}
|
25
18
|
|
@@ -44,12 +37,14 @@ export default (code, flags) => {
|
|
44
37
|
opt(funcs, globals, pages, tags, exceptions);
|
45
38
|
if (Prefs.profileCompiler) console.log(`3. optimized in ${(performance.now() - t2).toFixed(2)}ms`);
|
46
39
|
|
47
|
-
if (Prefs.optFuncs) logFuncs(funcs, globals, exceptions);
|
40
|
+
// if (Prefs.optFuncs) logFuncs(funcs, globals, exceptions);
|
48
41
|
|
49
42
|
const t3 = performance.now();
|
50
43
|
const wasm = assemble(funcs, globals, tags, pages, data, flags);
|
51
44
|
if (Prefs.profileCompiler) console.log(`4. assembled in ${(performance.now() - t3).toFixed(2)}ms`);
|
52
45
|
|
46
|
+
if (Prefs.optFuncs) logFuncs(funcs, globals, exceptions);
|
47
|
+
|
53
48
|
if (Prefs.allocLog) {
|
54
49
|
const wasmPages = Math.ceil((pages.size * pageSize) / 65536);
|
55
50
|
const bytes = wasmPages * 65536;
|
package/compiler/precompile.js
CHANGED
@@ -18,7 +18,7 @@ const compile = async (file, [ _funcs, _globals ]) => {
|
|
18
18
|
first = source.slice(0, source.indexOf('\n'));
|
19
19
|
}
|
20
20
|
|
21
|
-
let args = ['--bytestring', '--todo-time=compile', '--no-aot-pointer-opt', '--no-treeshake-wasm-imports', '--no-rm-unused-types', '--scoped-page-names', '--funsafe-no-unlikely-proto-checks', '--parse-types', '--opt-types'];
|
21
|
+
let args = ['--bytestring', '--todo-time=compile', '--no-aot-pointer-opt', '--no-indirect-calls', '--no-treeshake-wasm-imports', '--no-rm-unused-types', '--scoped-page-names', '--funsafe-no-unlikely-proto-checks', '--parse-types', '--opt-types'];
|
22
22
|
if (first.startsWith('// @porf')) {
|
23
23
|
args = args.concat(first.slice('// @porf '.length).split(' '));
|
24
24
|
}
|
package/compiler/prefs.js
CHANGED
package/compiler/wrap.js
CHANGED
@@ -1,6 +1,7 @@
|
|
1
|
+
import { encodeVector, encodeLocal } from './encoding.js';
|
2
|
+
import { importedFuncs } from './builtins.js';
|
1
3
|
import compile from './index.js';
|
2
4
|
import decompile from './decompile.js';
|
3
|
-
import { encodeVector, encodeLocal } from './encoding.js';
|
4
5
|
import { TYPES } from './types.js';
|
5
6
|
import { log } from './log.js';
|
6
7
|
import Prefs from './prefs.js';
|
@@ -14,9 +15,13 @@ const porfToJSValue = (memory, funcs, value, type) => {
|
|
14
15
|
case TYPES.object: return value === 0 ? null : {};
|
15
16
|
|
16
17
|
case TYPES.function: {
|
17
|
-
|
18
|
-
|
19
|
-
|
18
|
+
let func;
|
19
|
+
if (value < 0) {
|
20
|
+
func = importedFuncs[value + importedFuncs.length];
|
21
|
+
} else {
|
22
|
+
func = funcs.find(x => ((x.originalIndex ?? x.index) - importedFuncs.length) === value);
|
23
|
+
}
|
24
|
+
|
20
25
|
if (!func) return function () {};
|
21
26
|
|
22
27
|
// make fake empty func for repl/etc
|
@@ -216,7 +221,7 @@ export default async (source, flags = [ 'module' ], customImports = {}, print =
|
|
216
221
|
|
217
222
|
if (ret == null) return undefined;
|
218
223
|
|
219
|
-
return porfToJSValue(memory, funcs, ret[0], ret[1])
|
224
|
+
return porfToJSValue(memory, funcs, ret[0], ret[1]);
|
220
225
|
} catch (e) {
|
221
226
|
if (e.is && e.is(exceptTag)) {
|
222
227
|
const exceptId = e.getArg(exceptTag, 0);
|
package/package.json
CHANGED