porffor 0.0.0-579ef36
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/LICENSE +21 -0
- package/README.md +275 -0
- package/compiler/builtins/base64.js +92 -0
- package/compiler/builtins.js +770 -0
- package/compiler/codeGen.js +2027 -0
- package/compiler/decompile.js +102 -0
- package/compiler/embedding.js +19 -0
- package/compiler/encoding.js +217 -0
- package/compiler/expression.js +70 -0
- package/compiler/index.js +67 -0
- package/compiler/opt.js +436 -0
- package/compiler/parse.js +8 -0
- package/compiler/prototype.js +272 -0
- package/compiler/sections.js +154 -0
- package/compiler/wasmSpec.js +200 -0
- package/compiler/wrap.js +119 -0
- package/package.json +23 -0
- package/porf.cmd +2 -0
- package/publish.js +13 -0
- package/runner/compare.js +35 -0
- package/runner/index.js +34 -0
- package/runner/info.js +54 -0
- package/runner/profile.js +47 -0
- package/runner/repl.js +104 -0
- package/runner/sizes.js +38 -0
- package/runner/transform.js +36 -0
- package/sw.js +26 -0
- package/util/enum.js +20 -0
package/compiler/wrap.js
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
import compile from './index.js';
|
2
|
+
import decompile from './decompile.js';
|
3
|
+
// import fs from 'node:fs';
|
4
|
+
|
5
|
+
const bold = x => `\u001b[1m${x}\u001b[0m`;
|
6
|
+
|
7
|
+
const typeBase = 0xffffffffffff0;
|
8
|
+
const TYPES = {
|
9
|
+
[typeBase]: 'number',
|
10
|
+
[typeBase + 1]: 'boolean',
|
11
|
+
[typeBase + 2]: 'string',
|
12
|
+
[typeBase + 3]: 'undefined',
|
13
|
+
[typeBase + 4]: 'object',
|
14
|
+
[typeBase + 5]: 'function',
|
15
|
+
[typeBase + 6]: 'symbol',
|
16
|
+
[typeBase + 7]: 'bigint',
|
17
|
+
|
18
|
+
// internal
|
19
|
+
[typeBase + 8]: '_array'
|
20
|
+
};
|
21
|
+
|
22
|
+
export default async (source, flags = [ 'module' ], customImports = {}, print = str => process.stdout.write(str)) => {
|
23
|
+
const times = [];
|
24
|
+
|
25
|
+
const t1 = performance.now();
|
26
|
+
const { wasm, funcs, globals, tags, exceptions, pages } = compile(source, flags);
|
27
|
+
|
28
|
+
if (source.includes('export function')) flags.push('module');
|
29
|
+
|
30
|
+
// fs.writeFileSync('out.wasm', Buffer.from(wasm));
|
31
|
+
|
32
|
+
times.push(performance.now() - t1);
|
33
|
+
if (flags.includes('info')) console.log(bold(`compiled in ${times[0].toFixed(2)}ms`));
|
34
|
+
|
35
|
+
const t2 = performance.now();
|
36
|
+
const { instance } = await WebAssembly.instantiate(wasm, {
|
37
|
+
'': {
|
38
|
+
p: valtype === 'i64' ? i => print(Number(i).toString()) : i => print(i.toString()),
|
39
|
+
c: valtype === 'i64' ? i => print(String.fromCharCode(Number(i))) : i => print(String.fromCharCode(i)),
|
40
|
+
a: c => { if (!Number(c)) throw new Error(`assert failed`); },
|
41
|
+
t: _ => performance.now(),
|
42
|
+
...customImports
|
43
|
+
}
|
44
|
+
});
|
45
|
+
|
46
|
+
times.push(performance.now() - t2);
|
47
|
+
if (flags.includes('info')) console.log(`instantiated in ${times[1].toFixed(2)}ms`);
|
48
|
+
|
49
|
+
const exports = {};
|
50
|
+
|
51
|
+
const exceptTag = instance.exports['0'], memory = instance.exports['$'];
|
52
|
+
for (const x in instance.exports) {
|
53
|
+
if (x === '0') continue;
|
54
|
+
if (x === '$') {
|
55
|
+
exports.$ = instance.exports.$;
|
56
|
+
continue;
|
57
|
+
}
|
58
|
+
|
59
|
+
const name = x === 'm' ? 'main' : x;
|
60
|
+
const func = funcs.find(x => x.name === name);
|
61
|
+
|
62
|
+
const exp = instance.exports[x];
|
63
|
+
exports[func.name] = exp;
|
64
|
+
|
65
|
+
exports[func.name] = function() {
|
66
|
+
try {
|
67
|
+
const ret = exp.apply(this, arguments);
|
68
|
+
|
69
|
+
if (ret >= typeBase && ret <= typeBase + 8) return ret > (typeBase + 7) ? 'object' : TYPES[ret];
|
70
|
+
|
71
|
+
switch (TYPES[func.returnType]) {
|
72
|
+
case 'boolean': return Boolean(ret);
|
73
|
+
case 'undefined': return undefined;
|
74
|
+
case 'object': return ret === 0 ? null : {};
|
75
|
+
|
76
|
+
case '_array': {
|
77
|
+
const pointer = ret;
|
78
|
+
const length = new Int32Array(memory.buffer, pointer, 1);
|
79
|
+
|
80
|
+
// have to slice because of memory alignment
|
81
|
+
const buf = memory.buffer.slice(pointer + 4, pointer + 4 + 8 * length);
|
82
|
+
|
83
|
+
return Array.from(new Float64Array(buf));
|
84
|
+
}
|
85
|
+
|
86
|
+
case 'string': {
|
87
|
+
const pointer = ret;
|
88
|
+
const length = new Int32Array(memory.buffer, pointer, 1);
|
89
|
+
|
90
|
+
return Array.from(new Uint16Array(memory.buffer, pointer + 4, length)).map(x => String.fromCharCode(x)).join('');
|
91
|
+
}
|
92
|
+
|
93
|
+
default: return ret;
|
94
|
+
}
|
95
|
+
} catch (e) {
|
96
|
+
if (e.is && e.is(exceptTag)) {
|
97
|
+
const exceptId = e.getArg(exceptTag, 0);
|
98
|
+
const exception = exceptions[exceptId];
|
99
|
+
|
100
|
+
const constructorName = exception.constructor;
|
101
|
+
|
102
|
+
// no constructor, just throw message
|
103
|
+
if (!constructorName) throw exception.message;
|
104
|
+
|
105
|
+
const constructor = globalThis[constructorName] ?? eval(`class ${constructorName} extends Error { constructor(message) { super(message); this.name = "${constructorName}"; } }; ${constructorName}`);
|
106
|
+
throw new constructor(exception.message);
|
107
|
+
}
|
108
|
+
|
109
|
+
throw e;
|
110
|
+
}
|
111
|
+
};
|
112
|
+
}
|
113
|
+
|
114
|
+
if (flags.includes('decomp')) {
|
115
|
+
return { exports, wasm, times, decomps: funcs.map(x => decompile(x.wasm, x.name, x.index, x.locals, x.params, x.returns, funcs, globals, exceptions)) };
|
116
|
+
}
|
117
|
+
|
118
|
+
return { exports, wasm, times, pages };
|
119
|
+
};
|
package/package.json
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
{
|
2
|
+
"name": "porffor",
|
3
|
+
"description": "a basic experimental wip aot optimizing js -> wasm engine/compiler/runtime in js",
|
4
|
+
"version": "0.0.0-579ef36",
|
5
|
+
"author": "CanadaHonk",
|
6
|
+
"license": "MIT",
|
7
|
+
"dependencies": {
|
8
|
+
"acorn": "^8.9.0"
|
9
|
+
},
|
10
|
+
"bin": {
|
11
|
+
"porf": "./runner/index.js"
|
12
|
+
},
|
13
|
+
"main": "./runner/index.js",
|
14
|
+
"type": "module",
|
15
|
+
"repository": {
|
16
|
+
"type": "git",
|
17
|
+
"url": "git+https://github.com/CanadaHonk/porffor.git"
|
18
|
+
},
|
19
|
+
"bugs": {
|
20
|
+
"url": "https://github.com/CanadaHonk/porffor/issues"
|
21
|
+
},
|
22
|
+
"homepage": "https://porffor.goose.icu"
|
23
|
+
}
|
package/porf.cmd
ADDED
package/publish.js
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
import { execSync } from 'node:child_process';
|
2
|
+
import fs from 'node:fs';
|
3
|
+
|
4
|
+
const rev = fs.readFileSync('.git/refs/heads/main', 'utf8').trim().slice(0, 7);
|
5
|
+
|
6
|
+
const packageJson = fs.readFileSync('package.json', 'utf8');
|
7
|
+
fs.writeFileSync('package.json', packageJson.replace('"0.0.0"', `"0.0.0-${rev}"`));
|
8
|
+
|
9
|
+
console.log(rev, packageJson);
|
10
|
+
|
11
|
+
execSync(`npm publish`, { stdio: 'inherit' });
|
12
|
+
|
13
|
+
fs.writeFileSync('package.json', packageJson);
|
@@ -0,0 +1,35 @@
|
|
1
|
+
import { execSync } from 'node:child_process';
|
2
|
+
import { pathToFileURL } from 'node:url';
|
3
|
+
import fs from 'node:fs';
|
4
|
+
|
5
|
+
const [ commitsAgo, file ] = process.argv.slice(2);
|
6
|
+
const source = fs.readFileSync(file, 'utf8');
|
7
|
+
|
8
|
+
const compileNow = (await import('../compiler/index.js')).default;
|
9
|
+
const wasmNow = compileNow(source).byteLength;
|
10
|
+
|
11
|
+
execSync(`git checkout HEAD~${commitsAgo}`);
|
12
|
+
|
13
|
+
let failed = false;
|
14
|
+
|
15
|
+
fs.writeFileSync('tmp.js', source);
|
16
|
+
try {
|
17
|
+
execSync(`node runner/index.js tmp.js`);
|
18
|
+
} catch {
|
19
|
+
failed = true;
|
20
|
+
} finally {
|
21
|
+
fs.rmSync('tmp.js');
|
22
|
+
execSync(`git checkout main`);
|
23
|
+
}
|
24
|
+
|
25
|
+
console.log();
|
26
|
+
|
27
|
+
if (failed) {
|
28
|
+
console.log(`!! failed to compile then`);
|
29
|
+
process.exit();
|
30
|
+
}
|
31
|
+
|
32
|
+
const wasmThen = Buffer.byteLength(fs.readFileSync('out.wasm'));
|
33
|
+
|
34
|
+
console.log(`now: ${wasmNow} bytes`);
|
35
|
+
console.log(`${commitsAgo} commit${commitsAgo > 1 ? 's' : ''} ago: ${wasmThen} bytes`);
|
package/runner/index.js
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
#!/usr/bin/env node
|
2
|
+
|
3
|
+
import compile from '../compiler/wrap.js';
|
4
|
+
import fs from 'node:fs';
|
5
|
+
|
6
|
+
const file = process.argv.slice(2).find(x => x[0] !== '-');
|
7
|
+
if (!file) {
|
8
|
+
// run repl if no file given
|
9
|
+
await import('./repl.js');
|
10
|
+
|
11
|
+
// do nothing for the rest of this file
|
12
|
+
await new Promise(() => {});
|
13
|
+
}
|
14
|
+
|
15
|
+
const source = fs.readFileSync(file, 'utf8');
|
16
|
+
|
17
|
+
let cache = '';
|
18
|
+
const print = str => {
|
19
|
+
cache += str;
|
20
|
+
|
21
|
+
if (str === '\n') {
|
22
|
+
process.stdout.write(cache);
|
23
|
+
cache = '';
|
24
|
+
}
|
25
|
+
};
|
26
|
+
|
27
|
+
try {
|
28
|
+
const { exports } = await compile(source, process.argv.includes('--module') ? [ 'module' ] : [], {}, print);
|
29
|
+
|
30
|
+
exports.main();
|
31
|
+
if (cache) process.stdout.write(cache);
|
32
|
+
} catch (e) {
|
33
|
+
console.error(`${e.constructor.name}: ${e.message}`);
|
34
|
+
}
|
package/runner/info.js
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
import compile from '../compiler/wrap.js';
|
2
|
+
import fs from 'node:fs';
|
3
|
+
|
4
|
+
/* if (globalThis.process) {
|
5
|
+
const v8 = await import('node:v8');
|
6
|
+
v8.setFlagsFromString('--experimental-wasm-gc');
|
7
|
+
} */
|
8
|
+
|
9
|
+
const raw = process.argv.includes('-raw');
|
10
|
+
|
11
|
+
const file = process.argv.slice(2).find(x => x[0] !== '-');
|
12
|
+
if (!file) {
|
13
|
+
// run repl if no file given
|
14
|
+
await import('./repl.js');
|
15
|
+
|
16
|
+
// do nothing for the rest of this file
|
17
|
+
await new Promise(() => {});
|
18
|
+
}
|
19
|
+
|
20
|
+
const source = fs.readFileSync(file, 'utf8');
|
21
|
+
|
22
|
+
const underline = x => `\u001b[4m\u001b[1m${x}\u001b[0m`;
|
23
|
+
const bold = x => `\u001b[1m${x}\u001b[0m`;
|
24
|
+
|
25
|
+
if (!raw) console.log(`\n${underline('source')}\n` + source);
|
26
|
+
if (!raw) console.log(`\n\n${underline('processing')}`);
|
27
|
+
|
28
|
+
let cache = '';
|
29
|
+
const print = str => {
|
30
|
+
cache += str;
|
31
|
+
|
32
|
+
if (str === '\n') {
|
33
|
+
process.stdout.write(cache);
|
34
|
+
cache = '';
|
35
|
+
}
|
36
|
+
};
|
37
|
+
|
38
|
+
const t0 = performance.now();
|
39
|
+
const { wasm, exports } = await compile(source, raw ? [ 'module' ] : [ 'module', 'info' ], {}, print);
|
40
|
+
|
41
|
+
if (!raw && typeof Deno === 'undefined') fs.writeFileSync('out.wasm', Buffer.from(wasm));
|
42
|
+
|
43
|
+
if (!process.argv.includes('-no-run')) {
|
44
|
+
console.log(`\n\n${underline('output')}`);
|
45
|
+
const t2 = performance.now();
|
46
|
+
|
47
|
+
exports.main();
|
48
|
+
print('\n');
|
49
|
+
|
50
|
+
if (!raw) console.log(bold(`\n\nexecuted in ${(performance.now() - t2).toFixed(2)}ms`));
|
51
|
+
}
|
52
|
+
|
53
|
+
if (!raw) console.log(bold(`wasm binary is ${wasm.byteLength} bytes`));
|
54
|
+
if (!raw) console.log(`total: ${(performance.now() - t0).toFixed(2)}ms`);
|
@@ -0,0 +1,47 @@
|
|
1
|
+
import compile from '../compiler/index.js';
|
2
|
+
import fs from 'node:fs';
|
3
|
+
|
4
|
+
let csv = `phase,time\n`;
|
5
|
+
|
6
|
+
csv += `node,${performance.now()}\n`;
|
7
|
+
|
8
|
+
const t0 = performance.now();
|
9
|
+
const file = process.argv.slice(2).find(x => x[0] !== '-');
|
10
|
+
const source = fs.readFileSync(file, 'utf8');
|
11
|
+
csv += `read,${performance.now() - t0}\n`;
|
12
|
+
|
13
|
+
console.log = x => {
|
14
|
+
if (x.includes(' in ')) {
|
15
|
+
csv += [ 'parse', 'codegen', 'opt', 'sections' ][parseInt(x[0]) - 1] + ',' + x.split(' in ')[1].slice(0, -2) + '\n';
|
16
|
+
}
|
17
|
+
};
|
18
|
+
|
19
|
+
const wasm = compile(source, [ 'info' ]);
|
20
|
+
|
21
|
+
let cache = '';
|
22
|
+
const print = str => {
|
23
|
+
cache += str;
|
24
|
+
|
25
|
+
if (str === '\n') {
|
26
|
+
process.stdout.write(cache);
|
27
|
+
cache = '';
|
28
|
+
}
|
29
|
+
};
|
30
|
+
|
31
|
+
const t1 = performance.now();
|
32
|
+
const { instance } = await WebAssembly.instantiate(wasm, {
|
33
|
+
'': {
|
34
|
+
p: i => print(Number(i).toString()),
|
35
|
+
c: i => print(String.fromCharCode(Number(i))),
|
36
|
+
a: c => { if (!Number(c)) throw new Error(`assert failed`); }
|
37
|
+
}
|
38
|
+
});
|
39
|
+
csv += `inst,${performance.now() - t1}\n`;
|
40
|
+
|
41
|
+
const t2 = performance.now();
|
42
|
+
instance.exports.m();
|
43
|
+
print('\n');
|
44
|
+
|
45
|
+
csv += `exec,${performance.now() - t2}`;
|
46
|
+
|
47
|
+
fs.writeFileSync(`profile.csv`, csv);
|
package/runner/repl.js
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
import compile from '../compiler/wrap.js';
|
2
|
+
|
3
|
+
import repl from 'node:repl';
|
4
|
+
import fs from 'node:fs';
|
5
|
+
|
6
|
+
let rev = 'unknown';
|
7
|
+
try {
|
8
|
+
rev = fs.readFileSync(new URL('../.git/refs/heads/main', import.meta.url), 'utf8').trim().slice(0, 7);
|
9
|
+
} catch {
|
10
|
+
rev = JSON.parse(fs.readFileSync(new URL('../package.json', import.meta.url), 'utf8')).version.split('-')[1];
|
11
|
+
}
|
12
|
+
|
13
|
+
// process.argv.push('-O0'); // disable opts
|
14
|
+
|
15
|
+
globalThis.valtype = 'f64';
|
16
|
+
|
17
|
+
const valtypeOpt = process.argv.find(x => x.startsWith('-valtype='));
|
18
|
+
if (valtypeOpt) valtype = valtypeOpt.split('=')[1];
|
19
|
+
|
20
|
+
console.log(`welcome to porffor rev ${rev.slice(0, 7)}`);
|
21
|
+
console.log(`info: using opt ${process.argv.find(x => x.startsWith('-O')) ?? '-O1'} and valtype ${valtype}`);
|
22
|
+
console.log();
|
23
|
+
|
24
|
+
let lastMemory, lastPages;
|
25
|
+
const PageSize = 65536;
|
26
|
+
const memoryToString = mem => {
|
27
|
+
let out = '';
|
28
|
+
const pages = lastPages.length;
|
29
|
+
const wasmPages = mem.buffer.byteLength / PageSize;
|
30
|
+
|
31
|
+
out += `\x1B[1mallocated ${mem.buffer.byteLength / 1024}KiB\x1B[0m for ${pages} things using ${wasmPages} Wasm page${wasmPages === 1 ? '' : 's'}\n`;
|
32
|
+
|
33
|
+
const buf = new Uint8Array(mem.buffer);
|
34
|
+
|
35
|
+
for (let i = 0; i < pages; i++) {
|
36
|
+
out += `\x1B[36m${lastPages[i]}\x1B[2m | \x1B[0m`;
|
37
|
+
|
38
|
+
for (let j = 0; j < 50; j++) {
|
39
|
+
const val = buf[i * pageSize + j];
|
40
|
+
if (val === 0) out += '\x1B[2m';
|
41
|
+
out += val.toString(16).padStart(2, '0');
|
42
|
+
if (val === 0) out += '\x1B[0m';
|
43
|
+
out += ' ';
|
44
|
+
}
|
45
|
+
out += '\n';
|
46
|
+
}
|
47
|
+
|
48
|
+
return out;
|
49
|
+
};
|
50
|
+
|
51
|
+
let prev = '';
|
52
|
+
const run = async (source, _context, _filename, callback, run = true) => {
|
53
|
+
let toRun = prev + source.trim();
|
54
|
+
// prev = toRun + ';\n';
|
55
|
+
|
56
|
+
const { exports, wasm, pages } = await compile(toRun, []);
|
57
|
+
fs.writeFileSync('out.wasm', Buffer.from(wasm));
|
58
|
+
|
59
|
+
if (exports.$) {
|
60
|
+
lastMemory = exports.$;
|
61
|
+
lastPages = [...pages.keys()];
|
62
|
+
}
|
63
|
+
|
64
|
+
const ret = run ? exports.main() : undefined;
|
65
|
+
callback(null, ret);
|
66
|
+
|
67
|
+
// if (source.includes(' = ') || source.includes('let ') || source.includes('var ') || source.includes('const ')) prev += source + ';\n';
|
68
|
+
prev = toRun + ';\n';
|
69
|
+
};
|
70
|
+
|
71
|
+
const replServer = repl.start({ prompt: '> ', eval: run });
|
72
|
+
|
73
|
+
replServer.setupHistory('.repl_history', () => {});
|
74
|
+
|
75
|
+
replServer.defineCommand('memory', {
|
76
|
+
help: 'Log Wasm memory',
|
77
|
+
action() {
|
78
|
+
this.clearBufferedCommand();
|
79
|
+
console.log(memoryToString(lastMemory));
|
80
|
+
this.displayPrompt();
|
81
|
+
}
|
82
|
+
});
|
83
|
+
replServer.defineCommand('asm', {
|
84
|
+
help: 'Log Wasm decompiled bytecode',
|
85
|
+
async action() {
|
86
|
+
this.clearBufferedCommand();
|
87
|
+
|
88
|
+
try {
|
89
|
+
process.argv.push('-opt-funcs');
|
90
|
+
await run('', null, null, () => {}, false);
|
91
|
+
process.argv.pop();
|
92
|
+
} catch { }
|
93
|
+
|
94
|
+
this.displayPrompt();
|
95
|
+
}
|
96
|
+
});
|
97
|
+
replServer.defineCommand('js', {
|
98
|
+
help: 'Log JS being actually ran',
|
99
|
+
async action() {
|
100
|
+
this.clearBufferedCommand();
|
101
|
+
console.log(prev);
|
102
|
+
this.displayPrompt();
|
103
|
+
}
|
104
|
+
});
|
package/runner/sizes.js
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
import fs from 'node:fs';
|
2
|
+
import compile from '../compiler/index.js';
|
3
|
+
|
4
|
+
// deno compat
|
5
|
+
const textEncoder = new TextEncoder();
|
6
|
+
if (typeof process === 'undefined') globalThis.process = { argv: ['', '', ...Deno.args], stdout: { write: str => Deno.writeAllSync(Deno.stdout, textEncoder.encode(str)) } };
|
7
|
+
|
8
|
+
let csv = `file,porffor i32 -O0,porffor i32 -O1,porffor i32 -O2,porffor i32 -O3,porffor i64 -O0,porffor i64 -O1,porffor i64 -O2,porffor i64 -O3,porffor f64 -O0, porffor f64 -O1, porffor f64 -O2, porffor f64 -O3\n`;
|
9
|
+
const perform = async (file, args) => {
|
10
|
+
process.argv = process.argv.slice(0, 2).concat(args);
|
11
|
+
const source = fs.readFileSync(file, 'utf8');
|
12
|
+
|
13
|
+
const { wasm } = compile(source, []);
|
14
|
+
const size = wasm.byteLength;
|
15
|
+
|
16
|
+
const label = `${file} ${args.join(' ')}`;
|
17
|
+
csv += `${size},`;
|
18
|
+
console.log(label, ' '.repeat(40 - label.length), `${size}b`);
|
19
|
+
};
|
20
|
+
|
21
|
+
const argsValtypes = [ '-valtype=i32', '-valtype=i64', '-valtype=f64' ];
|
22
|
+
const argsOptlevels = [ '-O0', '-O1', '-O2', '-O3' ];
|
23
|
+
|
24
|
+
for (const file of [ 'bench/prime_basic.js', 'bench/fib_iter.js', 'test/math_1.js', 'test/math_3.js', 'test/while_1.js', 'test/for_2.js', 'test/unary_3.js', 'test/updateexp_1.js', 'test/eq_3.js', 'test/empty.js' ]) {
|
25
|
+
const niceFile = file.split('/')[1].slice(0, -3);
|
26
|
+
csv += `${niceFile},`;
|
27
|
+
|
28
|
+
for (const x of argsValtypes) {
|
29
|
+
for (const y of argsOptlevels) {
|
30
|
+
await perform(file, [ x, y ]);
|
31
|
+
}
|
32
|
+
}
|
33
|
+
|
34
|
+
csv = csv.slice(0, -1) + '\n';
|
35
|
+
}
|
36
|
+
|
37
|
+
fs.writeFileSync('sizes.csv', csv);
|
38
|
+
console.log(csv);
|
@@ -0,0 +1,36 @@
|
|
1
|
+
import compile from '../compiler/wrap.js';
|
2
|
+
import fs from 'node:fs';
|
3
|
+
|
4
|
+
const file = process.argv.slice(2).find(x => x[0] !== '-');
|
5
|
+
|
6
|
+
const source = fs.readFileSync(file, 'utf8');
|
7
|
+
|
8
|
+
const underline = x => `\u001b[4m\u001b[1m${x}\u001b[0m`;
|
9
|
+
const bold = x => `\u001b[1m${x}\u001b[0m`;
|
10
|
+
|
11
|
+
let cache = '';
|
12
|
+
const print = str => {
|
13
|
+
cache += str;
|
14
|
+
|
15
|
+
if (str === '\n') {
|
16
|
+
process.stdout.write(cache);
|
17
|
+
cache = '';
|
18
|
+
}
|
19
|
+
};
|
20
|
+
|
21
|
+
const { wasm } = await compile(source);
|
22
|
+
|
23
|
+
if (!raw && typeof Deno === 'undefined') fs.writeFileSync('out.wasm', Buffer.from(wasm));
|
24
|
+
|
25
|
+
if (!process.argv.includes('-no-run')) {
|
26
|
+
console.log(`\n\n${underline('output')}`);
|
27
|
+
const t2 = performance.now();
|
28
|
+
|
29
|
+
exports.main();
|
30
|
+
print('\n');
|
31
|
+
|
32
|
+
if (!raw) console.log(bold(`\n\nexecuted in ${(performance.now() - t2).toFixed(2)}ms`));
|
33
|
+
}
|
34
|
+
|
35
|
+
if (!raw) console.log(bold(`wasm binary is ${wasm.byteLength} bytes`));
|
36
|
+
if (!raw) console.log(`total: ${(performance.now() - t0).toFixed(2)}ms`);
|
package/sw.js
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
self.addEventListener('install', () => self.skipWaiting());
|
2
|
+
self.addEventListener('activate', e => e.waitUntil(self.clients.claim()));
|
3
|
+
|
4
|
+
const handleFetch = async request => {
|
5
|
+
const r = await fetch(request.mode === 'no-cors' ? new Request(request, { credentials: 'omit' }) : request).catch(e => console.error(e));
|
6
|
+
|
7
|
+
if (r.status === 0) {
|
8
|
+
return r;
|
9
|
+
}
|
10
|
+
|
11
|
+
const headers = new Headers(r.headers);
|
12
|
+
headers.set('Cross-Origin-Embedder-Policy', 'credentialless');
|
13
|
+
headers.set('Cross-Origin-Opener-Policy', 'same-origin');
|
14
|
+
// headers.set('Cross-Origin-Resource-Policy', 'cross-origin');
|
15
|
+
|
16
|
+
return new Response(r.body, { status: r.status, statusText: r.statusText, headers });
|
17
|
+
};
|
18
|
+
|
19
|
+
self.addEventListener('fetch', e => {
|
20
|
+
const { request } = e;
|
21
|
+
if (request.cache === 'only-if-cached' && request.mode !== 'same-origin') {
|
22
|
+
return;
|
23
|
+
}
|
24
|
+
|
25
|
+
e.respondWith(handleFetch(request));
|
26
|
+
});
|
package/util/enum.js
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
export const enumify = (...args) => {
|
2
|
+
const obj = {};
|
3
|
+
|
4
|
+
for (let i = 0; i < args.length; i++) {
|
5
|
+
obj[i] = args[i];
|
6
|
+
obj[args[i]] = i;
|
7
|
+
}
|
8
|
+
|
9
|
+
return obj;
|
10
|
+
};
|
11
|
+
|
12
|
+
// a procedural enum ;)
|
13
|
+
export const procEnum = () => {
|
14
|
+
let n = 0;
|
15
|
+
return new Proxy({}, {
|
16
|
+
get(target, p) {
|
17
|
+
return target[p] ?? (target[p] = n++);
|
18
|
+
}
|
19
|
+
});
|
20
|
+
};
|