porffor 0.2.0-c7b7423 → 0.2.0-cb647c8
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 +89 -47
- package/compiler/2c.js +321 -71
- package/compiler/builtins/base64.ts +68 -0
- package/compiler/builtins/porffor.d.ts +2 -0
- package/compiler/builtins.js +177 -60
- package/compiler/codeGen.js +461 -227
- package/compiler/decompile.js +3 -3
- package/compiler/encoding.js +2 -116
- package/compiler/index.js +15 -9
- package/compiler/opt.js +24 -2
- package/compiler/parse.js +11 -12
- package/compiler/prototype.js +171 -16
- package/compiler/sections.js +1 -1
- package/compiler/wasmSpec.js +6 -2
- package/compiler/wrap.js +103 -9
- package/demo.js +3 -0
- package/demo.ts +1 -0
- package/filesize.cmd +2 -0
- package/package.json +1 -1
- package/porf +2 -0
- package/runner/index.js +20 -3
- package/runner/repl.js +2 -2
- package/tmp.c +1231 -52
- package/compiler/builtins/base64.js +0 -92
package/compiler/wrap.js
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
import compile from './index.js';
|
2
2
|
import decompile from './decompile.js';
|
3
|
+
import { encodeVector, encodeLocal } from './encoding.js';
|
3
4
|
// import fs from 'node:fs';
|
4
5
|
|
5
6
|
const bold = x => `\u001b[1m${x}\u001b[0m`;
|
@@ -18,7 +19,8 @@ const TYPES = {
|
|
18
19
|
|
19
20
|
// internal
|
20
21
|
[internalTypeBase]: '_array',
|
21
|
-
[internalTypeBase + 1]: '_regexp'
|
22
|
+
[internalTypeBase + 1]: '_regexp',
|
23
|
+
[internalTypeBase + 2]: '_bytestring'
|
22
24
|
};
|
23
25
|
|
24
26
|
export default async (source, flags = [ 'module' ], customImports = {}, print = str => process.stdout.write(str)) => {
|
@@ -35,14 +37,98 @@ export default async (source, flags = [ 'module' ], customImports = {}, print =
|
|
35
37
|
if (flags.includes('info')) console.log(bold(`compiled in ${times[0].toFixed(2)}ms`));
|
36
38
|
|
37
39
|
const t2 = performance.now();
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
40
|
+
|
41
|
+
let instance;
|
42
|
+
try {
|
43
|
+
0, { instance } = await WebAssembly.instantiate(wasm, {
|
44
|
+
'': {
|
45
|
+
p: valtype === 'i64' ? i => print(Number(i).toString()) : i => print(i.toString()),
|
46
|
+
c: valtype === 'i64' ? i => print(String.fromCharCode(Number(i))) : i => print(String.fromCharCode(i)),
|
47
|
+
t: _ => performance.now(),
|
48
|
+
...customImports
|
49
|
+
}
|
50
|
+
});
|
51
|
+
} catch (e) {
|
52
|
+
// only backtrace for runner, not test262/etc
|
53
|
+
if (!process.argv[1].includes('/runner')) throw e;
|
54
|
+
|
55
|
+
const funcInd = parseInt(e.message.match(/function #([0-9]+) /)[1]);
|
56
|
+
const blobOffset = parseInt(e.message.split('@')[1]);
|
57
|
+
|
58
|
+
// convert blob offset -> function wasm offset.
|
59
|
+
// this is not good code and is somewhat duplicated
|
60
|
+
// I just want it to work for debugging, I don't care about perf/yes
|
61
|
+
|
62
|
+
const func = funcs.find(x => x.index === funcInd);
|
63
|
+
const locals = Object.values(func.locals).sort((a, b) => a.idx - b.idx).slice(func.params.length).sort((a, b) => a.idx - b.idx);
|
64
|
+
|
65
|
+
let localDecl = [], typeCount = 0, lastType;
|
66
|
+
for (let i = 0; i < locals.length; i++) {
|
67
|
+
const local = locals[i];
|
68
|
+
if (i !== 0 && local.type !== lastType) {
|
69
|
+
localDecl.push(encodeLocal(typeCount, lastType));
|
70
|
+
typeCount = 0;
|
71
|
+
}
|
72
|
+
|
73
|
+
typeCount++;
|
74
|
+
lastType = local.type;
|
75
|
+
}
|
76
|
+
|
77
|
+
if (typeCount !== 0) localDecl.push(encodeLocal(typeCount, lastType));
|
78
|
+
|
79
|
+
const toFind = encodeVector(localDecl).concat(func.wasm.flat().filter(x => x != null && x <= 0xff).slice(0, 40));
|
80
|
+
|
81
|
+
let i = 0;
|
82
|
+
for (; i < wasm.length; i++) {
|
83
|
+
let mismatch = false;
|
84
|
+
for (let j = 0; j < toFind.length; j++) {
|
85
|
+
if (wasm[i + j] !== toFind[j]) {
|
86
|
+
mismatch = true;
|
87
|
+
break;
|
88
|
+
}
|
89
|
+
}
|
90
|
+
|
91
|
+
if (!mismatch) break;
|
92
|
+
}
|
93
|
+
|
94
|
+
if (i === wasm.length) throw e;
|
95
|
+
|
96
|
+
const offset = (blobOffset - i) + encodeVector(localDecl).length;
|
97
|
+
|
98
|
+
let cumLen = 0;
|
99
|
+
i = 0;
|
100
|
+
for (; i < func.wasm.length; i++) {
|
101
|
+
cumLen += func.wasm[i].filter(x => x != null && x <= 0xff).length;
|
102
|
+
if (cumLen === offset) break;
|
103
|
+
}
|
104
|
+
|
105
|
+
if (cumLen !== offset) throw e;
|
106
|
+
|
107
|
+
i -= 1;
|
108
|
+
|
109
|
+
console.log(`\x1B[35m\x1B[1mporffor backtrace\u001b[0m`);
|
110
|
+
|
111
|
+
console.log('\x1B[4m' + func.name + '\x1B[0m');
|
112
|
+
|
113
|
+
const surrounding = 6;
|
114
|
+
|
115
|
+
const decomp = decompile(func.wasm.slice(i - surrounding, i + surrounding + 1), '', 0, func.locals, func.params, func.returns, funcs, globals, exceptions).slice(0, -1).split('\n');
|
116
|
+
|
117
|
+
const noAnsi = s => s.replace(/\u001b\[[0-9]+m/g, '');
|
118
|
+
let longest = 0;
|
119
|
+
for (let j = 0; j < decomp.length; j++) {
|
120
|
+
longest = Math.max(longest, noAnsi(decomp[j]).length);
|
44
121
|
}
|
45
|
-
|
122
|
+
|
123
|
+
const middle = Math.floor(decomp.length / 2);
|
124
|
+
decomp[middle] = `\x1B[47m\x1B[30m${noAnsi(decomp[middle])}${'\u00a0'.repeat(longest - noAnsi(decomp[middle]).length)}\x1B[0m`;
|
125
|
+
|
126
|
+
console.log('\x1B[90m...\x1B[0m');
|
127
|
+
console.log(decomp.join('\n'));
|
128
|
+
console.log('\x1B[90m...\x1B[0m\n');
|
129
|
+
|
130
|
+
throw e;
|
131
|
+
}
|
46
132
|
|
47
133
|
times.push(performance.now() - t2);
|
48
134
|
if (flags.includes('info')) console.log(`instantiated in ${times[1].toFixed(2)}ms`);
|
@@ -95,10 +181,18 @@ export default async (source, flags = [ 'module' ], customImports = {}, print =
|
|
95
181
|
return Array.from(new Uint16Array(memory.buffer, pointer + 4, length)).map(x => String.fromCharCode(x)).join('');
|
96
182
|
}
|
97
183
|
|
184
|
+
case '_bytestring': {
|
185
|
+
const pointer = ret;
|
186
|
+
const length = new Int32Array(memory.buffer, pointer, 1);
|
187
|
+
|
188
|
+
return Array.from(new Uint8Array(memory.buffer, pointer + 4, length)).map(x => String.fromCharCode(x)).join('');
|
189
|
+
}
|
190
|
+
|
98
191
|
case 'function': {
|
99
192
|
// wasm func index, including all imports
|
100
193
|
const func = funcs.find(x => (x.originalIndex ?? x.index) === ret);
|
101
|
-
if (!func) return ret;
|
194
|
+
// if (!func) return ret;
|
195
|
+
if (!func) return function () {};
|
102
196
|
|
103
197
|
// make fake empty func for repl/etc
|
104
198
|
return {[func.name]() {}}[func.name];
|
package/demo.js
ADDED
package/demo.ts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
console.log("hello world");
|
package/filesize.cmd
ADDED
package/package.json
CHANGED
package/porf
ADDED
package/runner/index.js
CHANGED
@@ -3,6 +3,8 @@
|
|
3
3
|
import compile from '../compiler/wrap.js';
|
4
4
|
import fs from 'node:fs';
|
5
5
|
|
6
|
+
const start = performance.now();
|
7
|
+
|
6
8
|
if (process.argv.includes('-compile-hints')) {
|
7
9
|
const v8 = await import('node:v8');
|
8
10
|
v8.setFlagsFromString(`--experimental-wasm-compilation-hints`);
|
@@ -15,9 +17,22 @@ if (process.argv.includes('-compile-hints')) {
|
|
15
17
|
// --experimental-wasm-return-call (on by default)
|
16
18
|
}
|
17
19
|
|
18
|
-
|
20
|
+
let file = process.argv.slice(2).find(x => x[0] !== '-');
|
21
|
+
if (['run', 'wasm', 'native', 'c'].includes(file)) {
|
22
|
+
if (['wasm', 'native', 'c'].includes(file)) {
|
23
|
+
process.argv.push(`-target=${file}`);
|
24
|
+
}
|
25
|
+
|
26
|
+
file = process.argv.slice(process.argv.indexOf(file) + 1).find(x => x[0] !== '-');
|
27
|
+
|
28
|
+
const nonOptOutFile = process.argv.slice(process.argv.indexOf(file) + 1).find(x => x[0] !== '-');
|
29
|
+
if (nonOptOutFile) {
|
30
|
+
process.argv.push(`-o=${nonOptOutFile}`);
|
31
|
+
}
|
32
|
+
}
|
33
|
+
|
19
34
|
if (!file) {
|
20
|
-
if (process.argv.includes('-v')) {
|
35
|
+
if (process.argv.includes('-v') || process.argv.includes('--version')) {
|
21
36
|
// just print version
|
22
37
|
console.log((await import('./version.js')).default);
|
23
38
|
process.exit(0);
|
@@ -52,4 +67,6 @@ try {
|
|
52
67
|
} catch (e) {
|
53
68
|
if (cache) process.stdout.write(cache);
|
54
69
|
console.error(process.argv.includes('-i') ? e : `${e.constructor.name}: ${e.message}`);
|
55
|
-
}
|
70
|
+
}
|
71
|
+
|
72
|
+
if (process.argv.includes('-t')) console.log(performance.now() - start);
|
package/runner/repl.js
CHANGED
@@ -45,9 +45,9 @@ let prev = '';
|
|
45
45
|
const run = async (source, _context, _filename, callback, run = true) => {
|
46
46
|
// hack: print "secret" before latest code ran to only enable printing for new code
|
47
47
|
|
48
|
-
let toRun = prev + `;\nprint(-0x1337);\n` + source.trim();
|
48
|
+
let toRun = (prev ? (prev + `;\nprint(-0x1337);\n`) : '') + source.trim();
|
49
49
|
|
50
|
-
let shouldPrint =
|
50
|
+
let shouldPrint = !prev;
|
51
51
|
const { exports, wasm, pages } = await compile(toRun, [], {}, str => {
|
52
52
|
if (shouldPrint) process.stdout.write(str);
|
53
53
|
if (str === '-4919') shouldPrint = true;
|