porffor 0.34.5 → 0.34.6

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.
@@ -615,148 +615,22 @@ const concatStrings = (scope, left, right, leftType, rightType, allBytestrings =
615
615
  ];
616
616
  };
617
617
 
618
- const compareStrings = (scope, left, right, leftType, rightType, allBytestrings = false, skipTypeCheck = false) => {
619
- // todo: this should be rewritten into a func
620
- // todo: convert left and right to strings if not
621
- // todo: optimize by looking up names in arrays and using that if exists?
622
- // todo: optimize this if using literals/known lengths?
623
-
624
- const leftPointer = localTmp(scope, 'compare_left_pointer', Valtype.i32);
625
- const leftLength = localTmp(scope, 'compare_left_length', Valtype.i32);
626
- const rightPointer = localTmp(scope, 'compare_right_pointer', Valtype.i32);
627
-
628
- const index = localTmp(scope, 'compare_index', Valtype.i32);
629
- const indexEnd = localTmp(scope, 'compare_index_end', Valtype.i32);
630
-
631
- if (!skipTypeCheck && !allBytestrings) includeBuiltin(scope, '__Porffor_bytestringToString');
618
+ const compareStrings = (scope, left, right, leftType, rightType) => {
619
+ // todo/perf: add mode to use strcmp instead
632
620
  return [
633
- // setup pointers
634
- ...(left.length === 0 ? [
635
- Opcodes.i32_to_u,
636
- [ Opcodes.local_set, rightPointer ],
637
-
638
- Opcodes.i32_to_u,
639
- [ Opcodes.local_set, leftPointer ],
640
-
641
- [ Opcodes.local_get, leftPointer ],
642
- [ Opcodes.local_get, rightPointer ],
643
- ] : [
644
- ...left,
645
- Opcodes.i32_to_u,
646
- [ Opcodes.local_tee, leftPointer ],
647
-
648
- ...right,
649
- Opcodes.i32_to_u,
650
- [ Opcodes.local_tee, rightPointer ],
651
- ]),
652
-
653
- // fast path: check leftPointer == rightPointer
654
- // use if (block) for everything after to "return" a value early
655
- [ Opcodes.i32_ne ],
656
- [ Opcodes.if, Valtype.i32 ],
657
-
658
- // get lengths
659
- [ Opcodes.local_get, leftPointer ],
660
- [ Opcodes.i32_load, 0, 0 ],
661
- [ Opcodes.local_tee, leftLength ],
662
-
663
- [ Opcodes.local_get, rightPointer ],
664
- [ Opcodes.i32_load, 0, 0 ],
665
-
666
- ...(skipTypeCheck || allBytestrings ? [] : [
667
- ...leftType,
668
- ...number(TYPES.bytestring, Valtype.i32),
669
- [ Opcodes.i32_eq ],
670
- [ Opcodes.if, Blocktype.void ],
671
- [ Opcodes.local_get, leftPointer ],
672
- [ Opcodes.local_get, leftLength ],
673
- [ Opcodes.call, funcIndex.__Porffor_bytestringToString ],
674
- [ Opcodes.local_set, leftPointer ],
675
- [ Opcodes.end ],
676
-
677
- ...rightType,
678
- ...number(TYPES.bytestring, Valtype.i32),
679
- [ Opcodes.i32_eq ],
680
- [ Opcodes.if, Blocktype.void ],
681
- [ Opcodes.local_get, rightPointer ],
682
- [ Opcodes.local_get, rightPointer ],
683
- [ Opcodes.i32_load, 0, 0 ],
684
- [ Opcodes.call, funcIndex.__Porffor_bytestringToString ],
685
- [ Opcodes.local_set, rightPointer ],
686
- [ Opcodes.end ]
687
- ]),
688
-
689
- // fast path: check leftLength != rightLength
690
- [ Opcodes.i32_ne ],
691
- [ Opcodes.if, Blocktype.void ],
692
- ...number(0, Valtype.i32),
693
- [ Opcodes.br, 1 ],
694
- [ Opcodes.end ],
695
-
696
- // no fast path for length = 0 as it would probably be slower for most of the time?
697
-
698
- // tmp could have already been used
699
- ...number(0, Valtype.i32),
700
- [ Opcodes.local_set, index ],
701
-
702
- // setup index end as length * sizeof valtype (1 for bytestring, 2 for string)
703
- // we do this instead of having to do mul/div each iter for perf™
704
- [ Opcodes.local_get, leftLength ],
705
- ...(allBytestrings ? [] : [
706
- ...number(ValtypeSize.i16, Valtype.i32),
707
- [ Opcodes.i32_mul ],
708
- ]),
709
- [ Opcodes.local_set, indexEnd ],
710
-
711
- // iterate over each char and check if eq
712
- [ Opcodes.loop, Blocktype.void ],
713
-
714
- // fetch left
715
- [ Opcodes.local_get, index ],
716
- [ Opcodes.local_get, leftPointer ],
717
- [ Opcodes.i32_add ],
718
- allBytestrings ?
719
- [ Opcodes.i32_load8_u, 0, ValtypeSize.i32 ] :
720
- [ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],
721
-
722
- // fetch right
723
- [ Opcodes.local_get, index ],
724
- [ Opcodes.local_get, rightPointer ],
725
- [ Opcodes.i32_add ],
726
- allBytestrings ?
727
- [ Opcodes.i32_load8_u, 0, ValtypeSize.i32 ] :
728
- [ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],
729
-
730
- // not equal, "return" false
731
- [ Opcodes.i32_ne ],
732
- [ Opcodes.if, Blocktype.void ],
733
- ...number(0, Valtype.i32),
734
- [ Opcodes.br, 2 ],
735
- [ Opcodes.end ],
736
-
737
- // index += sizeof valtype (1 for bytestring, 2 for string)
738
- [ Opcodes.local_get, index ],
739
- ...number(allBytestrings ? ValtypeSize.i8 : ValtypeSize.i16, Valtype.i32),
740
- [ Opcodes.i32_add ],
741
- [ Opcodes.local_tee, index ],
742
-
743
- // if index < index end (length * sizeof valtype), loop
744
- [ Opcodes.local_get, indexEnd ],
745
- [ Opcodes.i32_lt_s ],
746
- [ Opcodes.br_if, 0 ],
747
- [ Opcodes.end ],
621
+ ...left,
622
+ ...(valtypeBinary === Valtype.i32 ? [ [ Opcodes.f64_convert_i32_s ] ] : []),
623
+ ...leftType,
748
624
 
749
- // no failed checks, so true!
750
- ...number(1, Valtype.i32),
625
+ ...right,
626
+ ...(valtypeBinary === Valtype.i32 ? [ [ Opcodes.f64_convert_i32_s ] ] : []),
627
+ ...rightType,
751
628
 
752
- // pointers match, so true
753
- [ Opcodes.else ],
754
- ...number(1, Valtype.i32),
755
- [ Opcodes.end ],
629
+ [ Opcodes.call, includeBuiltin(scope, '__Porffor_compareStrings').index ],
630
+ [ Opcodes.drop ],
756
631
 
757
- // convert i32 result to valtype
758
- // do not do as automatically added by binary exp gen for equality ops
759
- // Opcodes.i32_from_u
632
+ // convert valtype result to i32 as i32 output expected
633
+ Opcodes.i32_trunc_sat_f64_u
760
634
  ];
761
635
  };
762
636
 
@@ -999,9 +873,7 @@ const performOp = (scope, op, left, right, leftType, rightType, _global = false,
999
873
  // string comparison
1000
874
  if (op === '===' || op === '==' || op === '!==' || op === '!=') {
1001
875
  return [
1002
- ...left,
1003
- ...right,
1004
- ...compareStrings(scope, [], [], leftType, rightType, false, knownLeft === TYPES.string && knownRight === TYPES.string),
876
+ ...compareStrings(scope, left, right, leftType, rightType),
1005
877
  ...(op === '!==' || op === '!=' ? [ [ Opcodes.i32_eqz ] ] : [])
1006
878
  ];
1007
879
  }
@@ -1027,9 +899,7 @@ const performOp = (scope, op, left, right, leftType, rightType, _global = false,
1027
899
  // string comparison
1028
900
  if (op === '===' || op === '==' || op === '!==' || op === '!=') {
1029
901
  return [
1030
- ...left,
1031
- ...right,
1032
- ...compareStrings(scope, [], [], leftType, rightType, knownLeft === TYPES.bytestring && knownRight === TYPES.bytestring),
902
+ ...compareStrings(scope, left, right, leftType, rightType),
1033
903
  ...(op === '!==' || op === '!=' ? [ [ Opcodes.i32_eqz ] ] : [])
1034
904
  ];
1035
905
  }
@@ -1118,43 +988,19 @@ const performOp = (scope, op, left, right, leftType, rightType, _global = false,
1118
988
  tmpRight = localTmp(scope, '__tmpop_right');
1119
989
 
1120
990
  ops.unshift(...stringOnly([
1121
- // if left is bytestring
991
+ // if left or right are string or bytestring
1122
992
  ...leftType,
993
+ ...number(TYPE_FLAGS.parity, Valtype.i32),
994
+ [ Opcodes.i32_or ],
1123
995
  ...number(TYPES.bytestring, Valtype.i32),
1124
996
  [ Opcodes.i32_eq ],
1125
997
 
1126
- // if right is bytestring
1127
998
  ...rightType,
1128
- ...number(TYPES.bytestring, Valtype.i32),
1129
- [ Opcodes.i32_eq ],
1130
-
1131
- // if both are true
1132
- [ Opcodes.i32_and ],
1133
- [ Opcodes.if, Blocktype.void ],
1134
- ...compareStrings(scope, [ [ Opcodes.local_get, tmpLeft ] ], [ [ Opcodes.local_get, tmpRight ] ], leftType, rightType, true),
1135
- ...(op === '!==' || op === '!=' ? [ [ Opcodes.i32_eqz ] ] : []),
1136
- [ Opcodes.br, 1 ],
1137
- [ Opcodes.end ],
1138
-
1139
- // if left is string or bytestring
1140
- ...leftType,
1141
- ...number(TYPES.string, Valtype.i32),
1142
- [ Opcodes.i32_eq ],
1143
- ...leftType,
1144
- ...number(TYPES.bytestring, Valtype.i32),
1145
- [ Opcodes.i32_eq ],
999
+ ...number(TYPE_FLAGS.parity, Valtype.i32),
1146
1000
  [ Opcodes.i32_or ],
1147
-
1148
- // if right is string or bytestring
1149
- ...rightType,
1150
- ...number(TYPES.string, Valtype.i32),
1151
- [ Opcodes.i32_eq ],
1152
- ...rightType,
1153
1001
  ...number(TYPES.bytestring, Valtype.i32),
1154
1002
  [ Opcodes.i32_eq ],
1155
- [ Opcodes.i32_or ],
1156
1003
 
1157
- // if either
1158
1004
  [ Opcodes.i32_or ],
1159
1005
  [ Opcodes.if, Blocktype.void ],
1160
1006
  ...compareStrings(scope, [ [ Opcodes.local_get, tmpLeft ] ], [ [ Opcodes.local_get, tmpRight ] ], leftType, rightType),
@@ -2589,7 +2435,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
2589
2435
 
2590
2436
  // get if func we are calling is a constructor or not
2591
2437
  [ Opcodes.local_get, funcLocal ],
2592
- ...number(128, Valtype.i32),
2438
+ ...number(64, Valtype.i32),
2593
2439
  [ Opcodes.i32_mul ],
2594
2440
  ...number(4, Valtype.i32),
2595
2441
  [ Opcodes.i32_add ],
@@ -2615,7 +2461,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
2615
2461
  // [ Opcodes.call, 1 ],
2616
2462
 
2617
2463
  // [ Opcodes.local_get, funcLocal ],
2618
- // ...number(128, Valtype.i32),
2464
+ // ...number(64, Valtype.i32),
2619
2465
  // [ Opcodes.i32_mul ],
2620
2466
  // [ Opcodes.i32_load16_u, 0, ...unsignedLEB128(allocPage(scope, 'func lut') * pageSize), 'read func lut' ],
2621
2467
  // Opcodes.i32_from_u,
@@ -2627,7 +2473,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
2627
2473
  ...brTable([
2628
2474
  // get argc of func we are calling
2629
2475
  [ Opcodes.local_get, funcLocal ],
2630
- ...number(128, Valtype.i32),
2476
+ ...number(64, Valtype.i32),
2631
2477
  [ Opcodes.i32_mul ],
2632
2478
  [ Opcodes.i32_load16_u, 0, ...unsignedLEB128(allocPage(scope, 'func lut') * pageSize), 'read func lut' ]
2633
2479
  ], tableBc, valtypeBinary)
package/compiler/wrap.js CHANGED
@@ -318,7 +318,7 @@ export default (source, flags = [ 'module' ], customImports = {}, print = str =>
318
318
  const printDecomp = (middleIndex, func, funcs, globals, exceptions) => {
319
319
  console.log(`\x1B[35m\x1B[1mporffor backtrace\u001b[0m`);
320
320
 
321
- const surrounding = Prefs.backtraceSurrounding ?? 5;
321
+ const surrounding = Prefs.backtraceSurrounding ?? 10;
322
322
  let min = middleIndex - surrounding;
323
323
  let max = middleIndex + surrounding + 1;
324
324
  if (Prefs.backtraceFunc || middleIndex == -1) {
@@ -350,7 +350,7 @@ export default (source, flags = [ 'module' ], customImports = {}, print = str =>
350
350
  Number.isNaN(funcInd) || Number.isNaN(blobOffset)) return false;
351
351
 
352
352
  // convert blob offset -> function wasm offset
353
- const func = funcs.find(x => x.index === funcInd);
353
+ const func = funcs.find(x => x.asmIndex === funcInd);
354
354
  if (!func) return false;
355
355
 
356
356
  const { wasm: assembledWasmFlat, wasmNonFlat: assembledWasmOps, localDecl } = func.assembled;
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.34.5+b927e0e77",
4
+ "version": "0.34.6+581b45353",
5
5
  "author": "CanadaHonk",
6
6
  "license": "MIT",
7
7
  "scripts": {},
package/r.js ADDED
@@ -0,0 +1,113 @@
1
+ function $DONE(error) {
2
+ if (error) {
3
+ Porffor.printStatic('Test262:AsyncTestFailure:Error: unknown');
4
+ } else {
5
+ Porffor.printStatic('Test262:AsyncTestComplete');
6
+ }
7
+ }
8
+ function assert(mustBeTrue) {
9
+ if (mustBeTrue === true) {
10
+ return;
11
+ }
12
+
13
+ throw new Test262Error('assert failed');
14
+ }
15
+
16
+ assert.throws = function (expectedErrorConstructor, func) {
17
+ if (typeof func !== 'function') {
18
+ throw new Test262Error('assert.throws invoked with a non-function value');
19
+ }
20
+
21
+ try {
22
+ func();
23
+ } catch {
24
+ return;
25
+ }
26
+
27
+ throw new Test262Error('assert.throws failed');
28
+ };
29
+
30
+ assert._isSameValue = function (a, b) {
31
+ if (a === b) {
32
+ // Handle +/-0 vs. -/+0
33
+ return a !== 0 || 1 / a === 1 / b;
34
+ }
35
+
36
+ // Handle NaN vs. NaN
37
+ return a !== a && b !== b;
38
+ };
39
+
40
+ assert.sameValue = function (actual, expected) {
41
+ if (assert._isSameValue(actual, expected)) {
42
+ return;
43
+ }
44
+
45
+ throw new Test262Error('assert.sameValue failed');
46
+ };
47
+
48
+ assert.notSameValue = function (actual, unexpected) {
49
+ if (!assert._isSameValue(actual, unexpected)) {
50
+ return;
51
+ }
52
+
53
+ throw new Test262Error('assert.notSameValue failed');
54
+ };
55
+ // define our $262 here too
56
+ var $262 = {
57
+ global: globalThis,
58
+ gc() { /* noop */ },
59
+ detachArrayBuffer(buffer) {
60
+ return Porffor.arraybuffer.detach(buffer);
61
+ },
62
+ getGlobal(name) {
63
+ return globalThis[name];
64
+ },
65
+ // todo: setGlobal
66
+ destroy() { /* noop */ },
67
+ agent: {}
68
+ };
69
+
70
+ function Test262Error() {}
71
+
72
+ Test262Error.thrower = function (message) {
73
+ throw new Test262Error(message);
74
+ };
75
+
76
+ function $DONOTEVALUATE() {
77
+ throw 'Test262: This statement should not be evaluated.';
78
+ }
79
+ // Copyright (C) 2015 the V8 project authors. All rights reserved.
80
+ // This code is governed by the BSD license found in the LICENSE file.
81
+ /*---
82
+ es6id: 25.4.5.3
83
+ description: PerformPromiseThen on a rejected promise
84
+ info: |
85
+ 7. Return PerformPromiseThen(promise, onFulfilled, onRejected,
86
+ resultCapability).
87
+
88
+ 25.4.5.3.1 PerformPromiseThen
89
+
90
+ [...]
91
+ 9. Else if the value of promise's [[PromiseState]] internal slot is
92
+ "rejected",
93
+ a. Let reason be the value of promise's [[PromiseResult]] internal slot.
94
+ b. Perform EnqueueJob("PromiseJobs", PromiseReactionJob,
95
+ «rejectReaction, reason»).
96
+ [...]
97
+ flags: [async]
98
+ ---*/
99
+
100
+ var value = {};
101
+ var p = new Promise(function(_, reject) {
102
+ reject(value);
103
+ });
104
+
105
+ p.then(function() {
106
+ $DONE('The `onFulfilled` handler should not be invoked.');
107
+ }, function(x) {
108
+ if (x !== value) {
109
+ $DONE('The `onRejected` handler should be invoked with the promise result.');
110
+ return;
111
+ }
112
+ $DONE();
113
+ });
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.34.5+b927e0e77';
3
+ globalThis.version = '0.34.6+581b45353';
4
4
 
5
5
  // deno compat
6
6
  if (typeof process === 'undefined' && typeof Deno !== 'undefined') {
package/runner/repl.js CHANGED
@@ -42,7 +42,7 @@ const memoryToString = mem => {
42
42
 
43
43
  const buf = new Uint8Array(mem.buffer);
44
44
 
45
- let longestType = 0, longestName = 0;
45
+ let longestType = 4, longestName = 4;
46
46
  for (const x of lastPages) {
47
47
  const [ type, name ] = x.split(': ');
48
48
  if (type.length > longestType) longestType = type.length;