porffor 0.1.1 → 0.2.0-c6c8c81
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/README.md +184 -204
- package/compiler/2c.js +377 -0
- package/compiler/builtins/base64.js +91 -91
- package/compiler/builtins.js +19 -13
- package/compiler/codeGen.js +1313 -418
- package/compiler/decompile.js +35 -9
- package/compiler/embedding.js +9 -5
- package/compiler/encoding.js +8 -2
- package/compiler/index.js +55 -17
- package/compiler/log.js +15 -0
- package/compiler/opt.js +357 -258
- package/compiler/parse.js +24 -1
- package/compiler/prototype.js +263 -56
- package/compiler/sections.js +51 -8
- package/compiler/wasmSpec.js +3 -0
- package/compiler/wrap.js +20 -6
- package/package.json +6 -1
- package/porf.cmd +1 -1
- package/rhemyn/README.md +37 -0
- package/rhemyn/compile.js +214 -0
- package/rhemyn/parse.js +321 -0
- package/rhemyn/test/parse.js +59 -0
- package/runner/index.js +54 -31
- package/runner/info.js +37 -2
- package/runner/profile.js +1 -2
- package/runner/repl.js +13 -11
- package/runner/results.json +1 -0
- package/runner/transform.js +15 -36
- package/runner/version.js +10 -0
- package/CNAME +0 -1
- package/index.html +0 -1264
- package/logo.png +0 -0
- package/sw.js +0 -26
package/compiler/decompile.js
CHANGED
@@ -17,8 +17,10 @@ export default (wasm, name = '', ind = 0, locals = {}, params = [], returns = []
|
|
17
17
|
const justLocals = Object.values(locals).sort((a, b) => a.idx - b.idx).slice(params.length);
|
18
18
|
if (justLocals.length > 0) out += ` local ${justLocals.map(x => invValtype[x.type]).join(' ')}\n`;
|
19
19
|
|
20
|
-
let i =
|
20
|
+
let i = -1, lastInst;
|
21
|
+
let byte = 0;
|
21
22
|
for (let inst of wasm.concat(name ? [ [ Opcodes.end ] ] : [])) {
|
23
|
+
i++;
|
22
24
|
if (inst[0] === null) continue;
|
23
25
|
|
24
26
|
if (inst[0] === 0xfd) { // simd inst prefix
|
@@ -32,9 +34,30 @@ export default (wasm, name = '', ind = 0, locals = {}, params = [], returns = []
|
|
32
34
|
|
33
35
|
if (inst[0] === Opcodes.end || inst[0] === Opcodes.else || inst[0] === Opcodes.catch_all) depth--;
|
34
36
|
|
35
|
-
|
36
|
-
|
37
|
-
|
37
|
+
out += ' '.repeat(Math.max(0, depth * 2));
|
38
|
+
|
39
|
+
let opStr = invOpcodes[inst[0]];
|
40
|
+
if (!opStr) {
|
41
|
+
console.log(`decomp: unknown op ${inst[0]?.toString?.(16)} @${i}`);
|
42
|
+
// console.log(`prior: ${invOpcodes[wasm[i - 1][0]]}`);
|
43
|
+
out += `;; unknown op ${inst[0]?.toString?.(16)}\n`;
|
44
|
+
continue;
|
45
|
+
}
|
46
|
+
|
47
|
+
// out += '0x' + byte.toString(10).padStart(2, '0');
|
48
|
+
byte += inst.length;
|
49
|
+
|
50
|
+
out += opStr.replace('_', '.').replace('return.', 'return_').replace('call.', 'call_').replace('br.', 'br_').replace('catch.', 'catch_');
|
51
|
+
|
52
|
+
const comments = [];
|
53
|
+
inst = inst.filter(x => {
|
54
|
+
if (typeof x === 'string') {
|
55
|
+
comments.push(x);
|
56
|
+
return false;
|
57
|
+
}
|
58
|
+
|
59
|
+
return true;
|
60
|
+
})
|
38
61
|
|
39
62
|
if (inst[0] === Opcodes.if || inst[0] === Opcodes.loop || inst[0] === Opcodes.block || inst[0] === Opcodes.else || inst[0] === Opcodes.try || inst[0] === Opcodes.catch_all) depth++;
|
40
63
|
|
@@ -42,8 +65,8 @@ export default (wasm, name = '', ind = 0, locals = {}, params = [], returns = []
|
|
42
65
|
out += ` ${read_ieee754_binary64(inst.slice(1))}`;
|
43
66
|
} else if (inst[0] === Opcodes.i32_const || inst[0] === Opcodes.i64_const) {
|
44
67
|
out += ` ${read_signedLEB128(inst.slice(1))}`;
|
45
|
-
} else if (inst[0] === Opcodes.i32_load || inst[0] === Opcodes.i64_load || inst[0] === Opcodes.f64_load || inst[0] === Opcodes.i32_store || inst[0] === Opcodes.i64_store || inst[0] === Opcodes.f64_store) {
|
46
|
-
out += ` ${inst[1]} ${read_unsignedLEB128(inst.slice(2))}
|
68
|
+
} else if (inst[0] === Opcodes.i32_load || inst[0] === Opcodes.i64_load || inst[0] === Opcodes.f64_load || inst[0] === Opcodes.i32_store || inst[0] === Opcodes.i64_store || inst[0] === Opcodes.f64_store || inst[0] === Opcodes.i32_store16 || inst[0] === Opcodes.i32_load16_u) {
|
69
|
+
out += ` ${inst[1]} ${read_unsignedLEB128(inst.slice(2))}`;
|
47
70
|
} else for (const operand of inst.slice(1)) {
|
48
71
|
if (inst[0] === Opcodes.if || inst[0] === Opcodes.loop || inst[0] === Opcodes.block) {
|
49
72
|
if (operand === Blocktype.void) continue;
|
@@ -53,11 +76,13 @@ export default (wasm, name = '', ind = 0, locals = {}, params = [], returns = []
|
|
53
76
|
}
|
54
77
|
}
|
55
78
|
|
79
|
+
if (comments.length > 0) out += ` ;; ${comments.join(' ')}`;
|
80
|
+
|
56
81
|
if (inst[0] === Opcodes.if || inst[0] === Opcodes.loop || inst[0] === Opcodes.block || inst[0] === Opcodes.else) {
|
57
82
|
out += ` ;; label @${depth}`;
|
58
83
|
}
|
59
84
|
|
60
|
-
if (inst[0] === Opcodes.br) {
|
85
|
+
if (inst[0] === Opcodes.br || inst[0] === Opcodes.br_if) {
|
61
86
|
out += ` ;; goto @${depth - inst[1]}`;
|
62
87
|
}
|
63
88
|
|
@@ -95,8 +120,9 @@ export const highlightAsm = asm =>
|
|
95
120
|
asm
|
96
121
|
.replace(/(local|global|memory)\.[^\s]*/g, _ => `\x1B[31m${_}\x1B[0m`)
|
97
122
|
.replace(/(i(8|16|32|64)x[0-9]+|v128)(\.[^\s]*)?/g, _ => `\x1B[34m${_}\x1B[0m`)
|
98
|
-
.replace(/[^m](i32|i64|f32|f64)(\.[^\s]*)?/g, _ => `${_[0]}\x1B[36m${_.slice(1)}\x1B[0m`)
|
123
|
+
.replace(/[^m](i32|i64|f32|f64|drop)(\.[^\s]*)?/g, _ => `${_[0]}\x1B[36m${_.slice(1)}\x1B[0m`)
|
99
124
|
.replace(/(return_call|call|br_if|br|return|throw|rethrow)/g, _ => `\x1B[35m${_}\x1B[0m`)
|
100
|
-
.replace(/(block|loop|if|end|else|try|catch|
|
125
|
+
.replace(/(block|loop|if|end|else|try|catch_all|catch|delegate)/g, _ => `\x1B[95m${_}\x1B[0m`)
|
126
|
+
.replace(/unreachable/g, _ => `\x1B[91m${_}\x1B[0m`)
|
101
127
|
.replace(/ \-?[0-9\.]+/g, _ => ` \x1B[33m${_.slice(1)}\x1B[0m`)
|
102
128
|
.replace(/ ;;.*$/gm, _ => `\x1B[90m${_.replaceAll(/\x1B\[[0-9]+m/g, '')}\x1B[0m`);
|
package/compiler/embedding.js
CHANGED
@@ -9,11 +9,15 @@ export const number = (n, valtype = valtypeBinary) => {
|
|
9
9
|
}
|
10
10
|
};
|
11
11
|
|
12
|
-
const
|
12
|
+
export const enforceOneByte = arr => [ arr[0] ?? 0 ];
|
13
|
+
export const enforceTwoBytes = arr => [ arr[0] ?? 0, arr[1] ?? 0 ];
|
14
|
+
export const enforceFourBytes = arr => [ arr[0] ?? 0, arr[1] ?? 0, arr[2] ?? 0, arr[3] ?? 0 ];
|
15
|
+
export const enforceEightBytes = arr => [ arr[0] ?? 0, arr[1] ?? 0, arr[2] ?? 0, arr[3] ?? 0, arr[4] ?? 0, arr[5] ?? 0, arr[6] ?? 0, arr[7] ?? 0 ];
|
16
|
+
|
13
17
|
export const i32x4 = (a, b, c, d) => [ [
|
14
18
|
...Opcodes.v128_const,
|
15
|
-
...
|
16
|
-
...
|
17
|
-
...
|
18
|
-
...
|
19
|
+
...enforceFourBytes(signedLEB128(a)),
|
20
|
+
...enforceFourBytes(signedLEB128(b)),
|
21
|
+
...enforceFourBytes(signedLEB128(c)),
|
22
|
+
...enforceFourBytes(signedLEB128(d))
|
19
23
|
] ];
|
package/compiler/encoding.js
CHANGED
@@ -22,15 +22,15 @@ export const encodeLocal = (count, type) => [
|
|
22
22
|
type
|
23
23
|
];
|
24
24
|
|
25
|
+
// todo: this only works with integers within 32 bit range
|
25
26
|
export const signedLEB128 = n => {
|
26
|
-
|
27
|
+
n |= 0;
|
27
28
|
|
28
29
|
// just input for small numbers (for perf as common)
|
29
30
|
if (n >= 0 && n <= 63) return [ n ];
|
30
31
|
if (n >= -64 && n <= 0) return [ 128 + n ];
|
31
32
|
|
32
33
|
const buffer = [];
|
33
|
-
n |= 0;
|
34
34
|
|
35
35
|
while (true) {
|
36
36
|
let byte = n & 0x7f;
|
@@ -50,6 +50,8 @@ export const signedLEB128 = n => {
|
|
50
50
|
};
|
51
51
|
|
52
52
|
export const unsignedLEB128 = n => {
|
53
|
+
n |= 0;
|
54
|
+
|
53
55
|
// just input for small numbers (for perf as common)
|
54
56
|
if (n >= 0 && n <= 127) return [ n ];
|
55
57
|
|
@@ -107,6 +109,8 @@ export const read_unsignedLEB128 = _input => {
|
|
107
109
|
// from https://github.com/feross/ieee754
|
108
110
|
// BSD 3-Clause. Copyright 2008 Fair Oaks Labs, Inc. (https://github.com/feross/ieee754/blob/master/LICENSE)
|
109
111
|
export const ieee754_binary64 = value => {
|
112
|
+
return [...new Uint8Array(new Float64Array([ value ]).buffer)];
|
113
|
+
|
110
114
|
let isLE = true, mLen = 52, nBytes = 8, offset = 0;
|
111
115
|
let buffer = new Array(nBytes).fill(0);
|
112
116
|
|
@@ -174,6 +178,8 @@ export const ieee754_binary64 = value => {
|
|
174
178
|
};
|
175
179
|
|
176
180
|
export const read_ieee754_binary64 = buffer => {
|
181
|
+
return new Float64Array(new Uint8Array(buffer).buffer)[0];
|
182
|
+
|
177
183
|
let isLE = true, mLen = 52, nBytes = 8, offset = 0;
|
178
184
|
|
179
185
|
let e, m
|
package/compiler/index.js
CHANGED
@@ -1,29 +1,20 @@
|
|
1
|
+
import { underline, bold, log } from './log.js';
|
1
2
|
import parse from './parse.js';
|
2
3
|
import codeGen from './codeGen.js';
|
3
4
|
import opt from './opt.js';
|
4
5
|
import produceSections from './sections.js';
|
5
6
|
import decompile from './decompile.js';
|
6
7
|
import { BuiltinPreludes } from './builtins.js';
|
8
|
+
import toc from './2c.js';
|
7
9
|
|
8
10
|
globalThis.decompile = decompile;
|
9
11
|
|
10
|
-
const rgb = (r, g, b, x) => `\x1b[38;2;${r};${g};${b}m${x}\u001b[0m`;
|
11
|
-
const underline = x => `\u001b[4m${x}\u001b[0m`;
|
12
|
-
const bold = x => `\u001b[1m${x}\u001b[0m`;
|
13
|
-
|
14
|
-
const areaColors = {
|
15
|
-
codegen: [ 20, 80, 250 ],
|
16
|
-
opt: [ 250, 20, 80 ],
|
17
|
-
sections: [ 20, 250, 80 ]
|
18
|
-
};
|
19
|
-
|
20
|
-
globalThis.log = (area, ...args) => console.log(`\u001b[90m[\u001b[0m${rgb(...areaColors[area], area)}\u001b[90m]\u001b[0m`, ...args);
|
21
|
-
|
22
12
|
const logFuncs = (funcs, globals, exceptions) => {
|
23
13
|
console.log('\n' + underline(bold('funcs')));
|
24
14
|
|
15
|
+
const startIndex = funcs.sort((a, b) => a.index - b.index)[0].index;
|
25
16
|
for (const f of funcs) {
|
26
|
-
console.log(`${underline(f.name)} (${f.index})`);
|
17
|
+
console.log(`${underline(f.name)} (${f.index - startIndex})`);
|
27
18
|
|
28
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(', ')}`);
|
29
20
|
console.log(`returns: ${f.returns.length > 0 ? true : false}`);
|
@@ -35,9 +26,16 @@ const logFuncs = (funcs, globals, exceptions) => {
|
|
35
26
|
console.log();
|
36
27
|
};
|
37
28
|
|
29
|
+
const getArg = name => process.argv.find(x => x.startsWith(`-${name}=`))?.slice(name.length + 2);
|
30
|
+
|
31
|
+
const writeFileSync = (typeof process !== 'undefined' ? (await import('node:fs')).writeFileSync : undefined);
|
32
|
+
const execSync = (typeof process !== 'undefined' ? (await import('node:child_process')).execSync : undefined);
|
33
|
+
|
38
34
|
export default (code, flags) => {
|
39
35
|
globalThis.optLog = process.argv.includes('-opt-log');
|
40
36
|
globalThis.codeLog = process.argv.includes('-code-log');
|
37
|
+
globalThis.allocLog = process.argv.includes('-alloc-log');
|
38
|
+
globalThis.regexLog = process.argv.includes('-regex-log');
|
41
39
|
|
42
40
|
for (const x in BuiltinPreludes) {
|
43
41
|
if (code.indexOf(x + '(') !== -1) code = BuiltinPreludes[x] + code;
|
@@ -48,20 +46,60 @@ export default (code, flags) => {
|
|
48
46
|
if (flags.includes('info')) console.log(`1. parsed in ${(performance.now() - t0).toFixed(2)}ms`);
|
49
47
|
|
50
48
|
const t1 = performance.now();
|
51
|
-
const { funcs, globals, tags, exceptions, pages } = codeGen(program);
|
49
|
+
const { funcs, globals, tags, exceptions, pages, data } = codeGen(program);
|
52
50
|
if (flags.includes('info')) console.log(`2. generated code in ${(performance.now() - t1).toFixed(2)}ms`);
|
53
51
|
|
54
52
|
if (process.argv.includes('-funcs')) logFuncs(funcs, globals, exceptions);
|
55
53
|
|
56
54
|
const t2 = performance.now();
|
57
|
-
opt(funcs, globals);
|
55
|
+
opt(funcs, globals, pages);
|
58
56
|
if (flags.includes('info')) console.log(`3. optimized code in ${(performance.now() - t2).toFixed(2)}ms`);
|
59
57
|
|
60
58
|
if (process.argv.includes('-opt-funcs')) logFuncs(funcs, globals, exceptions);
|
61
59
|
|
62
60
|
const t3 = performance.now();
|
63
|
-
const sections = produceSections(funcs, globals, tags, pages, flags);
|
61
|
+
const sections = produceSections(funcs, globals, tags, pages, data, flags);
|
64
62
|
if (flags.includes('info')) console.log(`4. produced sections in ${(performance.now() - t3).toFixed(2)}ms`);
|
65
63
|
|
66
|
-
|
64
|
+
if (allocLog) {
|
65
|
+
const wasmPages = Math.ceil((pages.size * pageSize) / 65536);
|
66
|
+
const bytes = wasmPages * 65536;
|
67
|
+
log('alloc', `\x1B[1mallocated ${bytes / 1024}KiB\x1B[0m for ${pages.size} things using ${wasmPages} Wasm page${wasmPages === 1 ? '' : 's'}`);
|
68
|
+
console.log([...pages.keys()].map(x => `\x1B[36m - ${x}\x1B[0m`).join('\n') + '\n');
|
69
|
+
}
|
70
|
+
|
71
|
+
const out = { wasm: sections, funcs, globals, tags, exceptions, pages };
|
72
|
+
|
73
|
+
const target = getArg('target') ?? getArg('t') ?? 'wasm';
|
74
|
+
const outFile = getArg('o');
|
75
|
+
|
76
|
+
if (target === 'c') {
|
77
|
+
const c = toc(out);
|
78
|
+
|
79
|
+
if (outFile) {
|
80
|
+
writeFileSync(outFile, c);
|
81
|
+
} else {
|
82
|
+
console.log(c);
|
83
|
+
}
|
84
|
+
|
85
|
+
process.exit();
|
86
|
+
}
|
87
|
+
|
88
|
+
if (target === 'native') {
|
89
|
+
const compiler = getArg('compiler') ?? 'clang';
|
90
|
+
const cO = getArg('cO') ?? 'Ofast';
|
91
|
+
|
92
|
+
const tmpfile = 'tmp.c';
|
93
|
+
const args = [ compiler, tmpfile, '-o', outFile ?? (process.platform === 'win32' ? 'out.exe' : 'out'), '-' + cO, '-march=native' ];
|
94
|
+
|
95
|
+
const c = toc(out);
|
96
|
+
writeFileSync(tmpfile, c);
|
97
|
+
|
98
|
+
// obvious command escape is obvious
|
99
|
+
execSync(args.join(' '), { stdio: 'inherit' });
|
100
|
+
|
101
|
+
process.exit();
|
102
|
+
}
|
103
|
+
|
104
|
+
return out;
|
67
105
|
};
|
package/compiler/log.js
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
export const rgb = (r, g, b, x) => `\x1b[38;2;${r};${g};${b}m${x}\u001b[0m`;
|
2
|
+
export const underline = x => `\u001b[4m${x}\u001b[0m`;
|
3
|
+
export const bold = x => `\u001b[1m${x}\u001b[0m`;
|
4
|
+
|
5
|
+
const areaColors = {
|
6
|
+
codegen: [ 20, 80, 250 ],
|
7
|
+
opt: [ 250, 20, 80 ],
|
8
|
+
sections: [ 20, 250, 80 ],
|
9
|
+
alloc: [ 250, 250, 20 ],
|
10
|
+
parser: [ 240, 240, 240 ],
|
11
|
+
'2c': [ 20, 250, 250 ]
|
12
|
+
};
|
13
|
+
|
14
|
+
export const log = (area, ...args) => console.log(`\u001b[90m[\u001b[0m${rgb(...areaColors[area], area)}\u001b[90m]\u001b[0m`, ...args);
|
15
|
+
log.warning = (area, ...args) => log(area, '\u001b[93m' + args[0], ...args.slice(1), '\u001b[0m');
|