porffor 0.2.0-cb647c8 → 0.2.0-dcc06c8
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 +1 -1
- package/compiler/builtins/base64.ts +23 -3
- package/compiler/builtins/porffor.d.ts +9 -1
- package/compiler/builtins.js +2 -1
- package/compiler/codeGen.js +91 -59
- package/compiler/generated_builtins.js +3 -0
- package/compiler/index.js +9 -15
- package/compiler/opt.js +39 -26
- package/compiler/parse.js +4 -2
- package/compiler/precompile.js +79 -0
- package/compiler/prefs.js +22 -0
- package/compiler/prototype.js +9 -8
- package/compiler/sections.js +7 -6
- package/demo.js +2 -2
- package/hello +0 -0
- package/package.json +1 -1
- package/rhemyn/compile.js +2 -1
- package/tmp.c +20 -1116
package/compiler/opt.js
CHANGED
@@ -2,6 +2,7 @@ import { Opcodes, Valtype } from "./wasmSpec.js";
|
|
2
2
|
import { number } from "./embedding.js";
|
3
3
|
import { read_signedLEB128, read_ieee754_binary64 } from "./encoding.js";
|
4
4
|
import { log } from "./log.js";
|
5
|
+
import Prefs from './prefs.js';
|
5
6
|
|
6
7
|
const performWasmOp = (op, a, b) => {
|
7
8
|
switch (op) {
|
@@ -11,21 +12,21 @@ const performWasmOp = (op, a, b) => {
|
|
11
12
|
}
|
12
13
|
};
|
13
14
|
|
14
|
-
export default (funcs, globals, pages, tags) => {
|
15
|
+
export default (funcs, globals, pages, tags, exceptions) => {
|
15
16
|
const optLevel = parseInt(process.argv.find(x => x.startsWith('-O'))?.[2] ?? 1);
|
16
17
|
if (optLevel === 0) return;
|
17
18
|
|
18
|
-
const tailCall =
|
19
|
+
const tailCall = Prefs.tailCall;
|
19
20
|
if (tailCall) log.warning('opt', 'tail call proposal is not widely implemented! (you used -tail-call)');
|
20
21
|
|
21
|
-
if (optLevel >= 2 && !
|
22
|
+
if (optLevel >= 2 && !Prefs.optNoInline) {
|
22
23
|
// inline pass (very WIP)
|
23
24
|
// get candidates for inlining
|
24
25
|
// todo: pick smart in future (if func is used <N times? or?)
|
25
26
|
const callsSelf = f => f.wasm.some(x => x[0] === Opcodes.call && x[1] === f.index);
|
26
27
|
const suitableReturns = wasm => wasm.reduce((acc, x) => acc + (x[0] === Opcodes.return), 0) <= 1;
|
27
28
|
const candidates = funcs.filter(x => x.name !== 'main' && Object.keys(x.locals).length === x.params.length && (x.returns.length === 0 || suitableReturns(x.wasm)) && !callsSelf(x) && !x.throws).reverse();
|
28
|
-
if (optLog) {
|
29
|
+
if (Prefs.optLog) {
|
29
30
|
log('opt', `found inline candidates: ${candidates.map(x => x.name).join(', ')} (${candidates.length}/${funcs.length - 1})`);
|
30
31
|
|
31
32
|
let reasons = {};
|
@@ -53,7 +54,7 @@ export default (funcs, globals, pages, tags) => {
|
|
53
54
|
for (let i = 0; i < tWasm.length; i++) {
|
54
55
|
const inst = tWasm[i];
|
55
56
|
if (inst[0] === Opcodes.call && inst[1] === c.index) {
|
56
|
-
if (optLog) log('opt', `inlining call for ${c.name} (in ${t.name})`);
|
57
|
+
if (Prefs.optLog) log('opt', `inlining call for ${c.name} (in ${t.name})`);
|
57
58
|
tWasm.splice(i, 1); // remove this call
|
58
59
|
|
59
60
|
// add params as locals and set in reverse order
|
@@ -80,7 +81,7 @@ export default (funcs, globals, pages, tags) => {
|
|
80
81
|
// adjust local operands to go to correct param index
|
81
82
|
for (const inst of iWasm) {
|
82
83
|
if ((inst[0] === Opcodes.local_get || inst[0] === Opcodes.local_set) && inst[1] < c.params.length) {
|
83
|
-
if (optLog) log('opt', `replacing local operand in inlined wasm (${inst[1]} -> ${paramIdx[inst[1]]})`);
|
84
|
+
if (Prefs.optLog) log('opt', `replacing local operand in inlined wasm (${inst[1]} -> ${paramIdx[inst[1]]})`);
|
84
85
|
inst[1] = paramIdx[inst[1]];
|
85
86
|
}
|
86
87
|
}
|
@@ -97,9 +98,10 @@ export default (funcs, globals, pages, tags) => {
|
|
97
98
|
}
|
98
99
|
}
|
99
100
|
|
100
|
-
if (
|
101
|
+
if (Prefs.optInlineOnly) return;
|
101
102
|
|
102
103
|
const tagUse = tags.reduce((acc, x) => { acc[x.idx] = 0; return acc; }, {});
|
104
|
+
const exceptionUse = exceptions.reduce((acc, _, i) => { acc[i] = 0; return acc; }, {});
|
103
105
|
|
104
106
|
// wasm transform pass
|
105
107
|
for (const f of funcs) {
|
@@ -129,7 +131,12 @@ export default (funcs, globals, pages, tags) => {
|
|
129
131
|
if (inst[0] === Opcodes.local_get) getCount[inst[1]]++;
|
130
132
|
if (inst[0] === Opcodes.local_set || inst[0] === Opcodes.local_tee) setCount[inst[1]]++;
|
131
133
|
|
132
|
-
if (inst[0] === Opcodes.throw)
|
134
|
+
if (inst[0] === Opcodes.throw) {
|
135
|
+
tagUse[inst[1]]++;
|
136
|
+
|
137
|
+
const exceptId = read_signedLEB128(wasm[i - 1].slice(1));
|
138
|
+
exceptionUse[exceptId]++;
|
139
|
+
}
|
133
140
|
|
134
141
|
if (inst[0] === Opcodes.block) {
|
135
142
|
// remove unneeded blocks (no brs inside)
|
@@ -160,7 +167,7 @@ export default (funcs, globals, pages, tags) => {
|
|
160
167
|
|
161
168
|
wasm.splice(j - 1, 1); // remove end of this block
|
162
169
|
|
163
|
-
if (optLog) log('opt', `removed unneeded block in for loop`);
|
170
|
+
if (Prefs.optLog) log('opt', `removed unneeded block in for loop`);
|
164
171
|
}
|
165
172
|
}
|
166
173
|
|
@@ -209,7 +216,7 @@ export default (funcs, globals, pages, tags) => {
|
|
209
216
|
i -= 4;
|
210
217
|
inst = wasm[i];
|
211
218
|
|
212
|
-
if (optLog) log('opt', `removed unneeded typeswitch check`);
|
219
|
+
if (Prefs.optLog) log('opt', `removed unneeded typeswitch check`);
|
213
220
|
}
|
214
221
|
}
|
215
222
|
|
@@ -232,7 +239,7 @@ export default (funcs, globals, pages, tags) => {
|
|
232
239
|
wasm.splice(j - 1, 2, [ Opcodes.drop ]); // remove typeswitch start
|
233
240
|
wasm.splice(i - 1, 1); // remove this inst
|
234
241
|
|
235
|
-
if (optLog) log('opt', 'removed unneeded entire typeswitch');
|
242
|
+
if (Prefs.optLog) log('opt', 'removed unneeded entire typeswitch');
|
236
243
|
|
237
244
|
if (i > 0) i--;
|
238
245
|
continue;
|
@@ -261,7 +268,7 @@ export default (funcs, globals, pages, tags) => {
|
|
261
268
|
|
262
269
|
getCount[inst[1]]--;
|
263
270
|
i--;
|
264
|
-
// if (optLog) log('opt', `consolidated set, get -> tee`);
|
271
|
+
// if (Prefs.optLog) log('opt', `consolidated set, get -> tee`);
|
265
272
|
continue;
|
266
273
|
}
|
267
274
|
|
@@ -329,7 +336,7 @@ export default (funcs, globals, pages, tags) => {
|
|
329
336
|
|
330
337
|
wasm.splice(i - 1, 2); // remove this inst and last
|
331
338
|
i -= 2;
|
332
|
-
// if (optLog) log('opt', `removed redundant i32 -> i64 -> i32 conversion ops`);
|
339
|
+
// if (Prefs.optLog) log('opt', `removed redundant i32 -> i64 -> i32 conversion ops`);
|
333
340
|
continue;
|
334
341
|
}
|
335
342
|
|
@@ -342,7 +349,7 @@ export default (funcs, globals, pages, tags) => {
|
|
342
349
|
|
343
350
|
wasm.splice(i - 1, 2); // remove this inst and last
|
344
351
|
i -= 2;
|
345
|
-
// if (optLog) log('opt', `removed redundant i32 -> f64 -> i32 conversion ops`);
|
352
|
+
// if (Prefs.optLog) log('opt', `removed redundant i32 -> f64 -> i32 conversion ops`);
|
346
353
|
continue;
|
347
354
|
}
|
348
355
|
|
@@ -357,7 +364,7 @@ export default (funcs, globals, pages, tags) => {
|
|
357
364
|
|
358
365
|
wasm.splice(i, 1); // remove this inst
|
359
366
|
i--;
|
360
|
-
if (optLog) log('opt', `converted const -> i32 convert into i32 const`);
|
367
|
+
if (Prefs.optLog) log('opt', `converted const -> i32 convert into i32 const`);
|
361
368
|
continue;
|
362
369
|
}
|
363
370
|
|
@@ -372,7 +379,7 @@ export default (funcs, globals, pages, tags) => {
|
|
372
379
|
|
373
380
|
wasm.splice(i, 1); // remove this inst
|
374
381
|
i--;
|
375
|
-
if (optLog) log('opt', `converted i32 const -> convert into const`);
|
382
|
+
if (Prefs.optLog) log('opt', `converted i32 const -> convert into const`);
|
376
383
|
continue;
|
377
384
|
}
|
378
385
|
|
@@ -387,7 +394,7 @@ export default (funcs, globals, pages, tags) => {
|
|
387
394
|
|
388
395
|
wasm.splice(i, 1); // remove this inst (return)
|
389
396
|
i--;
|
390
|
-
if (optLog) log('opt', `tail called return, call`);
|
397
|
+
if (Prefs.optLog) log('opt', `tail called return, call`);
|
391
398
|
continue;
|
392
399
|
}
|
393
400
|
|
@@ -400,7 +407,7 @@ export default (funcs, globals, pages, tags) => {
|
|
400
407
|
|
401
408
|
wasm.splice(i, 1); // remove this inst (return)
|
402
409
|
i--;
|
403
|
-
// if (optLog) log('opt', `removed redundant return at end`);
|
410
|
+
// if (Prefs.optLog) log('opt', `removed redundant return at end`);
|
404
411
|
continue;
|
405
412
|
}
|
406
413
|
|
@@ -430,7 +437,7 @@ export default (funcs, globals, pages, tags) => {
|
|
430
437
|
// <nothing>
|
431
438
|
|
432
439
|
wasm.splice(i - 2, 3); // remove this, last, 2nd last insts
|
433
|
-
if (optLog) log('opt', `removed redundant inline param local handling`);
|
440
|
+
if (Prefs.optLog) log('opt', `removed redundant inline param local handling`);
|
434
441
|
i -= 3;
|
435
442
|
continue;
|
436
443
|
}
|
@@ -438,12 +445,12 @@ export default (funcs, globals, pages, tags) => {
|
|
438
445
|
|
439
446
|
if (optLevel < 2) continue;
|
440
447
|
|
441
|
-
if (optLog) log('opt', `get counts: ${Object.keys(f.locals).map(x => `${x} (${f.locals[x].idx}): ${getCount[f.locals[x].idx]}`).join(', ')}`);
|
448
|
+
if (Prefs.optLog) log('opt', `get counts: ${Object.keys(f.locals).map(x => `${x} (${f.locals[x].idx}): ${getCount[f.locals[x].idx]}`).join(', ')}`);
|
442
449
|
|
443
450
|
// remove unneeded var: remove pass
|
444
451
|
// locals only got once. we don't need to worry about sets/else as these are only candidates and we will check for matching set + get insts in wasm
|
445
452
|
let unneededCandidates = Object.keys(getCount).filter(x => getCount[x] === 0 || (getCount[x] === 1 && setCount[x] === 0)).map(x => parseInt(x));
|
446
|
-
if (optLog) log('opt', `found unneeded locals candidates: ${unneededCandidates.join(', ')} (${unneededCandidates.length}/${Object.keys(getCount).length})`);
|
453
|
+
if (Prefs.optLog) log('opt', `found unneeded locals candidates: ${unneededCandidates.join(', ')} (${unneededCandidates.length}/${Object.keys(getCount).length})`);
|
447
454
|
|
448
455
|
// note: disabled for now due to instability
|
449
456
|
if (unneededCandidates.length > 0 && false) for (let i = 0; i < wasm.length; i++) {
|
@@ -461,7 +468,7 @@ export default (funcs, globals, pages, tags) => {
|
|
461
468
|
wasm.splice(i - 1, 2); // remove insts
|
462
469
|
i -= 2;
|
463
470
|
delete f.locals[Object.keys(f.locals)[inst[1]]]; // remove from locals
|
464
|
-
if (optLog) log('opt', `removed redundant local (get set ${inst[1]})`);
|
471
|
+
if (Prefs.optLog) log('opt', `removed redundant local (get set ${inst[1]})`);
|
465
472
|
}
|
466
473
|
|
467
474
|
if (inst[0] === Opcodes.local_tee && unneededCandidates.includes(inst[1])) {
|
@@ -489,7 +496,7 @@ export default (funcs, globals, pages, tags) => {
|
|
489
496
|
unneededCandidates.splice(unneededCandidates.indexOf(inst[1]), 1);
|
490
497
|
unneededCandidates = unneededCandidates.map(x => x > removedIdx ? (x - 1) : x);
|
491
498
|
|
492
|
-
if (optLog) log('opt', `removed redundant local ${localName} (tee ${inst[1]})`);
|
499
|
+
if (Prefs.optLog) log('opt', `removed redundant local ${localName} (tee ${inst[1]})`);
|
493
500
|
}
|
494
501
|
}
|
495
502
|
|
@@ -525,7 +532,7 @@ export default (funcs, globals, pages, tags) => {
|
|
525
532
|
let b = lastInst[1];
|
526
533
|
|
527
534
|
const val = performWasmOp(inst[0], a, b);
|
528
|
-
if (optLog) log('opt', `inlined math op (${a} ${inst[0].toString(16)} ${b} -> ${val})`);
|
535
|
+
if (Prefs.optLog) log('opt', `inlined math op (${a} ${inst[0].toString(16)} ${b} -> ${val})`);
|
529
536
|
|
530
537
|
wasm.splice(i - 2, 3, ...number(val)); // remove consts, math op and add new const
|
531
538
|
i -= 2;
|
@@ -537,12 +544,12 @@ export default (funcs, globals, pages, tags) => {
|
|
537
544
|
for (const x in useCount) {
|
538
545
|
if (useCount[x] === 0) {
|
539
546
|
const name = Object.keys(f.locals)[localIdxs.indexOf(parseInt(x))];
|
540
|
-
if (optLog) log('opt', `removed internal local ${x} (${name})`);
|
547
|
+
if (Prefs.optLog) log('opt', `removed internal local ${x} (${name})`);
|
541
548
|
delete f.locals[name];
|
542
549
|
}
|
543
550
|
}
|
544
551
|
|
545
|
-
if (optLog) log('opt', `final use counts: ${Object.keys(f.locals).map(x => `${x} (${f.locals[x].idx}): ${useCount[f.locals[x].idx]}`).join(', ')}`);
|
552
|
+
if (Prefs.optLog) log('opt', `final use counts: ${Object.keys(f.locals).map(x => `${x} (${f.locals[x].idx}): ${useCount[f.locals[x].idx]}`).join(', ')}`);
|
546
553
|
}
|
547
554
|
}
|
548
555
|
|
@@ -553,5 +560,11 @@ export default (funcs, globals, pages, tags) => {
|
|
553
560
|
}
|
554
561
|
}
|
555
562
|
|
563
|
+
for (const x of Object.keys(exceptionUse).sort((a, b) => b - a)) {
|
564
|
+
if (exceptionUse[x] === 0) {
|
565
|
+
exceptions.splice(+x, 1);
|
566
|
+
}
|
567
|
+
}
|
568
|
+
|
556
569
|
// return funcs;
|
557
570
|
};
|
package/compiler/parse.js
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
import { log } from "./log.js";
|
2
|
+
import Prefs from './prefs.js';
|
3
|
+
|
2
4
|
// import { parse } from 'acorn';
|
3
5
|
|
4
6
|
// deno compat
|
@@ -8,8 +10,8 @@ if (typeof process === 'undefined' && typeof Deno !== 'undefined') {
|
|
8
10
|
}
|
9
11
|
|
10
12
|
// should we try to support types (while parsing)
|
11
|
-
const types =
|
12
|
-
globalThis.typedInput = types &&
|
13
|
+
const types = Prefs.parseTypes;
|
14
|
+
globalThis.typedInput = types && Prefs.optTypes;
|
13
15
|
|
14
16
|
// todo: review which to use by default
|
15
17
|
// supported parsers:
|
@@ -0,0 +1,79 @@
|
|
1
|
+
import fs from 'node:fs';
|
2
|
+
import { join } from 'node:path';
|
3
|
+
|
4
|
+
import { fileURLToPath } from 'node:url';
|
5
|
+
const __dirname = fileURLToPath(new URL('.', import.meta.url));
|
6
|
+
|
7
|
+
// import porfParse from './parse.js';
|
8
|
+
// import porfCodegen from './codeGen.js';
|
9
|
+
|
10
|
+
const argv = process.argv.slice();
|
11
|
+
|
12
|
+
const compile = async (file, [ _funcs, _globals ]) => {
|
13
|
+
const source = fs.readFileSync(file, 'utf8');
|
14
|
+
const first = source.slice(0, source.indexOf('\n'));
|
15
|
+
|
16
|
+
let args = ['-bytestring'];
|
17
|
+
if (file.endsWith('.ts')) args.push('-parse-types', '-opt-types');
|
18
|
+
if (first.startsWith('// @porf')) {
|
19
|
+
args = args.concat(first.slice('// @porf '.length).split(' '));
|
20
|
+
}
|
21
|
+
process.argv = argv.concat(args);
|
22
|
+
|
23
|
+
// globalThis.optLog = process.argv.includes('-opt-log');
|
24
|
+
// globalThis.codeLog = process.argv.includes('-code-log');
|
25
|
+
// globalThis.allocLog = process.argv.includes('-alloc-log');
|
26
|
+
// globalThis.regexLog = process.argv.includes('-regex-log');
|
27
|
+
|
28
|
+
// const porfParse = (await import(`./parse.js?_=${Date.now()}`)).default;
|
29
|
+
// const porfCodegen = (await import(`./codeGen.js?_=${Date.now()}`)).default;
|
30
|
+
|
31
|
+
// let { funcs, globals, data } = porfCodegen(porfParse(source, ['module']));
|
32
|
+
|
33
|
+
const porfCompile = (await import(`./index.js?_=${Date.now()}`)).default;
|
34
|
+
|
35
|
+
let { funcs, globals, data, exceptions } = porfCompile(source, ['module']);
|
36
|
+
|
37
|
+
funcs = funcs.filter(x => x.export);
|
38
|
+
for (const x of funcs) {
|
39
|
+
if (x.data) x.data = x.data.map(x => data[x]);
|
40
|
+
if (x.exceptions) x.exceptions = x.exceptions.map(x => {
|
41
|
+
const obj = exceptions[x];
|
42
|
+
if (obj) obj.exceptId = x;
|
43
|
+
return obj;
|
44
|
+
}).filter(x => x);
|
45
|
+
}
|
46
|
+
|
47
|
+
_funcs.push(...funcs);
|
48
|
+
_globals.push(...Object.values(globals));
|
49
|
+
};
|
50
|
+
|
51
|
+
const precompile = async () => {
|
52
|
+
const dir = join(__dirname, 'builtins');
|
53
|
+
|
54
|
+
let funcs = [], globals = [];
|
55
|
+
for (const file of fs.readdirSync(dir)) {
|
56
|
+
if (file.endsWith('.d.ts')) continue;
|
57
|
+
await compile(join(dir, file), [ funcs, globals ]);
|
58
|
+
}
|
59
|
+
|
60
|
+
// todo: globals, exceptions, pages per func
|
61
|
+
|
62
|
+
return `// autogenerated by precompile.js
|
63
|
+
|
64
|
+
export const BuiltinFuncs = function() {
|
65
|
+
${funcs.map(x => ` this.${x.name} = {
|
66
|
+
wasm: ${JSON.stringify(x.wasm)},
|
67
|
+
params: ${JSON.stringify(x.params)},
|
68
|
+
typedParams: true,
|
69
|
+
returns: ${JSON.stringify(x.returns)},
|
70
|
+
typedReturns: true,
|
71
|
+
locals: ${JSON.stringify(Object.values(x.locals).slice(x.params.length * 2).map(x => x.type))},
|
72
|
+
${x.pages && x.pages.size > 0 ? ` pages: ${JSON.stringify(Object.fromEntries(x.pages.entries()))},` : ''}
|
73
|
+
${x.data && x.data.length > 0 ? ` data: ${JSON.stringify(x.data)},` : ''}
|
74
|
+
${x.exceptions && x.exceptions.length > 0 ? ` exceptions: ${JSON.stringify(x.exceptions)},` : ''}
|
75
|
+
};`.replaceAll('\n\n', '\n')).join('\n')}
|
76
|
+
}`;
|
77
|
+
};
|
78
|
+
|
79
|
+
console.log(await precompile());
|
@@ -0,0 +1,22 @@
|
|
1
|
+
const cache = {};
|
2
|
+
const obj = new Proxy({}, {
|
3
|
+
get(_, p) {
|
4
|
+
// intentionally misses with undefined values cached
|
5
|
+
if (cache[p]) return cache[p];
|
6
|
+
|
7
|
+
return cache[p] = (() => {
|
8
|
+
// fooBar -> foo-bar
|
9
|
+
const name = p[0] === '_' ? p : p.replace(/[A-Z]/g, c => `-${c.toLowerCase()}`);
|
10
|
+
if (process.argv.includes('-' + name)) return true;
|
11
|
+
|
12
|
+
const valArg = process.argv.find(x => x.startsWith(`-${name}=`));
|
13
|
+
if (valArg) return valArg.slice(name.length + 2);
|
14
|
+
|
15
|
+
return undefined;
|
16
|
+
})();
|
17
|
+
}
|
18
|
+
});
|
19
|
+
|
20
|
+
obj.uncache = () => cache = {};
|
21
|
+
|
22
|
+
export default obj;
|
package/compiler/prototype.js
CHANGED
@@ -2,6 +2,7 @@ import { Opcodes, Blocktype, Valtype, ValtypeSize, PageSize } from "./wasmSpec.j
|
|
2
2
|
import { number } from "./embedding.js";
|
3
3
|
import { unsignedLEB128 } from "./encoding.js";
|
4
4
|
import { UNDEFINED } from "./builtins.js";
|
5
|
+
import Prefs from './prefs.js';
|
5
6
|
|
6
7
|
// todo: do not duplicate this
|
7
8
|
const TYPES = {
|
@@ -23,9 +24,10 @@ const TYPES = {
|
|
23
24
|
// todo: turn these into built-ins once arrays and these become less hacky
|
24
25
|
|
25
26
|
export const PrototypeFuncs = function() {
|
26
|
-
const noUnlikelyChecks =
|
27
|
-
|
28
|
-
|
27
|
+
const noUnlikelyChecks = Prefs.funsafeNoUnlikelyProtoChecks;
|
28
|
+
|
29
|
+
let zeroChecks;
|
30
|
+
if (Prefs.zeroChecks) zeroChecks = Prefs.zeroChecks.split('=')[1].split(',').reduce((acc, x) => { acc[x.toLowerCase()] = true; return acc; }, {});
|
29
31
|
else zeroChecks = {};
|
30
32
|
|
31
33
|
this[TYPES._array] = {
|
@@ -342,8 +344,8 @@ export const PrototypeFuncs = function() {
|
|
342
344
|
...number(0, Valtype.i32), // base 0 for store later
|
343
345
|
|
344
346
|
...wIndex,
|
345
|
-
|
346
347
|
Opcodes.i32_to,
|
348
|
+
|
347
349
|
...number(ValtypeSize.i16, Valtype.i32),
|
348
350
|
[ Opcodes.i32_mul ],
|
349
351
|
|
@@ -489,10 +491,10 @@ export const PrototypeFuncs = function() {
|
|
489
491
|
this[TYPES.string].isWellFormed.local2 = Valtype.i32;
|
490
492
|
this[TYPES.string].isWellFormed.returnType = TYPES.boolean;
|
491
493
|
|
492
|
-
if (
|
494
|
+
if (Prefs.bytestring) {
|
493
495
|
this[TYPES._bytestring] = {
|
494
496
|
at: (pointer, length, wIndex, iTmp, _, arrayShell) => {
|
495
|
-
const [ newOut, newPointer ] = arrayShell(1, '
|
497
|
+
const [ newOut, newPointer ] = arrayShell(1, 'i8');
|
496
498
|
|
497
499
|
return [
|
498
500
|
// setup new/out array
|
@@ -548,7 +550,7 @@ export const PrototypeFuncs = function() {
|
|
548
550
|
|
549
551
|
// todo: out of bounds properly
|
550
552
|
charAt: (pointer, length, wIndex, _1, _2, arrayShell) => {
|
551
|
-
const [ newOut, newPointer ] = arrayShell(1, '
|
553
|
+
const [ newOut, newPointer ] = arrayShell(1, 'i8');
|
552
554
|
|
553
555
|
return [
|
554
556
|
// setup new/out array
|
@@ -558,7 +560,6 @@ export const PrototypeFuncs = function() {
|
|
558
560
|
...number(0, Valtype.i32), // base 0 for store later
|
559
561
|
|
560
562
|
...wIndex,
|
561
|
-
|
562
563
|
Opcodes.i32_to,
|
563
564
|
|
564
565
|
...pointer,
|
package/compiler/sections.js
CHANGED
@@ -3,6 +3,7 @@ import { encodeVector, encodeString, encodeLocal, unsignedLEB128, signedLEB128 }
|
|
3
3
|
import { number } from './embedding.js';
|
4
4
|
import { importedFuncs } from './builtins.js';
|
5
5
|
import { log } from "./log.js";
|
6
|
+
import Prefs from './prefs.js';
|
6
7
|
|
7
8
|
const createSection = (type, data) => [
|
8
9
|
type,
|
@@ -26,12 +27,12 @@ export default (funcs, globals, tags, pages, data, flags) => {
|
|
26
27
|
|
27
28
|
const optLevel = parseInt(process.argv.find(x => x.startsWith('-O'))?.[2] ?? 1);
|
28
29
|
|
29
|
-
const compileHints =
|
30
|
+
const compileHints = Prefs.compileHints;
|
30
31
|
if (compileHints) log.warning('sections', 'compile hints is V8 only w/ experimental arg! (you used -compile-hints)');
|
31
32
|
|
32
33
|
const getType = (params, returns) => {
|
33
34
|
const hash = `${params.join(',')}_${returns.join(',')}`;
|
34
|
-
if (optLog) log('sections', `getType(${JSON.stringify(params)}, ${JSON.stringify(returns)}) -> ${hash} | cache: ${typeCache[hash]}`);
|
35
|
+
if (Prefs.optLog) log('sections', `getType(${JSON.stringify(params)}, ${JSON.stringify(returns)}) -> ${hash} | cache: ${typeCache[hash]}`);
|
35
36
|
if (optLevel >= 1 && typeCache[hash] !== undefined) return typeCache[hash];
|
36
37
|
|
37
38
|
const type = [ FuncType, ...encodeVector(params), ...encodeVector(returns) ];
|
@@ -79,7 +80,7 @@ export default (funcs, globals, tags, pages, data, flags) => {
|
|
79
80
|
}
|
80
81
|
globalThis.importFuncs = importFuncs;
|
81
82
|
|
82
|
-
if (optLog) log('sections', `treeshake: using ${importFuncs.length}/${importedFuncs.length} imports`);
|
83
|
+
if (Prefs.optLog) log('sections', `treeshake: using ${importFuncs.length}/${importedFuncs.length} imports`);
|
83
84
|
|
84
85
|
const importSection = importFuncs.length === 0 ? [] : createSection(
|
85
86
|
Section.import,
|
@@ -95,7 +96,7 @@ export default (funcs, globals, tags, pages, data, flags) => {
|
|
95
96
|
// https://github.com/WebAssembly/design/issues/1473#issuecomment-1431274746
|
96
97
|
const chSection = !compileHints ? [] : customSection(
|
97
98
|
'compilationHints',
|
98
|
-
// for now just do everything as
|
99
|
+
// for now just do everything as optimize eager
|
99
100
|
encodeVector(funcs.map(_ => chHint(0x02, 0x02, 0x02)))
|
100
101
|
);
|
101
102
|
|
@@ -106,7 +107,7 @@ export default (funcs, globals, tags, pages, data, flags) => {
|
|
106
107
|
|
107
108
|
const exports = funcs.filter(x => x.export).map((x, i) => [ ...encodeString(x.name === 'main' ? 'm' : x.name), ExportDesc.func, x.index ]);
|
108
109
|
|
109
|
-
if (
|
110
|
+
if (Prefs.alwaysMemory && pages.size === 0) pages.set('-always-memory', 0);
|
110
111
|
if (optLevel === 0) pages.set('O0 precaution', 0);
|
111
112
|
|
112
113
|
const usesMemory = pages.size > 0;
|
@@ -169,7 +170,7 @@ export default (funcs, globals, tags, pages, data, flags) => {
|
|
169
170
|
unsignedLEB128(data.length)
|
170
171
|
);
|
171
172
|
|
172
|
-
if (
|
173
|
+
if (Prefs.sections) console.log({
|
173
174
|
typeSection: typeSection.map(x => x.toString(16)),
|
174
175
|
importSection: importSection.map(x => x.toString(16)),
|
175
176
|
funcSection: funcSection.map(x => x.toString(16)),
|
package/demo.js
CHANGED
@@ -1,3 +1,3 @@
|
|
1
|
-
foo();
|
1
|
+
// foo();
|
2
2
|
|
3
|
-
|
3
|
+
console.log('Hello, World!');
|
package/hello
ADDED
Binary file
|
package/package.json
CHANGED
package/rhemyn/compile.js
CHANGED
@@ -2,6 +2,7 @@ import { Blocktype, Opcodes, Valtype, PageSize, ValtypeSize } from '../compiler/
|
|
2
2
|
import { number } from '../compiler/embedding.js';
|
3
3
|
import { signedLEB128, unsignedLEB128 } from '../compiler/encoding.js';
|
4
4
|
import parse from './parse.js';
|
5
|
+
import Prefs from '../compiler/prefs.js';
|
5
6
|
|
6
7
|
// local indexes
|
7
8
|
const BasePointer = 0; // base string pointer
|
@@ -80,7 +81,7 @@ const generate = (node, negated = false, get = true, func = 'test') => {
|
|
80
81
|
})[func], Valtype.i32)
|
81
82
|
];
|
82
83
|
|
83
|
-
if (
|
84
|
+
if (Prefs.regexLog) {
|
84
85
|
const underline = x => `\u001b[4m\u001b[1m${x}\u001b[0m`;
|
85
86
|
console.log(`\n${underline('ast')}`);
|
86
87
|
console.log(node);
|