porffor 0.50.26 → 0.50.27
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/CONTRIBUTING.md +1 -1
- package/README.md +1 -1
- package/compiler/assemble.js +1 -1
- package/compiler/builtins.js +0 -1
- package/compiler/{decompile.js → disassemble.js} +1 -1
- package/compiler/encoding.js +0 -10
- package/compiler/index.js +7 -5
- package/compiler/parse.js +1 -3
- package/compiler/wrap.js +14 -21
- package/package.json +1 -1
- package/rhemyn/compile.js +1 -1
- package/runner/index.js +39 -2
- package/runner/repl.js +1 -1
package/CONTRIBUTING.md
CHANGED
@@ -291,7 +291,7 @@ i32.eq
|
|
291
291
|
i32.and
|
292
292
|
```
|
293
293
|
|
294
|
-
This part is a little more complicated, first you have to understand how Wasm represents function parameters and local variables in general. When looking at the
|
294
|
+
This part is a little more complicated, first you have to understand how Wasm represents function parameters and local variables in general. When looking at the disassembled output of something like `let a = 1;`, you'll likely see something like this:
|
295
295
|
```
|
296
296
|
f64.const 1
|
297
297
|
i32.const 1
|
package/README.md
CHANGED
@@ -107,7 +107,7 @@ Porffor can run Test262 via some hacks/transforms which remove unsupported featu
|
|
107
107
|
- `builtins_precompiled.js`: dynamically generated builtins from the `builtins/` folder
|
108
108
|
- `codegen.js`: code (wasm) generation, ast -> wasm. The bulk of the effort
|
109
109
|
- `cyclone.js`: wasm partial constant evaluator (it is fast and dangerous hence "cyclone")
|
110
|
-
- `
|
110
|
+
- `disassemble.js`: wasm disassembler using internal debug info
|
111
111
|
- `embedding.js`: utils for embedding consts
|
112
112
|
- `encoding.js`: utils for encoding things as bytes as wasm expects
|
113
113
|
- `expression.js`: mapping most operators to an opcode (advanced are as built-ins eg `f64_%`)
|
package/compiler/assemble.js
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
import { Valtype, FuncType, ExportDesc, Section, Magic, Opcodes, PageSize, Reftype } from './wasmSpec.js';
|
2
|
-
import { encodeVector, encodeString,
|
2
|
+
import { encodeVector, encodeString, unsignedLEB128, signedLEB128, unsignedLEB128_into, signedLEB128_into, ieee754_binary64, ieee754_binary64_into, unsignedLEB128_length } from './encoding.js';
|
3
3
|
import { importedFuncs } from './builtins.js';
|
4
4
|
import { log } from './log.js';
|
5
5
|
import './prefs.js';
|
package/compiler/builtins.js
CHANGED
@@ -49,7 +49,7 @@ export default (wasm, name = '', ind = 0, locals = {}, params = [], returns = []
|
|
49
49
|
|
50
50
|
let opStr = invOpcodes[inst[0]];
|
51
51
|
if (!opStr) {
|
52
|
-
console.log(`
|
52
|
+
console.log(`disasm: unknown op ${inst[0]?.toString?.(16)} @${i}`);
|
53
53
|
// console.log(`prior: ${invOpcodes[wasm[i - 1][0]]}`);
|
54
54
|
out += `;; unknown op ${inst[0]?.toString?.(16)}\n`;
|
55
55
|
continue;
|
package/compiler/encoding.js
CHANGED
@@ -10,15 +10,8 @@ export const codifyString = str => {
|
|
10
10
|
export const encodeString = str => unsignedLEB128(str.length).concat(codifyString(str));
|
11
11
|
export const encodeVector = data => unsignedLEB128(data.length).concat(data.flat());
|
12
12
|
|
13
|
-
export const encodeLocal = (count, type) => [
|
14
|
-
...unsignedLEB128(count),
|
15
|
-
type
|
16
|
-
];
|
17
|
-
|
18
13
|
// todo: this only works with integers within 32 bit range
|
19
14
|
export const signedLEB128 = n => {
|
20
|
-
if (typeof n === 'bigint') return big_signedLEB128(n);
|
21
|
-
|
22
15
|
n |= 0;
|
23
16
|
|
24
17
|
// just input for small numbers (for perf as common)
|
@@ -45,8 +38,6 @@ export const signedLEB128 = n => {
|
|
45
38
|
};
|
46
39
|
|
47
40
|
export const unsignedLEB128 = n => {
|
48
|
-
if (typeof n === 'bigint') return big_unsignedLEB128(n);
|
49
|
-
|
50
41
|
n |= 0;
|
51
42
|
|
52
43
|
// just input for small numbers (for perf as common)
|
@@ -217,5 +208,4 @@ export const unsignedLEB128_into = (n, buffer) => {
|
|
217
208
|
export const ieee754_binary64_into = (value, buffer) => {
|
218
209
|
const data = new Uint8Array(new Float64Array([ value ]).buffer);
|
219
210
|
for (let i = 0; i < 8; i++) buffer.push(data[i]);
|
220
|
-
// buffer.push(...new Uint8Array(new Float64Array([ value ]).buffer));
|
221
211
|
};
|
package/compiler/index.js
CHANGED
@@ -4,21 +4,23 @@ import parse from './parse.js';
|
|
4
4
|
import codegen from './codegen.js';
|
5
5
|
import opt from './opt.js';
|
6
6
|
import assemble from './assemble.js';
|
7
|
-
import
|
7
|
+
import disassemble from './disassemble.js';
|
8
8
|
import toc from './2c.js';
|
9
9
|
import * as pgo from './pgo.js';
|
10
10
|
import cyclone from './cyclone.js';
|
11
11
|
import './prefs.js';
|
12
12
|
|
13
|
-
globalThis.
|
13
|
+
globalThis.disassemble = disassemble;
|
14
14
|
|
15
15
|
const logFuncs = (funcs, globals, exceptions) => {
|
16
16
|
console.log('\n' + underline(bold('funcs')));
|
17
17
|
|
18
|
-
|
18
|
+
let wanted = Prefs.f;
|
19
|
+
if (typeof wanted !== 'string') wanted = null;
|
20
|
+
|
19
21
|
for (const f of funcs) {
|
20
22
|
if ((wanted && f.name !== wanted) || (!wanted && f.internal)) continue;
|
21
|
-
console.log(
|
23
|
+
console.log(disassemble(f.wasm, f.name, f.index, f.locals, f.params, f.returns, funcs, globals, exceptions));
|
22
24
|
}
|
23
25
|
|
24
26
|
console.log();
|
@@ -75,7 +77,7 @@ export default (code, module = undefined) => {
|
|
75
77
|
|
76
78
|
// change some prefs by default for c/native
|
77
79
|
if (target !== 'wasm') {
|
78
|
-
Prefs.pgo = Prefs.pgo === false || globalThis.document ? false : true; // enable pgo
|
80
|
+
// Prefs.pgo = Prefs.pgo === false || globalThis.document ? false : true; // enable pgo by default
|
79
81
|
Prefs.passiveData = false; // disable using passive Wasm data as unsupported by 2c for now
|
80
82
|
}
|
81
83
|
|
package/compiler/parse.js
CHANGED
@@ -3,13 +3,11 @@ import './prefs.js';
|
|
3
3
|
|
4
4
|
const file = globalThis.file;
|
5
5
|
|
6
|
-
// should we try to support types (while parsing)
|
7
6
|
const types = Prefs.parseTypes || Prefs.t || file?.endsWith('.ts');
|
8
7
|
globalThis.typedInput = types && Prefs.optTypes;
|
9
8
|
|
10
|
-
// todo: review which to use by default
|
11
9
|
// supported parsers:
|
12
|
-
// - acorn
|
10
|
+
// - acorn (default)
|
13
11
|
// - meriyah
|
14
12
|
// - hermes-parser
|
15
13
|
// - @babel/parser
|
package/compiler/wrap.js
CHANGED
@@ -1,7 +1,7 @@
|
|
1
|
-
import { encodeVector
|
1
|
+
import { encodeVector } from './encoding.js';
|
2
2
|
import { importedFuncs } from './builtins.js';
|
3
3
|
import compile from './index.js';
|
4
|
-
import
|
4
|
+
import disassemble from './disassemble.js';
|
5
5
|
import { TYPES, TYPE_NAMES } from './types.js';
|
6
6
|
import { log } from './log.js';
|
7
7
|
import './prefs.js';
|
@@ -352,7 +352,7 @@ export default (source, module = undefined, customImports = {}, print = str => p
|
|
352
352
|
times.push(performance.now() - t1);
|
353
353
|
if (Prefs.profileCompiler && !globalThis.onProgress) console.log(`\u001b[1mcompiled in ${times[0].toFixed(2)}ms\u001b[0m`);
|
354
354
|
|
355
|
-
const
|
355
|
+
const printBacktrace = (middleIndex, func, funcs, globals, exceptions) => {
|
356
356
|
console.log(`\x1B[35m\x1B[1mporffor backtrace\u001b[0m`);
|
357
357
|
|
358
358
|
const surrounding = Prefs.backtraceSurrounding ?? 10;
|
@@ -363,22 +363,22 @@ export default (source, module = undefined, customImports = {}, print = str => p
|
|
363
363
|
max = func.wasm.length;
|
364
364
|
}
|
365
365
|
|
366
|
-
const
|
366
|
+
const disasm = disassemble(func.wasm.slice(min, max), func.name, 0, func.locals, func.params, func.returns, funcs, globals, exceptions)
|
367
367
|
.slice(0, -1).split('\n').filter(x => !x.startsWith('\x1B[90m;;'));
|
368
368
|
|
369
369
|
const noAnsi = s => s.replace(/\u001b\[[0-9]+m/g, '');
|
370
370
|
let longest = 0;
|
371
|
-
for (let j = 0; j <
|
372
|
-
longest = Math.max(longest, noAnsi(
|
371
|
+
for (let j = 0; j < disassemble.length; j++) {
|
372
|
+
longest = Math.max(longest, noAnsi(disassemble[j]).length);
|
373
373
|
}
|
374
374
|
|
375
375
|
if (middleIndex != -1) {
|
376
|
-
const middle = Math.floor(
|
377
|
-
|
376
|
+
const middle = Math.floor(disasm.length / 2);
|
377
|
+
disasm[middle] = `\x1B[47m\x1B[30m${noAnsi(disasm[middle])}${'\u00a0'.repeat(longest - noAnsi(disasm[middle]).length)}\x1B[0m`;
|
378
378
|
}
|
379
379
|
|
380
380
|
if (min != 0) console.log('\x1B[90m...\x1B[0m');
|
381
|
-
console.log(
|
381
|
+
console.log(disasm.join('\n'));
|
382
382
|
if (max > func.wasm.length) console.log('\x1B[90m...\x1B[0m\n');
|
383
383
|
};
|
384
384
|
|
@@ -407,7 +407,7 @@ export default (source, module = undefined, customImports = {}, print = str => p
|
|
407
407
|
}
|
408
408
|
|
409
409
|
if (i === wasm.length) {
|
410
|
-
|
410
|
+
printBacktrace(-1, func, funcs, globals, exceptions);
|
411
411
|
return false;
|
412
412
|
}
|
413
413
|
|
@@ -421,11 +421,11 @@ export default (source, module = undefined, customImports = {}, print = str => p
|
|
421
421
|
}
|
422
422
|
|
423
423
|
if (cumLen !== offset) {
|
424
|
-
|
424
|
+
printBacktrace(-1, func, funcs, globals, exceptions);
|
425
425
|
return false;
|
426
426
|
}
|
427
427
|
|
428
|
-
|
428
|
+
printBacktrace(i + 1, func, funcs, globals, exceptions);
|
429
429
|
return true;
|
430
430
|
};
|
431
431
|
|
@@ -433,13 +433,6 @@ export default (source, module = undefined, customImports = {}, print = str => p
|
|
433
433
|
|
434
434
|
let instance;
|
435
435
|
try {
|
436
|
-
// let wasmEngine = WebAssembly;
|
437
|
-
// if (Prefs.asur) {
|
438
|
-
// log.warning('wrap', 'using our !experimental! asur wasm engine instead of host to run');
|
439
|
-
// wasmEngine = await import('../asur/index.js');
|
440
|
-
// }
|
441
|
-
|
442
|
-
// 0, { instance } = await wasmEngine.instantiate(wasm, {
|
443
436
|
const module = new WebAssembly.Module(wasm);
|
444
437
|
instance = new WebAssembly.Instance(module, {
|
445
438
|
'': {
|
@@ -543,8 +536,8 @@ export default (source, module = undefined, customImports = {}, print = str => p
|
|
543
536
|
};
|
544
537
|
}
|
545
538
|
|
546
|
-
if (Prefs.
|
547
|
-
return { exports, wasm, times,
|
539
|
+
if (Prefs.disassemble) {
|
540
|
+
return { exports, wasm, times, disams: funcs.map(x => disassemble(x.wasm, x.name, x.index, x.locals, x.params, x.returns, funcs, globals, exceptions)), c };
|
548
541
|
}
|
549
542
|
|
550
543
|
return { exports, wasm, times, pages, c };
|
package/package.json
CHANGED
package/rhemyn/compile.js
CHANGED
@@ -92,7 +92,7 @@ const generate = (node, negated = false, get = true, stringSize = 2, func = 'tes
|
|
92
92
|
const underline = x => `\u001b[4m\u001b[1m${x}\u001b[0m`;
|
93
93
|
console.log(`\n${underline('ast')}`);
|
94
94
|
console.log(node);
|
95
|
-
console.log(`\n${underline('wasm bytecode')}\n` +
|
95
|
+
console.log(`\n${underline('wasm bytecode')}\n` + disassemble(out) + '\n');
|
96
96
|
}
|
97
97
|
|
98
98
|
break;
|
package/runner/index.js
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
#!/usr/bin/env node
|
2
2
|
import fs from 'node:fs';
|
3
|
-
globalThis.version = '0.50.
|
3
|
+
globalThis.version = '0.50.27';
|
4
4
|
|
5
5
|
// deno compat
|
6
6
|
if (typeof process === 'undefined' && typeof Deno !== 'undefined') {
|
@@ -11,7 +11,7 @@ const start = performance.now();
|
|
11
11
|
|
12
12
|
if (process.argv.includes('--help')) {
|
13
13
|
// description + version
|
14
|
-
console.log(`\x1B[1m\x1B[35mPorffor\x1B[0m is a JavaScript/TypeScript engine/compiler/runtime. \x1B[
|
14
|
+
console.log(`\x1B[1m\x1B[35mPorffor\x1B[0m is a JavaScript/TypeScript engine/compiler/runtime. \x1B[2m(${globalThis.version})\x1B[0m`);
|
15
15
|
|
16
16
|
// basic usage
|
17
17
|
console.log(`Usage: \x1B[1mporf <command> [...prefs] path/to/script.js [...args]\x1B[0m`);
|
@@ -43,6 +43,43 @@ if (process.argv.includes('--help')) {
|
|
43
43
|
console.log(` \x1B[90mporf\x1B[0m \x1B[1m\x1B[${color}m${cmd}\x1B[0m\x1B[2m${post}\x1B[0m ${' '.repeat(30 - cmd.length - post.length)}${desc}`);
|
44
44
|
}
|
45
45
|
|
46
|
+
// flags
|
47
|
+
console.log(`\n\x1B[1m\x1B[4mFlags\x1B[0m`);
|
48
|
+
for (let [ flag, desc ] of Object.entries({
|
49
|
+
module: 'Parse input as a module',
|
50
|
+
t: 'Force TypeScript input',
|
51
|
+
d: 'Debug mode (include names in Wasm and debug logs)'
|
52
|
+
})) {
|
53
|
+
flag = '-' + flag;
|
54
|
+
if (flag.length > 3) flag = '-' + flag;
|
55
|
+
|
56
|
+
console.log(` \x1B[1m${flag}\x1B[0m${' '.repeat(36 - flag.length)}${desc}`);
|
57
|
+
}
|
58
|
+
|
59
|
+
// niche flags
|
60
|
+
if (process.argv.includes('--flags')) {
|
61
|
+
for (let [ flag, desc ] of Object.entries({
|
62
|
+
f: 'Print disassembled Wasm generated from user functions',
|
63
|
+
pgo: 'Enable PGO (profile-guided optimization)',
|
64
|
+
'profile-compiler': 'Log general compiler performance (on by default when compiling to a file)',
|
65
|
+
valtype: 'Valtype to use (i32|i64|\x1B[1mf64\x1B[0m)',
|
66
|
+
prng: 'PRNG algorithm to use (lcg32_glibc|lcg32_minstd|xorshift32+|xorshift64+|\x1B[1mxorshift128+\x1B[0m|xoroshiro128+|xoshiro128+)',
|
67
|
+
allocator: 'Allocator to use (oneshot|\x1B[1mchunk\x1B[0m)',
|
68
|
+
'exception-mode': 'Exception mode to use (lut|\x1B[1mstack\x1B[0m)',
|
69
|
+
fastLength: 'Spec non-compliant optimization to make .length faster',
|
70
|
+
'no-coctc': 'Disable COCTC (cross-object compile-time cache)',
|
71
|
+
cyclone: 'Enable experimental Cyclone optimizer',
|
72
|
+
'no-treeshake-wasm-imports': 'Do not treeshake Wasm imports'
|
73
|
+
})) {
|
74
|
+
flag = '-' + flag;
|
75
|
+
if (flag.length > 3) flag = '-' + flag;
|
76
|
+
|
77
|
+
console.log(` \x1B[1m${flag}\x1B[0m${' '.repeat(36 - flag.length)}${desc}`);
|
78
|
+
}
|
79
|
+
} else {
|
80
|
+
console.log(` \x1B[2m(To view all flags use --flags)\x1B[0m`);
|
81
|
+
}
|
82
|
+
|
46
83
|
console.log();
|
47
84
|
process.exit(0);
|
48
85
|
}
|
package/runner/repl.js
CHANGED