porffor 0.2.0-9ca9aed → 0.2.0-9f8ffb2

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.
@@ -15,7 +15,7 @@ export default (wasm, name = '', ind = 0, locals = {}, params = [], returns = []
15
15
  if (name) out += `${makeSignature(params, returns)} ;; $${name} (${ind})\n`;
16
16
 
17
17
  const justLocals = Object.values(locals).sort((a, b) => a.idx - b.idx).slice(params.length);
18
- if (justLocals.length > 0) out += ` local ${justLocals.map(x => invValtype[x.type]).join(' ')}\n`;
18
+ if (name && justLocals.length > 0) out += ` local ${justLocals.map(x => invValtype[x.type]).join(' ')}\n`;
19
19
 
20
20
  let i = -1, lastInst;
21
21
  let byte = 0;
@@ -32,7 +32,7 @@ export default (wasm, name = '', ind = 0, locals = {}, params = [], returns = []
32
32
  inst = [ [ inst[0], inst[1] ], ...inst.slice(2) ];
33
33
  }
34
34
 
35
- if (inst[0] === Opcodes.end || inst[0] === Opcodes.else || inst[0] === Opcodes.catch_all) depth--;
35
+ if (depth > 0 && (inst[0] === Opcodes.end || inst[0] === Opcodes.else || inst[0] === Opcodes.catch_all)) depth--;
36
36
 
37
37
  out += ' '.repeat(Math.max(0, depth * 2));
38
38
 
@@ -119,7 +119,7 @@ export default (wasm, name = '', ind = 0, locals = {}, params = [], returns = []
119
119
  export const highlightAsm = asm => asm
120
120
  .replace(/(local|global|memory)\.[^\s]*/g, _ => `\x1B[31m${_}\x1B[0m`)
121
121
  .replace(/(i(8|16|32|64)x[0-9]+|v128)(\.[^\s]*)?/g, _ => `\x1B[34m${_}\x1B[0m`)
122
- .replace(/[^m](i32|i64|f32|f64|drop)(\.[^\s]*)?/g, _ => `${_[0]}\x1B[36m${_.slice(1)}\x1B[0m`)
122
+ .replace(/(i32|i64|f32|f64|drop)(\.[^\s]*)?/g, _ => `\x1B[36m${_}\x1B[0m`)
123
123
  .replace(/(return_call|call|br_if|br|return|rethrow|throw)/g, _ => `\x1B[35m${_}\x1B[0m`)
124
124
  .replace(/(block|loop|if|end|else|try|catch_all|catch|delegate)/g, _ => `\x1B[95m${_}\x1B[0m`)
125
125
  .replace(/unreachable/g, _ => `\x1B[91m${_}\x1B[0m`)
package/compiler/index.js CHANGED
@@ -52,7 +52,7 @@ export default (code, flags) => {
52
52
  if (process.argv.includes('-funcs')) logFuncs(funcs, globals, exceptions);
53
53
 
54
54
  const t2 = performance.now();
55
- opt(funcs, globals, pages);
55
+ opt(funcs, globals, pages, tags);
56
56
  if (flags.includes('info')) console.log(`3. optimized code in ${(performance.now() - t2).toFixed(2)}ms`);
57
57
 
58
58
  if (process.argv.includes('-opt-funcs')) logFuncs(funcs, globals, exceptions);
package/compiler/opt.js CHANGED
@@ -11,7 +11,7 @@ const performWasmOp = (op, a, b) => {
11
11
  }
12
12
  };
13
13
 
14
- export default (funcs, globals, pages) => {
14
+ export default (funcs, globals, pages, tags) => {
15
15
  const optLevel = parseInt(process.argv.find(x => x.startsWith('-O'))?.[2] ?? 1);
16
16
  if (optLevel === 0) return;
17
17
 
@@ -99,10 +99,14 @@ export default (funcs, globals, pages) => {
99
99
 
100
100
  if (process.argv.includes('-opt-inline-only')) return;
101
101
 
102
+ const tagUse = tags.reduce((acc, x) => { acc[x.idx] = 0; return acc; }, {});
103
+
102
104
  // wasm transform pass
103
105
  for (const f of funcs) {
104
106
  const wasm = f.wasm;
105
107
 
108
+ const lastType = f.locals['#last_type'];
109
+
106
110
  let runs = 2; // how many by default? add arg?
107
111
  while (runs > 0) {
108
112
  runs--;
@@ -125,6 +129,8 @@ export default (funcs, globals, pages) => {
125
129
  if (inst[0] === Opcodes.local_get) getCount[inst[1]]++;
126
130
  if (inst[0] === Opcodes.local_set || inst[0] === Opcodes.local_tee) setCount[inst[1]]++;
127
131
 
132
+ if (inst[0] === Opcodes.throw) tagUse[inst[1]]++;
133
+
128
134
  if (inst[0] === Opcodes.block) {
129
135
  // remove unneeded blocks (no brs inside)
130
136
  // block
@@ -141,7 +147,7 @@ export default (funcs, globals, pages) => {
141
147
  depth--;
142
148
  if (depth <= 0) break;
143
149
  }
144
- if (op === Opcodes.br || op === Opcodes.br_if) {
150
+ if (op === Opcodes.br || op === Opcodes.br_if || op === Opcodes.br_table) {
145
151
  hasBranch = true;
146
152
  break;
147
153
  }
@@ -186,6 +192,7 @@ export default (funcs, globals, pages) => {
186
192
  let missing = false;
187
193
  if (type === 'Array') missing = !pages.hasArray;
188
194
  if (type === 'String') missing = !pages.hasString;
195
+ if (type === 'ByteString') missing = !pages.hasByteString;
189
196
 
190
197
  if (missing) {
191
198
  let j = i, depth = 0;
@@ -221,6 +228,7 @@ export default (funcs, globals, pages) => {
221
228
  }
222
229
 
223
230
  if (checks === 0) {
231
+ // todo: review indexes below
224
232
  wasm.splice(j - 1, 2, [ Opcodes.drop ]); // remove typeswitch start
225
233
  wasm.splice(i - 1, 1); // remove this inst
226
234
 
@@ -231,6 +239,13 @@ export default (funcs, globals, pages) => {
231
239
  }
232
240
  }
233
241
 
242
+ // remove setting last type if it is never gotten
243
+ if (!f.gotLastType && inst[0] === Opcodes.local_set && inst[1] === lastType?.idx) {
244
+ // replace this inst with drop
245
+ wasm.splice(i, 1, [ Opcodes.drop ]); // remove this and last inst
246
+ if (i > 0) i--;
247
+ }
248
+
234
249
  if (i < 1) continue;
235
250
  let lastInst = wasm[i - 1];
236
251
 
@@ -531,5 +546,12 @@ export default (funcs, globals, pages) => {
531
546
  }
532
547
  }
533
548
 
549
+ for (const x in tagUse) {
550
+ if (tagUse[x] === 0) {
551
+ const el = tags.find(y => y.idx === x);
552
+ tags.splice(tags.indexOf(el), 1);
553
+ }
554
+ }
555
+
534
556
  // return funcs;
535
557
  };
package/compiler/parse.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { log } from "./log.js";
2
+ // import { parse } from 'acorn';
2
3
 
3
4
  // deno compat
4
5
  if (typeof process === 'undefined' && typeof Deno !== 'undefined') {
@@ -6,16 +7,9 @@ if (typeof process === 'undefined' && typeof Deno !== 'undefined') {
6
7
  globalThis.process = { argv: ['', '', ...Deno.args], stdout: { write: str => Deno.writeAllSync(Deno.stdout, textEncoder.encode(str)) } };
7
8
  }
8
9
 
9
- // import { parse } from 'acorn';
10
-
11
- let parser, parse;
12
-
13
- const loadParser = async () => {
14
- parser = process.argv.find(x => x.startsWith('-parser='))?.split('=')?.[1] ?? 'acorn';
15
- 0, { parse } = (await import((globalThis.document ? 'https://esm.sh/' : '') + parser));
16
- };
17
- globalThis._porf_loadParser = loadParser;
18
- await loadParser();
10
+ // should we try to support types (while parsing)
11
+ const types = process.argv.includes('-parse-types');
12
+ globalThis.typedInput = types && process.argv.includes('-opt-types');
19
13
 
20
14
  // todo: review which to use by default
21
15
  // supported parsers:
@@ -24,8 +18,13 @@ await loadParser();
24
18
  // - hermes-parser
25
19
  // - @babel/parser
26
20
 
27
- // should we try to support types (while parsing)
28
- const types = process.argv.includes('-types');
21
+ let parser, parse;
22
+ const loadParser = async (fallbackParser = 'acorn', forceParser) => {
23
+ parser = forceParser ?? process.argv.find(x => x.startsWith('-parser='))?.split('=')?.[1] ?? fallbackParser;
24
+ 0, { parse } = (await import((globalThis.document ? 'https://esm.sh/' : '') + parser));
25
+ };
26
+ globalThis._porf_loadParser = loadParser;
27
+ await loadParser(types ? '@babel/parser' : undefined);
29
28
 
30
29
  if (types && !['@babel/parser', 'hermes-parser'].includes(parser)) log.warning('parser', `passed -types with a parser (${parser}) which does not support`);
31
30
 
@@ -16,7 +16,8 @@ const TYPES = {
16
16
 
17
17
  // these are not "typeof" types but tracked internally
18
18
  _array: 0x10,
19
- _regexp: 0x11
19
+ _regexp: 0x11,
20
+ _bytestring: 0x12
20
21
  };
21
22
 
22
23
  // todo: turn these into built-ins once arrays and these become less hacky
@@ -71,7 +72,7 @@ export const PrototypeFuncs = function() {
71
72
  ],
72
73
 
73
74
  // todo: only for 1 argument
74
- push: (pointer, length, wNewMember) => [
75
+ push: (pointer, length, wNewMember, _1, _2, _3, unusedValue) => [
75
76
  // get memory offset of array at last index (length)
76
77
  ...length.getCachedI32(),
77
78
  ...number(ValtypeSize[valtype], Valtype.i32),
@@ -92,22 +93,28 @@ export const PrototypeFuncs = function() {
92
93
  ...number(1, Valtype.i32),
93
94
  [ Opcodes.i32_add ],
94
95
 
95
- ...length.setCachedI32(),
96
- ...length.getCachedI32(),
96
+ ...(unusedValue() ? [] : [
97
+ ...length.setCachedI32(),
98
+ ...length.getCachedI32(),
99
+ ])
97
100
  ]),
98
101
 
99
- ...length.getCachedI32(),
100
- Opcodes.i32_from_u
102
+ ...(unusedValue() ? [] : [
103
+ ...length.getCachedI32(),
104
+ Opcodes.i32_from_u
105
+ ])
101
106
 
102
107
  // ...length.get()
103
108
  ],
104
109
 
105
- pop: (pointer, length) => [
110
+ pop: (pointer, length, _1, _2, _3, _4, unusedValue) => [
106
111
  // if length == 0, noop
107
112
  ...length.getCachedI32(),
108
113
  [ Opcodes.i32_eqz ],
109
114
  [ Opcodes.if, Blocktype.void ],
110
- ...number(UNDEFINED),
115
+ ...(unusedValue() ? [] : [
116
+ ...number(UNDEFINED),
117
+ ]),
111
118
  [ Opcodes.br, 1 ],
112
119
  [ Opcodes.end ],
113
120
 
@@ -119,19 +126,23 @@ export const PrototypeFuncs = function() {
119
126
  ...number(1, Valtype.i32),
120
127
  [ Opcodes.i32_sub ],
121
128
 
122
- ...length.setCachedI32(),
123
- ...length.getCachedI32(),
129
+ ...(unusedValue() ? [] : [
130
+ ...length.setCachedI32(),
131
+ ...length.getCachedI32(),
132
+ ])
124
133
  ]),
125
134
 
126
135
  // load last element
127
- ...length.getCachedI32(),
128
- ...number(ValtypeSize[valtype], Valtype.i32),
129
- [ Opcodes.i32_mul ],
136
+ ...(unusedValue() ? [] : [
137
+ ...length.getCachedI32(),
138
+ ...number(ValtypeSize[valtype], Valtype.i32),
139
+ [ Opcodes.i32_mul ],
130
140
 
131
- ...pointer,
132
- [ Opcodes.i32_add ],
141
+ ...pointer,
142
+ [ Opcodes.i32_add ],
133
143
 
134
- [ Opcodes.load, Math.log2(ValtypeSize[valtype]) - 1, ...unsignedLEB128(ValtypeSize.i32) ]
144
+ [ Opcodes.load, Math.log2(ValtypeSize[valtype]) - 1, ...unsignedLEB128(ValtypeSize.i32) ]
145
+ ])
135
146
  ],
136
147
 
137
148
  shift: (pointer, length) => [
@@ -472,8 +483,152 @@ export const PrototypeFuncs = function() {
472
483
  this[TYPES.string].at.returnType = TYPES.string;
473
484
  this[TYPES.string].charAt.returnType = TYPES.string;
474
485
  this[TYPES.string].charCodeAt.local = Valtype.i32;
486
+ this[TYPES.string].charCodeAt.noPointerCache = zeroChecks.charcodeat;
475
487
 
476
488
  this[TYPES.string].isWellFormed.local = Valtype.i32;
477
489
  this[TYPES.string].isWellFormed.local2 = Valtype.i32;
478
490
  this[TYPES.string].isWellFormed.returnType = TYPES.boolean;
491
+
492
+ if (process.argv.includes('-bytestring')) {
493
+ this[TYPES._bytestring] = {
494
+ at: (pointer, length, wIndex, iTmp, _, arrayShell) => {
495
+ const [ newOut, newPointer ] = arrayShell(1, 'i16');
496
+
497
+ return [
498
+ // setup new/out array
499
+ ...newOut,
500
+ [ Opcodes.drop ],
501
+
502
+ ...number(0, Valtype.i32), // base 0 for store later
503
+
504
+ ...wIndex,
505
+ Opcodes.i32_to_u,
506
+ [ Opcodes.local_tee, iTmp ],
507
+
508
+ // if index < 0: access index + array length
509
+ ...number(0, Valtype.i32),
510
+ [ Opcodes.i32_lt_s ],
511
+ [ Opcodes.if, Blocktype.void ],
512
+ [ Opcodes.local_get, iTmp ],
513
+ ...length.getCachedI32(),
514
+ [ Opcodes.i32_add ],
515
+ [ Opcodes.local_set, iTmp ],
516
+ [ Opcodes.end ],
517
+
518
+ // if still < 0 or >= length: return undefined
519
+ [ Opcodes.local_get, iTmp ],
520
+ ...number(0, Valtype.i32),
521
+ [ Opcodes.i32_lt_s ],
522
+
523
+ [ Opcodes.local_get, iTmp ],
524
+ ...length.getCachedI32(),
525
+ [ Opcodes.i32_ge_s ],
526
+ [ Opcodes.i32_or ],
527
+
528
+ [ Opcodes.if, Blocktype.void ],
529
+ ...number(UNDEFINED),
530
+ [ Opcodes.br, 1 ],
531
+ [ Opcodes.end ],
532
+
533
+ [ Opcodes.local_get, iTmp ],
534
+
535
+ ...pointer,
536
+ [ Opcodes.i32_add ],
537
+
538
+ // load current string ind {arg}
539
+ [ Opcodes.i32_load8_u, 0, ...unsignedLEB128(ValtypeSize.i32) ],
540
+
541
+ // store to new string ind 0
542
+ [ Opcodes.i32_store8, 0, ...unsignedLEB128(newPointer + ValtypeSize.i32) ],
543
+
544
+ // return new string (pointer)
545
+ ...number(newPointer)
546
+ ];
547
+ },
548
+
549
+ // todo: out of bounds properly
550
+ charAt: (pointer, length, wIndex, _1, _2, arrayShell) => {
551
+ const [ newOut, newPointer ] = arrayShell(1, 'i16');
552
+
553
+ return [
554
+ // setup new/out array
555
+ ...newOut,
556
+ [ Opcodes.drop ],
557
+
558
+ ...number(0, Valtype.i32), // base 0 for store later
559
+
560
+ ...wIndex,
561
+
562
+ Opcodes.i32_to,
563
+
564
+ ...pointer,
565
+ [ Opcodes.i32_add ],
566
+
567
+ // load current string ind {arg}
568
+ [ Opcodes.i32_load8_u, 0, ...unsignedLEB128(ValtypeSize.i32) ],
569
+
570
+ // store to new string ind 0
571
+ [ Opcodes.i32_store8, 0, ...unsignedLEB128(newPointer + ValtypeSize.i32) ],
572
+
573
+ // return new string (page)
574
+ ...number(newPointer)
575
+ ];
576
+ },
577
+
578
+ charCodeAt: (pointer, length, wIndex, iTmp) => {
579
+ return [
580
+ ...wIndex,
581
+ Opcodes.i32_to,
582
+
583
+ ...(zeroChecks.charcodeat ? [] : [
584
+ [ Opcodes.local_set, iTmp ],
585
+
586
+ // index < 0
587
+ ...(noUnlikelyChecks ? [] : [
588
+ [ Opcodes.local_get, iTmp ],
589
+ ...number(0, Valtype.i32),
590
+ [ Opcodes.i32_lt_s ],
591
+ ]),
592
+
593
+ // index >= length
594
+ [ Opcodes.local_get, iTmp ],
595
+ ...length.getCachedI32(),
596
+ [ Opcodes.i32_ge_s ],
597
+
598
+ ...(noUnlikelyChecks ? [] : [ [ Opcodes.i32_or ] ]),
599
+ [ Opcodes.if, Blocktype.void ],
600
+ ...number(NaN),
601
+ [ Opcodes.br, 1 ],
602
+ [ Opcodes.end ],
603
+
604
+ [ Opcodes.local_get, iTmp ],
605
+ ]),
606
+
607
+ ...pointer,
608
+ [ Opcodes.i32_add ],
609
+
610
+ // load current string ind {arg}
611
+ [ Opcodes.i32_load8_u, 0, ...unsignedLEB128(ValtypeSize.i32) ],
612
+ Opcodes.i32_from_u
613
+ ];
614
+ },
615
+
616
+ isWellFormed: () => {
617
+ return [
618
+ // we know it must be true as it is a bytestring lol
619
+ ...number(1)
620
+ ]
621
+ }
622
+ };
623
+
624
+ this[TYPES._bytestring].at.local = Valtype.i32;
625
+ this[TYPES._bytestring].at.returnType = TYPES._bytestring;
626
+ this[TYPES._bytestring].charAt.returnType = TYPES._bytestring;
627
+ this[TYPES._bytestring].charCodeAt.local = Valtype.i32;
628
+ this[TYPES._bytestring].charCodeAt.noPointerCache = zeroChecks.charcodeat;
629
+
630
+ this[TYPES._bytestring].isWellFormed.local = Valtype.i32;
631
+ this[TYPES._bytestring].isWellFormed.local2 = Valtype.i32;
632
+ this[TYPES._bytestring].isWellFormed.returnType = TYPES.boolean;
633
+ }
479
634
  };
@@ -150,7 +150,7 @@ export default (funcs, globals, tags, pages, data, flags) => {
150
150
 
151
151
  if (typeCount !== 0) localDecl.push(encodeLocal(typeCount, lastType));
152
152
 
153
- return encodeVector([ ...encodeVector(localDecl), ...x.wasm.flat().filter(x => x <= 0xff), Opcodes.end ]);
153
+ return encodeVector([ ...encodeVector(localDecl), ...x.wasm.flat().filter(x => x != null && x <= 0xff), Opcodes.end ]);
154
154
  }))
155
155
  );
156
156
 
@@ -32,8 +32,6 @@ export const Opcodes = {
32
32
  throw: 0x08,
33
33
  rethrow: 0x09,
34
34
 
35
- return: 0x0F,
36
-
37
35
  call: 0x10,
38
36
  call_indirect: 0x11,
39
37
  return_call: 0x12,
@@ -42,7 +40,10 @@ export const Opcodes = {
42
40
  end: 0x0b,
43
41
  br: 0x0c,
44
42
  br_if: 0x0d,
43
+ br_table: 0x0e,
44
+ return: 0x0f,
45
45
  call: 0x10,
46
+
46
47
  drop: 0x1a,
47
48
 
48
49
  local_get: 0x20,
@@ -56,9 +57,12 @@ export const Opcodes = {
56
57
  i64_load: 0x29,
57
58
  f64_load: 0x2b,
58
59
 
60
+ i32_load8_s: 0x2c,
61
+ i32_load8_u: 0x2d,
59
62
  i32_load16_s: 0x2e,
60
63
  i32_load16_u: 0x2f,
61
64
 
65
+ i32_store8: 0x3a,
62
66
  i32_store16: 0x3b,
63
67
 
64
68
  i32_store: 0x36,
package/compiler/wrap.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import compile from './index.js';
2
2
  import decompile from './decompile.js';
3
+ import { encodeVector, encodeLocal } from './encoding.js';
3
4
  // import fs from 'node:fs';
4
5
 
5
6
  const bold = x => `\u001b[1m${x}\u001b[0m`;
@@ -18,7 +19,8 @@ const TYPES = {
18
19
 
19
20
  // internal
20
21
  [internalTypeBase]: '_array',
21
- [internalTypeBase + 1]: '_regexp'
22
+ [internalTypeBase + 1]: '_regexp',
23
+ [internalTypeBase + 2]: '_bytestring'
22
24
  };
23
25
 
24
26
  export default async (source, flags = [ 'module' ], customImports = {}, print = str => process.stdout.write(str)) => {
@@ -35,14 +37,98 @@ export default async (source, flags = [ 'module' ], customImports = {}, print =
35
37
  if (flags.includes('info')) console.log(bold(`compiled in ${times[0].toFixed(2)}ms`));
36
38
 
37
39
  const t2 = performance.now();
38
- const { instance } = await WebAssembly.instantiate(wasm, {
39
- '': {
40
- p: valtype === 'i64' ? i => print(Number(i).toString()) : i => print(i.toString()),
41
- c: valtype === 'i64' ? i => print(String.fromCharCode(Number(i))) : i => print(String.fromCharCode(i)),
42
- t: _ => performance.now(),
43
- ...customImports
40
+
41
+ let instance;
42
+ try {
43
+ 0, { instance } = await WebAssembly.instantiate(wasm, {
44
+ '': {
45
+ p: valtype === 'i64' ? i => print(Number(i).toString()) : i => print(i.toString()),
46
+ c: valtype === 'i64' ? i => print(String.fromCharCode(Number(i))) : i => print(String.fromCharCode(i)),
47
+ t: _ => performance.now(),
48
+ ...customImports
49
+ }
50
+ });
51
+ } catch (e) {
52
+ // only backtrace for runner, not test262/etc
53
+ if (!process.argv[1].includes('/runner')) throw e;
54
+
55
+ const funcInd = parseInt(e.message.match(/function #([0-9]+) /)[1]);
56
+ const blobOffset = parseInt(e.message.split('@')[1]);
57
+
58
+ // convert blob offset -> function wasm offset.
59
+ // this is not good code and is somewhat duplicated
60
+ // I just want it to work for debugging, I don't care about perf/yes
61
+
62
+ const func = funcs.find(x => x.index === funcInd);
63
+ const locals = Object.values(func.locals).sort((a, b) => a.idx - b.idx).slice(func.params.length).sort((a, b) => a.idx - b.idx);
64
+
65
+ let localDecl = [], typeCount = 0, lastType;
66
+ for (let i = 0; i < locals.length; i++) {
67
+ const local = locals[i];
68
+ if (i !== 0 && local.type !== lastType) {
69
+ localDecl.push(encodeLocal(typeCount, lastType));
70
+ typeCount = 0;
71
+ }
72
+
73
+ typeCount++;
74
+ lastType = local.type;
75
+ }
76
+
77
+ if (typeCount !== 0) localDecl.push(encodeLocal(typeCount, lastType));
78
+
79
+ const toFind = encodeVector(localDecl).concat(func.wasm.flat().filter(x => x != null && x <= 0xff).slice(0, 40));
80
+
81
+ let i = 0;
82
+ for (; i < wasm.length; i++) {
83
+ let mismatch = false;
84
+ for (let j = 0; j < toFind.length; j++) {
85
+ if (wasm[i + j] !== toFind[j]) {
86
+ mismatch = true;
87
+ break;
88
+ }
89
+ }
90
+
91
+ if (!mismatch) break;
92
+ }
93
+
94
+ if (i === wasm.length) throw e;
95
+
96
+ const offset = (blobOffset - i) + encodeVector(localDecl).length;
97
+
98
+ let cumLen = 0;
99
+ i = 0;
100
+ for (; i < func.wasm.length; i++) {
101
+ cumLen += func.wasm[i].filter(x => x != null && x <= 0xff).length;
102
+ if (cumLen === offset) break;
103
+ }
104
+
105
+ if (cumLen !== offset) throw e;
106
+
107
+ i -= 1;
108
+
109
+ console.log(`\x1B[35m\x1B[1mporffor backtrace\u001b[0m`);
110
+
111
+ console.log('\x1B[4m' + func.name + '\x1B[0m');
112
+
113
+ const surrounding = 6;
114
+
115
+ const decomp = decompile(func.wasm.slice(i - surrounding, i + surrounding + 1), '', 0, func.locals, func.params, func.returns, funcs, globals, exceptions).slice(0, -1).split('\n');
116
+
117
+ const noAnsi = s => s.replace(/\u001b\[[0-9]+m/g, '');
118
+ let longest = 0;
119
+ for (let j = 0; j < decomp.length; j++) {
120
+ longest = Math.max(longest, noAnsi(decomp[j]).length);
44
121
  }
45
- });
122
+
123
+ const middle = Math.floor(decomp.length / 2);
124
+ decomp[middle] = `\x1B[47m\x1B[30m${noAnsi(decomp[middle])}${'\u00a0'.repeat(longest - noAnsi(decomp[middle]).length)}\x1B[0m`;
125
+
126
+ console.log('\x1B[90m...\x1B[0m');
127
+ console.log(decomp.join('\n'));
128
+ console.log('\x1B[90m...\x1B[0m\n');
129
+
130
+ throw e;
131
+ }
46
132
 
47
133
  times.push(performance.now() - t2);
48
134
  if (flags.includes('info')) console.log(`instantiated in ${times[1].toFixed(2)}ms`);
@@ -95,6 +181,13 @@ export default async (source, flags = [ 'module' ], customImports = {}, print =
95
181
  return Array.from(new Uint16Array(memory.buffer, pointer + 4, length)).map(x => String.fromCharCode(x)).join('');
96
182
  }
97
183
 
184
+ case '_bytestring': {
185
+ const pointer = ret;
186
+ const length = new Int32Array(memory.buffer, pointer, 1);
187
+
188
+ return Array.from(new Uint8Array(memory.buffer, pointer + 4, length)).map(x => String.fromCharCode(x)).join('');
189
+ }
190
+
98
191
  case 'function': {
99
192
  // wasm func index, including all imports
100
193
  const func = funcs.find(x => (x.originalIndex ?? x.index) === ret);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "porffor",
3
3
  "description": "a basic experimental wip aot optimizing js -> wasm engine/compiler/runtime in js",
4
- "version": "0.2.0-9ca9aed",
4
+ "version": "0.2.0-9f8ffb2",
5
5
  "author": "CanadaHonk",
6
6
  "license": "MIT",
7
7
  "dependencies": {
package/runner/repl.js CHANGED
@@ -45,9 +45,9 @@ let prev = '';
45
45
  const run = async (source, _context, _filename, callback, run = true) => {
46
46
  // hack: print "secret" before latest code ran to only enable printing for new code
47
47
 
48
- let toRun = prev + `;\nprint(-0x1337);\n` + source.trim();
48
+ let toRun = (prev ? (prev + `;\nprint(-0x1337);\n`) : '') + source.trim();
49
49
 
50
- let shouldPrint = false;
50
+ let shouldPrint = !prev;
51
51
  const { exports, wasm, pages } = await compile(toRun, [], {}, str => {
52
52
  if (shouldPrint) process.stdout.write(str);
53
53
  if (str === '-4919') shouldPrint = true;
package/tmp.c DELETED
@@ -1,71 +0,0 @@
1
-
2
- #include <stdio.h>
3
-
4
- struct ReturnValue {
5
- double value;
6
- long type;
7
- };
8
-
9
- double sum = 0;
10
- long sumdtype = 0;
11
- double counter = 0;
12
- long counterdtype = 0;
13
-
14
- double inline f64_f(double x, double y) {
15
- return (x - ((int)(x / y) * y));
16
- }
17
-
18
- struct ReturnValue isPrime(double number, long numberdtype) {
19
- double i = 0;
20
- long idtype = 0;
21
- double __tmpop_left = 0;
22
- double __tmpop_right = 0;
23
- long compare_left_pointer = 0;
24
- long compare_left_length = 0;
25
- long compare_right_pointer = 0;
26
- long compare_right_length = 0;
27
- long compare_index = 0;
28
- long compare_index_end = 0;
29
-
30
- if (number < 2e+0) {
31
- return (struct ReturnValue){ 1, 0e+0 };
32
- }
33
- i = 2e+0;
34
- idtype = 0;
35
- while (i < number) {
36
- if (f64_f(number, i) == 0e+0) {
37
- return (struct ReturnValue){ 1, 0e+0 };
38
- }
39
- i = i + 1e+0;
40
- }
41
- return (struct ReturnValue){ 1, 1e+0 };
42
- }
43
-
44
- double inline __console_log(double x) {
45
- printf("%f\n", x);
46
- printf("%c", (int)(1e+1));
47
- }
48
-
49
- int main() {
50
- long dlast_type = 0;
51
- double elogicinner_tmp = 0;
52
- long dtypeswitch_tmp = 0;
53
-
54
- sum = 0e+0;
55
- sumdtype = 0;
56
- counter = 0e+0;
57
- counterdtype = 0;
58
- while (counter <= 1e+5) {
59
- const struct ReturnValue _ = isPrime(counter, counterdtype);
60
- dlast_type = _.type;
61
- if ((unsigned long)(elogicinner_tmp = _.value) == 1e+0) {
62
- sum = sum + counter;
63
- sumdtype = 0;
64
- }
65
- counter = counter + 1e+0;
66
- }
67
- __console_log(sum);
68
-
69
- return 0;
70
- }
71
-