porffor 0.37.24 → 0.37.26
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/compiler/builtins/boolean.ts +10 -4
- package/compiler/builtins/number.ts +3 -3
- package/compiler/builtins/object.ts +28 -3
- package/compiler/builtins/porffor.d.ts +6 -0
- package/compiler/builtins_precompiled.js +140 -137
- package/compiler/codegen.js +108 -43
- package/compiler/types.js +3 -0
- package/compiler/wrap.js +5 -0
- package/nova.comp.cjs +3 -0
- package/package.json +1 -1
- package/runner/index.js +1 -1
package/compiler/codegen.js
CHANGED
@@ -357,6 +357,13 @@ const generateIdent = (scope, decl) => {
|
|
357
357
|
}
|
358
358
|
|
359
359
|
if (local?.idx === undefined) {
|
360
|
+
if (name === 'arguments' && scope.name !== 'main' && !scope.arrow) {
|
361
|
+
// todo: stub arguments as [] for now :)
|
362
|
+
return generateArray(scope, {
|
363
|
+
elements: []
|
364
|
+
}, false, '#arguments');
|
365
|
+
}
|
366
|
+
|
360
367
|
// no local var with name
|
361
368
|
if (Object.hasOwn(globals, name)) return [ [ Opcodes.global_get, globals[name].idx ] ];
|
362
369
|
|
@@ -559,7 +566,8 @@ const truthy = (scope, wasm, type, intIn = false, intOut = false, forceTruthyMod
|
|
559
566
|
const useTmp = knownType(scope, type) == null;
|
560
567
|
const tmp = useTmp && localTmp(scope, `#logicinner_tmp${intIn ? '_int' : ''}`, intIn ? Valtype.i32 : valtypeBinary);
|
561
568
|
|
562
|
-
const
|
569
|
+
const truthyMode = forceTruthyMode ?? Prefs.truthy ?? 'full';
|
570
|
+
const def = (() => {
|
563
571
|
if (truthyMode === 'full') return [
|
564
572
|
// if value != 0 or NaN
|
565
573
|
...(!useTmp ? [] : [ [ Opcodes.local_get, tmp ] ]),
|
@@ -584,7 +592,7 @@ const truthy = (scope, wasm, type, intIn = false, intOut = false, forceTruthyMod
|
|
584
592
|
...(!useTmp ? [] : [ [ Opcodes.local_get, tmp ] ]),
|
585
593
|
...(!intOut || (intIn && intOut) ? [] : [ Opcodes.i32_to_u ])
|
586
594
|
];
|
587
|
-
})(
|
595
|
+
})();
|
588
596
|
|
589
597
|
return [
|
590
598
|
...wasm,
|
@@ -603,6 +611,17 @@ const truthy = (scope, wasm, type, intIn = false, intOut = false, forceTruthyMod
|
|
603
611
|
[ Opcodes.i32_eqz ], */
|
604
612
|
...(intOut ? [] : [ Opcodes.i32_from_u ])
|
605
613
|
] ],
|
614
|
+
// [ [ TYPES.boolean, TYPES.number, TYPES.object, TYPES.undefined, TYPES.empty ], def ],
|
615
|
+
// [ 'default', [
|
616
|
+
// // other types are always truthy
|
617
|
+
// ...(!useTmp ? [ [ Opcodes.drop ] ] : []),
|
618
|
+
// ...number(1, intOut ? Valtype.i32 : valtypeBinary)
|
619
|
+
// ] ]
|
620
|
+
...(truthyMode === 'full' ? [ [ [ TYPES.booleanobject, TYPES.numberobject ], [
|
621
|
+
// always truthy :))
|
622
|
+
...(!useTmp ? [ [ Opcodes.drop ] ] : []),
|
623
|
+
...number(1, intOut ? Valtype.i32 : valtypeBinary)
|
624
|
+
] ] ] : []),
|
606
625
|
[ 'default', def ]
|
607
626
|
], intOut ? Valtype.i32 : valtypeBinary)
|
608
627
|
];
|
@@ -612,7 +631,8 @@ const falsy = (scope, wasm, type, intIn = false, intOut = false, forceTruthyMode
|
|
612
631
|
const useTmp = knownType(scope, type) == null;
|
613
632
|
const tmp = useTmp && localTmp(scope, `#logicinner_tmp${intIn ? '_int' : ''}`, intIn ? Valtype.i32 : valtypeBinary);
|
614
633
|
|
615
|
-
const
|
634
|
+
const truthyMode = forceTruthyMode ?? Prefs.truthy ?? 'full';
|
635
|
+
const def = (() => {
|
616
636
|
if (truthyMode === 'full') return [
|
617
637
|
// if value == 0 or NaN
|
618
638
|
...(!useTmp ? [] : [ [ Opcodes.local_get, tmp ] ]),
|
@@ -638,7 +658,7 @@ const falsy = (scope, wasm, type, intIn = false, intOut = false, forceTruthyMode
|
|
638
658
|
...(intIn ? [ [ Opcodes.i32_eqz ] ] : [ ...Opcodes.eqz ]),
|
639
659
|
...(intOut ? [] : [ Opcodes.i32_from_u ])
|
640
660
|
];
|
641
|
-
})(
|
661
|
+
})();
|
642
662
|
|
643
663
|
return [
|
644
664
|
...wasm,
|
@@ -656,6 +676,17 @@ const falsy = (scope, wasm, type, intIn = false, intOut = false, forceTruthyMode
|
|
656
676
|
[ Opcodes.i32_eqz ],
|
657
677
|
...(intOut ? [] : [ Opcodes.i32_from_u ])
|
658
678
|
] ],
|
679
|
+
// [ [ TYPES.boolean, TYPES.number, TYPES.object, TYPES.undefined, TYPES.empty ], def ],
|
680
|
+
// [ 'default', [
|
681
|
+
// // other types are always truthy
|
682
|
+
// ...(!useTmp ? [ [ Opcodes.drop ] ] : []),
|
683
|
+
// ...number(0, intOut ? Valtype.i32 : valtypeBinary)
|
684
|
+
// ] ]
|
685
|
+
...(truthyMode === 'full' ? [ [ [ TYPES.booleanobject, TYPES.numberobject ], [
|
686
|
+
// always truthy :))
|
687
|
+
...(!useTmp ? [ [ Opcodes.drop ] ] : []),
|
688
|
+
...number(0, intOut ? Valtype.i32 : valtypeBinary)
|
689
|
+
] ] ] : []),
|
659
690
|
[ 'default', def ]
|
660
691
|
], intOut ? Valtype.i32 : valtypeBinary)
|
661
692
|
];
|
@@ -1143,6 +1174,10 @@ const getType = (scope, _name) => {
|
|
1143
1174
|
return number(TYPES.undefined, Valtype.i32);
|
1144
1175
|
}
|
1145
1176
|
|
1177
|
+
if (name === 'arguments' && scope.name !== 'main' && !scope.arrow) {
|
1178
|
+
return number(TYPES.array, Valtype.i32);
|
1179
|
+
}
|
1180
|
+
|
1146
1181
|
if (Object.hasOwn(globals, name)) {
|
1147
1182
|
if (globals[name]?.metadata?.type != null) return number(globals[name].metadata.type, Valtype.i32);
|
1148
1183
|
|
@@ -1680,6 +1715,20 @@ const setObjProp = (obj, prop, value) => {
|
|
1680
1715
|
});
|
1681
1716
|
};
|
1682
1717
|
|
1718
|
+
const aliasPrimObjsBC = bc => {
|
1719
|
+
const add = (x, y) => {
|
1720
|
+
if (bc[x] == null) return;
|
1721
|
+
|
1722
|
+
// bc[`${x},${y}`] = original;
|
1723
|
+
|
1724
|
+
// intentionally duplicate to avoid extra bc for prim objs as rarely used
|
1725
|
+
bc[y] = bc[x];
|
1726
|
+
};
|
1727
|
+
|
1728
|
+
add(TYPES.boolean, TYPES.booleanobject);
|
1729
|
+
add(TYPES.number, TYPES.numberobject);
|
1730
|
+
};
|
1731
|
+
|
1683
1732
|
const createThisArg = (scope, decl) => {
|
1684
1733
|
const name = mapName(decl.callee?.name);
|
1685
1734
|
if (decl._new) {
|
@@ -2075,6 +2124,9 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
|
|
2075
2124
|
// fallback to object prototype impl as a basic prototype chain hack
|
2076
2125
|
if (protoBC[TYPES.object]) def = protoBC[TYPES.object];
|
2077
2126
|
|
2127
|
+
// alias primitive prototype with primitive object types
|
2128
|
+
aliasPrimObjsBC(protoBC);
|
2129
|
+
|
2078
2130
|
return [
|
2079
2131
|
...out,
|
2080
2132
|
|
@@ -2718,27 +2770,40 @@ const typeUsed = (scope, x) => {
|
|
2718
2770
|
scope.usedTypes ??= new Set();
|
2719
2771
|
scope.usedTypes.add(x);
|
2720
2772
|
};
|
2773
|
+
|
2721
2774
|
const typeSwitch = (scope, type, bc, returns = valtypeBinary, fallthrough = false) => {
|
2775
|
+
if (typeof bc === 'function') bc = bc();
|
2776
|
+
|
2777
|
+
let def;
|
2778
|
+
if (!Array.isArray(bc)) {
|
2779
|
+
def = bc.default;
|
2780
|
+
bc = Object.entries(bc);
|
2781
|
+
|
2782
|
+
// turn keys back into numbers from keys
|
2783
|
+
for (const x of bc) {
|
2784
|
+
const k = x[0];
|
2785
|
+
if (k === 'default') continue;
|
2786
|
+
|
2787
|
+
// uncomment if needed/used again
|
2788
|
+
// x[0] = k.split(',').map(x => +x);
|
2789
|
+
x[0] = +k;
|
2790
|
+
}
|
2791
|
+
}
|
2792
|
+
|
2722
2793
|
const known = knownType(scope, type);
|
2723
2794
|
if (known != null) {
|
2724
|
-
|
2725
|
-
|
2726
|
-
|
2727
|
-
|
2728
|
-
def = wasm;
|
2729
|
-
continue;
|
2730
|
-
}
|
2731
|
-
|
2732
|
-
if (Array.isArray(type)) {
|
2733
|
-
if (type.includes(known)) return typeof wasm === 'function' ? wasm() : wasm;
|
2734
|
-
} else if (type === known) return typeof wasm === 'function' ? wasm() : wasm;
|
2795
|
+
for (const [ type, wasm ] of bc) {
|
2796
|
+
if (type === 'default') {
|
2797
|
+
def = wasm;
|
2798
|
+
continue;
|
2735
2799
|
}
|
2736
2800
|
|
2737
|
-
|
2738
|
-
|
2739
|
-
|
2740
|
-
return typeof wasm === 'function' ? wasm() : wasm;
|
2801
|
+
if (type === known || (Array.isArray(type) && type.includes(known))) {
|
2802
|
+
return typeof wasm === 'function' ? wasm() : wasm;
|
2803
|
+
}
|
2741
2804
|
}
|
2805
|
+
|
2806
|
+
return typeof def === 'function' ? def() : def;
|
2742
2807
|
}
|
2743
2808
|
|
2744
2809
|
if (Prefs.typeswitchBrtable) {
|
@@ -2753,19 +2818,6 @@ const typeSwitch = (scope, type, bc, returns = valtypeBinary, fallthrough = fals
|
|
2753
2818
|
[ Opcodes.block, returns ]
|
2754
2819
|
];
|
2755
2820
|
|
2756
|
-
if (typeof bc === 'function') bc = bc();
|
2757
|
-
|
2758
|
-
let def;
|
2759
|
-
if (!Array.isArray(bc)) {
|
2760
|
-
def = bc.default;
|
2761
|
-
bc = Object.entries(bc);
|
2762
|
-
|
2763
|
-
// turn keys back into numbers from keys
|
2764
|
-
for (const x of bc) {
|
2765
|
-
if (x[0] !== 'default') x[0] = +x[0];
|
2766
|
-
}
|
2767
|
-
}
|
2768
|
-
|
2769
2821
|
for (let i = 0; i < bc.length; i++) {
|
2770
2822
|
let [ types, wasm ] = bc[i];
|
2771
2823
|
if (types === 'default') {
|
@@ -2837,6 +2889,17 @@ const typeIsOneOf = (type, types, valtype = Valtype.i32) => {
|
|
2837
2889
|
return out;
|
2838
2890
|
};
|
2839
2891
|
|
2892
|
+
const typeIsNotOneOf = (type, types, valtype = Valtype.i32) => {
|
2893
|
+
const out = [];
|
2894
|
+
|
2895
|
+
for (let i = 0; i < types.length; i++) {
|
2896
|
+
out.push(...type, ...number(types[i], valtype), valtype === Valtype.f64 ? [ Opcodes.f64_ne ] : [ Opcodes.i32_ne ]);
|
2897
|
+
if (i !== 0) out.push([ Opcodes.i32_and ]);
|
2898
|
+
}
|
2899
|
+
|
2900
|
+
return out;
|
2901
|
+
};
|
2902
|
+
|
2840
2903
|
const allocVar = (scope, name, global = false, type = true) => {
|
2841
2904
|
const target = global ? globals : scope.locals;
|
2842
2905
|
|
@@ -3565,7 +3628,7 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
|
|
3565
3628
|
// default: internalThrow(scope, 'TypeError', `Cannot assign member with this type`)
|
3566
3629
|
default: () => [
|
3567
3630
|
...objectWasm,
|
3568
|
-
Opcodes.
|
3631
|
+
Opcodes.i32_to,
|
3569
3632
|
...(op === '=' ? [] : [ [ Opcodes.local_tee, localTmp(scope, '#objset_object', Valtype.i32) ] ]),
|
3570
3633
|
...getNodeType(scope, object),
|
3571
3634
|
|
@@ -5411,7 +5474,10 @@ const generateMember = (scope, decl, _global, _name, _objectWasm = undefined) =>
|
|
5411
5474
|
if (type === known) return bc[type]();
|
5412
5475
|
}
|
5413
5476
|
|
5414
|
-
if (known == null)
|
5477
|
+
if (known == null) {
|
5478
|
+
aliasPrimObjsBC(bc);
|
5479
|
+
extraBC = bc;
|
5480
|
+
}
|
5415
5481
|
}
|
5416
5482
|
|
5417
5483
|
// todo/perf: use i32 object (and prop?) locals
|
@@ -5574,7 +5640,7 @@ const generateMember = (scope, decl, _global, _name, _objectWasm = undefined) =>
|
|
5574
5640
|
// default: internalThrow(scope, 'TypeError', 'Unsupported member expression object', true)
|
5575
5641
|
default: () => [
|
5576
5642
|
...objectWasm,
|
5577
|
-
Opcodes.
|
5643
|
+
Opcodes.i32_to,
|
5578
5644
|
...getNodeType(scope, object),
|
5579
5645
|
|
5580
5646
|
...toPropertyKey(scope, propertyWasm, getNodeType(scope, property), decl.computed, true),
|
@@ -5892,6 +5958,7 @@ const generateFunc = (scope, decl) => {
|
|
5892
5958
|
const params = decl.params ?? [];
|
5893
5959
|
|
5894
5960
|
// TODO: share scope/locals between !!!
|
5961
|
+
const arrow = decl.type === 'ArrowFunctionExpression' || decl.type === 'Program';
|
5895
5962
|
const func = {
|
5896
5963
|
locals: {},
|
5897
5964
|
localInd: 0,
|
@@ -5899,11 +5966,8 @@ const generateFunc = (scope, decl) => {
|
|
5899
5966
|
returns: [ valtypeBinary, Valtype.i32 ],
|
5900
5967
|
name,
|
5901
5968
|
index: currentFuncIndex++,
|
5902
|
-
|
5903
|
-
|
5904
|
-
(decl.type && decl.type !== 'ArrowFunctionExpression' && decl.type !== 'Program') &&
|
5905
|
-
// not async or generator
|
5906
|
-
!decl.async && !decl.generator,
|
5969
|
+
arrow,
|
5970
|
+
constr: !arrow && !decl.generator && !decl.async,
|
5907
5971
|
_onlyConstr: decl._onlyConstr, _onlyThisMethod: decl._onlyThisMethod,
|
5908
5972
|
strict: scope.strict || decl.strict,
|
5909
5973
|
|
@@ -6097,10 +6161,11 @@ const generateFunc = (scope, decl) => {
|
|
6097
6161
|
TYPES.weakref, TYPES.weakset, TYPES.weakmap,
|
6098
6162
|
TYPES.arraybuffer, TYPES.sharedarraybuffer, TYPES.dataview
|
6099
6163
|
].includes(typeAnno.type)) {
|
6164
|
+
let types = [ typeAnno.type ];
|
6165
|
+
if (typeAnno.type === TYPES.number) types.push(TYPES.numberobject);
|
6166
|
+
|
6100
6167
|
prelude.push(
|
6101
|
-
[ Opcodes.local_get, func.locals[name].idx + 1 ],
|
6102
|
-
...number(typeAnno.type, Valtype.i32),
|
6103
|
-
[ Opcodes.i32_ne ],
|
6168
|
+
...typeIsNotOneOf([ [ Opcodes.local_get, func.locals[name].idx + 1 ] ], types),
|
6104
6169
|
[ Opcodes.if, Blocktype.void ],
|
6105
6170
|
...internalThrow(func, 'TypeError', `${unhackName(func.name)} expects 'this' to be a ${TYPE_NAMES[typeAnno.type]}`),
|
6106
6171
|
[ Opcodes.end ]
|
package/compiler/types.js
CHANGED
@@ -74,6 +74,9 @@ registerInternalType('WeakMap');
|
|
74
74
|
|
75
75
|
registerInternalType('Promise');
|
76
76
|
|
77
|
+
registerInternalType('BooleanObject');
|
78
|
+
registerInternalType('NumberObject');
|
79
|
+
|
77
80
|
if (Prefs.largestTypes) {
|
78
81
|
const typeKeys = Object.keys(TYPES);
|
79
82
|
const typeVals = Object.values(TYPES);
|
package/compiler/wrap.js
CHANGED
@@ -41,7 +41,12 @@ const porfToJSValue = ({ memory, funcs, pages }, value, type, override = undefin
|
|
41
41
|
case TYPES.undefined:
|
42
42
|
return undefined;
|
43
43
|
|
44
|
+
case TYPES.number: return value;
|
45
|
+
case TYPES.numberobject: return new Number(value);
|
46
|
+
|
44
47
|
case TYPES.boolean: return Boolean(value);
|
48
|
+
case TYPES.booleanobject: return new Boolean(value);
|
49
|
+
|
45
50
|
case TYPES.object: {
|
46
51
|
if (value === 0 || checkOOB(memory, value)) return null;
|
47
52
|
|
package/nova.comp.cjs
ADDED
@@ -0,0 +1,3 @@
|
|
1
|
+
const uniq = [...new Set(require('../nova.json').pass.map(x => x.slice(5))).difference(new Set(require('./test262/results.json').passes))];
|
2
|
+
console.log([...uniq.reduce((acc, x) => { let k = x.split('/').slice(0, -1).join('/'); return acc.set(k, (acc.get(k) || 0) + 1); }, new Map()).entries()].sort((a, b) => a[1] - b[1]).slice(-20).map(x => x[0] + ': ' + x[1]).join('\n'));
|
3
|
+
console.log(uniq.filter(x => x.startsWith('built-ins/Object/defineProperty')).join('\n'))
|
package/package.json
CHANGED