porffor 0.2.0-fde989a → 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 +262 -0
- package/LICENSE +20 -20
- package/README.md +135 -94
- package/asur/README.md +2 -0
- package/asur/index.js +1262 -0
- package/byg/index.js +216 -0
- package/compiler/2c.js +66 -54
- package/compiler/{sections.js → assemble.js} +109 -21
- package/compiler/builtins/annexb_string.js +72 -0
- package/compiler/builtins/annexb_string.ts +19 -0
- package/compiler/builtins/array.ts +225 -0
- package/compiler/builtins/base64.ts +77 -0
- package/compiler/builtins/boolean.ts +20 -0
- package/compiler/builtins/crypto.ts +121 -0
- package/compiler/builtins/date.ts +2069 -0
- package/compiler/builtins/error.js +22 -0
- package/compiler/builtins/escape.ts +140 -0
- package/compiler/builtins/function.ts +7 -0
- package/compiler/builtins/int.ts +147 -0
- package/compiler/builtins/math.ts +410 -0
- package/compiler/builtins/number.ts +531 -0
- package/compiler/builtins/object.ts +6 -0
- package/compiler/builtins/porffor.d.ts +60 -0
- package/compiler/builtins/set.ts +199 -0
- package/compiler/builtins/string.ts +1081 -0
- package/compiler/builtins/symbol.ts +62 -0
- package/compiler/builtins.js +466 -284
- package/compiler/{codeGen.js → codegen.js} +1573 -656
- package/compiler/decompile.js +3 -4
- package/compiler/embedding.js +22 -22
- package/compiler/encoding.js +94 -10
- package/compiler/expression.js +1 -1
- package/compiler/generated_builtins.js +2110 -0
- package/compiler/index.js +29 -44
- package/compiler/log.js +6 -3
- package/compiler/opt.js +55 -41
- package/compiler/parse.js +38 -30
- package/compiler/precompile.js +121 -0
- package/compiler/prefs.js +31 -0
- package/compiler/prototype.js +209 -201
- package/compiler/types.js +38 -0
- package/compiler/wasmSpec.js +33 -8
- package/compiler/wrap.js +154 -89
- package/package.json +9 -5
- package/porf +2 -0
- package/porffor_tmp.c +202 -0
- package/rhemyn/compile.js +46 -27
- package/rhemyn/parse.js +322 -320
- package/rhemyn/test/parse.js +58 -58
- package/runner/compare.js +33 -34
- package/runner/debug.js +117 -0
- package/runner/index.js +80 -12
- package/runner/profiler.js +75 -0
- package/runner/repl.js +58 -15
- package/runner/sizes.js +37 -37
- package/runner/version.js +10 -8
- package/compiler/builtins/base64.js +0 -92
- package/filesize.cmd +0 -2
- package/runner/info.js +0 -89
- package/runner/profile.js +0 -46
- package/runner/results.json +0 -1
- package/runner/transform.js +0 -15
- package/tmp.c +0 -661
- package/util/enum.js +0 -20
package/byg/index.js
ADDED
@@ -0,0 +1,216 @@
|
|
1
|
+
import fs from 'node:fs';
|
2
|
+
|
3
|
+
const noAnsi = s => s.replace(/\u001b\[[0-9]+m/g, '');
|
4
|
+
const printLine = (line, number, breakpoint = false, current = false, selected = false) => {
|
5
|
+
console.log(`\x1b[${breakpoint ? (selected ? '43' : '103') : (selected ? '47' : '100')}m\x1b[${selected || breakpoint ? '30' : '97'}m${number.toFixed(0).padStart(4, ' ')}\x1b[${breakpoint ? (selected ? '33' : '93') : (selected ? '37' : '90')}m\x1b[${current ? '47' : '40'}m▌ \x1b[${current ? '47' : '40'}m\x1b[${current ? '30' : '37'}m${current ? noAnsi(line) : line}\x1b[0K`);
|
6
|
+
};
|
7
|
+
|
8
|
+
const box = (x, y, width, height, title = '', content = [], color = ['90', '100', '37', '35', '45'], padding = true) => {
|
9
|
+
if (padding) {
|
10
|
+
width += 1;
|
11
|
+
height += 1;
|
12
|
+
|
13
|
+
// top
|
14
|
+
process.stdout.write(`\x1b[48m\x1b[${y + 1};${x + 1}H\x1b[${color[0]}m` + '▄'.repeat(width));
|
15
|
+
// bottom
|
16
|
+
process.stdout.write(`\x1b[${y + height + 1};${x + 1}H▝` + '▀'.repeat(width - 1) + '▘');
|
17
|
+
// left
|
18
|
+
process.stdout.write(`\x1b[${y + 1};${x + 1}H▗` + '\x1b[1B\x1b[1D▐'.repeat(height - 1));
|
19
|
+
// right
|
20
|
+
process.stdout.write(`\x1b[${y + 1};${x + width + 1}H▖` + '\x1b[1B\x1b[1D▌'.repeat(height - 1));
|
21
|
+
|
22
|
+
x += 1;
|
23
|
+
y += 1;
|
24
|
+
width -= 1;
|
25
|
+
height -= 1;
|
26
|
+
}
|
27
|
+
|
28
|
+
// bg
|
29
|
+
process.stdout.write(`\x1b[${y + 1};${x + 1}H\x1b[${color[1]}m` + ' '.repeat(width) + (`\x1b[1B\x1b[${width}D` + ' '.repeat(width)).repeat(Math.max(0, height - 1)));
|
30
|
+
|
31
|
+
// title
|
32
|
+
if (title) process.stdout.write(`\x1b[${y};${x}H\x1b[0m\x1b[${color[3]}m▐\x1b[${color[4]}m\x1b[${color[2]}m\x1b[1m${' '.repeat((width - title.length) / 2 | 0)}${title}${' '.repeat(width - (((width - title.length) / 2 | 0)) - title.length)}\x1b[0m\x1b[${color[3]}m▌`);
|
33
|
+
|
34
|
+
// content
|
35
|
+
process.stdout.write(`\x1b[${y + (title ? 1 : 1)};${x + 1}H\x1b[${color[1]}m\x1b[${color[2]}m${content.join(`\x1b[1B\x1b[${x + 1}G`)}`);
|
36
|
+
};
|
37
|
+
|
38
|
+
const controls = {
|
39
|
+
'ret': 'resume ',
|
40
|
+
'b': 'breakpoint ',
|
41
|
+
's': 'step over',
|
42
|
+
'i': 'step in',
|
43
|
+
'o': 'step out ',
|
44
|
+
};
|
45
|
+
|
46
|
+
const controlInfo = Object.keys(controls).reduce((acc, x, i) => acc + `\x1B[45m\x1B[97m${x}\x1b[105m\x1b[37m ${controls[x]} `, '');
|
47
|
+
const plainControlInfo = noAnsi(controlInfo);
|
48
|
+
|
49
|
+
globalThis.termWidth = process.stdout.columns || 80;
|
50
|
+
globalThis.termHeight = process.stdout.rows || 24;
|
51
|
+
|
52
|
+
export default ({ lines, pause, breakpoint }) => {
|
53
|
+
process.stdin.setRawMode(true);
|
54
|
+
process.stdin.resume();
|
55
|
+
process.stdin.setEncoding('utf8');
|
56
|
+
|
57
|
+
process.stdin.on('data', s => {
|
58
|
+
// ctrl c
|
59
|
+
if (s === '\u0003') {
|
60
|
+
process.exit();
|
61
|
+
}
|
62
|
+
|
63
|
+
if (!paused) pause();
|
64
|
+
});
|
65
|
+
|
66
|
+
const stdin = fs.openSync('/dev/stdin', 'r+');
|
67
|
+
const readCharSync = () => {
|
68
|
+
const buffer = Buffer.alloc(1);
|
69
|
+
fs.readSync(stdin, buffer, 0, 1);
|
70
|
+
return buffer.toString('utf8');
|
71
|
+
};
|
72
|
+
|
73
|
+
const tooManyLines = lines.length > (termHeight - 1);
|
74
|
+
const breakpoints = {};
|
75
|
+
|
76
|
+
process.on('exit', () => {
|
77
|
+
process.stdout.write('\x1b[0m');
|
78
|
+
});
|
79
|
+
|
80
|
+
console.clear();
|
81
|
+
|
82
|
+
let paused = true;
|
83
|
+
return (_paused, currentLine, text, boxes = []) => {
|
84
|
+
paused = _paused;
|
85
|
+
|
86
|
+
let scrollOffset = 0;
|
87
|
+
let currentLinePos = currentLine;
|
88
|
+
|
89
|
+
const draw = () => {
|
90
|
+
console.clear();
|
91
|
+
process.stdout.write(`\x1b[1;1H`);
|
92
|
+
|
93
|
+
if (tooManyLines) {
|
94
|
+
const edgePadding = (termHeight / 2) - 1;
|
95
|
+
let beforePadding = currentLine - edgePadding;
|
96
|
+
let afterPadding = currentLine + edgePadding + 1;
|
97
|
+
|
98
|
+
if (beforePadding < 0) {
|
99
|
+
afterPadding += Math.abs(beforePadding);
|
100
|
+
beforePadding = 0;
|
101
|
+
}
|
102
|
+
|
103
|
+
beforePadding += scrollOffset;
|
104
|
+
afterPadding += scrollOffset;
|
105
|
+
|
106
|
+
if (afterPadding > lines.length) {
|
107
|
+
beforePadding -= afterPadding - lines.length;
|
108
|
+
afterPadding = lines.length;
|
109
|
+
}
|
110
|
+
|
111
|
+
for (let i = Math.max(0, beforePadding); i < Math.max(0, beforePadding) + (termHeight - 1); i++) {
|
112
|
+
printLine(lines[i], i + 1, !!breakpoints[i], currentLine === i, currentLine + scrollOffset === i);
|
113
|
+
}
|
114
|
+
|
115
|
+
currentLinePos = currentLine - beforePadding;
|
116
|
+
} else {
|
117
|
+
for (let i = 0; i < lines.length; i++) {
|
118
|
+
printLine(lines[i], i + 1, !!breakpoints[i], currentLine === i, currentLine + scrollOffset === i);
|
119
|
+
}
|
120
|
+
}
|
121
|
+
|
122
|
+
for (const x of boxes) {
|
123
|
+
const y = x.y({ currentLinePos });
|
124
|
+
if (y < 0 || y >= termHeight) continue;
|
125
|
+
|
126
|
+
box(x.x, y, x.width, x.height, x.title, x.content);
|
127
|
+
}
|
128
|
+
|
129
|
+
// text += ` | rss: ${(process.memoryUsage.rss() / 1024 / 1024).toFixed(2)}mb`;
|
130
|
+
|
131
|
+
process.stdout.write(`\x1b[${termHeight};1H\x1b[105m\x1b[37m${text}${' '.repeat(termWidth - plainControlInfo.length - noAnsi(text).length - 1)}${controlInfo} \x1b[0m`);
|
132
|
+
};
|
133
|
+
|
134
|
+
draw();
|
135
|
+
|
136
|
+
let lastSpecial = false;
|
137
|
+
while (true) {
|
138
|
+
const char = readCharSync();
|
139
|
+
|
140
|
+
if (char === '[') {
|
141
|
+
lastSpecial = true;
|
142
|
+
continue;
|
143
|
+
}
|
144
|
+
|
145
|
+
switch (char.toLowerCase()) {
|
146
|
+
case '\r': {
|
147
|
+
paused = false;
|
148
|
+
return 'resume';
|
149
|
+
}
|
150
|
+
|
151
|
+
case 's': {
|
152
|
+
return 'stepOver';
|
153
|
+
}
|
154
|
+
|
155
|
+
case 'i': {
|
156
|
+
return 'stepIn';
|
157
|
+
}
|
158
|
+
|
159
|
+
case 'o': {
|
160
|
+
return 'stepOut';
|
161
|
+
}
|
162
|
+
|
163
|
+
case 'b': {
|
164
|
+
if (!lastSpecial) {
|
165
|
+
// b pressed normally
|
166
|
+
breakpoints[currentLine + scrollOffset] = !breakpoints[currentLine + scrollOffset];
|
167
|
+
draw();
|
168
|
+
|
169
|
+
breakpoint(currentLine + scrollOffset, breakpoints[currentLine + scrollOffset]);
|
170
|
+
break;
|
171
|
+
}
|
172
|
+
|
173
|
+
// arrow down
|
174
|
+
if (scrollOffset < lines.length - currentLine - 1) scrollOffset++;
|
175
|
+
draw();
|
176
|
+
break;
|
177
|
+
}
|
178
|
+
|
179
|
+
case 'a': {
|
180
|
+
if (!lastSpecial) break;
|
181
|
+
|
182
|
+
// arrow up
|
183
|
+
if (scrollOffset > -currentLine) scrollOffset--;
|
184
|
+
draw();
|
185
|
+
|
186
|
+
break;
|
187
|
+
}
|
188
|
+
|
189
|
+
case '5': {
|
190
|
+
if (!lastSpecial) break;
|
191
|
+
|
192
|
+
// page up
|
193
|
+
scrollOffset -= Math.min(scrollOffset + currentLine, termHeight - 1);
|
194
|
+
draw();
|
195
|
+
break;
|
196
|
+
}
|
197
|
+
|
198
|
+
case '6': {
|
199
|
+
if (!lastSpecial) break;
|
200
|
+
|
201
|
+
// page down
|
202
|
+
scrollOffset += Math.min(lines.length - (scrollOffset + currentLine) - 1, termHeight - 1);
|
203
|
+
draw();
|
204
|
+
break;
|
205
|
+
}
|
206
|
+
|
207
|
+
case 'q':
|
208
|
+
case '\u0003': {
|
209
|
+
process.exit();
|
210
|
+
}
|
211
|
+
}
|
212
|
+
|
213
|
+
lastSpecial = false;
|
214
|
+
}
|
215
|
+
};
|
216
|
+
};
|
package/compiler/2c.js
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
import { read_ieee754_binary64, read_signedLEB128, read_unsignedLEB128 } from './encoding.js';
|
2
2
|
import { Blocktype, Opcodes, Valtype } from './wasmSpec.js';
|
3
3
|
import { operatorOpcode } from './expression.js';
|
4
|
-
import { log } from
|
4
|
+
import { log } from './log.js';
|
5
5
|
|
6
6
|
const CValtype = {
|
7
7
|
i8: 'i8',
|
@@ -106,17 +106,6 @@ for (const x in CValtype) {
|
|
106
106
|
if (Valtype[x]) CValtype[Valtype[x]] = CValtype[x];
|
107
107
|
}
|
108
108
|
|
109
|
-
const todo = msg => {
|
110
|
-
class TodoError extends Error {
|
111
|
-
constructor(message) {
|
112
|
-
super(message);
|
113
|
-
this.name = 'TodoError';
|
114
|
-
}
|
115
|
-
}
|
116
|
-
|
117
|
-
throw new TodoError(`todo: ${msg}`);
|
118
|
-
};
|
119
|
-
|
120
109
|
const removeBrackets = str => {
|
121
110
|
// return str;
|
122
111
|
// if (str.startsWith(`(${CValtype.i32})(${CValtype.u32})`)) return `(${CValtype.i32})(${CValtype.u32})(` + removeBrackets(str.slice(22, -1)) + ')';
|
@@ -130,6 +119,9 @@ const removeBrackets = str => {
|
|
130
119
|
};
|
131
120
|
|
132
121
|
export default ({ funcs, globals, tags, data, exceptions, pages }) => {
|
122
|
+
// fix declaring order for c
|
123
|
+
funcs.reverse();
|
124
|
+
|
133
125
|
const invOperatorOpcode = Object.values(operatorOpcode).reduce((acc, x) => {
|
134
126
|
for (const k in x) {
|
135
127
|
acc[x[k]] = k;
|
@@ -167,10 +159,10 @@ export default ({ funcs, globals, tags, data, exceptions, pages }) => {
|
|
167
159
|
prependMain.set('_data', data.map(x => `memcpy(_memory + ${x.offset}, (unsigned char[]){${x.bytes.join(',')}}, ${x.bytes.length});`).join('\n'));
|
168
160
|
}
|
169
161
|
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
162
|
+
if (importFuncs.find(x => x.name === '__Porffor_readArgv')) {
|
163
|
+
prepend.set('argv', `int _argc; char** _argv;`);
|
164
|
+
prependMain.set('argv', `_argc = argc; _argv = argv;`);
|
165
|
+
}
|
174
166
|
|
175
167
|
if (out) out += '\n';
|
176
168
|
|
@@ -213,9 +205,9 @@ export default ({ funcs, globals, tags, data, exceptions, pages }) => {
|
|
213
205
|
|
214
206
|
for (const f of funcs) {
|
215
207
|
depth = 1;
|
208
|
+
brDepth = 0;
|
216
209
|
|
217
210
|
const invLocals = inv(f.locals, x => x.idx);
|
218
|
-
// if (f.returns.length > 1) todo('funcs returning >1 value unsupported');
|
219
211
|
|
220
212
|
for (const x in invLocals) {
|
221
213
|
invLocals[x] = sanitize(invLocals[x]);
|
@@ -223,8 +215,9 @@ export default ({ funcs, globals, tags, data, exceptions, pages }) => {
|
|
223
215
|
|
224
216
|
const returns = f.returns.length > 0;
|
225
217
|
|
226
|
-
const shouldInline = f.internal;
|
227
|
-
|
218
|
+
const shouldInline = false; // f.internal;
|
219
|
+
if (f.name === 'main') out += `int main(${prependMain.has('argv') ? 'int argc, char* argv[]' : ''}) {\n`;
|
220
|
+
else out += `${f.internal ? (returns ? CValtype.f64 : 'void') : 'struct ReturnValue'} ${shouldInline ? 'inline ' : ''}${sanitize(f.name)}(${f.params.map((x, i) => `${CValtype[x]} ${invLocals[i]}`).join(', ')}) {\n`;
|
228
221
|
|
229
222
|
if (f.name === 'main') {
|
230
223
|
out += [...prependMain.values()].join('\n');
|
@@ -247,12 +240,7 @@ export default ({ funcs, globals, tags, data, exceptions, pages }) => {
|
|
247
240
|
const brs = [];
|
248
241
|
let lastCond = false;
|
249
242
|
|
250
|
-
// let brDepth = 0;
|
251
|
-
|
252
243
|
const blockStart = (i, loop) => {
|
253
|
-
// reset "stack"
|
254
|
-
// vals = [];
|
255
|
-
|
256
244
|
rets.push(i[1]);
|
257
245
|
|
258
246
|
const br = brId++;
|
@@ -269,25 +257,6 @@ export default ({ funcs, globals, tags, data, exceptions, pages }) => {
|
|
269
257
|
brDepth++;
|
270
258
|
};
|
271
259
|
|
272
|
-
const highlight = i => {
|
273
|
-
const surrounding = 6;
|
274
|
-
|
275
|
-
const decomp = decompile(f.wasm.slice(i - surrounding, i + surrounding + 1), '', 0, f.locals, f.params, f.returns, funcs, globals, exceptions).slice(0, -1).split('\n');
|
276
|
-
|
277
|
-
const noAnsi = s => s.replace(/\u001b\[[0-9]+m/g, '');
|
278
|
-
let longest = 0;
|
279
|
-
for (let j = 0; j < decomp.length; j++) {
|
280
|
-
longest = Math.max(longest, noAnsi(decomp[j]).length);
|
281
|
-
}
|
282
|
-
|
283
|
-
const middle = Math.floor(decomp.length / 2);
|
284
|
-
decomp[middle] = `\x1B[47m\x1B[30m${noAnsi(decomp[middle])}${'\u00a0'.repeat(longest - noAnsi(decomp[middle]).length)}\x1B[0m`;
|
285
|
-
|
286
|
-
console.log('\x1B[90m...\x1B[0m');
|
287
|
-
console.log(decomp.join('\n'));
|
288
|
-
console.log('\x1B[90m...\x1B[0m\n');
|
289
|
-
};
|
290
|
-
|
291
260
|
for (let _ = 0; _ < f.wasm.length; _++) {
|
292
261
|
const i = f.wasm[_];
|
293
262
|
if (!i || !i[0]) continue;
|
@@ -415,8 +384,6 @@ export default ({ funcs, globals, tags, data, exceptions, pages }) => {
|
|
415
384
|
const br = brs.at(-1);
|
416
385
|
const ret = rets.at(-1);
|
417
386
|
if (ret && ret !== Blocktype.void) {
|
418
|
-
// console.log(vals, ret);
|
419
|
-
// console.log(decompile(f.wasm.slice(_ - 5, _ + 1)));
|
420
387
|
if (vals.length > 0) line(`_r${br} = ${removeBrackets(vals.pop())}`);
|
421
388
|
// vals.push(`_r${br}`);
|
422
389
|
}
|
@@ -425,8 +392,6 @@ export default ({ funcs, globals, tags, data, exceptions, pages }) => {
|
|
425
392
|
line(`} else {`, false);
|
426
393
|
depth++;
|
427
394
|
|
428
|
-
// reset "stack"
|
429
|
-
// vals = [];
|
430
395
|
break;
|
431
396
|
}
|
432
397
|
|
@@ -441,8 +406,6 @@ export default ({ funcs, globals, tags, data, exceptions, pages }) => {
|
|
441
406
|
const br = brs.pop();
|
442
407
|
const ret = rets.pop();
|
443
408
|
if (ret && ret !== Blocktype.void) {
|
444
|
-
// console.log(vals, ret);
|
445
|
-
// console.log(decompile(f.wasm.slice(_ - 5, _ + 1)));
|
446
409
|
if (vals.length > 0) line(`_r${br} = ${removeBrackets(vals.pop())}`);
|
447
410
|
vals.push(`_r${br}`);
|
448
411
|
}
|
@@ -505,6 +468,60 @@ _time_out = _time.tv_nsec / 1000000. + _time.tv_sec * 1000.;`);
|
|
505
468
|
winIncludes.set('windows.h', true);
|
506
469
|
break;
|
507
470
|
|
471
|
+
case '__Porffor_readArgv':
|
472
|
+
includes.set('stdlib.h', true);
|
473
|
+
|
474
|
+
prepend.set('__Porffor_readArgv',
|
475
|
+
`void __Porffor_readArgv(u32 index, u32 outPtr) {
|
476
|
+
if (index >= _argc) {
|
477
|
+
printf("expected %d arguments\\n", index);
|
478
|
+
exit(1);
|
479
|
+
}
|
480
|
+
|
481
|
+
char* arg = _argv[index];
|
482
|
+
|
483
|
+
u32 read = 0;
|
484
|
+
char* out = _memory + outPtr + 4;
|
485
|
+
char ch;
|
486
|
+
while ((ch = *(arg++)) != 0) {
|
487
|
+
out[read++] = ch;
|
488
|
+
}
|
489
|
+
|
490
|
+
memcpy(_memory + outPtr, &read, sizeof(read));
|
491
|
+
}`);
|
492
|
+
|
493
|
+
line(`__Porffor_readArgv((u32)(${vals.at(-2)}), (u32)(${vals.pop()}))`);
|
494
|
+
vals.pop();
|
495
|
+
break;
|
496
|
+
|
497
|
+
case '__Porffor_readFile':
|
498
|
+
includes.set('stdio.h', true);
|
499
|
+
includes.set('stdlib.h', true);
|
500
|
+
|
501
|
+
prepend.set('__Porffor_readFile',
|
502
|
+
`void __Porffor_readFile(u32 pathPtr, u32 outPtr) {
|
503
|
+
char* path = _memory + pathPtr + 4;
|
504
|
+
FILE* fp = fopen(path, "r");
|
505
|
+
if (fp == NULL) {
|
506
|
+
printf("failed to open file: %s\\n", path);
|
507
|
+
exit(1);
|
508
|
+
}
|
509
|
+
|
510
|
+
u32 read = 0;
|
511
|
+
char* out = _memory + outPtr + 4;
|
512
|
+
char ch;
|
513
|
+
while ((ch = fgetc(fp)) != EOF) {
|
514
|
+
out[read++] = ch;
|
515
|
+
}
|
516
|
+
|
517
|
+
fclose(fp);
|
518
|
+
|
519
|
+
memcpy(_memory + outPtr, &read, sizeof(read));
|
520
|
+
}`);
|
521
|
+
line(`__Porffor_readFile((u32)(${vals.at(-2)}), (u32)(${vals.pop()}))`);
|
522
|
+
vals.pop();
|
523
|
+
break;
|
524
|
+
|
508
525
|
default:
|
509
526
|
log.warning('2c', `unimplemented import: ${importFunc.name}`);
|
510
527
|
break;
|
@@ -541,18 +558,14 @@ _time_out = _time.tv_nsec / 1000000. + _time.tv_sec * 1000.;`);
|
|
541
558
|
|
542
559
|
case Opcodes.br: {
|
543
560
|
const ret = rets[brDepth - i[1] - 1];
|
544
|
-
// console.log(rets, brDepth, i[1], brDepth - i[1] - 1, ret, vals);
|
545
561
|
if (ret !== Blocktype.void) line(`_r${brs[brDepth - i[1] - 1]} = ${removeBrackets(vals.pop())}`);
|
546
562
|
line(`goto j${brs[brDepth - i[1] - 1]}`);
|
547
563
|
|
548
|
-
// // reset "stack"
|
549
|
-
// vals = [];
|
550
564
|
break;
|
551
565
|
}
|
552
566
|
|
553
567
|
case Opcodes.br_if: {
|
554
568
|
const ret = rets[brDepth - i[1] - 1];
|
555
|
-
// console.log(rets, brDepth, i[1], brDepth - i[1] - 1, ret, vals);
|
556
569
|
|
557
570
|
let cond = removeBrackets(vals.pop());
|
558
571
|
if (!lastCond) {
|
@@ -602,7 +615,6 @@ _time_out = _time.tv_nsec / 1000000. + _time.tv_sec * 1000.;`);
|
|
602
615
|
}
|
603
616
|
|
604
617
|
log.warning('2c', `unimplemented op: ${invOpcodes[i[0]]}`);
|
605
|
-
// todo(`unimplemented op: ${invOpcodes[i[0]]}`);
|
606
618
|
}
|
607
619
|
|
608
620
|
lastCond = false;
|
@@ -1,8 +1,8 @@
|
|
1
|
-
import { Valtype, FuncType,
|
2
|
-
import { encodeVector, encodeString, encodeLocal, unsignedLEB128, signedLEB128 } from './encoding.js';
|
3
|
-
import { number } from './embedding.js';
|
1
|
+
import { Valtype, FuncType, ExportDesc, Section, Magic, ModuleVersion, Opcodes, PageSize, Reftype } from './wasmSpec.js';
|
2
|
+
import { encodeVector, encodeString, encodeLocal, unsignedLEB128, signedLEB128, unsignedLEB128_into, signedLEB128_into, ieee754_binary64_into } from './encoding.js';
|
4
3
|
import { importedFuncs } from './builtins.js';
|
5
|
-
import { log } from
|
4
|
+
import { log } from './log.js';
|
5
|
+
import Prefs from './prefs.js';
|
6
6
|
|
7
7
|
const createSection = (type, data) => [
|
8
8
|
type,
|
@@ -26,12 +26,12 @@ export default (funcs, globals, tags, pages, data, flags) => {
|
|
26
26
|
|
27
27
|
const optLevel = parseInt(process.argv.find(x => x.startsWith('-O'))?.[2] ?? 1);
|
28
28
|
|
29
|
-
const compileHints =
|
30
|
-
if (compileHints) log.warning('
|
29
|
+
const compileHints = Prefs.compileHints;
|
30
|
+
if (compileHints) log.warning('assemble', 'compile hints is V8 only w/ experimental arg! (you used -compile-hints)');
|
31
31
|
|
32
32
|
const getType = (params, returns) => {
|
33
33
|
const hash = `${params.join(',')}_${returns.join(',')}`;
|
34
|
-
if (optLog) log('
|
34
|
+
if (Prefs.optLog) log('assemble', `getType(${JSON.stringify(params)}, ${JSON.stringify(returns)}) -> ${hash} | cache: ${typeCache[hash]}`);
|
35
35
|
if (optLevel >= 1 && typeCache[hash] !== undefined) return typeCache[hash];
|
36
36
|
|
37
37
|
const type = [ FuncType, ...encodeVector(params), ...encodeVector(returns) ];
|
@@ -44,7 +44,7 @@ export default (funcs, globals, tags, pages, data, flags) => {
|
|
44
44
|
|
45
45
|
let importFuncs = [];
|
46
46
|
|
47
|
-
if (optLevel < 1) {
|
47
|
+
if (optLevel < 1 || !Prefs.treeshakeWasmImports) {
|
48
48
|
importFuncs = importedFuncs;
|
49
49
|
} else {
|
50
50
|
let imports = new Map();
|
@@ -65,6 +65,7 @@ export default (funcs, globals, tags, pages, data, flags) => {
|
|
65
65
|
importFuncs = [...imports.values()];
|
66
66
|
|
67
67
|
// fix call indexes for non-imports
|
68
|
+
// also fix call_indirect types
|
68
69
|
const delta = importedFuncs.length - importFuncs.length;
|
69
70
|
for (const f of funcs) {
|
70
71
|
f.originalIndex = f.index;
|
@@ -74,16 +75,26 @@ export default (funcs, globals, tags, pages, data, flags) => {
|
|
74
75
|
if ((inst[0] === Opcodes.call || inst[0] === Opcodes.return_call) && inst[1] >= importedFuncs.length) {
|
75
76
|
inst[1] -= delta;
|
76
77
|
}
|
78
|
+
|
79
|
+
if (inst[0] === Opcodes.call_indirect) {
|
80
|
+
const params = [];
|
81
|
+
for (let i = 0; i < inst[1]; i++) {
|
82
|
+
params.push(valtypeBinary, Valtype.i32);
|
83
|
+
}
|
84
|
+
|
85
|
+
const returns = [ valtypeBinary, Valtype.i32 ];
|
86
|
+
inst[1] = getType(params, returns);
|
87
|
+
}
|
77
88
|
}
|
78
89
|
}
|
79
90
|
}
|
80
91
|
globalThis.importFuncs = importFuncs;
|
81
92
|
|
82
|
-
if (optLog) log('
|
93
|
+
if (Prefs.optLog) log('assemble', `treeshake: using ${importFuncs.length}/${importedFuncs.length} imports`);
|
83
94
|
|
84
95
|
const importSection = importFuncs.length === 0 ? [] : createSection(
|
85
96
|
Section.import,
|
86
|
-
encodeVector(importFuncs.map(x => [ 0, ...encodeString(x.import), ExportDesc.func, getType(new Array(x.params).fill(valtypeBinary), new Array(x.returns).fill(valtypeBinary)) ]))
|
97
|
+
encodeVector(importFuncs.map(x => [ 0, ...encodeString(x.import), ExportDesc.func, getType(new Array(x.params).fill(x.name.startsWith('profile') ? Valtype.i32 : valtypeBinary), new Array(x.returns).fill(valtypeBinary)) ]))
|
87
98
|
);
|
88
99
|
|
89
100
|
const funcSection = createSection(
|
@@ -91,22 +102,89 @@ export default (funcs, globals, tags, pages, data, flags) => {
|
|
91
102
|
encodeVector(funcs.map(x => getType(x.params, x.returns))) // type indexes
|
92
103
|
);
|
93
104
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
'compilationHints',
|
98
|
-
// for now just do everything as optimise eager
|
99
|
-
encodeVector(funcs.map(_ => chHint(0x02, 0x02, 0x02)))
|
105
|
+
const tableSection = !funcs.table ? [] : createSection(
|
106
|
+
Section.table,
|
107
|
+
encodeVector([ [ Reftype.funcref, 0x00, funcs.length ] ])
|
100
108
|
);
|
101
109
|
|
102
|
-
const
|
103
|
-
Section.
|
104
|
-
encodeVector(
|
110
|
+
const elementSection = !funcs.table ? [] : createSection(
|
111
|
+
Section.element,
|
112
|
+
encodeVector([ [
|
113
|
+
0x00,
|
114
|
+
Opcodes.i32_const, 0, Opcodes.end,
|
115
|
+
...encodeVector(funcs.map(x => x.index))
|
116
|
+
] ])
|
105
117
|
);
|
106
118
|
|
119
|
+
if (pages.has('func argc lut')) {
|
120
|
+
// generate func argc lut data
|
121
|
+
const bytes = [];
|
122
|
+
for (let i = 0; i < funcs.length; i++) {
|
123
|
+
const argc = Math.floor(funcs[i].params.length / 2);
|
124
|
+
bytes.push(argc % 256, (argc / 256 | 0) % 256);
|
125
|
+
}
|
126
|
+
|
127
|
+
data.push({
|
128
|
+
offset: pages.get('func argc lut').ind * pageSize,
|
129
|
+
bytes
|
130
|
+
});
|
131
|
+
}
|
132
|
+
|
133
|
+
// const t0 = performance.now();
|
134
|
+
|
135
|
+
// specially optimized assembly for globals as this version is much (>5x) faster than traditional createSection()
|
136
|
+
const globalsValues = Object.values(globals);
|
137
|
+
|
138
|
+
let globalSection = [];
|
139
|
+
if (globalsValues.length > 0) {
|
140
|
+
let data = unsignedLEB128(globalsValues.length);
|
141
|
+
for (let i = 0; i < globalsValues.length; i++) {
|
142
|
+
const global = globalsValues[i];
|
143
|
+
|
144
|
+
switch (global.type) {
|
145
|
+
case Valtype.i32:
|
146
|
+
if (i > 0) data.push(Opcodes.end, Valtype.i32, 0x01, Opcodes.i32_const);
|
147
|
+
else data.push(Valtype.i32, 0x01, Opcodes.i32_const);
|
148
|
+
|
149
|
+
signedLEB128_into(global.init ?? 0, data);
|
150
|
+
break;
|
151
|
+
|
152
|
+
case Valtype.i64:
|
153
|
+
if (i > 0) data.push(Opcodes.end, Valtype.i64, 0x01, Opcodes.i64_const);
|
154
|
+
else data.push(Valtype.i64, 0x01, Opcodes.i64_const);
|
155
|
+
|
156
|
+
signedLEB128_into(global.init ?? 0, data);
|
157
|
+
break;
|
158
|
+
|
159
|
+
case Valtype.f64:
|
160
|
+
if (i > 0) data.push(Opcodes.end, Valtype.f64, 0x01, Opcodes.f64_const);
|
161
|
+
else data.push(Valtype.f64, 0x01, Opcodes.f64_const);
|
162
|
+
|
163
|
+
ieee754_binary64_into(global.init ?? 0, data);
|
164
|
+
break;
|
165
|
+
}
|
166
|
+
}
|
167
|
+
|
168
|
+
data.push(Opcodes.end);
|
169
|
+
|
170
|
+
globalSection.push(Section.global);
|
171
|
+
|
172
|
+
unsignedLEB128_into(data.length, globalSection);
|
173
|
+
globalSection = globalSection.concat(data);
|
174
|
+
}
|
175
|
+
|
176
|
+
// if (Prefs.profileCompiler) {
|
177
|
+
// const log = console.log;
|
178
|
+
// console.log = function () {
|
179
|
+
// log.apply(this, arguments);
|
180
|
+
// console.log = log;
|
181
|
+
// console.log(` a. assembled global section in ${(performance.now() - t0).toFixed(2)}ms\n`);
|
182
|
+
// };
|
183
|
+
// }
|
184
|
+
|
107
185
|
const exports = funcs.filter(x => x.export).map((x, i) => [ ...encodeString(x.name === 'main' ? 'm' : x.name), ExportDesc.func, x.index ]);
|
108
186
|
|
109
|
-
if (
|
187
|
+
if (Prefs.alwaysMemory && pages.size === 0) pages.set('--always-memory', 0);
|
110
188
|
if (optLevel === 0) pages.set('O0 precaution', 0);
|
111
189
|
|
112
190
|
const usesMemory = pages.size > 0;
|
@@ -169,7 +247,7 @@ export default (funcs, globals, tags, pages, data, flags) => {
|
|
169
247
|
unsignedLEB128(data.length)
|
170
248
|
);
|
171
249
|
|
172
|
-
if (
|
250
|
+
if (Prefs.sections) console.log({
|
173
251
|
typeSection: typeSection.map(x => x.toString(16)),
|
174
252
|
importSection: importSection.map(x => x.toString(16)),
|
175
253
|
funcSection: funcSection.map(x => x.toString(16)),
|
@@ -179,6 +257,14 @@ export default (funcs, globals, tags, pages, data, flags) => {
|
|
179
257
|
dataSection: dataSection.map(x => x.toString(16)),
|
180
258
|
});
|
181
259
|
|
260
|
+
// compilation hints section - unspecd, v8 only
|
261
|
+
// https://github.com/WebAssembly/design/issues/1473#issuecomment-1431274746
|
262
|
+
const chSection = !compileHints ? [] : customSection(
|
263
|
+
'compilationHints',
|
264
|
+
// for now just do everything as optimize eager
|
265
|
+
encodeVector(funcs.map(_ => chHint(0x02, 0x02, 0x02)))
|
266
|
+
);
|
267
|
+
|
182
268
|
return Uint8Array.from([
|
183
269
|
...Magic,
|
184
270
|
...ModuleVersion,
|
@@ -186,10 +272,12 @@ export default (funcs, globals, tags, pages, data, flags) => {
|
|
186
272
|
...importSection,
|
187
273
|
...funcSection,
|
188
274
|
...chSection,
|
275
|
+
...tableSection,
|
189
276
|
...memorySection,
|
190
277
|
...tagSection,
|
191
278
|
...globalSection,
|
192
279
|
...exportSection,
|
280
|
+
...elementSection,
|
193
281
|
...dataCountSection,
|
194
282
|
...codeSection,
|
195
283
|
...dataSection
|