porffor 0.50.26 → 0.50.28

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 CHANGED
@@ -291,7 +291,7 @@ i32.eq
291
291
  i32.and
292
292
  ```
293
293
 
294
- This part is a little more complicated, first you have to understand how Wasm represents function parameters and local variables in general. When looking at the decompiled output of something like `let a = 1;`, you'll likely see something like this:
294
+ This part is a little more complicated, first you have to understand how Wasm represents function parameters and local variables in general. When looking at the disassembled output of something like `let a = 1;`, you'll likely see something like this:
295
295
  ```
296
296
  f64.const 1
297
297
  i32.const 1
package/README.md CHANGED
@@ -107,7 +107,7 @@ Porffor can run Test262 via some hacks/transforms which remove unsupported featu
107
107
  - `builtins_precompiled.js`: dynamically generated builtins from the `builtins/` folder
108
108
  - `codegen.js`: code (wasm) generation, ast -> wasm. The bulk of the effort
109
109
  - `cyclone.js`: wasm partial constant evaluator (it is fast and dangerous hence "cyclone")
110
- - `decompile.js`: basic wasm decompiler for debug info
110
+ - `disassemble.js`: wasm disassembler using internal debug info
111
111
  - `embedding.js`: utils for embedding consts
112
112
  - `encoding.js`: utils for encoding things as bytes as wasm expects
113
113
  - `expression.js`: mapping most operators to an opcode (advanced are as built-ins eg `f64_%`)
@@ -1,5 +1,5 @@
1
1
  import { Valtype, FuncType, ExportDesc, Section, Magic, Opcodes, PageSize, Reftype } from './wasmSpec.js';
2
- import { encodeVector, encodeString, encodeLocal, unsignedLEB128, signedLEB128, unsignedLEB128_into, signedLEB128_into, ieee754_binary64, ieee754_binary64_into, unsignedLEB128_length } from './encoding.js';
2
+ import { encodeVector, encodeString, unsignedLEB128, signedLEB128, unsignedLEB128_into, signedLEB128_into, ieee754_binary64, ieee754_binary64_into, unsignedLEB128_length } from './encoding.js';
3
3
  import { importedFuncs } from './builtins.js';
4
4
  import { log } from './log.js';
5
5
  import './prefs.js';
@@ -364,13 +364,13 @@ export const BuiltinFuncs = function() {
364
364
  const prngSeed0 = (Math.random() * (2 ** 30)) | 0, prngSeed1 = (Math.random() * (2 ** 30)) | 0;
365
365
 
366
366
  const prng = ({
367
- 'lcg32_glibc': {
367
+ 'lcg32': {
368
368
  globals: [ Valtype.i32 ],
369
369
  locals: [],
370
370
  returns: Valtype.i32,
371
371
  wasm: [
372
+ // use glibc/musl's constants
372
373
  // seed = (MULTIPLIER * seed + INCREMENT) % MODULUS
373
- // MULTIPLIER * state0
374
374
  [ Opcodes.global_get, 0 ],
375
375
  number(1103515245, Valtype.i32),
376
376
  [ Opcodes.i32_mul ],
@@ -380,30 +380,8 @@ export const BuiltinFuncs = function() {
380
380
  [ Opcodes.i32_add ],
381
381
 
382
382
  // % MODULUS
383
- number(2 ** 31, Valtype.i32),
384
- [ Opcodes.i32_rem_s ],
385
-
386
- // state0 =
387
- [ Opcodes.global_set, 0 ],
388
-
389
- // state0
390
- [ Opcodes.global_get, 0 ],
391
- ],
392
- },
393
- 'lcg32_minstd': {
394
- globals: [ Valtype.i32 ],
395
- locals: [],
396
- returns: Valtype.i32,
397
- wasm: [
398
- // seed = (MULTIPLIER * seed + INCREMENT) % MODULUS
399
- // MULTIPLIER * state0
400
- [ Opcodes.global_get, 0 ],
401
- number(48271, Valtype.i32),
402
- [ Opcodes.i32_mul ],
403
-
404
- // % MODULUS
405
- number((2 ** 31) - 1, Valtype.i32),
406
- [ Opcodes.i32_rem_s ],
383
+ number(0x7fffffff, Valtype.i32),
384
+ [ Opcodes.i32_and ],
407
385
 
408
386
  // state0 =
409
387
  [ Opcodes.global_set, 0 ],
@@ -412,7 +390,6 @@ export const BuiltinFuncs = function() {
412
390
  [ Opcodes.global_get, 0 ],
413
391
  ],
414
392
  },
415
- 'lcg64_musl': 0, // todo
416
393
 
417
394
  'xorshift32+': {
418
395
  globals: [ Valtype.i32 ],
@@ -485,11 +462,6 @@ export const BuiltinFuncs = function() {
485
462
  // state0 = s1
486
463
  [ Opcodes.global_set, 0 ],
487
464
 
488
- // // s1 * 0x2545F4914F6CDD1D
489
- // [ Opcodes.local_get, 0 ],
490
- // [ Opcodes.i64_const, 0x9d, 0xba, 0xb3, 0xfb, 0x94, 0x92, 0xfd, 0xa2, 0x25 ],
491
- // [ Opcodes.i64_mul ]
492
-
493
465
  // s1
494
466
  [ Opcodes.local_get, 0 ],
495
467
  ],
@@ -49,7 +49,7 @@ export default (wasm, name = '', ind = 0, locals = {}, params = [], returns = []
49
49
 
50
50
  let opStr = invOpcodes[inst[0]];
51
51
  if (!opStr) {
52
- console.log(`decomp: unknown op ${inst[0]?.toString?.(16)} @${i}`);
52
+ console.log(`disasm: unknown op ${inst[0]?.toString?.(16)} @${i}`);
53
53
  // console.log(`prior: ${invOpcodes[wasm[i - 1][0]]}`);
54
54
  out += `;; unknown op ${inst[0]?.toString?.(16)}\n`;
55
55
  continue;
@@ -10,15 +10,8 @@ export const codifyString = str => {
10
10
  export const encodeString = str => unsignedLEB128(str.length).concat(codifyString(str));
11
11
  export const encodeVector = data => unsignedLEB128(data.length).concat(data.flat());
12
12
 
13
- export const encodeLocal = (count, type) => [
14
- ...unsignedLEB128(count),
15
- type
16
- ];
17
-
18
13
  // todo: this only works with integers within 32 bit range
19
14
  export const signedLEB128 = n => {
20
- if (typeof n === 'bigint') return big_signedLEB128(n);
21
-
22
15
  n |= 0;
23
16
 
24
17
  // just input for small numbers (for perf as common)
@@ -45,8 +38,6 @@ export const signedLEB128 = n => {
45
38
  };
46
39
 
47
40
  export const unsignedLEB128 = n => {
48
- if (typeof n === 'bigint') return big_unsignedLEB128(n);
49
-
50
41
  n |= 0;
51
42
 
52
43
  // just input for small numbers (for perf as common)
@@ -217,5 +208,4 @@ export const unsignedLEB128_into = (n, buffer) => {
217
208
  export const ieee754_binary64_into = (value, buffer) => {
218
209
  const data = new Uint8Array(new Float64Array([ value ]).buffer);
219
210
  for (let i = 0; i < 8; i++) buffer.push(data[i]);
220
- // buffer.push(...new Uint8Array(new Float64Array([ value ]).buffer));
221
211
  };
package/compiler/index.js CHANGED
@@ -4,21 +4,23 @@ import parse from './parse.js';
4
4
  import codegen from './codegen.js';
5
5
  import opt from './opt.js';
6
6
  import assemble from './assemble.js';
7
- import decompile from './decompile.js';
7
+ import disassemble from './disassemble.js';
8
8
  import toc from './2c.js';
9
9
  import * as pgo from './pgo.js';
10
10
  import cyclone from './cyclone.js';
11
11
  import './prefs.js';
12
12
 
13
- globalThis.decompile = decompile;
13
+ globalThis.disassemble = disassemble;
14
14
 
15
15
  const logFuncs = (funcs, globals, exceptions) => {
16
16
  console.log('\n' + underline(bold('funcs')));
17
17
 
18
- const wanted = Prefs.f;
18
+ let wanted = Prefs.f;
19
+ if (typeof wanted !== 'string') wanted = null;
20
+
19
21
  for (const f of funcs) {
20
22
  if ((wanted && f.name !== wanted) || (!wanted && f.internal)) continue;
21
- console.log(decompile(f.wasm, f.name, f.index, f.locals, f.params, f.returns, funcs, globals, exceptions));
23
+ console.log(disassemble(f.wasm, f.name, f.index, f.locals, f.params, f.returns, funcs, globals, exceptions));
22
24
  }
23
25
 
24
26
  console.log();
@@ -75,7 +77,7 @@ export default (code, module = undefined) => {
75
77
 
76
78
  // change some prefs by default for c/native
77
79
  if (target !== 'wasm') {
78
- Prefs.pgo = Prefs.pgo === false || globalThis.document ? false : true; // enable pgo
80
+ // Prefs.pgo = Prefs.pgo === false || globalThis.document ? false : true; // enable pgo by default
79
81
  Prefs.passiveData = false; // disable using passive Wasm data as unsupported by 2c for now
80
82
  }
81
83
 
package/compiler/parse.js CHANGED
@@ -3,13 +3,11 @@ import './prefs.js';
3
3
 
4
4
  const file = globalThis.file;
5
5
 
6
- // should we try to support types (while parsing)
7
6
  const types = Prefs.parseTypes || Prefs.t || file?.endsWith('.ts');
8
7
  globalThis.typedInput = types && Prefs.optTypes;
9
8
 
10
- // todo: review which to use by default
11
9
  // supported parsers:
12
- // - acorn
10
+ // - acorn (default)
13
11
  // - meriyah
14
12
  // - hermes-parser
15
13
  // - @babel/parser
package/compiler/wrap.js CHANGED
@@ -1,7 +1,7 @@
1
- import { encodeVector, encodeLocal } from './encoding.js';
1
+ import { encodeVector } from './encoding.js';
2
2
  import { importedFuncs } from './builtins.js';
3
3
  import compile from './index.js';
4
- import decompile from './decompile.js';
4
+ import disassemble from './disassemble.js';
5
5
  import { TYPES, TYPE_NAMES } from './types.js';
6
6
  import { log } from './log.js';
7
7
  import './prefs.js';
@@ -352,7 +352,7 @@ export default (source, module = undefined, customImports = {}, print = str => p
352
352
  times.push(performance.now() - t1);
353
353
  if (Prefs.profileCompiler && !globalThis.onProgress) console.log(`\u001b[1mcompiled in ${times[0].toFixed(2)}ms\u001b[0m`);
354
354
 
355
- const printDecomp = (middleIndex, func, funcs, globals, exceptions) => {
355
+ const printBacktrace = (middleIndex, func, funcs, globals, exceptions) => {
356
356
  console.log(`\x1B[35m\x1B[1mporffor backtrace\u001b[0m`);
357
357
 
358
358
  const surrounding = Prefs.backtraceSurrounding ?? 10;
@@ -363,22 +363,22 @@ export default (source, module = undefined, customImports = {}, print = str => p
363
363
  max = func.wasm.length;
364
364
  }
365
365
 
366
- const decomp = decompile(func.wasm.slice(min, max), func.name, 0, func.locals, func.params, func.returns, funcs, globals, exceptions)
366
+ const disasm = disassemble(func.wasm.slice(min, max), func.name, 0, func.locals, func.params, func.returns, funcs, globals, exceptions)
367
367
  .slice(0, -1).split('\n').filter(x => !x.startsWith('\x1B[90m;;'));
368
368
 
369
369
  const noAnsi = s => s.replace(/\u001b\[[0-9]+m/g, '');
370
370
  let longest = 0;
371
- for (let j = 0; j < decomp.length; j++) {
372
- longest = Math.max(longest, noAnsi(decomp[j]).length);
371
+ for (let j = 0; j < disassemble.length; j++) {
372
+ longest = Math.max(longest, noAnsi(disassemble[j]).length);
373
373
  }
374
374
 
375
375
  if (middleIndex != -1) {
376
- const middle = Math.floor(decomp.length / 2);
377
- decomp[middle] = `\x1B[47m\x1B[30m${noAnsi(decomp[middle])}${'\u00a0'.repeat(longest - noAnsi(decomp[middle]).length)}\x1B[0m`;
376
+ const middle = Math.floor(disasm.length / 2);
377
+ disasm[middle] = `\x1B[47m\x1B[30m${noAnsi(disasm[middle])}${'\u00a0'.repeat(longest - noAnsi(disasm[middle]).length)}\x1B[0m`;
378
378
  }
379
379
 
380
380
  if (min != 0) console.log('\x1B[90m...\x1B[0m');
381
- console.log(decomp.join('\n'));
381
+ console.log(disasm.join('\n'));
382
382
  if (max > func.wasm.length) console.log('\x1B[90m...\x1B[0m\n');
383
383
  };
384
384
 
@@ -407,7 +407,7 @@ export default (source, module = undefined, customImports = {}, print = str => p
407
407
  }
408
408
 
409
409
  if (i === wasm.length) {
410
- printDecomp(-1, func, funcs, globals, exceptions);
410
+ printBacktrace(-1, func, funcs, globals, exceptions);
411
411
  return false;
412
412
  }
413
413
 
@@ -421,11 +421,11 @@ export default (source, module = undefined, customImports = {}, print = str => p
421
421
  }
422
422
 
423
423
  if (cumLen !== offset) {
424
- printDecomp(-1, func, funcs, globals, exceptions);
424
+ printBacktrace(-1, func, funcs, globals, exceptions);
425
425
  return false;
426
426
  }
427
427
 
428
- printDecomp(i + 1, func, funcs, globals, exceptions);
428
+ printBacktrace(i + 1, func, funcs, globals, exceptions);
429
429
  return true;
430
430
  };
431
431
 
@@ -433,13 +433,6 @@ export default (source, module = undefined, customImports = {}, print = str => p
433
433
 
434
434
  let instance;
435
435
  try {
436
- // let wasmEngine = WebAssembly;
437
- // if (Prefs.asur) {
438
- // log.warning('wrap', 'using our !experimental! asur wasm engine instead of host to run');
439
- // wasmEngine = await import('../asur/index.js');
440
- // }
441
-
442
- // 0, { instance } = await wasmEngine.instantiate(wasm, {
443
436
  const module = new WebAssembly.Module(wasm);
444
437
  instance = new WebAssembly.Instance(module, {
445
438
  '': {
@@ -543,8 +536,8 @@ export default (source, module = undefined, customImports = {}, print = str => p
543
536
  };
544
537
  }
545
538
 
546
- if (Prefs.decomp) {
547
- return { exports, wasm, times, decomps: funcs.map(x => decompile(x.wasm, x.name, x.index, x.locals, x.params, x.returns, funcs, globals, exceptions)), c };
539
+ if (Prefs.disassemble) {
540
+ return { exports, wasm, times, disams: funcs.map(x => disassemble(x.wasm, x.name, x.index, x.locals, x.params, x.returns, funcs, globals, exceptions)), c };
548
541
  }
549
542
 
550
543
  return { exports, wasm, times, pages, c };
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.50.26",
4
+ "version": "0.50.28",
5
5
  "author": "CanadaHonk",
6
6
  "license": "MIT",
7
7
  "scripts": {},
package/rhemyn/compile.js CHANGED
@@ -92,7 +92,7 @@ const generate = (node, negated = false, get = true, stringSize = 2, func = 'tes
92
92
  const underline = x => `\u001b[4m\u001b[1m${x}\u001b[0m`;
93
93
  console.log(`\n${underline('ast')}`);
94
94
  console.log(node);
95
- console.log(`\n${underline('wasm bytecode')}\n` + decompile(out) + '\n');
95
+ console.log(`\n${underline('wasm bytecode')}\n` + disassemble(out) + '\n');
96
96
  }
97
97
 
98
98
  break;
package/runner/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import fs from 'node:fs';
3
- globalThis.version = '0.50.26';
3
+ globalThis.version = '0.50.28';
4
4
 
5
5
  // deno compat
6
6
  if (typeof process === 'undefined' && typeof Deno !== 'undefined') {
@@ -11,7 +11,7 @@ const start = performance.now();
11
11
 
12
12
  if (process.argv.includes('--help')) {
13
13
  // description + version
14
- console.log(`\x1B[1m\x1B[35mPorffor\x1B[0m is a JavaScript/TypeScript engine/compiler/runtime. \x1B[90m(${globalThis.version})\x1B[0m`);
14
+ console.log(`\x1B[1m\x1B[35mPorffor\x1B[0m is a JavaScript/TypeScript engine/compiler/runtime. \x1B[2m(${globalThis.version})\x1B[0m`);
15
15
 
16
16
  // basic usage
17
17
  console.log(`Usage: \x1B[1mporf <command> [...prefs] path/to/script.js [...args]\x1B[0m`);
@@ -43,6 +43,43 @@ if (process.argv.includes('--help')) {
43
43
  console.log(` \x1B[90mporf\x1B[0m \x1B[1m\x1B[${color}m${cmd}\x1B[0m\x1B[2m${post}\x1B[0m ${' '.repeat(30 - cmd.length - post.length)}${desc}`);
44
44
  }
45
45
 
46
+ // flags
47
+ console.log(`\n\x1B[1m\x1B[4mFlags\x1B[0m`);
48
+ for (let [ flag, desc ] of Object.entries({
49
+ module: 'Parse input as a module',
50
+ t: 'Force TypeScript input',
51
+ d: 'Debug mode (include names in Wasm and debug logs)'
52
+ })) {
53
+ flag = '-' + flag;
54
+ if (flag.length > 3) flag = '-' + flag;
55
+
56
+ console.log(` \x1B[1m${flag}\x1B[0m${' '.repeat(36 - flag.length)}${desc}`);
57
+ }
58
+
59
+ // niche flags
60
+ if (process.argv.includes('--flags')) {
61
+ for (let [ flag, desc ] of Object.entries({
62
+ f: 'Print disassembled Wasm generated from user functions',
63
+ pgo: 'Enable PGO (profile-guided optimization)',
64
+ 'profile-compiler': 'Log general compiler performance (on by default when compiling to a file)',
65
+ valtype: 'Valtype to use (i32|i64|\x1B[1mf64\x1B[0m)',
66
+ prng: 'PRNG algorithm to use (lcg32|xorshift32+|xorshift64+|\x1B[1mxorshift128+\x1B[0m|xoroshiro128+|xoshiro128+)',
67
+ allocator: 'Allocator to use (oneshot|\x1B[1mchunk\x1B[0m)',
68
+ 'exception-mode': 'Exception mode to use (lut|\x1B[1mstack\x1B[0m)',
69
+ fastLength: 'Spec non-compliant optimization to make .length faster',
70
+ 'no-coctc': 'Disable COCTC (cross-object compile-time cache)',
71
+ cyclone: 'Enable experimental Cyclone optimizer',
72
+ 'no-treeshake-wasm-imports': 'Do not treeshake Wasm imports'
73
+ })) {
74
+ flag = '-' + flag;
75
+ if (flag.length > 3) flag = '-' + flag;
76
+
77
+ console.log(` \x1B[1m${flag}\x1B[0m${' '.repeat(36 - flag.length)}${desc}`);
78
+ }
79
+ } else {
80
+ console.log(` \x1B[2m(To view all flags use --flags)\x1B[0m`);
81
+ }
82
+
46
83
  console.log();
47
84
  process.exit(0);
48
85
  }
package/runner/repl.js CHANGED
@@ -137,7 +137,7 @@ replServer.defineCommand('memory', {
137
137
  }
138
138
  });
139
139
  replServer.defineCommand('asm', {
140
- help: 'Log Wasm decompiled bytecode',
140
+ help: 'Log Wasm disassembled bytecode',
141
141
  action() {
142
142
  this.clearBufferedCommand();
143
143