porffor 0.2.0-6aff0fa → 0.2.0-6bc63ef

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.
Files changed (54) hide show
  1. package/CONTRIBUTING.md +256 -0
  2. package/LICENSE +20 -20
  3. package/README.md +115 -82
  4. package/asur/index.js +624 -340
  5. package/byg/index.js +216 -0
  6. package/compiler/2c.js +2 -53
  7. package/compiler/{sections.js → assemble.js} +60 -14
  8. package/compiler/builtins/annexb_string.js +72 -0
  9. package/compiler/builtins/annexb_string.ts +18 -0
  10. package/compiler/builtins/array.ts +145 -0
  11. package/compiler/builtins/base64.ts +7 -84
  12. package/compiler/builtins/boolean.ts +18 -0
  13. package/compiler/builtins/crypto.ts +120 -0
  14. package/compiler/builtins/date.ts +2067 -0
  15. package/compiler/builtins/escape.ts +141 -0
  16. package/compiler/builtins/function.ts +5 -0
  17. package/compiler/builtins/int.ts +145 -0
  18. package/compiler/builtins/number.ts +529 -0
  19. package/compiler/builtins/object.ts +4 -0
  20. package/compiler/builtins/porffor.d.ts +44 -7
  21. package/compiler/builtins/set.ts +187 -0
  22. package/compiler/builtins/string.ts +1080 -0
  23. package/compiler/builtins.js +400 -120
  24. package/compiler/{codeGen.js → codegen.js} +850 -402
  25. package/compiler/decompile.js +2 -3
  26. package/compiler/embedding.js +22 -22
  27. package/compiler/encoding.js +94 -10
  28. package/compiler/expression.js +1 -1
  29. package/compiler/generated_builtins.js +1613 -3
  30. package/compiler/index.js +16 -16
  31. package/compiler/log.js +2 -2
  32. package/compiler/opt.js +28 -27
  33. package/compiler/parse.js +36 -30
  34. package/compiler/precompile.js +37 -46
  35. package/compiler/prefs.js +7 -6
  36. package/compiler/prototype.js +20 -36
  37. package/compiler/types.js +38 -0
  38. package/compiler/wasmSpec.js +14 -1
  39. package/compiler/wrap.js +79 -69
  40. package/package.json +9 -5
  41. package/porf +2 -0
  42. package/rhemyn/compile.js +44 -26
  43. package/rhemyn/parse.js +322 -320
  44. package/rhemyn/test/parse.js +58 -58
  45. package/runner/compare.js +33 -34
  46. package/runner/debug.js +117 -0
  47. package/runner/index.js +69 -12
  48. package/runner/profiler.js +22 -30
  49. package/runner/repl.js +40 -13
  50. package/runner/sizes.js +37 -37
  51. package/runner/version.js +3 -3
  52. package/runner/info.js +0 -89
  53. package/runner/transform.js +0 -15
  54. 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
- globals[i] = { valtype, mutable, init };
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
- codes[i] = { locals, wasm };
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
- return { types, imports, funcs, globals, exports, codes };
209
- };
210
-
211
- const inv = (obj, keyMap = x => x) => Object.keys(obj).reduce((acc, x) => { acc[keyMap(obj[x])] = x; return acc; }, {});
212
- const Opcodes = (await import('../compiler/wasmSpec.js')).Opcodes;
213
- const invOpcodes = inv(Opcodes, x => {
214
- if (typeof x === 'number') return x;
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
- const vm = ({ types, imports, funcs, globals, exports, codes }, importImpls, startFunc) => {
219
- const constCache = {};
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
- input = activeCode.wasm; // active code
228
- offset = 0; // PC
405
+ offset = runExpr(init);
229
406
 
230
- locals = new Array(activeCode.locals.length).fill(0);
407
+ break;
231
408
 
232
- for (let i = 0; i < params.length; i++) locals[i] = params[i];
233
- }
409
+ default:
410
+ throw new Error('todo');
411
+ }
234
412
 
235
- if (!constCache[activeFunc]) constCache[activeFunc] = {};
236
- if (!skipCache[activeFunc]) skipCache[activeFunc] = {};
413
+ const bytesLength = unsignedLEB128();
414
+ const bytes = new Array(bytesLength);
237
415
 
238
- let stack = [];
416
+ for (let j = 0; j < bytesLength; j++) bytes[j] = read();
239
417
 
240
- let depth = 0;
418
+ datas[i] = { offset, bytes };
419
+ }
420
+ }
241
421
 
242
- let skipStart = 0;
243
- let skipUntilEnd = 0;
244
- let skipUntilElse = 0;
245
- let loopStarts = [];
246
- let rets = [];
422
+ if (section === 12) { // data count
423
+ datas.dataCount = unsignedLEB128();
424
+ }
425
+ }
247
426
 
248
- while (true) {
249
- let opcode = read();
427
+ return { types, imports, funcs, memories, tags, globals, exports, codes, datas };
428
+ };
250
429
 
251
- const skip = skipUntilEnd !== 0 || skipUntilElse !== 0;
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
- if (opcode === 0xfc) { // multibyte op
254
- opcode = (opcode << 8) + read();
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
- // console.log((skip ? '\x1B[90m' : '') + ' '.repeat(depth * 2) + invOpcodes[opcode] + '\x1B[0m', stack, depth);
443
+ let times = {};
444
+ let amounts = {};
258
445
 
259
- const blockStart = (loop) => {
260
- const returns = read();
261
- rets.push(returns !== 0x40);
446
+ const vm = ({ types, imports, funcs, globals, exports, codes }, importImpls, startFunc) => {
447
+ const run = (bc, locals = []) => {
448
+ let stack = [];
262
449
 
263
- loopStarts.push(loop ? offset : null);
450
+ let parents = [ bc ];
451
+ let parent = bc;
264
452
 
265
- depth++;
266
- };
453
+ parent.pc = 0;
267
454
 
268
- const skipEnd = until => {
269
- if (skipCache[activeFunc][offset]) {
270
- offset = skipCache[activeFunc][offset];
271
- } else {
272
- skipUntilEnd = until;
273
- skipStart = offset;
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
- const skipElse = until => {
278
- skipUntilElse = until;
469
+ continue;
470
+ }
279
471
 
280
- if (skipCache[activeFunc][offset]) {
281
- offset = skipCache[activeFunc][offset];
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
- skipStart = offset;
482
+ parents = parents.slice(0, ind);
483
+ parent = parents[parents.length - 1];
284
484
  }
285
485
  };
286
486
 
287
- const br = n => {
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
- blockStart(false);
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
- blockStart(true);
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
- } else skipElse(depth); // skip to else
345
-
346
- break;
347
- }
348
-
349
- case 0x05: { // else
350
- if (skipUntilElse === depth) { // were skipping to else, stop skip
351
- skipUntilElse = 0;
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
- if (skip) {
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 (skip) {
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
- if (skip) {
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
- const ret = importImpls[mod][name](...params);
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 type = types[funcs[func - imports.length]];
441
- const paramCount = type.params.length;
561
+ const code = codes[op.func - imports.length];
442
562
 
443
- const params = new Array(paramCount);
563
+ // console.log(bc.name, '->', code.bc.name);
444
564
 
445
- if (paramCount === 0) {}
446
- else if (paramCount === 1) params[0] = stack.pop();
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
- // for (let i = paramCount - 1; i >= 0; i--) params[i] = stack.pop();
451
-
452
- const _input = input;
453
- const _offset = offset;
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(func, params);
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
- input = _input;
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
- if (skip) {
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
- if (skip) {
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
- if (skip) {
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
- if (skip) {
509
- read();
510
- break;
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
- const ind = read();
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
- if (skip) {
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
- if (skip) {
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
- if (skip) {
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
- if (skip) {
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, depth);
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
- return (...args) => run(startFunc, args);
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] = vm(parsed, importImpls, index);
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