porffor 0.55.14 → 0.55.16
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/README.md +0 -1
- package/compiler/builtins/_internal_object.ts +10 -2
- package/compiler/builtins/bigint.ts +233 -0
- package/compiler/builtins/number.ts +2 -0
- package/compiler/builtins.js +21 -89
- package/compiler/builtins_objects.js +1 -1
- package/compiler/builtins_precompiled.js +489 -402
- package/compiler/codegen.js +2 -3
- package/compiler/cyclone.js +1 -2
- package/compiler/encoding.js +10 -0
- package/compiler/opt.js +1 -2
- package/compiler/pgo.js +2 -2
- package/compiler/precompile.js +2 -2
- package/compiler/prototype.js +1 -1
- package/compiler/types.js +5 -19
- package/compiler/wrap.js +14 -0
- package/package.json +1 -1
- package/r.cjs +0 -11
- package/rhemyn/compile.js +2 -2
- package/runner/flamegraph.js +1 -1
- package/runner/index.js +1 -1
- package/.fails.cjs +0 -20
- package/all.json +0 -1
- package/compiler/cache.js +0 -44
- package/compiler/embedding.js +0 -11
package/README.md
CHANGED
@@ -108,7 +108,6 @@ Porffor can run Test262 via some hacks/transforms which remove unsupported featu
|
|
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
110
|
- `disassemble.js`: wasm disassembler using internal debug info
|
111
|
-
- `embedding.js`: utils for embedding consts
|
112
111
|
- `encoding.js`: utils for encoding things as bytes as wasm expects
|
113
112
|
- `expression.js`: mapping most operators to an opcode (advanced are as built-ins eg `f64_%`)
|
114
113
|
- `havoc.js`: wasm rewrite library (it wreaks havoc upon wasm bytecode hence "havoc")
|
@@ -135,11 +135,16 @@ export const __Porffor_object_lookup = (obj: any, target: any): i32 => {
|
|
135
135
|
const size: i32 = Porffor.wasm.i32.load(obj, 0, 0);
|
136
136
|
const endPtr: i32 = ptr + size * 14;
|
137
137
|
|
138
|
+
let out: boolean = false;
|
138
139
|
if (targetType == Porffor.TYPES.symbol) {
|
139
140
|
const targetSym: symbol = target;
|
140
141
|
for (; ptr < endPtr; ptr += 14) {
|
141
142
|
const keyRaw: i32 = Porffor.wasm.i32.load(ptr, 0, 0);
|
142
|
-
if (keyRaw == 0)
|
143
|
+
if (keyRaw == 0) {
|
144
|
+
if (out) break; // ran out of keys
|
145
|
+
out = true;
|
146
|
+
}
|
147
|
+
|
143
148
|
if (keyRaw >>> 30 == 3) { // MSB 1 and 2 set, symbol
|
144
149
|
const keySym: symbol = keyRaw & 0x3FFFFFFF; // unset MSB
|
145
150
|
if (keySym == targetSym) return ptr;
|
@@ -148,7 +153,10 @@ export const __Porffor_object_lookup = (obj: any, target: any): i32 => {
|
|
148
153
|
} else {
|
149
154
|
for (; ptr < endPtr; ptr += 14) {
|
150
155
|
const keyRaw: i32 = Porffor.wasm.i32.load(ptr, 0, 0);
|
151
|
-
if (keyRaw == 0)
|
156
|
+
if (keyRaw == 0) {
|
157
|
+
if (out) break; // ran out of keys
|
158
|
+
out = true;
|
159
|
+
}
|
152
160
|
|
153
161
|
const msb: i32 = keyRaw >>> 30;
|
154
162
|
if (msb == 0) {
|
@@ -0,0 +1,233 @@
|
|
1
|
+
import type {} from './porffor.d.ts';
|
2
|
+
|
3
|
+
// digits is an array of u32s as digits in base 2^32
|
4
|
+
export const __Porffor_bigint_fromDigits = (negative: boolean, digits: i32[]): bigint => {
|
5
|
+
const len: i32 = digits.length;
|
6
|
+
if (len > 16383) throw new RangeError('Maximum BigInt size exceeded'); // (65536 - 4) / 4
|
7
|
+
|
8
|
+
// const ptr: i32 = Porffor.allocate();
|
9
|
+
const ptr: i32 = Porffor.wasm`local.get ${digits}`;
|
10
|
+
|
11
|
+
Porffor.wasm.i32.store8(ptr, negative ? 1 : 0, 0, 0);
|
12
|
+
Porffor.wasm.i32.store16(ptr, len, 0, 2);
|
13
|
+
|
14
|
+
for (let i: i32 = 0; i < len; i++) {
|
15
|
+
Porffor.wasm.i32.store(ptr + i * 4, digits[i], 0, 4);
|
16
|
+
}
|
17
|
+
|
18
|
+
const out: bigint = ptr;
|
19
|
+
return out;
|
20
|
+
};
|
21
|
+
|
22
|
+
export const __Porffor_bigint_fromNumber = (n: number): bigint => {
|
23
|
+
if (!Number.isInteger(n) || !Number.isFinite(n)) throw new RangeError('Cannot convert non-integer to BigInt');
|
24
|
+
|
25
|
+
const negative: boolean = n < 0;
|
26
|
+
n = Math.abs(n);
|
27
|
+
|
28
|
+
const digits: i32[] = Porffor.allocate();
|
29
|
+
while (n > 0) {
|
30
|
+
digits.unshift(n % 0x100000000);
|
31
|
+
n = Math.trunc(n / 0x100000000);
|
32
|
+
}
|
33
|
+
|
34
|
+
return __Porffor_bigint_fromDigits(negative, digits);
|
35
|
+
};
|
36
|
+
|
37
|
+
export const __Porffor_bigint_toNumber = (ptr: i32): number => {
|
38
|
+
const negative: boolean = Porffor.wasm.i32.load8_u(ptr, 0, 0) != 0;
|
39
|
+
const len: i32 = Porffor.wasm.i32.load16_u(ptr, 0, 2);
|
40
|
+
|
41
|
+
let out: number = 0;
|
42
|
+
for (let i: i32 = 0; i < len; i++) {
|
43
|
+
const d: i32 = Porffor.wasm.i32.load(ptr + i * 4, 0, 4);
|
44
|
+
out = out * 0x100000000 + d;
|
45
|
+
}
|
46
|
+
|
47
|
+
if (negative) out = -out;
|
48
|
+
return out;
|
49
|
+
};
|
50
|
+
|
51
|
+
export const __Porffor_bigint_fromString = (n: string|bytestring): bigint => {
|
52
|
+
const len: i32 = n.length;
|
53
|
+
|
54
|
+
let negative: boolean = false;
|
55
|
+
let end: i32 = 0;
|
56
|
+
if (n[0] === '-') {
|
57
|
+
negative = true;
|
58
|
+
end = 1;
|
59
|
+
} else if (n[0] === '+') {
|
60
|
+
end = 1;
|
61
|
+
}
|
62
|
+
|
63
|
+
// n -> digits (base 2^32) (most to least significant)
|
64
|
+
// 4294967294 -> [ 4294967294 ]
|
65
|
+
// 4294967295 -> [ 4294967295 ]
|
66
|
+
// 4294967296 -> [ 1, 0 ]
|
67
|
+
// 4294967297 -> [ 1, 1 ]
|
68
|
+
// 4294967298 -> [ 1, 2 ]
|
69
|
+
// 9007199254740992 -> [ 2097152 ]
|
70
|
+
// 9007199254740993 -> [ 2097152, 1 ]
|
71
|
+
// 9007199254740994 -> [ 2097152, 2 ]
|
72
|
+
// 9007199254740995 -> [ 2097152, 3 ]
|
73
|
+
|
74
|
+
const digits: i32[] = Porffor.allocate();
|
75
|
+
|
76
|
+
const base = 0x100000000; // 2^32
|
77
|
+
|
78
|
+
for (let i: i32 = end; i < len; i++) {
|
79
|
+
const char: i32 = n.charCodeAt(i);
|
80
|
+
const digit: i32 = char - 48;
|
81
|
+
if (digit < 0 || digit > 9) throw new SyntaxError('Invalid characters in BigInt string');
|
82
|
+
|
83
|
+
// Multiply current digits by 10 and add the new digit
|
84
|
+
let carry: i32 = digit;
|
85
|
+
for (let j: i32 = 0; j < digits.length; j++) {
|
86
|
+
const value: i32 = digits[j] * 10 + carry;
|
87
|
+
digits[j] = value % base;
|
88
|
+
carry = Math.trunc(value / base);
|
89
|
+
}
|
90
|
+
|
91
|
+
// If there's a carry left, push it as a new digit
|
92
|
+
if (carry > 0) {
|
93
|
+
digits.push(carry);
|
94
|
+
}
|
95
|
+
}
|
96
|
+
|
97
|
+
return __Porffor_bigint_fromDigits(negative, digits);
|
98
|
+
};
|
99
|
+
|
100
|
+
export const __Porffor_bigint_toString = (ptr: i32, radix: number): string => {
|
101
|
+
// todo
|
102
|
+
// return '';
|
103
|
+
};
|
104
|
+
|
105
|
+
export const __Porffor_bigint_add = (a: i32, b: i32, sub: boolean): bigint => {
|
106
|
+
const aNegative: boolean = Porffor.wasm.i32.load8_u(a, 0, 0) != 0;
|
107
|
+
const aLen: i32 = Porffor.wasm.i32.load16_u(a, 0, 2);
|
108
|
+
|
109
|
+
let bNegative: boolean = Porffor.wasm.i32.load8_u(b, 0, 0) != 0;
|
110
|
+
if (sub) bNegative = !bNegative;
|
111
|
+
const bLen: i32 = Porffor.wasm.i32.load16_u(b, 0, 2);
|
112
|
+
|
113
|
+
const maxLen: i32 = Math.max(aLen, bLen);
|
114
|
+
const digits: i32[] = Porffor.allocate();
|
115
|
+
|
116
|
+
// fast path: same sign
|
117
|
+
let negative: boolean = false;
|
118
|
+
let carry: i32 = 0;
|
119
|
+
if (aNegative == bNegative) {
|
120
|
+
negative = aNegative;
|
121
|
+
|
122
|
+
for (let i: i32 = 0; i < maxLen; i++) {
|
123
|
+
let aDigit: i32 = 0;
|
124
|
+
const aOffset: i32 = aLen - i;
|
125
|
+
if (aOffset > 0) aDigit = Porffor.wasm.i32.load(a + aOffset * 4, 0, 0);
|
126
|
+
|
127
|
+
let bDigit: i32 = 0;
|
128
|
+
const bOffset: i32 = bLen - i;
|
129
|
+
if (bOffset > 0) bDigit = Porffor.wasm.i32.load(b + bOffset * 4, 0, 0);
|
130
|
+
|
131
|
+
let sum: i32 = aDigit + bDigit + carry;
|
132
|
+
if (sum >= 0x100000000) {
|
133
|
+
sum -= 0x100000000;
|
134
|
+
carry = 1;
|
135
|
+
} else if (sum < 0) {
|
136
|
+
sum += 0x100000000;
|
137
|
+
carry = 1;
|
138
|
+
} else {
|
139
|
+
carry = 0;
|
140
|
+
}
|
141
|
+
|
142
|
+
digits.unshift(sum);
|
143
|
+
}
|
144
|
+
} else {
|
145
|
+
let aLarger: i32 = 0;
|
146
|
+
for (let i: i32 = 0; i < maxLen; i++) {
|
147
|
+
let aDigit: i32 = 0;
|
148
|
+
const aOffset: i32 = aLen - i;
|
149
|
+
if (aOffset > 0) aDigit = Porffor.wasm.i32.load(a + aOffset * 4, 0, 0);
|
150
|
+
|
151
|
+
let bDigit: i32 = 0;
|
152
|
+
const bOffset: i32 = bLen - i;
|
153
|
+
if (bOffset > 0) bDigit = Porffor.wasm.i32.load(b + bOffset * 4, 0, 0);
|
154
|
+
|
155
|
+
let sum: i32 = carry;
|
156
|
+
if (aNegative) sum -= aDigit;
|
157
|
+
else sum += aDigit;
|
158
|
+
if (bNegative) sum -= bDigit;
|
159
|
+
else sum += bDigit;
|
160
|
+
|
161
|
+
if (aDigit != bDigit) aLarger = aDigit > bDigit ? 1 : -1;
|
162
|
+
|
163
|
+
if (sum >= 0x100000000) {
|
164
|
+
sum -= 0x100000000;
|
165
|
+
carry = 1;
|
166
|
+
} else if (sum < 0) {
|
167
|
+
sum += 0x100000000;
|
168
|
+
carry = -1;
|
169
|
+
} else {
|
170
|
+
carry = 0;
|
171
|
+
}
|
172
|
+
|
173
|
+
digits.unshift(sum);
|
174
|
+
}
|
175
|
+
|
176
|
+
if (aLarger == 1) negative = aNegative;
|
177
|
+
else if (aLarger == -1) negative = bNegative;
|
178
|
+
}
|
179
|
+
|
180
|
+
if (carry != 0) {
|
181
|
+
digits.unshift(Math.abs(carry));
|
182
|
+
if (carry < 0) negative = !negative;
|
183
|
+
}
|
184
|
+
|
185
|
+
return __Porffor_bigint_fromDigits(negative, digits);
|
186
|
+
};
|
187
|
+
|
188
|
+
export const __Porffor_bigint_sub = (a: i32, b: i32): bigint => {
|
189
|
+
return __Porffor_bigint_add(a, b, true);
|
190
|
+
};
|
191
|
+
|
192
|
+
export const __Porffor_bigint_mul = (a: i32, b: i32): bigint => {
|
193
|
+
// todo
|
194
|
+
// return 0n;
|
195
|
+
};
|
196
|
+
|
197
|
+
export const __Porffor_bigint_div = (a: i32, b: i32): bigint => {
|
198
|
+
// todo
|
199
|
+
// return 0n;
|
200
|
+
};
|
201
|
+
|
202
|
+
export const __Porffor_bigint_rem = (a: i32, b: i32): bigint => {
|
203
|
+
// todo
|
204
|
+
// return 0n;
|
205
|
+
};
|
206
|
+
|
207
|
+
export const __Porffor_bigint_eq = (a: i32, b: i32): boolean => {
|
208
|
+
// todo
|
209
|
+
// return false;
|
210
|
+
};
|
211
|
+
|
212
|
+
export const __Porffor_bigint_ne = (a: i32, b: i32): boolean => {
|
213
|
+
return !__Porffor_bigint_eq(a, b);
|
214
|
+
};
|
215
|
+
|
216
|
+
export const __Porffor_bigint_gt = (a: i32, b: i32): boolean => {
|
217
|
+
// todo
|
218
|
+
// return false;
|
219
|
+
};
|
220
|
+
|
221
|
+
export const __Porffor_bigint_ge = (a: i32, b: i32): boolean => {
|
222
|
+
// todo
|
223
|
+
// return false;
|
224
|
+
};
|
225
|
+
|
226
|
+
export const __Porffor_bigint_lt = (a: i32, b: i32): boolean => {
|
227
|
+
return !__Porffor_bigint_ge(a, b);
|
228
|
+
};
|
229
|
+
|
230
|
+
export const __Porffor_bigint_le = (a: i32, b: i32): boolean => {
|
231
|
+
return !__Porffor_bigint_gt(a, b);
|
232
|
+
};
|
233
|
+
|
@@ -559,6 +559,8 @@ export const parseInt = (input: any, radix: any): f64 => {
|
|
559
559
|
|
560
560
|
let defaultRadix: boolean = false;
|
561
561
|
radix = ecma262.ToIntegerOrInfinity(radix);
|
562
|
+
if (!Number.isFinite(radix)) radix = 0; // infinity/NaN -> default
|
563
|
+
|
562
564
|
if (radix == 0) {
|
563
565
|
defaultRadix = true;
|
564
566
|
radix = 10;
|
package/compiler/builtins.js
CHANGED
@@ -1,10 +1,9 @@
|
|
1
1
|
import * as PrecompiledBuiltins from './builtins_precompiled.js';
|
2
2
|
import ObjectBuiltins from './builtins_objects.js';
|
3
3
|
import { Blocktype, Opcodes, Valtype, ValtypeSize } from './wasmSpec.js';
|
4
|
-
import { number } from './embedding.js';
|
5
4
|
import { TYPES, TYPE_NAMES } from './types.js';
|
5
|
+
import { number, unsignedLEB128 } from './encoding.js';
|
6
6
|
import './prefs.js';
|
7
|
-
import { unsignedLEB128 } from './encoding.js';
|
8
7
|
|
9
8
|
export const importedFuncs = [
|
10
9
|
{
|
@@ -230,90 +229,26 @@ export const BuiltinFuncs = function() {
|
|
230
229
|
};
|
231
230
|
|
232
231
|
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
]
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
[ Opcodes.f64_abs ]
|
254
|
-
]
|
255
|
-
};
|
256
|
-
|
257
|
-
this.__Math_sign = {
|
258
|
-
floatOnly: true,
|
259
|
-
params: [ valtypeBinary ],
|
260
|
-
locals: [],
|
261
|
-
returns: [ valtypeBinary ],
|
262
|
-
returnType: TYPES.number,
|
263
|
-
wasm: [
|
264
|
-
number(1),
|
265
|
-
[ Opcodes.local_get, 0 ],
|
266
|
-
[ Opcodes.f64_copysign ]
|
267
|
-
]
|
268
|
-
};
|
269
|
-
|
270
|
-
this.__Math_floor = {
|
271
|
-
floatOnly: true,
|
272
|
-
params: [ valtypeBinary ],
|
273
|
-
locals: [],
|
274
|
-
returns: [ valtypeBinary ],
|
275
|
-
returnType: TYPES.number,
|
276
|
-
wasm: [
|
277
|
-
[ Opcodes.local_get, 0 ],
|
278
|
-
[ Opcodes.f64_floor ]
|
279
|
-
]
|
280
|
-
};
|
281
|
-
|
282
|
-
this.__Math_ceil = {
|
283
|
-
floatOnly: true,
|
284
|
-
params: [ valtypeBinary ],
|
285
|
-
locals: [],
|
286
|
-
returns: [ valtypeBinary ],
|
287
|
-
returnType: TYPES.number,
|
288
|
-
wasm: [
|
289
|
-
[ Opcodes.local_get, 0 ],
|
290
|
-
[ Opcodes.f64_ceil ]
|
291
|
-
]
|
292
|
-
};
|
293
|
-
|
294
|
-
this.__Math_round = {
|
295
|
-
floatOnly: true,
|
296
|
-
params: [ valtypeBinary ],
|
297
|
-
locals: [],
|
298
|
-
returns: [ valtypeBinary ],
|
299
|
-
returnType: TYPES.number,
|
300
|
-
wasm: [
|
301
|
-
[ Opcodes.local_get, 0 ],
|
302
|
-
[ Opcodes.f64_nearest ]
|
303
|
-
]
|
304
|
-
};
|
305
|
-
|
306
|
-
this.__Math_trunc = {
|
307
|
-
floatOnly: true,
|
308
|
-
params: [ valtypeBinary ],
|
309
|
-
locals: [],
|
310
|
-
returns: [ valtypeBinary ],
|
311
|
-
returnType: TYPES.number,
|
312
|
-
wasm: [
|
313
|
-
[ Opcodes.local_get, 0 ],
|
314
|
-
[ Opcodes.f64_trunc ]
|
315
|
-
]
|
316
|
-
};
|
232
|
+
for (const [ name, op, prefix = [ [ Opcodes.local_get, 0 ] ] ] of [
|
233
|
+
[ 'sqrt', Opcodes.f64_sqrt ],
|
234
|
+
[ 'abs', Opcodes.f64_abs ],
|
235
|
+
[ 'sign', Opcodes.f64_copysign, [ number(1), [ Opcodes.local_get, 0 ] ] ],
|
236
|
+
[ 'floor', Opcodes.f64_floor ],
|
237
|
+
[ 'ceil', Opcodes.f64_ceil ],
|
238
|
+
[ 'round', Opcodes.f64_nearest ],
|
239
|
+
[ 'trunc', Opcodes.f64_trunc ]
|
240
|
+
]) {
|
241
|
+
this[`__Math_${name}`] = {
|
242
|
+
params: [ Valtype.f64 ],
|
243
|
+
locals: [],
|
244
|
+
returns: [ Valtype.f64 ],
|
245
|
+
returnType: TYPES.number,
|
246
|
+
wasm: [
|
247
|
+
...prefix,
|
248
|
+
[ op ]
|
249
|
+
]
|
250
|
+
};
|
251
|
+
}
|
317
252
|
|
318
253
|
// todo: does not follow spec with +-Infinity and values >2**32
|
319
254
|
this.__Math_clz32 = {
|
@@ -359,10 +294,7 @@ export const BuiltinFuncs = function() {
|
|
359
294
|
]
|
360
295
|
};
|
361
296
|
|
362
|
-
// this is an implementation of xorshift128+ (in wasm bytecode)
|
363
|
-
// fun fact: v8, SM, JSC also use this (you will need this fun fact to maintain your sanity reading this code)
|
364
297
|
const prngSeed0 = (Math.random() * (2 ** 30)) | 0, prngSeed1 = (Math.random() * (2 ** 30)) | 0;
|
365
|
-
|
366
298
|
const prng = ({
|
367
299
|
'lcg32': {
|
368
300
|
globals: [ Valtype.i32 ],
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import { Blocktype, Opcodes, PageSize, Valtype } from './wasmSpec.js';
|
2
2
|
import { TYPES } from './types.js';
|
3
|
-
import { number } from './
|
3
|
+
import { number } from './encoding.js';
|
4
4
|
|
5
5
|
export default function({ builtinFuncs }, Prefs) {
|
6
6
|
const makePrefix = name => (name.startsWith('__') ? '' : '__') + name + '_';
|