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 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) break; // ran out of keys
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) break; // ran out of keys
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;
@@ -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
- this.__Math_sqrt = {
234
- floatOnly: true,
235
- params: [ valtypeBinary ],
236
- locals: [],
237
- returns: [ valtypeBinary ],
238
- returnType: TYPES.number,
239
- wasm: [
240
- [ Opcodes.local_get, 0 ],
241
- [ Opcodes.f64_sqrt ]
242
- ]
243
- };
244
-
245
- this.__Math_abs = {
246
- floatOnly: true,
247
- params: [ valtypeBinary ],
248
- locals: [],
249
- returns: [ valtypeBinary ],
250
- returnType: TYPES.number,
251
- wasm: [
252
- [ Opcodes.local_get, 0 ],
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 './embedding.js';
3
+ import { number } from './encoding.js';
4
4
 
5
5
  export default function({ builtinFuncs }, Prefs) {
6
6
  const makePrefix = name => (name.startsWith('__') ? '' : '__') + name + '_';