porffor 0.2.0-fdf0fc5 → 0.14.0-032e4ad08
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 +9 -3
- package/README.md +17 -14
- package/asur/index.js +1 -1
- package/byg/index.js +3 -24
- package/compiler/2c.js +66 -54
- package/compiler/assemble.js +51 -11
- package/compiler/builtins/annexb_string.js +10 -10
- package/compiler/builtins/annexb_string.ts +4 -3
- package/compiler/builtins/array.ts +85 -9
- package/compiler/builtins/base64.ts +2 -1
- package/compiler/builtins/boolean.ts +2 -2
- package/compiler/builtins/crypto.ts +2 -1
- package/compiler/builtins/date.ts +2 -3
- package/compiler/builtins/error.js +22 -0
- package/compiler/builtins/escape.ts +2 -3
- package/compiler/builtins/function.ts +1 -1
- package/compiler/builtins/int.ts +1 -1
- package/compiler/builtins/math.ts +410 -0
- package/compiler/builtins/number.ts +4 -7
- package/compiler/builtins/object.ts +1 -1
- package/compiler/builtins/porffor.d.ts +9 -8
- package/compiler/builtins/set.ts +197 -3
- package/compiler/builtins/string.ts +2 -1
- package/compiler/builtins/symbol.ts +62 -0
- package/compiler/builtins.js +41 -15
- package/compiler/codegen.js +653 -366
- package/compiler/decompile.js +3 -3
- package/compiler/embedding.js +2 -2
- package/compiler/encoding.js +0 -14
- package/compiler/expression.js +1 -1
- package/compiler/generated_builtins.js +771 -187
- package/compiler/index.js +5 -11
- package/compiler/opt.js +7 -7
- package/compiler/parse.js +2 -4
- package/compiler/precompile.js +18 -25
- package/compiler/prefs.js +6 -2
- package/compiler/prototype.js +185 -162
- package/compiler/wasmSpec.js +5 -0
- package/compiler/wrap.js +150 -90
- package/package.json +1 -1
- package/porffor_tmp.c +202 -0
- package/runner/compare.js +0 -1
- package/runner/debug.js +1 -6
- package/runner/index.js +5 -4
- package/runner/profiler.js +15 -42
- package/runner/repl.js +20 -10
- package/runner/sizes.js +2 -2
- package/runner/version.js +10 -8
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;
|
@@ -89,9 +84,8 @@ export default (code, flags) => {
|
|
89
84
|
else compiler = [ compiler ];
|
90
85
|
|
91
86
|
const tmpfile = 'porffor_tmp.c';
|
92
|
-
|
93
|
-
|
94
|
-
const args = [ ...compiler, tmpfile, '-o', outFile ?? (process.platform === 'win32' ? 'out.exe' : 'out'), '-' + cO, '-march=native', '-s', '-ffast-math', '-fno-exceptions' ];
|
87
|
+
const args = [ ...compiler, tmpfile, '-o', outFile ?? (process.platform === 'win32' ? 'out.exe' : 'out'), '-' + cO ];
|
88
|
+
if (!Prefs.compiler) args.push('-flto=thin', '-march=native', '-s', '-ffast-math', '-fno-exceptions', '-fno-ident', '-fno-asynchronous-unwind-tables', '-ffunction-sections', '-fdata-sections', '-Wl,--gc-sections');
|
95
89
|
|
96
90
|
const c = toc(out);
|
97
91
|
fs.writeFileSync(tmpfile, c);
|
package/compiler/opt.js
CHANGED
@@ -1,7 +1,7 @@
|
|
1
|
-
import { Opcodes, Valtype } from
|
2
|
-
import { number } from
|
3
|
-
import { read_signedLEB128, read_ieee754_binary64 } from
|
4
|
-
import { log } from
|
1
|
+
import { Opcodes, Valtype } from './wasmSpec.js';
|
2
|
+
import { number } from './embedding.js';
|
3
|
+
import { read_signedLEB128, read_ieee754_binary64 } from './encoding.js';
|
4
|
+
import { log } from './log.js';
|
5
5
|
import Prefs from './prefs.js';
|
6
6
|
|
7
7
|
const performWasmOp = (op, a, b) => {
|
@@ -172,14 +172,14 @@ export default (funcs, globals, pages, tags, exceptions) => {
|
|
172
172
|
}
|
173
173
|
}
|
174
174
|
|
175
|
-
if (inst[inst.length - 1] === 'string_only' && !pages.hasAnyString) {
|
175
|
+
if (inst[inst.length - 1] === 'string_only' && !pages.hasAnyString && !Prefs.noRmUnusedTypes) {
|
176
176
|
// remove this inst
|
177
177
|
wasm.splice(i, 1);
|
178
178
|
if (i > 0) i--;
|
179
179
|
inst = wasm[i];
|
180
180
|
}
|
181
181
|
|
182
|
-
if (inst[inst.length - 1] === 'string_only|start' && !pages.hasAnyString) {
|
182
|
+
if (inst[inst.length - 1] === 'string_only|start' && !pages.hasAnyString&& !Prefs.noRmUnusedTypes) {
|
183
183
|
let j = i;
|
184
184
|
for (; j < wasm.length; j++) {
|
185
185
|
const op = wasm[j];
|
@@ -193,7 +193,7 @@ export default (funcs, globals, pages, tags, exceptions) => {
|
|
193
193
|
inst = wasm[i];
|
194
194
|
}
|
195
195
|
|
196
|
-
if (inst[0] === Opcodes.if && typeof inst[2] === 'string') {
|
196
|
+
if (inst[0] === Opcodes.if && typeof inst[2] === 'string' && !Prefs.noRmUnusedTypes) {
|
197
197
|
// remove unneeded typeswitch checks
|
198
198
|
|
199
199
|
const type = inst[2].split('|')[1];
|
package/compiler/parse.js
CHANGED
@@ -1,15 +1,13 @@
|
|
1
|
-
import { log } from
|
1
|
+
import { log } from './log.js';
|
2
2
|
import Prefs from './prefs.js';
|
3
3
|
|
4
|
-
// import { parse } from 'acorn';
|
5
|
-
|
6
4
|
// deno compat
|
7
5
|
if (typeof process === 'undefined' && typeof Deno !== 'undefined') {
|
8
6
|
const textEncoder = new TextEncoder();
|
9
7
|
globalThis.process = { argv: ['', '', ...Deno.args], stdout: { write: str => Deno.writeAllSync(Deno.stdout, textEncoder.encode(str)) } };
|
10
8
|
}
|
11
9
|
|
12
|
-
const file = process.argv.slice(2).find(x => x[0] !== '-');
|
10
|
+
const file = process.argv.slice(2).find(x => x[0] !== '-' && !['run', 'wasm', 'native', 'c', 'profile', 'debug', 'debug-wasm'].includes(x));
|
13
11
|
|
14
12
|
// should we try to support types (while parsing)
|
15
13
|
const types = Prefs.parseTypes || file?.endsWith('.ts');
|
package/compiler/precompile.js
CHANGED
@@ -7,9 +7,6 @@ import { join } from 'node:path';
|
|
7
7
|
import { fileURLToPath } from 'node:url';
|
8
8
|
const __dirname = fileURLToPath(new URL('.', import.meta.url));
|
9
9
|
|
10
|
-
// import porfParse from './parse.js';
|
11
|
-
// import porfCodegen from './codeGen.js';
|
12
|
-
|
13
10
|
const argv = process.argv.slice();
|
14
11
|
|
15
12
|
const compile = async (file, [ _funcs, _globals ]) => {
|
@@ -21,17 +18,12 @@ const compile = async (file, [ _funcs, _globals ]) => {
|
|
21
18
|
first = source.slice(0, source.indexOf('\n'));
|
22
19
|
}
|
23
20
|
|
24
|
-
let args = ['--bytestring', '--todo-time=compile', '--no-
|
21
|
+
let args = ['--bytestring', '--todo-time=compile', '--truthy=no_nan_negative', '--no-treeshake-wasm-imports', '--no-rm-unused-types', '--scoped-page-names', '--funsafe-no-unlikely-proto-checks', '--fast-length', '--parse-types', '--opt-types'];
|
25
22
|
if (first.startsWith('// @porf')) {
|
26
|
-
args =
|
23
|
+
args = first.slice('// @porf '.length).split(' ').concat(args);
|
27
24
|
}
|
28
25
|
process.argv = argv.concat(args);
|
29
26
|
|
30
|
-
// const porfParse = (await import(`./parse.js?_=${Date.now()}`)).default;
|
31
|
-
// const porfCodegen = (await import(`./codeGen.js?_=${Date.now()}`)).default;
|
32
|
-
|
33
|
-
// let { funcs, globals, data } = porfCodegen(porfParse(source, ['module']));
|
34
|
-
|
35
27
|
const porfCompile = (await import(`./index.js?_=${Date.now()}`)).default;
|
36
28
|
|
37
29
|
let { funcs, globals, data, exceptions } = porfCompile(source, ['module']);
|
@@ -78,7 +70,14 @@ const compile = async (file, [ _funcs, _globals ]) => {
|
|
78
70
|
allocated.add(pageName);
|
79
71
|
|
80
72
|
y.splice(0, 10, 'alloc', pageName, x.pages.get(pageName).type, valtypeBinary);
|
81
|
-
|
73
|
+
}
|
74
|
+
|
75
|
+
if (y[0] === Opcodes.i32_const && n[0] === Opcodes.throw) {
|
76
|
+
const id = y[1];
|
77
|
+
y.splice(0, 10, 'throw', exceptions[id].constructor, exceptions[id].message);
|
78
|
+
|
79
|
+
// remove throw inst
|
80
|
+
x.wasm.splice(i + 1, 1);
|
82
81
|
}
|
83
82
|
}
|
84
83
|
}
|
@@ -98,18 +97,14 @@ const precompile = async () => {
|
|
98
97
|
await compile(join(dir, file), [ funcs, globals ]);
|
99
98
|
}
|
100
99
|
|
101
|
-
// const a = funcs.find(x => x.name === '__ecma262_ToUTCDTSF');
|
102
|
-
// console.log(Object.values(a.locals).slice(a.params.length));
|
103
|
-
|
104
|
-
// ${x.pages && x.pages.size > 0 ? ` pages: ${JSON.stringify(Object.fromEntries(x.pages.entries()))},` : ''}
|
105
|
-
// ${x.used && x.used.length > 0 ? ` used: ${JSON.stringify(x.used)},` : ''}
|
106
|
-
|
107
100
|
return `// autogenerated by compiler/precompile.js
|
108
101
|
import { number } from './embedding.js';
|
109
102
|
|
110
103
|
export const BuiltinFuncs = function() {
|
111
|
-
${funcs.map(x =>
|
112
|
-
|
104
|
+
${funcs.map(x => {
|
105
|
+
const wasm = JSON.stringify(x.wasm.filter(x => x.length && x[0] != null)).replace(/\["alloc","(.*?)","(.*?)",(.*?)\]/g, (_, reason, type, valtype) => `...number(allocPage(scope, '${reason}', '${type}') * pageSize, ${valtype})`).replace(/\[16,"(.*?)"]/g, (_, name) => `[16, builtin('${name}')]`).replace(/\["throw","(.*?)","(.*?)"\]/g, (_, constructor, message) => `...internalThrow(scope, '${constructor}', \`${message}\`)`);
|
106
|
+
return ` this.${x.name} = {
|
107
|
+
wasm: (scope, {${wasm.includes('allocPage(') ? 'allocPage,' : ''}${wasm.includes('builtin(') ? 'builtin,' : ''}${wasm.includes('internalThrow(') ? 'internalThrow,' : ''}}) => ${wasm},
|
113
108
|
params: ${JSON.stringify(x.params)},
|
114
109
|
typedParams: true,
|
115
110
|
returns: ${JSON.stringify(x.returns)},
|
@@ -117,12 +112,10 @@ ${funcs.map(x => ` this.${x.name} = {
|
|
117
112
|
locals: ${JSON.stringify(Object.values(x.locals).slice(x.params.length).map(x => x.type))},
|
118
113
|
localNames: ${JSON.stringify(Object.keys(x.locals))},
|
119
114
|
${x.data && x.data.length > 0 ? ` data: ${JSON.stringify(x.data)},` : ''}
|
120
|
-
${x.
|
121
|
-
};`.replaceAll('\n\n', '\n').replaceAll('\n\n', '\n')
|
115
|
+
${x.table ? ` table: true` : ''}
|
116
|
+
};`.replaceAll('\n\n', '\n').replaceAll('\n\n', '\n').replaceAll('\n\n', '\n');
|
117
|
+
}).join('\n')}
|
122
118
|
};`;
|
123
119
|
};
|
124
120
|
|
125
|
-
|
126
|
-
// console.log(code);
|
127
|
-
|
128
|
-
fs.writeFileSync(join(__dirname, 'generated_builtins.js'), code);
|
121
|
+
fs.writeFileSync(join(__dirname, 'generated_builtins.js'), await precompile());
|
package/compiler/prefs.js
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
const onByDefault = [ 'bytestring', '
|
1
|
+
const onByDefault = [ 'bytestring', 'treeshakeWasmImports', 'alwaysMemory', 'indirectCalls', 'optUnused' ];
|
2
2
|
|
3
3
|
let cache = {};
|
4
4
|
const obj = new Proxy({}, {
|
@@ -6,7 +6,7 @@ const obj = new Proxy({}, {
|
|
6
6
|
// intentionally misses with undefined values cached
|
7
7
|
if (cache[p]) return cache[p];
|
8
8
|
|
9
|
-
|
9
|
+
const ret = (() => {
|
10
10
|
// fooBar -> foo-bar
|
11
11
|
const name = p[0] === '_' ? p : p.replace(/[A-Z]/g, c => `-${c.toLowerCase()}`);
|
12
12
|
const prefix = name.length === 1 ? '-' : '--';
|
@@ -19,6 +19,10 @@ const obj = new Proxy({}, {
|
|
19
19
|
if (onByDefault.includes(p)) return true;
|
20
20
|
return undefined;
|
21
21
|
})();
|
22
|
+
|
23
|
+
// do not cache in web demo as args are changed live
|
24
|
+
if (!globalThis.document) cache[p] = ret;
|
25
|
+
return ret;
|
22
26
|
}
|
23
27
|
});
|
24
28
|
|