porffor 0.55.27 → 0.55.31

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.
@@ -3,7 +3,7 @@ import { number, ieee754_binary64, signedLEB128, unsignedLEB128, encodeVector, r
3
3
  import { operatorOpcode } from './expression.js';
4
4
  import { BuiltinFuncs, BuiltinVars, importedFuncs, NULL, UNDEFINED } from './builtins.js';
5
5
  import { PrototypeFuncs } from './prototype.js';
6
- import { TYPES, TYPE_FLAGS, TYPE_NAMES, typeHasFlag } from './types.js';
6
+ import { TYPES, TYPE_FLAGS, TYPE_NAMES } from './types.js';
7
7
  import * as Rhemyn from '../rhemyn/compile.js';
8
8
  import parse from './parse.js';
9
9
  import { log } from './log.js';
@@ -1505,7 +1505,18 @@ const setType = (scope, name, type, noInfer = false) => {
1505
1505
  };
1506
1506
 
1507
1507
  const getLastType = scope => {
1508
- if (!scope.locals['#last_type']) return [ number(TYPES.number, Valtype.i32) ];
1508
+ if (!scope.locals['#last_type']) return [
1509
+ [ null, () => {
1510
+ if (scope.locals['#last_type']) {
1511
+ scope.gotLastType = true;
1512
+ return [
1513
+ [ Opcodes.local_get, localTmp(scope, '#last_type', Valtype.i32) ]
1514
+ ];
1515
+ }
1516
+
1517
+ return [ number(TYPES.number, Valtype.i32) ];
1518
+ } ]
1519
+ ];
1509
1520
 
1510
1521
  scope.gotLastType = true;
1511
1522
  return [
@@ -1664,7 +1675,7 @@ const getNodeType = (scope, node) => {
1664
1675
 
1665
1676
  const objectKnownType = knownType(scope, getNodeType(scope, node.object));
1666
1677
  if (objectKnownType != null) {
1667
- if (name === 'length' && typeHasFlag(objectKnownType, TYPE_FLAGS.length)) return TYPES.number;
1678
+ if (name === 'length' && (objectKnownType & TYPE_FLAGS.length) !== 0) return TYPES.number;
1668
1679
 
1669
1680
  if (node.computed) {
1670
1681
  if (objectKnownType === TYPES.string) return TYPES.string;
@@ -3653,7 +3664,7 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
3653
3664
 
3654
3665
  const type = getNodeType(scope, decl.left.object);
3655
3666
  const known = knownType(scope, type);
3656
- if (known != null && typeHasFlag(known, TYPE_FLAGS.length)) return [
3667
+ if (known != null && (known & TYPE_FLAGS.length) !== 0) return [
3657
3668
  ...out,
3658
3669
  ...optional([ Opcodes.local_tee, pointerTmp ]),
3659
3670
 
@@ -5678,7 +5689,7 @@ const generateMember = (scope, decl, _global, _name) => {
5678
5689
 
5679
5690
  const type = getNodeType(scope, object);
5680
5691
  const known = knownType(scope, type);
5681
- if (known != null && typeHasFlag(known, TYPE_FLAGS.length)) return [
5692
+ if (known != null && (known & TYPE_FLAGS.length) !== 0) return [
5682
5693
  ...out,
5683
5694
 
5684
5695
  [ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
@@ -6655,6 +6666,7 @@ const generateFunc = (scope, decl, forceNoExpr = false) => {
6655
6666
  if (typedInput && decl.returnType) {
6656
6667
  const { type } = extractTypeAnnotation(decl.returnType);
6657
6668
  if (type != null) {
6669
+ typeUsed(func, type);
6658
6670
  func.returnType = type;
6659
6671
  func.returns = func.returnType === TYPES.undefined && !func.async && !func.generator ? [] : [ valtypeBinary ];
6660
6672
  }
@@ -1,6 +1,7 @@
1
1
  // cyclone: wasm partial constant evaluator (it is fast and dangerous hence "cyclone")
2
2
  import { number, signedLEB128, ieee754_binary64, read_ieee754_binary64, read_signedLEB128 } from './encoding.js';
3
3
  import { Opcodes, Valtype } from './wasmSpec.js';
4
+ import './prefs.js';
4
5
 
5
6
  const f64ToI32Op = {
6
7
  [Opcodes.f64_eq]: Opcodes.i32_eq,
@@ -15,8 +16,16 @@ const f64ToI32Op = {
15
16
  [Opcodes.f64_div]: Opcodes.i32_div_s,
16
17
  };
17
18
 
18
- export default wasm => {
19
- let stack = []; // """""stack"""""
19
+ export default ({ name, wasm, locals: _locals, params }) => {
20
+ let locals = Object.values(_locals);
21
+ const localValtypes = locals.map(x => x.type);
22
+
23
+ const resetLocals = () => {
24
+ locals = new Array(locals.length).fill(false);
25
+ };
26
+ resetLocals();
27
+
28
+ let stack = []; // "stack"
20
29
  for (let i = 0; i < wasm.length; i++) {
21
30
  let op = wasm[i];
22
31
  if (!op) continue;
@@ -33,8 +42,13 @@ export default wasm => {
33
42
  stack.push({ val, op });
34
43
  };
35
44
 
45
+ const peek = () => stack[stack.length - 1]?.val;
46
+ const popWithoutRemove = () => stack.pop().val;
47
+
48
+ // let debugPops = [];
36
49
  const pop = () => {
37
50
  const popped = stack.pop();
51
+ // debugPops.unshift({ ...popped, index: wasm.indexOf(popped.op) });
38
52
 
39
53
  // remove the op
40
54
  wasm.splice(wasm.indexOf(popped.op), 1);
@@ -42,12 +56,18 @@ export default wasm => {
42
56
 
43
57
  return popped.val;
44
58
  };
45
-
46
59
  const pop2 = () => [ pop(), pop() ];
47
60
 
48
61
  const bool = v => v ? 1 : 0;
49
62
 
50
63
  const replaceOp = newOp => {
64
+ // console.log(`\x1b[4m${name}\x1b[0m`);
65
+ // const oldOps = [ ...debugPops, { op, index: i + debugPops.length } ];
66
+ // for (const x of oldOps) {
67
+ // console.log(`\x1b[90m${x.index.toString().padStart(4)} ▌\x1b[0m ${disassemble([ x.op ], undefined, undefined, _locals).slice(0, -1)}${x.val != null ? ` \x1b[2m(${x.val})\x1b[0m` : ''}`);
68
+ // }
69
+ // process.stdout.write(`\x1b[s\x1b[${oldOps.length}A\x1b[40C\x1b[2m->\x1b[0m ${disassemble([ newOp ]).slice(0, -1)}\x1b[u\n`);
70
+
51
71
  op.splice(0, op.length, ...newOp);
52
72
  };
53
73
  const replaceVal = (val, valtype) => replaceOp(number(val, valtype));
@@ -57,41 +77,41 @@ export default wasm => {
57
77
  };
58
78
 
59
79
  switch (opcode) {
60
- case Opcodes.if: {
61
- if (stack.length < 1) { empty(); break; }
62
- const cond = bool(pop());
63
-
64
- // find else split and end
65
- let j = i + 1;
66
- let depth = 0, elseStart = 0;
67
- for (; j < wasm.length; j++) {
68
- const op = wasm[j][0];
69
- if (op === Opcodes.if || op === Opcodes.block || op === Opcodes.loop || op === Opcodes.try) depth++;
70
- if (op === Opcodes.else && depth === 0) elseStart = j;
71
- if (op === Opcodes.end) {
72
- depth--;
73
- if (depth < 0) break;
74
- }
75
- if (op === Opcodes.br || op === Opcodes.br_if) wasm[j][1] -= 1;
76
- }
77
-
78
- if (cond) {
79
- // remove else if it exists, or just remove end
80
- if (elseStart) wasm.splice(elseStart, j - elseStart + 1);
81
- else wasm.splice(j, 1);
82
- } else {
83
- // remove truthy conseq and keep else if it exists, or just remove entire thing
84
- if (elseStart) {
85
- wasm.splice(j, 1); // remove end
86
- wasm.splice(i + 1, elseStart - i + 1); // remove truthy conseq
87
- } else wasm.splice(i + 1, j - i + 0); // no else, remove entire if
88
- }
89
-
90
- // remove this if op
91
- wasm.splice(i, 1);
80
+ // case Opcodes.if: {
81
+ // if (stack.length < 1) { empty(); break; }
82
+ // const cond = bool(pop());
83
+
84
+ // // find else split and end
85
+ // let j = i + 1;
86
+ // let depth = 0, elseStart = 0;
87
+ // for (; j < wasm.length; j++) {
88
+ // const op = wasm[j][0];
89
+ // if (op === Opcodes.if || op === Opcodes.block || op === Opcodes.loop || op === Opcodes.try) depth++;
90
+ // if (op === Opcodes.else && depth === 0) elseStart = j;
91
+ // if (op === Opcodes.end) {
92
+ // depth--;
93
+ // if (depth < 0) break;
94
+ // }
95
+ // if (op === Opcodes.br || op === Opcodes.br_if) wasm[j][1] -= 1;
96
+ // }
97
+
98
+ // if (cond) {
99
+ // // remove else if it exists, or just remove end
100
+ // if (elseStart) wasm.splice(elseStart, j - elseStart + 1);
101
+ // else wasm.splice(j, 1);
102
+ // } else {
103
+ // // remove truthy conseq and keep else if it exists, or just remove entire thing
104
+ // if (elseStart) {
105
+ // wasm.splice(j, 1); // remove end
106
+ // wasm.splice(i + 1, elseStart - i + 1); // remove truthy conseq
107
+ // } else wasm.splice(i + 1, j - i + 0); // no else, remove entire if
108
+ // }
109
+
110
+ // // remove this if op
111
+ // wasm.splice(i, 1);
92
112
 
93
- break;
94
- }
113
+ // break;
114
+ // }
95
115
 
96
116
  case Opcodes.i32_const: {
97
117
  const n = read_signedLEB128(op.slice(1));
@@ -448,8 +468,8 @@ export default wasm => {
448
468
  break;
449
469
  }
450
470
 
451
- case Opcodes.f64_convert_i32_u:
452
- case Opcodes.f64_convert_i32_s: {
471
+ case Opcodes.f64_convert_i32_s:
472
+ case Opcodes.f64_convert_i32_u: {
453
473
  if (stack.length < 1) { empty(); break; };
454
474
  const v = pop();
455
475
 
@@ -458,7 +478,8 @@ export default wasm => {
458
478
  break;
459
479
  }
460
480
 
461
- case 0xfc02: { // i32_trunc_sat_f64_s
481
+ case 0xfc02: // i32.trunc_sat_f64_s
482
+ case 0xfc03: { // i32.trunc_sat_f64_u
462
483
  if (stack.length < 1) { empty(); break; }
463
484
  const v = pop();
464
485
 
@@ -467,20 +488,60 @@ export default wasm => {
467
488
  break;
468
489
  }
469
490
 
470
- case 0xfc03: { // i32_trunc_sat_f64_u
491
+ case Opcodes.drop: {
471
492
  if (stack.length < 1) { empty(); break; }
472
- const v = pop();
493
+ pop();
494
+ break;
495
+ }
473
496
 
474
- replaceVal(v, Valtype.i32);
475
- push(v);
497
+ case Opcodes.local_get: {
498
+ const x = locals[op[1]];
499
+ if (x === false) {
500
+ empty();
501
+ } else {
502
+ replaceVal(x, localValtypes[op[1]]);
503
+ push(x);
504
+ }
476
505
  break;
477
506
  }
478
507
 
479
- // case Opcodes.local_tee: {
480
- // if (stack.length < 1) { empty(); break; }
481
- // push(pop());
482
- // break;
483
- // }
508
+ case Opcodes.local_set: {
509
+ if (stack.length < 1) {
510
+ locals[op[1]] = false;
511
+ empty();
512
+ break;
513
+ }
514
+
515
+ const x = popWithoutRemove();
516
+ locals[op[1]] = x;
517
+ break;
518
+ }
519
+
520
+ case Opcodes.local_tee: {
521
+ if (stack.length < 1) {
522
+ locals[op[1]] = false;
523
+ empty();
524
+ break;
525
+ }
526
+
527
+ const x = pop();
528
+ locals[op[1]] = x;
529
+ replaceVal(x, localValtypes[op[1]]);
530
+ push(x);
531
+ break;
532
+ }
533
+
534
+ case Opcodes.block:
535
+ case Opcodes.loop:
536
+ case Opcodes.try:
537
+ case Opcodes.if:
538
+ case Opcodes.else:
539
+ case Opcodes.catch:
540
+ case Opcodes.end: {
541
+ resetLocals();
542
+ empty();
543
+ break;
544
+ }
484
545
 
485
546
  default: {
486
547
  empty();
@@ -500,69 +561,69 @@ export default wasm => {
500
561
  // i32.const 1
501
562
  // i32.add
502
563
  // local.set 7 ;; $i (i32)
503
- if (i >= 2 &&
504
- ((opcode >= 0xa0 && opcode <= 0xa3) || // main f64 math op
505
- (opcode >= 0x61 && opcode <= 0x66)) // main f64 eq op
506
- ) {
507
- const o2 = wasm[i - 1][0];
508
- if (o2 === Opcodes.f64_const) { // f64.const
509
- const o3 = wasm[i - 2][0];
510
- if (o3 === Opcodes.f64_convert_i32_s || o3 === Opcodes.f64_convert_i32_u) {
511
- // remove now unneeded i32 -> f64 convert
512
- wasm.splice(i - 2, 1);
513
- i--;
514
-
515
- // convert f64.const -> i32.const
516
- const n = wasm[i - 1][1];
517
- wasm.splice(i - 1, 1, number(n, Valtype.i32));
518
-
519
- // convert math op from f64 to i32
520
- wasm[i][0] = f64ToI32Op[wasm[i][0]];
521
-
522
- const nextOp = wasm[i + 1];
523
- if (nextOp && opcode >= 0xa0 && opcode <= 0xa3) {
524
- if (nextOp[0] === 0xfc && (nextOp[1] === 0x02 || nextOp[1] === 0x03)) {
525
- // remove optional unneeded f64 -> i32 convert after
526
- wasm.splice(i + 1, 1);
527
- } else {
528
- // add now needed i32 -> f64 convert after
529
- wasm.splice(i + 1, Opcodes.i32_trunc_sat_f64_s);
530
- }
531
- }
532
- }
533
- }
534
- }
535
-
536
- if ((opcode === 0xfc02 || opcode === 0xfc03) && i >= 3) { // i32.trunc_sat_f64_s/u
537
- const o2 = wasm[i - 1][0];
538
- if (
539
- (o2 >= 0xa0 && o2 <= 0xa3) || // main f64 math op
540
- (o2 >= 0x61 && o2 <= 0x66) // main f64 eq op
541
- ) {
542
- const o3 = wasm[i - 2][0];
543
- if (o3 === Opcodes.f64_const) { // f64.const
544
- const o4 = wasm[i - 3][0];
545
- if (o4 === Opcodes.f64_convert_i32_s || o4 === Opcodes.f64_convert_i32_u) {
546
- // remove now unneeded i32 -> f64 convert
547
- wasm.splice(i - 3, 1);
548
- i--;
549
- } else {
550
- // add now needed f64 -> i32 convert prior
551
- wasm.splice(i - 2, 0, Opcodes.i32_trunc_sat_f64_s);
552
- i++;
553
- }
554
-
555
- // convert f64.const -> i32.const
556
- const n = wasm[i - 2][1];
557
- wasm.splice(i - 2, 1, number(n, Valtype.i32));
558
-
559
- // convert math op from f64 to i32
560
- wasm[i - 1][0] = f64ToI32Op[wasm[i - 1][0]];
561
-
562
- // remove this now unneeded f64 -> i32 convert
563
- wasm.splice(i, 1);
564
- }
565
- }
566
- }
564
+ // if (i >= 2 &&
565
+ // ((opcode >= 0xa0 && opcode <= 0xa3) || // main f64 math op
566
+ // (opcode >= 0x61 && opcode <= 0x66)) // main f64 eq op
567
+ // ) {
568
+ // const o2 = wasm[i - 1][0];
569
+ // if (o2 === Opcodes.f64_const) { // f64.const
570
+ // const o3 = wasm[i - 2][0];
571
+ // if (o3 === Opcodes.f64_convert_i32_s || o3 === Opcodes.f64_convert_i32_u) {
572
+ // // remove now unneeded i32 -> f64 convert
573
+ // wasm.splice(i - 2, 1);
574
+ // i--;
575
+
576
+ // // convert f64.const -> i32.const
577
+ // const n = wasm[i - 1][1];
578
+ // wasm.splice(i - 1, 1, number(n, Valtype.i32));
579
+
580
+ // // convert math op from f64 to i32
581
+ // wasm[i][0] = f64ToI32Op[wasm[i][0]];
582
+
583
+ // const nextOp = wasm[i + 1];
584
+ // if (nextOp && opcode >= 0xa0 && opcode <= 0xa3) {
585
+ // if (nextOp[0] === 0xfc && (nextOp[1] === 0x02 || nextOp[1] === 0x03)) {
586
+ // // remove optional unneeded f64 -> i32 convert after
587
+ // wasm.splice(i + 1, 1);
588
+ // } else {
589
+ // // add now needed i32 -> f64 convert after
590
+ // wasm.splice(i + 1, Opcodes.i32_trunc_sat_f64_s);
591
+ // }
592
+ // }
593
+ // }
594
+ // }
595
+ // }
596
+
597
+ // if ((opcode === 0xfc02 || opcode === 0xfc03) && i >= 3) { // i32.trunc_sat_f64_s/u
598
+ // const o2 = wasm[i - 1][0];
599
+ // if (
600
+ // (o2 >= 0xa0 && o2 <= 0xa3) || // main f64 math op
601
+ // (o2 >= 0x61 && o2 <= 0x66) // main f64 eq op
602
+ // ) {
603
+ // const o3 = wasm[i - 2][0];
604
+ // if (o3 === Opcodes.f64_const) { // f64.const
605
+ // const o4 = wasm[i - 3][0];
606
+ // if (o4 === Opcodes.f64_convert_i32_s || o4 === Opcodes.f64_convert_i32_u) {
607
+ // // remove now unneeded i32 -> f64 convert
608
+ // wasm.splice(i - 3, 1);
609
+ // i--;
610
+ // } else {
611
+ // // add now needed f64 -> i32 convert prior
612
+ // wasm.splice(i - 2, 0, Opcodes.i32_trunc_sat_f64_s);
613
+ // i++;
614
+ // }
615
+
616
+ // // convert f64.const -> i32.const
617
+ // const n = wasm[i - 2][1];
618
+ // wasm.splice(i - 2, 1, number(n, Valtype.i32));
619
+
620
+ // // convert math op from f64 to i32
621
+ // wasm[i - 1][0] = f64ToI32Op[wasm[i - 1][0]];
622
+
623
+ // // remove this now unneeded f64 -> i32 convert
624
+ // wasm.splice(i, 1);
625
+ // }
626
+ // }
627
+ // }
567
628
  }
568
629
  };
@@ -18,7 +18,7 @@ export default (wasm, name = '', ind = 0, locals = {}, params = [], returns = []
18
18
  }
19
19
 
20
20
  return `(${params.map((x, i) => invValtype[x]).join(', ')}) -> (${returns.map(x => invValtype[x]).join(', ')})`;
21
- }
21
+ };
22
22
 
23
23
  let out = '', depth = 0;
24
24
  if (name) out += `${name}(${ind}) ${makeSignature(params, returns, locals)}\n`;
package/compiler/index.js CHANGED
@@ -132,9 +132,9 @@ export default (code, module = undefined) => {
132
132
 
133
133
  for (const x of funcs) {
134
134
  const preOps = x.wasm.length;
135
- cyclone(x.wasm);
135
+ cyclone(x);
136
136
 
137
- console.log(`${x.name}: ${preOps} -> ${x.wasm.length} ops`);
137
+ if (preOps !== x.wasm.length) console.log(`${x.name}: ${preOps} -> ${x.wasm.length} ops`);
138
138
  }
139
139
  opt(funcs, globals, pages, tags, exceptions);
140
140
 
@@ -144,7 +144,7 @@ export default (code, module = undefined) => {
144
144
  console.log(`cyclone size diff: ${oldSize - newSize} bytes (${oldSize} -> ${newSize})\n`);
145
145
  } else {
146
146
  for (const x of funcs) {
147
- cyclone(x.wasm);
147
+ cyclone(x);
148
148
  }
149
149
  }
150
150
  }
package/compiler/types.js CHANGED
@@ -30,10 +30,7 @@ export const TYPE_NAMES = {
30
30
  [TYPES.bigint]: 'BigInt'
31
31
  };
32
32
 
33
- export const typeHasFlag = (type, flag) => (type & flag) !== 0;
34
-
35
- export const INTERNAL_TYPE_BASE = 0x10;
36
- let internalTypeIndex = INTERNAL_TYPE_BASE;
33
+ let internalTypeIndex = TYPES.object + 1;
37
34
  const registerInternalType = (name, flags = [], overrideType = undefined) => {
38
35
  let n = overrideType ?? internalTypeIndex++;
39
36
 
@@ -72,12 +69,13 @@ registerInternalType('BooleanObject');
72
69
  registerInternalType('NumberObject');
73
70
  registerInternalType('StringObject');
74
71
 
75
- for (const x of [ '', 'Aggregate', 'Type', 'Reference', 'Syntax', 'Range', 'Eval', 'URI', 'Test262', 'Todo' ])
76
- registerInternalType(`${x}Error`);
77
-
78
72
  registerInternalType('__Porffor_Generator');
79
73
  registerInternalType('__Porffor_AsyncGenerator');
80
74
 
75
+ // from here, remapped object types only
76
+ for (const x of [ '', 'Aggregate', 'Type', 'Reference', 'Syntax', 'Range', 'Eval', 'URI', 'Test262' ])
77
+ registerInternalType(`${x}Error`);
78
+
81
79
  if (Prefs.largestTypes) {
82
80
  const typeKeys = Object.keys(TYPES);
83
81
  const typeVals = Object.values(TYPES);
@@ -88,11 +86,11 @@ if (Prefs.largestTypes) {
88
86
  return [ val, key ];
89
87
  };
90
88
 
91
- const unflag = val => val & 0b00111111;
92
-
93
89
  const logType = (label, val, key) => console.log(`${label} ${key} - ${val} (0x${val.toString(16)}, 0b${val.toString(2).padStart(8, '0')})`);
94
90
 
95
- logType(`largest type: `, ...largestType(typeVals.map(unflag), typeKeys));
91
+ const largestUnflagged = largestType(typeVals.map(x => x & 0b00111111), typeKeys);
92
+ logType(`largest type: `, ...largestUnflagged);
96
93
  logType(`largest type w/ flags:`, ...largestType(typeVals, typeKeys));
94
+ console.log('types left:', 0b00111111 - largestUnflagged[0]);
97
95
  console.log();
98
96
  }
package/compiler/wrap.js CHANGED
@@ -311,8 +311,7 @@ ${flags & 0b0001 ? ` get func idx: ${get}
311
311
  case TYPES.rangeerror:
312
312
  case TYPES.evalerror:
313
313
  case TYPES.urierror:
314
- case TYPES.test262error:
315
- case TYPES.todoerror: {
314
+ case TYPES.test262error: {
316
315
  const obj = porfToJSValue({ memory, funcs, pages }, value, TYPES.object);
317
316
  const err = new (globalThis[TYPE_NAMES[type]] ?? Error)(obj.message);
318
317
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "porffor",
3
3
  "description": "An ahead-of-time JavaScript compiler",
4
- "version": "0.55.27",
4
+ "version": "0.55.31",
5
5
  "author": "Oliver Medhurst <honk@goose.icu>",
6
6
  "license": "MIT",
7
7
  "scripts": {},