porffor 0.2.0-6aff0fa → 0.2.0-75bc012
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 +256 -0
- package/LICENSE +20 -20
- package/README.md +115 -82
- package/asur/index.js +624 -340
- package/byg/index.js +237 -0
- package/compiler/2c.js +1 -1
- package/compiler/{sections.js → assemble.js} +59 -12
- package/compiler/builtins/annexb_string.js +72 -0
- package/compiler/builtins/annexb_string.ts +18 -0
- package/compiler/builtins/array.ts +145 -0
- package/compiler/builtins/base64.ts +7 -84
- package/compiler/builtins/boolean.ts +20 -0
- package/compiler/builtins/crypto.ts +120 -0
- package/compiler/builtins/date.ts +2070 -0
- package/compiler/builtins/escape.ts +141 -0
- package/compiler/builtins/int.ts +147 -0
- package/compiler/builtins/number.ts +534 -0
- package/compiler/builtins/porffor.d.ts +43 -7
- package/compiler/builtins/string.ts +1080 -0
- package/compiler/builtins/tostring.ts +25 -0
- package/compiler/builtins.js +398 -115
- package/compiler/{codeGen.js → codegen.js} +856 -323
- package/compiler/decompile.js +0 -1
- package/compiler/embedding.js +22 -22
- package/compiler/encoding.js +108 -10
- package/compiler/generated_builtins.js +1504 -2
- package/compiler/index.js +16 -14
- package/compiler/log.js +2 -2
- package/compiler/opt.js +23 -22
- package/compiler/parse.js +30 -22
- package/compiler/precompile.js +26 -27
- package/compiler/prefs.js +7 -6
- package/compiler/prototype.js +16 -32
- package/compiler/types.js +37 -0
- package/compiler/wasmSpec.js +14 -1
- package/compiler/wrap.js +41 -44
- package/package.json +9 -5
- package/porf +2 -0
- package/rhemyn/compile.js +44 -26
- package/rhemyn/parse.js +322 -320
- package/rhemyn/test/parse.js +58 -58
- package/runner/compare.js +34 -34
- package/runner/debug.js +122 -0
- package/runner/index.js +69 -12
- package/runner/profiler.js +45 -26
- package/runner/repl.js +42 -9
- package/runner/sizes.js +37 -37
- package/runner/info.js +0 -89
- package/runner/transform.js +0 -15
- package/util/enum.js +0 -20
package/asur/index.js
CHANGED
@@ -49,6 +49,144 @@ const string = () => {
|
|
49
49
|
return out;
|
50
50
|
};
|
51
51
|
|
52
|
+
const wasmToBC = (code, { types, funcs, imports }) => {
|
53
|
+
const _input = input;
|
54
|
+
const _offset = offset;
|
55
|
+
|
56
|
+
input = code;
|
57
|
+
offset = 0;
|
58
|
+
|
59
|
+
const top = { body: [] };
|
60
|
+
|
61
|
+
let parents = [ top ];
|
62
|
+
let parent = top;
|
63
|
+
|
64
|
+
let depth = 0;
|
65
|
+
|
66
|
+
read: while (offset < input.length) {
|
67
|
+
let opcode = read();
|
68
|
+
// console.log(invOpcodes[opcode], depth, invOpcodes[parent.opcode]);
|
69
|
+
|
70
|
+
if (opcode === 0xfc) { // multibyte op
|
71
|
+
opcode = (opcode << 8) + read();
|
72
|
+
}
|
73
|
+
|
74
|
+
switch (opcode) {
|
75
|
+
case 0x01: { // nop
|
76
|
+
break;
|
77
|
+
}
|
78
|
+
|
79
|
+
case 0x02: // block
|
80
|
+
case 0x03: // loop
|
81
|
+
case 0x04: { // if
|
82
|
+
const ret = read();
|
83
|
+
const obj = { opcode, returns: ret, doesReturn: ret !== 0x40, body: [] };
|
84
|
+
parent.body.push(obj);
|
85
|
+
|
86
|
+
parent = obj;
|
87
|
+
parents.push(obj);
|
88
|
+
|
89
|
+
depth++;
|
90
|
+
|
91
|
+
break;
|
92
|
+
}
|
93
|
+
|
94
|
+
case 0x05: { // else
|
95
|
+
const obj = [];
|
96
|
+
parent.else = obj;
|
97
|
+
parent = { body: obj }; // mock parent obj for else branch
|
98
|
+
|
99
|
+
break;
|
100
|
+
}
|
101
|
+
|
102
|
+
case 0x0b: { // end
|
103
|
+
parents.pop();
|
104
|
+
parent = parents[parents.length - 1];
|
105
|
+
|
106
|
+
depth--;
|
107
|
+
|
108
|
+
// if (depth === -1) break read;
|
109
|
+
|
110
|
+
break;
|
111
|
+
}
|
112
|
+
|
113
|
+
case 0x0c: // br
|
114
|
+
case 0x0d: { // br_if
|
115
|
+
parent.body.push({ opcode, goto: read() });
|
116
|
+
break;
|
117
|
+
}
|
118
|
+
|
119
|
+
case 0x10: { // call
|
120
|
+
const func = read(); // unsignedLEB128();
|
121
|
+
const obj = { opcode, func };
|
122
|
+
|
123
|
+
if (func < imports.length) {
|
124
|
+
const mod = imports[func].module;
|
125
|
+
const name = imports[func].name;
|
126
|
+
|
127
|
+
obj.import = { mod, name };
|
128
|
+
|
129
|
+
const type = types[imports[func].typeIdx];
|
130
|
+
obj.type = type;
|
131
|
+
|
132
|
+
obj.paramCount = type.params.length;
|
133
|
+
obj.returnCount = type.returns.length;
|
134
|
+
|
135
|
+
parent.body.push(obj);
|
136
|
+
break;
|
137
|
+
}
|
138
|
+
|
139
|
+
const type = types[funcs[func - imports.length]];
|
140
|
+
obj.type = type;
|
141
|
+
|
142
|
+
obj.paramCount = type.params.length;
|
143
|
+
obj.returnCount = type.returns.length;
|
144
|
+
|
145
|
+
parent.body.push(obj);
|
146
|
+
break;
|
147
|
+
}
|
148
|
+
|
149
|
+
case 0x20: // local.get
|
150
|
+
case 0x21: // local.set
|
151
|
+
case 0x22: // local.tee
|
152
|
+
case 0x23: // global.get
|
153
|
+
case 0x24: { // global.set
|
154
|
+
parent.body.push({ opcode, idx: read() });
|
155
|
+
break;
|
156
|
+
}
|
157
|
+
|
158
|
+
case 0x41: { // i32.const
|
159
|
+
parent.body.push({ opcode, val: signedLEB128() });
|
160
|
+
break;
|
161
|
+
}
|
162
|
+
case 0x42: { // i64.const
|
163
|
+
parent.body.push({ opcode, val: signedLEB128() });
|
164
|
+
break;
|
165
|
+
}
|
166
|
+
case 0x44: { // f64.const
|
167
|
+
parent.body.push({ opcode, val: ieee754() });
|
168
|
+
break;
|
169
|
+
}
|
170
|
+
|
171
|
+
default: {
|
172
|
+
parent.body.push({ opcode });
|
173
|
+
break;
|
174
|
+
}
|
175
|
+
}
|
176
|
+
}
|
177
|
+
|
178
|
+
input = _input;
|
179
|
+
offset = _offset;
|
180
|
+
|
181
|
+
if (parents.length > 1) {
|
182
|
+
// console.log(parents);
|
183
|
+
// console.log(stringifyOp({ types, funcs, imports }, top));
|
184
|
+
throw new Error('wasmToBC failed');
|
185
|
+
}
|
186
|
+
|
187
|
+
return top;
|
188
|
+
};
|
189
|
+
|
52
190
|
const parse = (binary) => {
|
53
191
|
offset = 0;
|
54
192
|
input = binary;
|
@@ -70,9 +208,12 @@ const parse = (binary) => {
|
|
70
208
|
let types = [],
|
71
209
|
imports = [],
|
72
210
|
funcs = [],
|
211
|
+
memories = [],
|
212
|
+
tags = [],
|
73
213
|
exports = [],
|
74
214
|
globals = [],
|
75
|
-
codes = []
|
215
|
+
codes = [],
|
216
|
+
datas = [];
|
76
217
|
|
77
218
|
const len = input.length;
|
78
219
|
while (offset < len) {
|
@@ -130,7 +271,38 @@ const parse = (binary) => {
|
|
130
271
|
}
|
131
272
|
|
132
273
|
if (section === 5) { // memory
|
274
|
+
const memoriesLength = unsignedLEB128();
|
275
|
+
memories = new Array(memoriesLength);
|
276
|
+
|
277
|
+
for (let i = 0; i < memoriesLength; i++) {
|
278
|
+
const flag = read();
|
279
|
+
|
280
|
+
let min = null, max = null;
|
281
|
+
switch (flag) {
|
282
|
+
case 0x00:
|
283
|
+
min = unsignedLEB128();
|
284
|
+
break;
|
285
|
+
|
286
|
+
case 0x01:
|
287
|
+
min = unsignedLEB128();
|
288
|
+
max = unsignedLEB128();
|
289
|
+
break;
|
290
|
+
}
|
291
|
+
|
292
|
+
memories[i] = { min, max };
|
293
|
+
}
|
294
|
+
}
|
133
295
|
|
296
|
+
if (section === 13) { // tag
|
297
|
+
const tagsLength = unsignedLEB128();
|
298
|
+
tags = new Array(tagsLength);
|
299
|
+
|
300
|
+
for (let i = 0; i < tagsLength; i++) {
|
301
|
+
const attr = read();
|
302
|
+
const type = unsignedLEB128();
|
303
|
+
|
304
|
+
tags[i] = { attr, type };
|
305
|
+
}
|
134
306
|
}
|
135
307
|
|
136
308
|
if (section === 6) { // global
|
@@ -149,7 +321,14 @@ const parse = (binary) => {
|
|
149
321
|
if (byte === 0x0b) break; // end
|
150
322
|
}
|
151
323
|
|
152
|
-
|
324
|
+
const bc = wasmToBC(init, { types, funcs, imports });
|
325
|
+
|
326
|
+
globals[i] = { valtype, mutable, init, bc };
|
327
|
+
if (globalThis.porfDebugInfo) {
|
328
|
+
for (const x in globalThis.porfDebugInfo.globals) {
|
329
|
+
if (globalThis.porfDebugInfo.globals[x].idx === i) globals[i].porfGlobalName = x;
|
330
|
+
}
|
331
|
+
}
|
153
332
|
}
|
154
333
|
|
155
334
|
continue;
|
@@ -180,7 +359,7 @@ const parse = (binary) => {
|
|
180
359
|
const size = unsignedLEB128();
|
181
360
|
const end = offset + size;
|
182
361
|
|
183
|
-
const locals = [];
|
362
|
+
const locals = types[funcs[i]].params.slice();
|
184
363
|
|
185
364
|
const localsLength = unsignedLEB128();
|
186
365
|
for (let j = 0; j < localsLength; j++) {
|
@@ -194,129 +373,119 @@ const parse = (binary) => {
|
|
194
373
|
const wasm = new Array(bytesLeft);
|
195
374
|
for (let j = 0; j < bytesLeft; j++) wasm[j] = read();
|
196
375
|
|
197
|
-
|
376
|
+
const bc = wasmToBC(wasm, { types, funcs, imports });
|
377
|
+
bc.codeIdx = i;
|
378
|
+
bc.wasmType = types[funcs[i]];
|
379
|
+
if (globalThis.porfDebugInfo) bc.porfFunc = globalThis.porfDebugInfo.funcs[i];
|
380
|
+
|
381
|
+
codes[i] = { locals, wasm, bc };
|
198
382
|
}
|
199
383
|
|
200
384
|
continue;
|
201
385
|
}
|
202
386
|
|
203
387
|
if (section === 11) { // data
|
388
|
+
const datasLength = unsignedLEB128();
|
389
|
+
datas = new Array(datasLength);
|
204
390
|
|
205
|
-
|
206
|
-
|
391
|
+
for (let i = 0; i < datasLength; i++) {
|
392
|
+
const mode = read();
|
207
393
|
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
const
|
214
|
-
|
215
|
-
return (x[0] << 8) + x[1];
|
216
|
-
});
|
394
|
+
let offset = 0;
|
395
|
+
switch (mode) {
|
396
|
+
case 0:
|
397
|
+
let init = [];
|
398
|
+
while (true) {
|
399
|
+
const byte = read();
|
400
|
+
init.push(byte);
|
217
401
|
|
218
|
-
|
219
|
-
|
220
|
-
const skipCache = {};
|
221
|
-
|
222
|
-
const run = (activeFunc, params = [], setup = true) => {
|
223
|
-
let locals = [];
|
224
|
-
if (setup) {
|
225
|
-
const activeCode = codes[activeFunc - imports.length];
|
402
|
+
if (byte === 0x0b) break; // end
|
403
|
+
}
|
226
404
|
|
227
|
-
|
228
|
-
offset = 0; // PC
|
405
|
+
offset = runExpr(init);
|
229
406
|
|
230
|
-
|
407
|
+
break;
|
231
408
|
|
232
|
-
|
233
|
-
|
409
|
+
default:
|
410
|
+
throw new Error('todo');
|
411
|
+
}
|
234
412
|
|
235
|
-
|
236
|
-
|
413
|
+
const bytesLength = unsignedLEB128();
|
414
|
+
const bytes = new Array(bytesLength);
|
237
415
|
|
238
|
-
|
416
|
+
for (let j = 0; j < bytesLength; j++) bytes[j] = read();
|
239
417
|
|
240
|
-
|
418
|
+
datas[i] = { offset, bytes };
|
419
|
+
}
|
420
|
+
}
|
241
421
|
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
let rets = [];
|
422
|
+
if (section === 12) { // data count
|
423
|
+
datas.dataCount = unsignedLEB128();
|
424
|
+
}
|
425
|
+
}
|
247
426
|
|
248
|
-
|
249
|
-
|
427
|
+
return { types, imports, funcs, memories, tags, globals, exports, codes, datas };
|
428
|
+
};
|
250
429
|
|
251
|
-
|
430
|
+
const inv = (obj, keyMap = x => x) => Object.keys(obj).reduce((acc, x) => {
|
431
|
+
const k = keyMap(obj[x]);
|
432
|
+
if (acc[k] == null) acc[k] = x;
|
433
|
+
return acc;
|
434
|
+
}, {});
|
252
435
|
|
253
|
-
|
254
|
-
|
255
|
-
|
436
|
+
// const { Opcodes, Valtype } = (await import('../compiler/wasmSpec.js'));
|
437
|
+
// const invOpcodes = inv(Opcodes, x => {
|
438
|
+
// if (typeof x === 'number') return x;
|
439
|
+
// return (x[0] << 8) + x[1];
|
440
|
+
// });
|
441
|
+
// const invValtype = inv(Valtype);
|
256
442
|
|
257
|
-
|
443
|
+
let times = {};
|
444
|
+
let amounts = {};
|
258
445
|
|
259
|
-
|
260
|
-
|
261
|
-
|
446
|
+
const vm = ({ types, imports, funcs, globals, exports, codes }, importImpls, startFunc) => {
|
447
|
+
const run = (bc, locals = []) => {
|
448
|
+
let stack = [];
|
262
449
|
|
263
|
-
|
450
|
+
let parents = [ bc ];
|
451
|
+
let parent = bc;
|
264
452
|
|
265
|
-
|
266
|
-
};
|
453
|
+
parent.pc = 0;
|
267
454
|
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
455
|
+
while (true) {
|
456
|
+
// const start = performance.now();
|
457
|
+
const op = parent.body[parent.pc++];
|
458
|
+
// if (bc.name === '__console_log') console.log(invOpcodes[op?.opcode], invOpcodes[parent?.opcode], parent.pc - 1, parent.body.length - 1, parents.length - 1);
|
459
|
+
if (!op) {
|
460
|
+
// presume end of op body
|
461
|
+
parents.pop();
|
462
|
+
parent = parents[parents.length - 1];
|
463
|
+
|
464
|
+
if (!parent) {
|
465
|
+
// presume end of func
|
466
|
+
return stack;
|
274
467
|
}
|
275
|
-
};
|
276
468
|
|
277
|
-
|
278
|
-
|
469
|
+
continue;
|
470
|
+
}
|
279
471
|
|
280
|
-
|
281
|
-
|
472
|
+
const br = n => {
|
473
|
+
const ind = parents.length - n - 1;
|
474
|
+
const target = parents[ind];
|
475
|
+
|
476
|
+
// console.log(n, parents.map(x => invOpcodes[x.opcode]), target);
|
477
|
+
if (target.opcode === 0x03) { // loop
|
478
|
+
parents = parents.slice(0, ind + 1);
|
479
|
+
parent = parents[parents.length - 1];
|
480
|
+
parent.pc = 0;
|
282
481
|
} else {
|
283
|
-
|
482
|
+
parents = parents.slice(0, ind);
|
483
|
+
parent = parents[parents.length - 1];
|
284
484
|
}
|
285
485
|
};
|
286
486
|
|
287
|
-
|
288
|
-
const ind = depth - n - 1;
|
289
|
-
|
290
|
-
// depth -= n;
|
291
|
-
if (loopStarts[ind]) {
|
292
|
-
depth -= n;
|
293
|
-
|
294
|
-
if (n === 0) {
|
295
|
-
|
296
|
-
} else if (n === 1) {
|
297
|
-
loopStarts.pop();
|
298
|
-
rets.pop();
|
299
|
-
} else {
|
300
|
-
// loopStarts.splice(loopStarts.length - n - 1, n);
|
301
|
-
// rets.splice(rets.length - n - 1, n);
|
302
|
-
loopStarts = loopStarts.slice(0, depth);
|
303
|
-
rets = rets.slice(0, depth);
|
304
|
-
}
|
305
|
-
|
306
|
-
// // loopStarts.splice(loopStarts.length - n - 1, n);
|
307
|
-
// // rets.splice(rets.length - n - 1, n);
|
308
|
-
// loopStarts = loopStarts.slice(0, depth);
|
309
|
-
// rets = rets.slice(0, depth);
|
310
|
-
|
311
|
-
offset = loopStarts[ind];
|
312
|
-
} else skipEnd(depth);
|
313
|
-
|
314
|
-
// if (rets[ind]) stack
|
315
|
-
};
|
316
|
-
|
317
|
-
switch (opcode) {
|
487
|
+
switch (op.opcode) {
|
318
488
|
case 0x00: { // unreachable
|
319
|
-
if (skip) break;
|
320
489
|
throw new Error('unreachable');
|
321
490
|
}
|
322
491
|
|
@@ -325,302 +494,170 @@ const vm = ({ types, imports, funcs, globals, exports, codes }, importImpls, sta
|
|
325
494
|
}
|
326
495
|
|
327
496
|
case 0x02: { // block
|
328
|
-
|
497
|
+
parents.push(op);
|
498
|
+
parent = op;
|
499
|
+
parent.pc = 0;
|
500
|
+
|
329
501
|
break;
|
330
502
|
}
|
331
503
|
|
332
504
|
case 0x03: { // loop
|
333
|
-
|
505
|
+
parents.push(op);
|
506
|
+
parent = op;
|
507
|
+
parent.pc = 0;
|
508
|
+
|
334
509
|
break;
|
335
510
|
}
|
336
511
|
|
337
512
|
case 0x04: { // if
|
338
|
-
blockStart(false);
|
339
|
-
if (skip) break;
|
340
|
-
|
341
513
|
const cond = stack.pop();
|
342
|
-
if (cond) {
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
if (!skipCache[activeFunc][skipStart]) {
|
354
|
-
// skipCache[activeFunc][skipStart] = offset - 1;
|
355
|
-
}
|
356
|
-
} else { // were running consequent, skip else
|
357
|
-
if (!skip) skipEnd(depth);
|
514
|
+
if (cond) { // true cond
|
515
|
+
parent = op;
|
516
|
+
parents.push(op);
|
517
|
+
parent.pc = 0;
|
518
|
+
} else if (op.else) { // false cond, else branch exists
|
519
|
+
parent = { body: op.else }; // mock parent for else branch
|
520
|
+
parents.push(op);
|
521
|
+
parent.pc = 0;
|
522
|
+
} else { // false cond, no else branch
|
523
|
+
// do nothing to just skip this op
|
358
524
|
}
|
359
525
|
|
360
526
|
break;
|
361
527
|
}
|
362
528
|
|
363
|
-
case 0x0b: { // end
|
364
|
-
if (depth === 0) return stack;
|
365
|
-
|
366
|
-
// were skipping to here, stop skip
|
367
|
-
if (skipUntilElse === depth || skipUntilEnd === depth) {
|
368
|
-
skipUntilElse = 0;
|
369
|
-
skipUntilEnd = 0;
|
370
|
-
|
371
|
-
if (!skipCache[activeFunc][skipStart]) {
|
372
|
-
// skipCache[activeFunc][skipStart] = offset - 1;
|
373
|
-
}
|
374
|
-
}
|
375
|
-
|
376
|
-
depth--;
|
377
|
-
|
378
|
-
rets.pop();
|
379
|
-
loopStarts.pop();
|
380
|
-
|
381
|
-
break;
|
382
|
-
}
|
383
|
-
|
384
529
|
case 0x0c: { // br
|
385
|
-
|
386
|
-
read();
|
387
|
-
break;
|
388
|
-
}
|
389
|
-
|
390
|
-
br(read());
|
530
|
+
br(op.goto);
|
391
531
|
break;
|
392
532
|
}
|
393
533
|
|
394
534
|
case 0x0d: { // br_if
|
395
|
-
if (
|
396
|
-
read();
|
397
|
-
break;
|
398
|
-
}
|
399
|
-
|
400
|
-
const n = read();
|
401
|
-
|
402
|
-
if (stack.pop()) br(n);
|
403
|
-
|
535
|
+
if (stack.pop()) br(op.goto);
|
404
536
|
break;
|
405
537
|
}
|
406
538
|
|
407
539
|
case 0x0f: { // return
|
408
|
-
if (skip) break;
|
409
|
-
|
410
540
|
return stack;
|
411
541
|
}
|
412
542
|
|
413
543
|
case 0x10: { // call
|
414
|
-
|
415
|
-
read();
|
416
|
-
break;
|
417
|
-
}
|
418
|
-
|
419
|
-
// const func = unsignedLEB128();
|
420
|
-
const func = read();
|
421
|
-
|
422
|
-
if (func < imports.length) {
|
423
|
-
const mod = imports[func].module;
|
424
|
-
const name = imports[func].name;
|
425
|
-
|
426
|
-
const type = types[imports[func].typeIdx];
|
427
|
-
|
428
|
-
const paramCount = type.params.length;
|
544
|
+
const paramCount = op.paramCount;
|
429
545
|
|
546
|
+
if (op.import) {
|
430
547
|
const params = new Array(paramCount);
|
431
|
-
for (let i = 0; i < paramCount; i++) params[i] = stack.pop();
|
432
548
|
|
433
|
-
|
549
|
+
if (paramCount === 0) {}
|
550
|
+
else if (paramCount === 1) params[0] = stack.pop();
|
551
|
+
else if (paramCount === 2) { params[1] = stack.pop(); params[0] = stack.pop(); }
|
552
|
+
else for (let i = paramCount - 1; i >= 0; i--) params[i] = stack.pop();
|
553
|
+
|
554
|
+
const ret = importImpls[op.import.mod][op.import.name](...params);
|
434
555
|
|
435
556
|
if (type.returns.length > 0) stack.push(ret);
|
436
557
|
|
437
558
|
break;
|
438
559
|
}
|
439
560
|
|
440
|
-
const
|
441
|
-
const paramCount = type.params.length;
|
561
|
+
const code = codes[op.func - imports.length];
|
442
562
|
|
443
|
-
|
563
|
+
// console.log(bc.name, '->', code.bc.name);
|
444
564
|
|
445
|
-
|
446
|
-
|
447
|
-
else if (paramCount === 2) { params[1] = stack.pop(); params[0] = stack.pop(); }
|
448
|
-
else for (let i = paramCount - 1; i >= 0; i--) params[i] = stack.pop();
|
565
|
+
const callBC = code.bc;
|
566
|
+
const locals = new Array(code.locals.length).fill(0);
|
449
567
|
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
568
|
+
if (paramCount === 0) {}
|
569
|
+
else if (paramCount === 1) locals[0] = stack.pop();
|
570
|
+
else if (paramCount === 2) { locals[1] = stack.pop(); locals[0] = stack.pop(); }
|
571
|
+
else for (let i = paramCount - 1; i >= 0; i--) locals[i] = stack.pop();
|
454
572
|
|
455
|
-
const outStack = run(
|
573
|
+
const outStack = run(callBC, locals);
|
456
574
|
stack.push(...outStack);
|
457
|
-
// while (outStack.length > 0) stack.push(outStack.pop());
|
458
|
-
// stack = stack.concat(outStack);
|
459
575
|
|
460
|
-
|
461
|
-
offset = _offset;
|
576
|
+
// console.log(bc.name, '<-', code.bc.name);
|
462
577
|
|
463
578
|
break;
|
464
579
|
}
|
465
580
|
|
466
581
|
case 0x1a: { // drop
|
467
|
-
if (skip) break;
|
468
|
-
|
469
582
|
stack.pop();
|
470
583
|
break;
|
471
584
|
}
|
472
585
|
|
473
586
|
case 0x20: { // local.get
|
474
|
-
|
475
|
-
read();
|
476
|
-
break;
|
477
|
-
}
|
478
|
-
|
479
|
-
// stack.push(locals[unsignedLEB128()]);
|
480
|
-
// stack.push(locals[input[offset++]]);
|
481
|
-
stack.push(locals[read()]);
|
587
|
+
stack.push(locals[op.idx]);
|
482
588
|
break;
|
483
589
|
}
|
484
590
|
|
485
591
|
case 0x21: { // local.set
|
486
|
-
|
487
|
-
read();
|
488
|
-
break;
|
489
|
-
}
|
490
|
-
|
491
|
-
// locals[unsignedLEB128()] = stack.pop();
|
492
|
-
locals[read()] = stack.pop();
|
592
|
+
locals[op.idx] = stack.pop();
|
493
593
|
break;
|
494
594
|
}
|
495
595
|
|
496
596
|
case 0x22: { // local.tee
|
497
|
-
|
498
|
-
read();
|
499
|
-
break;
|
500
|
-
}
|
501
|
-
|
502
|
-
// stack.push(locals[unsignedLEB128()] = stack.pop());
|
503
|
-
stack.push(locals[read()] = stack.pop());
|
597
|
+
stack.push(locals[op.idx] = stack.pop());
|
504
598
|
break;
|
505
599
|
}
|
506
600
|
|
507
601
|
case 0x23: { // global.get
|
508
|
-
|
509
|
-
|
510
|
-
|
602
|
+
// lazily evaluate global init exprs
|
603
|
+
const idx = op.idx;
|
604
|
+
if (globals[idx].value == null) {
|
605
|
+
globals[idx].value = run(globals[idx].bc, [], false)[0];
|
511
606
|
}
|
512
607
|
|
513
|
-
|
514
|
-
if (globals[ind].value == null) {
|
515
|
-
const _input = input;
|
516
|
-
const _offset = offset;
|
517
|
-
|
518
|
-
input = globals[ind].init;
|
519
|
-
offset = 0;
|
520
|
-
|
521
|
-
globals[ind].value = run(null, [], false)[0];
|
522
|
-
|
523
|
-
input = _input;
|
524
|
-
offset = _offset;
|
525
|
-
}
|
526
|
-
|
527
|
-
// stack.push(globals[unsignedLEB128()]);
|
528
|
-
stack.push(globals[ind].value);
|
608
|
+
stack.push(globals[idx].value);
|
529
609
|
break;
|
530
610
|
}
|
531
611
|
|
532
612
|
case 0x24: { // global.set
|
533
|
-
|
534
|
-
read();
|
535
|
-
break;
|
536
|
-
}
|
537
|
-
|
538
|
-
// globals[unsignedLEB128()] = stack.pop();
|
539
|
-
globals[read()].value = stack.pop();
|
613
|
+
globals[op.idx].value = stack.pop();
|
540
614
|
break;
|
541
615
|
}
|
542
616
|
|
543
617
|
case 0x41: { // i32.const
|
544
|
-
|
545
|
-
signedLEB128();
|
546
|
-
break;
|
547
|
-
}
|
548
|
-
|
549
|
-
stack.push(signedLEB128());
|
618
|
+
stack.push(op.val);
|
550
619
|
break;
|
551
620
|
}
|
552
621
|
case 0x42: { // i64.const
|
553
|
-
|
554
|
-
signedLEB128();
|
555
|
-
break;
|
556
|
-
}
|
557
|
-
|
558
|
-
stack.push(signedLEB128());
|
622
|
+
stack.push(op.val);
|
559
623
|
break;
|
560
624
|
}
|
561
625
|
case 0x44: { // f64.const
|
562
|
-
|
563
|
-
offset += 8;
|
564
|
-
break;
|
565
|
-
}
|
566
|
-
|
567
|
-
if (constCache[activeFunc][offset] != null) {
|
568
|
-
stack.push(constCache[activeFunc][offset]);
|
569
|
-
offset += 8;
|
570
|
-
break;
|
571
|
-
}
|
572
|
-
|
573
|
-
const val = ieee754();
|
574
|
-
constCache[activeFunc][offset - 8] = val;
|
575
|
-
stack.push(val);
|
626
|
+
stack.push(op.val);
|
576
627
|
break;
|
577
628
|
}
|
578
629
|
|
579
630
|
case 0x45: { // i32_eqz
|
580
|
-
if (skip) break;
|
581
|
-
|
582
631
|
stack.push(stack.pop() === 0);
|
583
632
|
break;
|
584
633
|
}
|
585
634
|
case 0x46: { // i32_eq
|
586
|
-
if (skip) break;
|
587
|
-
|
588
635
|
stack.push(stack.pop() === stack.pop());
|
589
636
|
break;
|
590
637
|
}
|
591
638
|
case 0x47: { // i32_ne
|
592
|
-
if (skip) break;
|
593
|
-
|
594
639
|
stack.push(stack.pop() !== stack.pop());
|
595
640
|
break;
|
596
641
|
}
|
597
642
|
case 0x48: { // i32.lt_s
|
598
|
-
if (skip) break;
|
599
|
-
|
600
643
|
const b = stack.pop();
|
601
644
|
const a = stack.pop();
|
602
645
|
stack.push(a < b);
|
603
646
|
break;
|
604
647
|
}
|
605
648
|
case 0x4c: { // i32.le_s
|
606
|
-
if (skip) break;
|
607
|
-
|
608
649
|
const b = stack.pop();
|
609
650
|
const a = stack.pop();
|
610
651
|
stack.push(a <= b);
|
611
652
|
break;
|
612
653
|
}
|
613
654
|
case 0x4a: { // i32.gt_s
|
614
|
-
if (skip) break;
|
615
|
-
|
616
655
|
const b = stack.pop();
|
617
656
|
const a = stack.pop();
|
618
657
|
stack.push(a > b);
|
619
658
|
break;
|
620
659
|
}
|
621
660
|
case 0x4e: { // i32_ge_s
|
622
|
-
if (skip) break;
|
623
|
-
|
624
661
|
const b = stack.pop();
|
625
662
|
const a = stack.pop();
|
626
663
|
stack.push(a >= b);
|
@@ -628,40 +665,30 @@ const vm = ({ types, imports, funcs, globals, exports, codes }, importImpls, sta
|
|
628
665
|
}
|
629
666
|
|
630
667
|
case 0x6a: { // i32_add
|
631
|
-
if (skip) break;
|
632
|
-
|
633
668
|
const b = stack.pop();
|
634
669
|
const a = stack.pop();
|
635
670
|
stack.push(a + b);
|
636
671
|
break;
|
637
672
|
}
|
638
673
|
case 0x6b: { // i32_sub
|
639
|
-
if (skip) break;
|
640
|
-
|
641
674
|
const b = stack.pop();
|
642
675
|
const a = stack.pop();
|
643
676
|
stack.push(a - b);
|
644
677
|
break;
|
645
678
|
}
|
646
679
|
case 0x6c: { // i32_mul
|
647
|
-
if (skip) break;
|
648
|
-
|
649
680
|
const b = stack.pop();
|
650
681
|
const a = stack.pop();
|
651
682
|
stack.push(a * b);
|
652
683
|
break;
|
653
684
|
}
|
654
685
|
case 0x6d: { // i32_div_s
|
655
|
-
if (skip) break;
|
656
|
-
|
657
686
|
const b = stack.pop();
|
658
687
|
const a = stack.pop();
|
659
688
|
stack.push(a / b);
|
660
689
|
break;
|
661
690
|
}
|
662
691
|
case 0x6f: { // i32_rem_s
|
663
|
-
if (skip) break;
|
664
|
-
|
665
692
|
const b = stack.pop();
|
666
693
|
const a = stack.pop();
|
667
694
|
stack.push(a % b);
|
@@ -669,48 +696,36 @@ const vm = ({ types, imports, funcs, globals, exports, codes }, importImpls, sta
|
|
669
696
|
}
|
670
697
|
|
671
698
|
case 0x71: { // i32_and
|
672
|
-
if (skip) break;
|
673
|
-
|
674
699
|
const b = stack.pop();
|
675
700
|
const a = stack.pop();
|
676
701
|
stack.push(a & b);
|
677
702
|
break;
|
678
703
|
}
|
679
704
|
case 0x72: { // i32_or
|
680
|
-
if (skip) break;
|
681
|
-
|
682
705
|
const b = stack.pop();
|
683
706
|
const a = stack.pop();
|
684
707
|
stack.push(a | b);
|
685
708
|
break;
|
686
709
|
}
|
687
710
|
case 0x73: { // i32_xor
|
688
|
-
if (skip) break;
|
689
|
-
|
690
711
|
const b = stack.pop();
|
691
712
|
const a = stack.pop();
|
692
713
|
stack.push(a ^ b);
|
693
714
|
break;
|
694
715
|
}
|
695
716
|
case 0x74: { // i32_shl
|
696
|
-
if (skip) break;
|
697
|
-
|
698
717
|
const b = stack.pop();
|
699
718
|
const a = stack.pop();
|
700
719
|
stack.push(a << b);
|
701
720
|
break;
|
702
721
|
}
|
703
722
|
case 0x75: { // i32_shr_s
|
704
|
-
if (skip) break;
|
705
|
-
|
706
723
|
const b = stack.pop();
|
707
724
|
const a = stack.pop();
|
708
725
|
stack.push(a >> b);
|
709
726
|
break;
|
710
727
|
}
|
711
728
|
case 0x76: { // i32_shr_u
|
712
|
-
if (skip) break;
|
713
|
-
|
714
729
|
const b = stack.pop();
|
715
730
|
const a = stack.pop();
|
716
731
|
stack.push(a >>> b);
|
@@ -776,45 +791,33 @@ const vm = ({ types, imports, funcs, globals, exports, codes }, importImpls, sta
|
|
776
791
|
// }
|
777
792
|
|
778
793
|
case 0x61: { // f64_eq
|
779
|
-
if (skip) break;
|
780
|
-
|
781
794
|
stack.push(stack.pop() === stack.pop());
|
782
795
|
break;
|
783
796
|
}
|
784
797
|
case 0x62: { // f64_ne
|
785
|
-
if (skip) break;
|
786
|
-
|
787
798
|
stack.push(stack.pop() !== stack.pop());
|
788
799
|
break;
|
789
800
|
}
|
790
801
|
|
791
802
|
case 0x63: { // f64_lt
|
792
|
-
if (skip) break;
|
793
|
-
|
794
803
|
const b = stack.pop();
|
795
804
|
const a = stack.pop();
|
796
805
|
stack.push(a < b);
|
797
806
|
break;
|
798
807
|
}
|
799
808
|
case 0x65: { // f64_le
|
800
|
-
if (skip) break;
|
801
|
-
|
802
809
|
const b = stack.pop();
|
803
810
|
const a = stack.pop();
|
804
811
|
stack.push(a <= b);
|
805
812
|
break;
|
806
813
|
}
|
807
814
|
case 0x64: { // f64_gt
|
808
|
-
if (skip) break;
|
809
|
-
|
810
815
|
const b = stack.pop();
|
811
816
|
const a = stack.pop();
|
812
817
|
stack.push(a > b);
|
813
818
|
break;
|
814
819
|
}
|
815
820
|
case 0x66: { // f64_ge
|
816
|
-
if (skip) break;
|
817
|
-
|
818
821
|
const b = stack.pop();
|
819
822
|
const a = stack.pop();
|
820
823
|
stack.push(a >= b);
|
@@ -822,92 +825,66 @@ const vm = ({ types, imports, funcs, globals, exports, codes }, importImpls, sta
|
|
822
825
|
}
|
823
826
|
|
824
827
|
case 0x99: { // f64_abs
|
825
|
-
if (skip) break;
|
826
|
-
|
827
828
|
stack.push(Math.abs(stack.pop()));
|
828
829
|
break;
|
829
830
|
}
|
830
831
|
case 0x9a: { // f64_neg
|
831
|
-
if (skip) break;
|
832
|
-
|
833
832
|
stack.push(stack.pop() * -1);
|
834
833
|
break;
|
835
834
|
}
|
836
835
|
|
837
836
|
case 0x9b: { // f64_ceil
|
838
|
-
if (skip) break;
|
839
|
-
|
840
837
|
stack.push(Math.ceil(stack.pop()));
|
841
838
|
break;
|
842
839
|
}
|
843
840
|
case 0x9c: { // f64_floor
|
844
|
-
if (skip) break;
|
845
|
-
|
846
841
|
stack.push(Math.floor(stack.pop()));
|
847
842
|
break;
|
848
843
|
}
|
849
844
|
case 0x9d: { // f64_trunc
|
850
|
-
if (skip) break;
|
851
|
-
|
852
845
|
stack.push(stack.pop() | 0);
|
853
846
|
break;
|
854
847
|
}
|
855
848
|
case 0x9e: { // f64_nearest
|
856
|
-
if (skip) break;
|
857
|
-
|
858
849
|
stack.push(Math.round(stack.pop()));
|
859
850
|
break;
|
860
851
|
}
|
861
852
|
|
862
853
|
case 0x9f: { // f64_sqrt
|
863
|
-
if (skip) break;
|
864
|
-
|
865
854
|
stack.push(Math.sqrt(stack.pop()));
|
866
855
|
break;
|
867
856
|
}
|
868
857
|
case 0xa0: { // f64_add
|
869
|
-
if (skip) break;
|
870
|
-
|
871
858
|
const b = stack.pop();
|
872
859
|
const a = stack.pop();
|
873
860
|
stack.push(a + b);
|
874
861
|
break;
|
875
862
|
}
|
876
863
|
case 0xa1: { // f64_sub
|
877
|
-
if (skip) break;
|
878
|
-
|
879
864
|
const b = stack.pop();
|
880
865
|
const a = stack.pop();
|
881
866
|
stack.push(a - b);
|
882
867
|
break;
|
883
868
|
}
|
884
869
|
case 0xa2: { // f64_mul
|
885
|
-
if (skip) break;
|
886
|
-
|
887
870
|
const b = stack.pop();
|
888
871
|
const a = stack.pop();
|
889
872
|
stack.push(a * b);
|
890
873
|
break;
|
891
874
|
}
|
892
875
|
case 0xa3: { // f64_div
|
893
|
-
if (skip) break;
|
894
|
-
|
895
876
|
const b = stack.pop();
|
896
877
|
const a = stack.pop();
|
897
878
|
stack.push(a / b);
|
898
879
|
break;
|
899
880
|
}
|
900
881
|
case 0xa4: { // f64_min
|
901
|
-
if (skip) break;
|
902
|
-
|
903
882
|
const b = stack.pop();
|
904
883
|
const a = stack.pop();
|
905
884
|
stack.push(a > b ? b : a);
|
906
885
|
break;
|
907
886
|
}
|
908
887
|
case 0xa5: { // f64_max
|
909
|
-
if (skip) break;
|
910
|
-
|
911
888
|
const b = stack.pop();
|
912
889
|
const a = stack.pop();
|
913
890
|
stack.push(a > b ? a : b);
|
@@ -953,23 +930,330 @@ const vm = ({ types, imports, funcs, globals, exports, codes }, importImpls, sta
|
|
953
930
|
}
|
954
931
|
|
955
932
|
default: {
|
956
|
-
console.log(activeFunc, offset, input.length,
|
957
|
-
throw new Error(`unimplemented op: 0x${opcode?.toString(16)}`);
|
933
|
+
console.log(activeFunc, offset, input.length, parents.length - 1);
|
934
|
+
throw new Error(`unimplemented op: 0x${op.opcode?.toString(16)}`);
|
958
935
|
}
|
959
936
|
}
|
937
|
+
|
938
|
+
// const t = performance.now() - start;
|
939
|
+
// times[invOpcodes[op.opcode]] = (times[invOpcodes[op.opcode]] ?? 0) + t;
|
940
|
+
// amounts[invOpcodes[op.opcode]] = (amounts[invOpcodes[op.opcode]] ?? 0) + 1;
|
960
941
|
}
|
961
942
|
};
|
962
943
|
|
963
|
-
|
944
|
+
const type = types[funcs[startFunc - imports.length]];
|
945
|
+
const code = codes[startFunc - imports.length];
|
946
|
+
|
947
|
+
return (...args) => {
|
948
|
+
const locals = new Array(code.locals.length).fill(0);
|
949
|
+
|
950
|
+
for (let i = 0; i < type.params.length; i++) locals[i] = args[i];
|
951
|
+
|
952
|
+
return run(code.bc, locals);
|
953
|
+
|
954
|
+
// times = {};
|
955
|
+
// const ret = run(code.bc, args);
|
956
|
+
// console.log('\n\n' + Object.keys(times).map(x => `${x}: ${((times[x] * 1000) / amounts[x]).toFixed(5)}s/op avg`).join('\n'));
|
957
|
+
// return ret;
|
958
|
+
};
|
959
|
+
};
|
960
|
+
|
961
|
+
const runExpr = wasm => vm({
|
962
|
+
types: [ { params: [] } ],
|
963
|
+
imports: [],
|
964
|
+
funcs: [ 0 ],
|
965
|
+
globals: [],
|
966
|
+
exports: [],
|
967
|
+
codes: [ { wasm, bc: wasmToBC(wasm, {}) } ]
|
968
|
+
}, {}, 0)();
|
969
|
+
|
970
|
+
const stringifyOp = ({ types, funcs, codes, imports, globals }, op, porfFunc = op.porfFunc, depth = 0) => {
|
971
|
+
const noHighlight = x => [...x].join('');
|
972
|
+
|
973
|
+
let str = ' '.repeat(depth * 2) + (op.opcode ?
|
974
|
+
invOpcodes[op.opcode].replace('_', '.').replace('return.', 'return_').replace('call.', 'call_').replace('br.', 'br_').replace('catch.', 'catch_') :
|
975
|
+
((op.porfFunc?.name ? `${noHighlight(op.porfFunc.name)} ` : '') + (op.wasmType?.params ? `(${op.wasmType.params.map(x => invValtype[x]).join(', ')}) -> (${op.wasmType.returns.map(x => invValtype[x]).join(', ')})` : ''))
|
976
|
+
);
|
977
|
+
|
978
|
+
// if (op.returns && op.returns !== 0x40) str += ` ${invValtype[op.returns]}`;
|
979
|
+
if (op.goto != null) str += ` ${op.goto}`;
|
980
|
+
if (op.func != null) str += ` ${op.func}`;
|
981
|
+
if (op.idx != null) str += ` ${op.idx}`;
|
982
|
+
if (op.val != null) str += ` ${op.val}`;
|
983
|
+
|
984
|
+
if (porfFunc) {
|
985
|
+
if (!porfFunc.invLocals) porfFunc.invLocals = inv(porfFunc.locals, x => x.idx);
|
986
|
+
|
987
|
+
if (op.func != null) {
|
988
|
+
str += ` \x1b[90m${op.func >= imports.length ? `${noHighlight(codes[op.func - imports.length].bc.porfFunc.name)}` : `${({ p: 'print', c: 'printChar', t: 'time', u: 'timeOrigin', y: 'profile1', z: 'profile2' })[imports[op.func].name]}`}`;
|
989
|
+
const type = types[op.func >= imports.length ? funcs[op.func - imports.length] : imports[op.func].typeIdx];
|
990
|
+
str += ` (${type.params.map(x => noHighlight(invValtype[x])).join(', ')}) -> (${type.returns.map(x => noHighlight(invValtype[x])).join(', ')})`;
|
991
|
+
str += '\x1b[0m';
|
992
|
+
}
|
993
|
+
|
994
|
+
if (op.opcode >= 0x20 && op.opcode <= 0x22) str += ` \x1b[90m${noHighlight(porfFunc.invLocals[op.idx] ?? '')}\x1b[0m`;
|
995
|
+
if (op.opcode >= 0x23 && op.opcode <= 0x24) str += ` \x1b[90m${noHighlight(globals[op.idx].porfGlobalName ?? '')}\x1b[0m`;
|
996
|
+
}
|
997
|
+
|
998
|
+
if (op.body) {
|
999
|
+
str += ':\n';
|
1000
|
+
for (const x of op.body) {
|
1001
|
+
str += stringifyOp({ types, funcs, codes, imports, globals }, x, porfFunc, depth + 1) + '\n';
|
1002
|
+
}
|
1003
|
+
|
1004
|
+
if (op.else) {
|
1005
|
+
str += ' '.repeat(depth * 2) + 'else:\n';
|
1006
|
+
for (const x of op.else) {
|
1007
|
+
str += stringifyOp({ types, funcs, codes, imports, globals }, x, porfFunc, depth + 1) + '\n';
|
1008
|
+
}
|
1009
|
+
}
|
1010
|
+
|
1011
|
+
str = str.slice(0, -1);
|
1012
|
+
// str += ' '.repeat(depth * 2) + 'end';
|
1013
|
+
}
|
1014
|
+
|
1015
|
+
const highlightAsm = asm => asm
|
1016
|
+
.replace(/(local|global|memory)\.[^\s]*/g, _ => `\x1B[31m${_}\x1B[0m`)
|
1017
|
+
.replace(/(i(8|16|32|64)x[0-9]+|v128)(\.[^\s]*)?/g, _ => `\x1B[34m${_}\x1B[0m`)
|
1018
|
+
.replace(/(i32|i64|f32|f64|drop)(\.[^\s]*)?/g, _ => `\x1B[36m${_}\x1B[0m`)
|
1019
|
+
.replace(/(return_call|call|br_if|br|return|rethrow|throw)/g, _ => `\x1B[35m${_}\x1B[0m`)
|
1020
|
+
.replace(/(block|loop|if|end|else|try|catch_all|catch|delegate):?/g, _ => `\x1B[95m${_}\x1B[0m`)
|
1021
|
+
.replace(/unreachable/g, _ => `\x1B[91m${_}\x1B[0m`)
|
1022
|
+
.replace(/ \-?[0-9\.]+/g, _ => ` \x1B[93m${_.slice(1)}\x1B[0m`)
|
1023
|
+
.replace(/ ;;.*$/gm, _ => `\x1B[90m${_.replaceAll(/\x1B\[[0-9]+m/g, '')}\x1B[0m`);
|
1024
|
+
|
1025
|
+
return highlightAsm(str);
|
964
1026
|
};
|
965
1027
|
|
1028
|
+
let Byg, invOpcodes, invValtype;
|
1029
|
+
|
1030
|
+
// setup a debug variant by self modifying code to avoid overhead when not debugging
|
1031
|
+
let _wasmDebugVm;
|
1032
|
+
const wasmDebugVm = (async () => {
|
1033
|
+
if (_wasmDebugVm) return _wasmDebugVm;
|
1034
|
+
|
1035
|
+
// imports only for debug
|
1036
|
+
const { Opcodes, Valtype } = (await import('../compiler/wasmSpec.js'));
|
1037
|
+
invOpcodes = inv(Opcodes, x => {
|
1038
|
+
if (typeof x === 'number') return x;
|
1039
|
+
return (x[0] << 8) + x[1];
|
1040
|
+
});
|
1041
|
+
invValtype = inv(Valtype);
|
1042
|
+
|
1043
|
+
Byg = (await import('../byg/index.js')).default;
|
1044
|
+
|
1045
|
+
|
1046
|
+
let str = vm.toString();
|
1047
|
+
|
1048
|
+
// add to start of vm()
|
1049
|
+
// make lines
|
1050
|
+
str = `({ types, imports, funcs, globals, exports, codes }, importImpls, startFunc) => {
|
1051
|
+
let paused = true;
|
1052
|
+
let stepIn = false, stepOut = false;
|
1053
|
+
const lines = codes.map(x => stringifyOp({ types, funcs, codes, imports, globals }, x.bc)).join('\\n\\n').split('\\n');
|
1054
|
+
const funcLines = new Array(codes.length);
|
1055
|
+
let j = 0;
|
1056
|
+
for (let i = 0; i < lines.length; i++) {
|
1057
|
+
const x = lines[i];
|
1058
|
+
if (x[0] !== ' ' && x !== '\\x1B[95mend\\x1B[0m' && x !== '') funcLines[j++] = i;
|
1059
|
+
}
|
1060
|
+
|
1061
|
+
let callStack = [];
|
1062
|
+
const byg = Byg({
|
1063
|
+
lines,
|
1064
|
+
pause: () => { paused = true; },
|
1065
|
+
breakpoint: (line, breakpoint) => {
|
1066
|
+
// it's (not) very effishient
|
1067
|
+
const funcOffset = funcLines.slice().reverse().find(x => line > x);
|
1068
|
+
const func = funcLines.indexOf(funcOffset);
|
1069
|
+
const totalOpIdx = line - funcOffset;
|
1070
|
+
|
1071
|
+
let op = 0;
|
1072
|
+
const iter = bc => {
|
1073
|
+
for (const x of bc) {
|
1074
|
+
op++;
|
1075
|
+
if (op === totalOpIdx) {
|
1076
|
+
op = x;
|
1077
|
+
return true;
|
1078
|
+
}
|
1079
|
+
|
1080
|
+
if (x.body) {
|
1081
|
+
if (iter(x.body)) return true;
|
1082
|
+
}
|
1083
|
+
|
1084
|
+
if (x.else) {
|
1085
|
+
op++;
|
1086
|
+
if (iter(x.else)) return true;
|
1087
|
+
}
|
1088
|
+
}
|
1089
|
+
};
|
1090
|
+
iter(codes[func].bc.body);
|
1091
|
+
|
1092
|
+
op.breakpoint = breakpoint;
|
1093
|
+
}
|
1094
|
+
});
|
1095
|
+
` + str.slice(str.indexOf('=>') + 4);
|
1096
|
+
|
1097
|
+
// add to start of run()
|
1098
|
+
str = str.replace('const run = (bc, locals = []) => {', `const run = (bc, locals = []) => {
|
1099
|
+
if (bc.porfFunc) callStack.push(bc.porfFunc.name);
|
1100
|
+
let lastDebugLocals = null, lastDebugGlobals = null;
|
1101
|
+
`);
|
1102
|
+
|
1103
|
+
// add to start of returns
|
1104
|
+
str = str.replaceAll('return stack;', `if (bc.porfFunc) callStack.pop();
|
1105
|
+
return stack;`);
|
1106
|
+
|
1107
|
+
// add to vm loop
|
1108
|
+
str = str.replace('const op = parent.body[parent.pc++];', `const op = parent.body[parent.pc++];
|
1109
|
+
if (op && op.breakpoint) paused = true;
|
1110
|
+
if (bc.porfFunc && paused && op) {
|
1111
|
+
stepIn = false; stepOut = false;
|
1112
|
+
|
1113
|
+
const currentFunc = bc.codeIdx;
|
1114
|
+
|
1115
|
+
let currentLine = 0;
|
1116
|
+
const addBodyLines = x => {
|
1117
|
+
currentLine += x.length;
|
1118
|
+
for (const y of x) {
|
1119
|
+
if (y.body) addBodyLines(y.body);
|
1120
|
+
if (y.else) addBodyLines(y.else);
|
1121
|
+
}
|
1122
|
+
};
|
1123
|
+
|
1124
|
+
for (let i = 0; i < parents.length; i++) {
|
1125
|
+
const x = parents[i];
|
1126
|
+
currentLine += x.pc;
|
1127
|
+
|
1128
|
+
for (let j = 0; j < x.pc - 1; j++) {
|
1129
|
+
if (x.body[j].body) addBodyLines(x.body[j].body);
|
1130
|
+
if (x.body[j].else) addBodyLines(x.body[j].else);
|
1131
|
+
}
|
1132
|
+
}
|
1133
|
+
|
1134
|
+
let localsChanged = new Array(locals.length);
|
1135
|
+
if (lastDebugLocals) {
|
1136
|
+
localsChanged = locals.map((x, i) => x !== lastDebugLocals[i]);
|
1137
|
+
}
|
1138
|
+
|
1139
|
+
let globalsChanged = new Array(globals.length);
|
1140
|
+
if (lastDebugGlobals) {
|
1141
|
+
globalsChanged = globals.map((x, i) => x.value !== lastDebugGlobals[i]);
|
1142
|
+
}
|
1143
|
+
|
1144
|
+
const longestLocal = Math.max(0, ...Object.values(bc.porfFunc.invLocals).map((x, i) => \`\${x} (\${i})\`.length));
|
1145
|
+
const localsWidth = longestLocal + 2 + 8 + 1;
|
1146
|
+
|
1147
|
+
const longestGlobal = Math.max(0, ...globals.map((x, i) => \`\${x.porfGlobalName} (\${i})\`.length));
|
1148
|
+
const globalsWidth = longestGlobal + 2 + 8 + 1;
|
1149
|
+
|
1150
|
+
const width = Math.max(localsWidth, globalsWidth);
|
1151
|
+
|
1152
|
+
// const longestStack = Math.max(5, ...stack.map(x => (+x).toString().length));
|
1153
|
+
// const stackWidth = longestStack + 2;
|
1154
|
+
|
1155
|
+
switch (byg(
|
1156
|
+
paused,
|
1157
|
+
funcLines[currentFunc] + currentLine,
|
1158
|
+
'\x1b[1masur\x1b[22m: ' + callStack.join(' -> ') + (parents.length > 1 ? \` | \${parents.slice(1).map(x => invOpcodes[x.opcode]).join(' -> ')}\` : ''),
|
1159
|
+
[
|
1160
|
+
{
|
1161
|
+
x: termWidth - 1 - width - 6,
|
1162
|
+
y: () => termHeight - Math.max(1, locals.length) - 1 - 4 - 3 - Math.max(1, stack.length) - (globals.length > 0 ? (globals.length + 4) : 0),
|
1163
|
+
width,
|
1164
|
+
height: Math.max(1, stack.length),
|
1165
|
+
title: 'stack',
|
1166
|
+
content: stack.map((x, i) => {
|
1167
|
+
const str = (+x).toString();
|
1168
|
+
return \`\\x1b[93m\${' '.repeat((width - str.length) / 2 | 0)}\${str}\`;
|
1169
|
+
})
|
1170
|
+
},
|
1171
|
+
{
|
1172
|
+
x: termWidth - 1 - width - 6,
|
1173
|
+
// x: termWidth / 3 | 0,
|
1174
|
+
y: () => termHeight - Math.max(1, locals.length) - 1 - 4 - (globals.length > 0 ? (globals.length + 4) : 0),
|
1175
|
+
// y: ({ currentLinePos }) => currentLinePos + locals.length + 4 > termHeight ? currentLinePos - locals.length - 2 : currentLinePos + 1,
|
1176
|
+
width,
|
1177
|
+
height: Math.max(1, locals.length),
|
1178
|
+
title: 'locals',
|
1179
|
+
content: locals.map((x, i) => {
|
1180
|
+
const changed = localsChanged[i];
|
1181
|
+
const valueLen = changed ? \`\${lastDebugLocals[i]} -> \${x}\`.length : x.toString().length;
|
1182
|
+
if (changed) x = \`\\x1b[30m\${lastDebugLocals[i]}\\x1b[90m -> \\x1b[31m\${x}\`;
|
1183
|
+
return \`\${changed ? '\\x1b[107m\\x1b[30m' : '\\x1b[100m\\x1b[37m\\x1b[1m'}\${bc.porfFunc.invLocals[i]}\${changed ? '\\x1b[90m' : '\\x1b[22m'} (\${i}) \${' '.repeat((width - 2 - 8 - 1 - \`\${bc.porfFunc.invLocals[i]} (\${i})\`.length) + 2 + (8 - valueLen))}\${changed ? '' : '\\x1b[93m'}\${x}\`;
|
1184
|
+
})
|
1185
|
+
},
|
1186
|
+
...(globals.length > 0 ? [{
|
1187
|
+
x: termWidth - 1 - width - 6,
|
1188
|
+
// x: termWidth / 3 | 0,
|
1189
|
+
y: () => termHeight - globals.length - 1 - 4,
|
1190
|
+
width,
|
1191
|
+
height: globals.length,
|
1192
|
+
title: 'globals',
|
1193
|
+
content: globals.map((x, i) => {
|
1194
|
+
if (x.value == null) {
|
1195
|
+
x.value = run(x.bc, [], false)[0];
|
1196
|
+
}
|
1197
|
+
|
1198
|
+
const changed = globalsChanged[i];
|
1199
|
+
const valueLen = changed ? \`\${lastDebugGlobals[i]} -> \${x.value}\`.length : x.value.toString().length;
|
1200
|
+
let display = x.value;
|
1201
|
+
if (changed) display = \`\\x1b[30m\${lastDebugGlobals[i]}\\x1b[90m -> \\x1b[31m\${x.value}\`;
|
1202
|
+
return \`\${changed ? '\\x1b[107m\\x1b[30m' : '\\x1b[100m\\x1b[37m\\x1b[1m'}\${x.porfGlobalName}\${changed ? '\\x1b[90m' : '\\x1b[22m'} (\${i}) \${' '.repeat((width - 2 - 8 - 1 - \`\${x.porfGlobalName} (\${i})\`.length) + 2 + (8 - valueLen))}\${changed ? '' : '\\x1b[93m'}\${display}\`;
|
1203
|
+
})
|
1204
|
+
}] : [])
|
1205
|
+
]
|
1206
|
+
)) {
|
1207
|
+
case 'resume': {
|
1208
|
+
paused = false;
|
1209
|
+
break;
|
1210
|
+
}
|
1211
|
+
|
1212
|
+
case 'stepOver': {
|
1213
|
+
break;
|
1214
|
+
}
|
1215
|
+
|
1216
|
+
case 'stepIn': {
|
1217
|
+
stepIn = true;
|
1218
|
+
// paused = false;
|
1219
|
+
break;
|
1220
|
+
}
|
1221
|
+
|
1222
|
+
case 'stepOut': {
|
1223
|
+
stepOut = true;
|
1224
|
+
paused = false;
|
1225
|
+
break;
|
1226
|
+
}
|
1227
|
+
}
|
1228
|
+
|
1229
|
+
lastDebugLocals = locals.slice();
|
1230
|
+
lastDebugGlobals = globals.map(x => x.value).slice();
|
1231
|
+
}`);
|
1232
|
+
|
1233
|
+
str = str.replace('const outStack = run(callBC, locals);', `
|
1234
|
+
const _paused = paused;
|
1235
|
+
if (!stepIn) paused = false;
|
1236
|
+
else paused = true;
|
1237
|
+
|
1238
|
+
const outStack = run(callBC, locals);
|
1239
|
+
|
1240
|
+
paused = _paused;`);
|
1241
|
+
|
1242
|
+
// (await import('fs')).writeFileSync('t.js', str);
|
1243
|
+
return _wasmDebugVm = eval(str);
|
1244
|
+
});
|
1245
|
+
|
966
1246
|
export const instantiate = async (binary, importImpls) => {
|
1247
|
+
const _vm = process?.argv?.includes('--wasm-debug') ? await wasmDebugVm() : vm;
|
1248
|
+
|
967
1249
|
const parsed = parse(binary);
|
968
1250
|
const exports = {};
|
969
1251
|
for (const { name, type, index } of parsed.exports) {
|
970
|
-
if (type === 0x00) exports[name] =
|
1252
|
+
if (type === 0x00) exports[name] = _vm(parsed, importImpls, index);
|
971
1253
|
}
|
972
1254
|
|
1255
|
+
// console.log(parsed);
|
1256
|
+
|
973
1257
|
return {
|
974
1258
|
instance: {
|
975
1259
|
exports
|