porffor 0.2.0-c7b7423 → 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 +89 -47
- package/compiler/2c.js +321 -71
- package/compiler/builtins/base64.ts +88 -0
- package/compiler/builtins/porffor.d.ts +10 -0
- package/compiler/builtins.js +178 -60
- package/compiler/codeGen.js +537 -271
- package/compiler/decompile.js +3 -3
- package/compiler/encoding.js +2 -116
- package/compiler/generated_builtins.js +3 -0
- package/compiler/index.js +22 -22
- package/compiler/opt.js +61 -26
- package/compiler/parse.js +13 -12
- package/compiler/precompile.js +79 -0
- package/compiler/prefs.js +22 -0
- package/compiler/prototype.js +176 -20
- package/compiler/sections.js +8 -7
- 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/hello +0 -0
- package/package.json +1 -1
- package/porf +2 -0
- package/rhemyn/compile.js +2 -1
- package/runner/index.js +20 -3
- package/runner/repl.js +2 -2
- package/tmp.c +136 -53
- package/compiler/builtins/base64.js +0 -92
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 = {
|
@@ -16,15 +17,17 @@ const TYPES = {
|
|
16
17
|
|
17
18
|
// these are not "typeof" types but tracked internally
|
18
19
|
_array: 0x10,
|
19
|
-
_regexp: 0x11
|
20
|
+
_regexp: 0x11,
|
21
|
+
_bytestring: 0x12
|
20
22
|
};
|
21
23
|
|
22
24
|
// todo: turn these into built-ins once arrays and these become less hacky
|
23
25
|
|
24
26
|
export const PrototypeFuncs = function() {
|
25
|
-
const noUnlikelyChecks =
|
26
|
-
|
27
|
-
|
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; }, {});
|
28
31
|
else zeroChecks = {};
|
29
32
|
|
30
33
|
this[TYPES._array] = {
|
@@ -71,7 +74,7 @@ export const PrototypeFuncs = function() {
|
|
71
74
|
],
|
72
75
|
|
73
76
|
// todo: only for 1 argument
|
74
|
-
push: (pointer, length, wNewMember) => [
|
77
|
+
push: (pointer, length, wNewMember, _1, _2, _3, unusedValue) => [
|
75
78
|
// get memory offset of array at last index (length)
|
76
79
|
...length.getCachedI32(),
|
77
80
|
...number(ValtypeSize[valtype], Valtype.i32),
|
@@ -92,22 +95,28 @@ export const PrototypeFuncs = function() {
|
|
92
95
|
...number(1, Valtype.i32),
|
93
96
|
[ Opcodes.i32_add ],
|
94
97
|
|
95
|
-
...
|
96
|
-
|
98
|
+
...(unusedValue() ? [] : [
|
99
|
+
...length.setCachedI32(),
|
100
|
+
...length.getCachedI32(),
|
101
|
+
])
|
97
102
|
]),
|
98
103
|
|
99
|
-
...
|
100
|
-
|
104
|
+
...(unusedValue() ? [] : [
|
105
|
+
...length.getCachedI32(),
|
106
|
+
Opcodes.i32_from_u
|
107
|
+
])
|
101
108
|
|
102
109
|
// ...length.get()
|
103
110
|
],
|
104
111
|
|
105
|
-
pop: (pointer, length) => [
|
112
|
+
pop: (pointer, length, _1, _2, _3, _4, unusedValue) => [
|
106
113
|
// if length == 0, noop
|
107
114
|
...length.getCachedI32(),
|
108
115
|
[ Opcodes.i32_eqz ],
|
109
116
|
[ Opcodes.if, Blocktype.void ],
|
110
|
-
...
|
117
|
+
...(unusedValue() ? [] : [
|
118
|
+
...number(UNDEFINED),
|
119
|
+
]),
|
111
120
|
[ Opcodes.br, 1 ],
|
112
121
|
[ Opcodes.end ],
|
113
122
|
|
@@ -119,19 +128,23 @@ export const PrototypeFuncs = function() {
|
|
119
128
|
...number(1, Valtype.i32),
|
120
129
|
[ Opcodes.i32_sub ],
|
121
130
|
|
122
|
-
...
|
123
|
-
|
131
|
+
...(unusedValue() ? [] : [
|
132
|
+
...length.setCachedI32(),
|
133
|
+
...length.getCachedI32(),
|
134
|
+
])
|
124
135
|
]),
|
125
136
|
|
126
137
|
// load last element
|
127
|
-
...
|
128
|
-
|
129
|
-
|
138
|
+
...(unusedValue() ? [] : [
|
139
|
+
...length.getCachedI32(),
|
140
|
+
...number(ValtypeSize[valtype], Valtype.i32),
|
141
|
+
[ Opcodes.i32_mul ],
|
130
142
|
|
131
|
-
|
132
|
-
|
143
|
+
...pointer,
|
144
|
+
[ Opcodes.i32_add ],
|
133
145
|
|
134
|
-
|
146
|
+
[ Opcodes.load, Math.log2(ValtypeSize[valtype]) - 1, ...unsignedLEB128(ValtypeSize.i32) ]
|
147
|
+
])
|
135
148
|
],
|
136
149
|
|
137
150
|
shift: (pointer, length) => [
|
@@ -331,8 +344,8 @@ export const PrototypeFuncs = function() {
|
|
331
344
|
...number(0, Valtype.i32), // base 0 for store later
|
332
345
|
|
333
346
|
...wIndex,
|
334
|
-
|
335
347
|
Opcodes.i32_to,
|
348
|
+
|
336
349
|
...number(ValtypeSize.i16, Valtype.i32),
|
337
350
|
[ Opcodes.i32_mul ],
|
338
351
|
|
@@ -472,8 +485,151 @@ export const PrototypeFuncs = function() {
|
|
472
485
|
this[TYPES.string].at.returnType = TYPES.string;
|
473
486
|
this[TYPES.string].charAt.returnType = TYPES.string;
|
474
487
|
this[TYPES.string].charCodeAt.local = Valtype.i32;
|
488
|
+
this[TYPES.string].charCodeAt.noPointerCache = zeroChecks.charcodeat;
|
475
489
|
|
476
490
|
this[TYPES.string].isWellFormed.local = Valtype.i32;
|
477
491
|
this[TYPES.string].isWellFormed.local2 = Valtype.i32;
|
478
492
|
this[TYPES.string].isWellFormed.returnType = TYPES.boolean;
|
493
|
+
|
494
|
+
if (Prefs.bytestring) {
|
495
|
+
this[TYPES._bytestring] = {
|
496
|
+
at: (pointer, length, wIndex, iTmp, _, arrayShell) => {
|
497
|
+
const [ newOut, newPointer ] = arrayShell(1, 'i8');
|
498
|
+
|
499
|
+
return [
|
500
|
+
// setup new/out array
|
501
|
+
...newOut,
|
502
|
+
[ Opcodes.drop ],
|
503
|
+
|
504
|
+
...number(0, Valtype.i32), // base 0 for store later
|
505
|
+
|
506
|
+
...wIndex,
|
507
|
+
Opcodes.i32_to_u,
|
508
|
+
[ Opcodes.local_tee, iTmp ],
|
509
|
+
|
510
|
+
// if index < 0: access index + array length
|
511
|
+
...number(0, Valtype.i32),
|
512
|
+
[ Opcodes.i32_lt_s ],
|
513
|
+
[ Opcodes.if, Blocktype.void ],
|
514
|
+
[ Opcodes.local_get, iTmp ],
|
515
|
+
...length.getCachedI32(),
|
516
|
+
[ Opcodes.i32_add ],
|
517
|
+
[ Opcodes.local_set, iTmp ],
|
518
|
+
[ Opcodes.end ],
|
519
|
+
|
520
|
+
// if still < 0 or >= length: return undefined
|
521
|
+
[ Opcodes.local_get, iTmp ],
|
522
|
+
...number(0, Valtype.i32),
|
523
|
+
[ Opcodes.i32_lt_s ],
|
524
|
+
|
525
|
+
[ Opcodes.local_get, iTmp ],
|
526
|
+
...length.getCachedI32(),
|
527
|
+
[ Opcodes.i32_ge_s ],
|
528
|
+
[ Opcodes.i32_or ],
|
529
|
+
|
530
|
+
[ Opcodes.if, Blocktype.void ],
|
531
|
+
...number(UNDEFINED),
|
532
|
+
[ Opcodes.br, 1 ],
|
533
|
+
[ Opcodes.end ],
|
534
|
+
|
535
|
+
[ Opcodes.local_get, iTmp ],
|
536
|
+
|
537
|
+
...pointer,
|
538
|
+
[ Opcodes.i32_add ],
|
539
|
+
|
540
|
+
// load current string ind {arg}
|
541
|
+
[ Opcodes.i32_load8_u, 0, ...unsignedLEB128(ValtypeSize.i32) ],
|
542
|
+
|
543
|
+
// store to new string ind 0
|
544
|
+
[ Opcodes.i32_store8, 0, ...unsignedLEB128(newPointer + ValtypeSize.i32) ],
|
545
|
+
|
546
|
+
// return new string (pointer)
|
547
|
+
...number(newPointer)
|
548
|
+
];
|
549
|
+
},
|
550
|
+
|
551
|
+
// todo: out of bounds properly
|
552
|
+
charAt: (pointer, length, wIndex, _1, _2, arrayShell) => {
|
553
|
+
const [ newOut, newPointer ] = arrayShell(1, 'i8');
|
554
|
+
|
555
|
+
return [
|
556
|
+
// setup new/out array
|
557
|
+
...newOut,
|
558
|
+
[ Opcodes.drop ],
|
559
|
+
|
560
|
+
...number(0, Valtype.i32), // base 0 for store later
|
561
|
+
|
562
|
+
...wIndex,
|
563
|
+
Opcodes.i32_to,
|
564
|
+
|
565
|
+
...pointer,
|
566
|
+
[ Opcodes.i32_add ],
|
567
|
+
|
568
|
+
// load current string ind {arg}
|
569
|
+
[ Opcodes.i32_load8_u, 0, ...unsignedLEB128(ValtypeSize.i32) ],
|
570
|
+
|
571
|
+
// store to new string ind 0
|
572
|
+
[ Opcodes.i32_store8, 0, ...unsignedLEB128(newPointer + ValtypeSize.i32) ],
|
573
|
+
|
574
|
+
// return new string (page)
|
575
|
+
...number(newPointer)
|
576
|
+
];
|
577
|
+
},
|
578
|
+
|
579
|
+
charCodeAt: (pointer, length, wIndex, iTmp) => {
|
580
|
+
return [
|
581
|
+
...wIndex,
|
582
|
+
Opcodes.i32_to,
|
583
|
+
|
584
|
+
...(zeroChecks.charcodeat ? [] : [
|
585
|
+
[ Opcodes.local_set, iTmp ],
|
586
|
+
|
587
|
+
// index < 0
|
588
|
+
...(noUnlikelyChecks ? [] : [
|
589
|
+
[ Opcodes.local_get, iTmp ],
|
590
|
+
...number(0, Valtype.i32),
|
591
|
+
[ Opcodes.i32_lt_s ],
|
592
|
+
]),
|
593
|
+
|
594
|
+
// index >= length
|
595
|
+
[ Opcodes.local_get, iTmp ],
|
596
|
+
...length.getCachedI32(),
|
597
|
+
[ Opcodes.i32_ge_s ],
|
598
|
+
|
599
|
+
...(noUnlikelyChecks ? [] : [ [ Opcodes.i32_or ] ]),
|
600
|
+
[ Opcodes.if, Blocktype.void ],
|
601
|
+
...number(NaN),
|
602
|
+
[ Opcodes.br, 1 ],
|
603
|
+
[ Opcodes.end ],
|
604
|
+
|
605
|
+
[ Opcodes.local_get, iTmp ],
|
606
|
+
]),
|
607
|
+
|
608
|
+
...pointer,
|
609
|
+
[ Opcodes.i32_add ],
|
610
|
+
|
611
|
+
// load current string ind {arg}
|
612
|
+
[ Opcodes.i32_load8_u, 0, ...unsignedLEB128(ValtypeSize.i32) ],
|
613
|
+
Opcodes.i32_from_u
|
614
|
+
];
|
615
|
+
},
|
616
|
+
|
617
|
+
isWellFormed: () => {
|
618
|
+
return [
|
619
|
+
// we know it must be true as it is a bytestring lol
|
620
|
+
...number(1)
|
621
|
+
]
|
622
|
+
}
|
623
|
+
};
|
624
|
+
|
625
|
+
this[TYPES._bytestring].at.local = Valtype.i32;
|
626
|
+
this[TYPES._bytestring].at.returnType = TYPES._bytestring;
|
627
|
+
this[TYPES._bytestring].charAt.returnType = TYPES._bytestring;
|
628
|
+
this[TYPES._bytestring].charCodeAt.local = Valtype.i32;
|
629
|
+
this[TYPES._bytestring].charCodeAt.noPointerCache = zeroChecks.charcodeat;
|
630
|
+
|
631
|
+
this[TYPES._bytestring].isWellFormed.local = Valtype.i32;
|
632
|
+
this[TYPES._bytestring].isWellFormed.local2 = Valtype.i32;
|
633
|
+
this[TYPES._bytestring].isWellFormed.returnType = TYPES.boolean;
|
634
|
+
}
|
479
635
|
};
|
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;
|
@@ -150,7 +151,7 @@ export default (funcs, globals, tags, pages, data, flags) => {
|
|
150
151
|
|
151
152
|
if (typeCount !== 0) localDecl.push(encodeLocal(typeCount, lastType));
|
152
153
|
|
153
|
-
return encodeVector([ ...encodeVector(localDecl), ...x.wasm.flat().filter(x => x <= 0xff), Opcodes.end ]);
|
154
|
+
return encodeVector([ ...encodeVector(localDecl), ...x.wasm.flat().filter(x => x != null && x <= 0xff), Opcodes.end ]);
|
154
155
|
}))
|
155
156
|
);
|
156
157
|
|
@@ -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/compiler/wasmSpec.js
CHANGED
@@ -32,8 +32,6 @@ export const Opcodes = {
|
|
32
32
|
throw: 0x08,
|
33
33
|
rethrow: 0x09,
|
34
34
|
|
35
|
-
return: 0x0F,
|
36
|
-
|
37
35
|
call: 0x10,
|
38
36
|
call_indirect: 0x11,
|
39
37
|
return_call: 0x12,
|
@@ -42,7 +40,10 @@ export const Opcodes = {
|
|
42
40
|
end: 0x0b,
|
43
41
|
br: 0x0c,
|
44
42
|
br_if: 0x0d,
|
43
|
+
br_table: 0x0e,
|
44
|
+
return: 0x0f,
|
45
45
|
call: 0x10,
|
46
|
+
|
46
47
|
drop: 0x1a,
|
47
48
|
|
48
49
|
local_get: 0x20,
|
@@ -56,9 +57,12 @@ export const Opcodes = {
|
|
56
57
|
i64_load: 0x29,
|
57
58
|
f64_load: 0x2b,
|
58
59
|
|
60
|
+
i32_load8_s: 0x2c,
|
61
|
+
i32_load8_u: 0x2d,
|
59
62
|
i32_load16_s: 0x2e,
|
60
63
|
i32_load16_u: 0x2f,
|
61
64
|
|
65
|
+
i32_store8: 0x3a,
|
62
66
|
i32_store16: 0x3b,
|
63
67
|
|
64
68
|
i32_store: 0x36,
|
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/hello
ADDED
Binary file
|
package/package.json
CHANGED
package/porf
ADDED
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);
|
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;
|