porffor 0.57.32 → 0.57.33

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.
@@ -61,14 +61,14 @@ export const UNDEFINED = 0;
61
61
  export const NULL = 0;
62
62
 
63
63
  export const BuiltinVars = function(ctx) {
64
- this.undefined = [ number(UNDEFINED) ];
64
+ this.undefined = () => [ number(UNDEFINED) ];
65
65
  this.undefined.type = TYPES.undefined;
66
66
 
67
- this.null = [ number(NULL) ];
67
+ this.null = () => [ number(NULL) ];
68
68
  this.null.type = TYPES.object;
69
69
 
70
- this.NaN = [ number(NaN) ];
71
- this.Infinity = [ number(Infinity) ];
70
+ this.NaN = () => [ number(NaN) ];
71
+ this.Infinity = () => [ number(Infinity) ];
72
72
 
73
73
  for (const x in TYPES) {
74
74
  this['__Porffor_TYPES_' + x] = () => [ number(TYPES[x]) ];
@@ -79,17 +79,17 @@ export const BuiltinVars = function(ctx) {
79
79
  ];
80
80
  this.__performance_timeOrigin.usesImports = true;
81
81
 
82
- this.__Uint8Array_BYTES_PER_ELEMENT = [ number(1) ];
83
- this.__Int8Array_BYTES_PER_ELEMENT = [ number(1) ];
84
- this.__Uint8ClampedArray_BYTES_PER_ELEMENT = [ number(1) ];
85
- this.__Uint16Array_BYTES_PER_ELEMENT = [ number(2) ];
86
- this.__Int16Array_BYTES_PER_ELEMENT = [ number(2) ];
87
- this.__Uint32Array_BYTES_PER_ELEMENT = [ number(4) ];
88
- this.__Int32Array_BYTES_PER_ELEMENT = [ number(4) ];
89
- this.__Float32Array_BYTES_PER_ELEMENT = [ number(4) ];
90
- this.__Float64Array_BYTES_PER_ELEMENT = [ number(8) ];
91
- this.__BigInt64Array_BYTES_PER_ELEMENT = [ number(8) ];
92
- this.__BigUint64Array_BYTES_PER_ELEMENT = [ number(8) ];
82
+ this.__Uint8Array_BYTES_PER_ELEMENT = () => [ number(1) ];
83
+ this.__Int8Array_BYTES_PER_ELEMENT = () => [ number(1) ];
84
+ this.__Uint8ClampedArray_BYTES_PER_ELEMENT = () => [ number(1) ];
85
+ this.__Uint16Array_BYTES_PER_ELEMENT = () => [ number(2) ];
86
+ this.__Int16Array_BYTES_PER_ELEMENT = () => [ number(2) ];
87
+ this.__Uint32Array_BYTES_PER_ELEMENT = () => [ number(4) ];
88
+ this.__Int32Array_BYTES_PER_ELEMENT = () => [ number(4) ];
89
+ this.__Float32Array_BYTES_PER_ELEMENT = () => [ number(4) ];
90
+ this.__Float64Array_BYTES_PER_ELEMENT = () => [ number(8) ];
91
+ this.__BigInt64Array_BYTES_PER_ELEMENT = () => [ number(8) ];
92
+ this.__BigUint64Array_BYTES_PER_ELEMENT = () => [ number(8) ];
93
93
 
94
94
  // well-known symbols
95
95
  for (const x of [
@@ -128,7 +128,7 @@ export const BuiltinFuncs = function() {
128
128
  locals: [],
129
129
  returns: [ valtypeBinary ],
130
130
  returnType: TYPES.boolean,
131
- wasm: [
131
+ wasm: () => [
132
132
  [ Opcodes.local_get, 0 ],
133
133
  [ Opcodes.local_get, 0 ],
134
134
  [ Opcodes.f64_ne ],
@@ -142,7 +142,7 @@ export const BuiltinFuncs = function() {
142
142
  locals: [ valtypeBinary ],
143
143
  returns: [ valtypeBinary ],
144
144
  returnType: TYPES.boolean,
145
- wasm: [
145
+ wasm: () => [
146
146
  [ Opcodes.local_get, 0 ],
147
147
  [ Opcodes.local_get, 0 ],
148
148
  [ Opcodes.f64_sub ],
@@ -160,7 +160,7 @@ export const BuiltinFuncs = function() {
160
160
  locals: [],
161
161
  returns: [ valtypeBinary ],
162
162
  returnType: TYPES.boolean,
163
- wasm: [
163
+ wasm: () => [
164
164
  [ Opcodes.local_get, 0 ],
165
165
  [ Opcodes.local_get, 0 ],
166
166
  [ Opcodes.f64_trunc ],
@@ -174,7 +174,7 @@ export const BuiltinFuncs = function() {
174
174
  locals: [],
175
175
  returns: [ valtypeBinary ],
176
176
  returnType: TYPES.boolean,
177
- wasm: [
177
+ wasm: () => [
178
178
  [ Opcodes.local_get, 0 ],
179
179
  [ Opcodes.local_get, 0 ],
180
180
  [ Opcodes.f64_trunc ],
@@ -206,7 +206,7 @@ export const BuiltinFuncs = function() {
206
206
  locals: [],
207
207
  returns: [ Valtype.f64 ],
208
208
  returnType: TYPES.number,
209
- wasm: [
209
+ wasm: () => [
210
210
  ...prefix,
211
211
  [ op ]
212
212
  ]
@@ -219,7 +219,7 @@ export const BuiltinFuncs = function() {
219
219
  locals: [],
220
220
  returns: [ valtypeBinary ],
221
221
  returnType: TYPES.number,
222
- wasm: [
222
+ wasm: () => [
223
223
  [ Opcodes.local_get, 0 ],
224
224
  Opcodes.i32_to_u,
225
225
  [ Opcodes.i32_clz ],
@@ -232,7 +232,7 @@ export const BuiltinFuncs = function() {
232
232
  locals: [],
233
233
  returns: [ valtypeBinary ],
234
234
  returnType: TYPES.number,
235
- wasm: [
235
+ wasm: () => [
236
236
  [ Opcodes.local_get, 0 ],
237
237
  [ Opcodes.f32_demote_f64 ],
238
238
  [ Opcodes.f64_promote_f32 ]
@@ -245,7 +245,7 @@ export const BuiltinFuncs = function() {
245
245
  locals: [],
246
246
  returns: [ valtypeBinary ],
247
247
  returnType: TYPES.number,
248
- wasm: [
248
+ wasm: () => [
249
249
  [ Opcodes.local_get, 0 ],
250
250
  Opcodes.i32_to,
251
251
  [ Opcodes.local_get, 1 ],
@@ -256,280 +256,252 @@ export const BuiltinFuncs = function() {
256
256
  };
257
257
 
258
258
  const prngSeed0 = (Math.random() * (2 ** 30)) | 0, prngSeed1 = (Math.random() * (2 ** 30)) | 0;
259
- const prng = ({
260
- 'lcg32': {
261
- globals: [ Valtype.i32 ],
262
- locals: [],
263
- returns: Valtype.i32,
264
- wasm: [
265
- // use glibc/musl's constants
266
- // seed = (MULTIPLIER * seed + INCREMENT) % MODULUS
267
- [ Opcodes.global_get, 0 ],
268
- number(1103515245, Valtype.i32),
269
- [ Opcodes.i32_mul ],
270
-
271
- // + INCREMENT
272
- number(12345, Valtype.i32),
273
- [ Opcodes.i32_add ],
274
-
275
- // % MODULUS
276
- number(0x7fffffff, Valtype.i32),
277
- [ Opcodes.i32_and ],
278
-
279
- // state0 =
280
- [ Opcodes.global_set, 0 ],
281
-
282
- // state0
283
- [ Opcodes.global_get, 0 ],
284
- ],
285
- },
286
-
287
- 'xorshift32+': {
288
- globals: [ Valtype.i32 ],
289
- locals: [ Valtype.i32 ],
290
- returns: Valtype.i32,
291
- wasm: [
292
- // setup: s1 = state0
293
- [ Opcodes.global_get, 0 ], // state0
294
- [ Opcodes.local_tee, 0 ], // s1
295
-
296
- // s1 ^= s1 << 13
297
- [ Opcodes.local_get, 0 ], // s1
298
- [ Opcodes.i32_const, 13 ],
299
- [ Opcodes.i32_shl ], // <<
300
- [ Opcodes.i32_xor ], // ^
301
- [ Opcodes.local_tee, 0 ], // s1
302
-
303
- // s1 ^= s1 >> 17
304
- [ Opcodes.local_get, 0 ], // s1
305
- [ Opcodes.i32_const, 17 ],
306
- [ Opcodes.i32_shr_s ], // >>
307
- [ Opcodes.i32_xor ], // ^
308
- [ Opcodes.local_tee, 0 ], // s1
309
-
310
- // s1 ^= s1 << 5
311
- [ Opcodes.local_get, 0 ], // s1
312
- [ Opcodes.i32_const, 5 ],
313
- [ Opcodes.i32_shl ], // <<
314
- [ Opcodes.i32_xor ], // ^
315
- [ Opcodes.local_tee, 0 ], // s1
316
-
317
- // state0 = s1
318
- [ Opcodes.global_set, 0 ],
319
-
320
- // s1
321
- [ Opcodes.local_get, 0 ],
322
- ],
323
- },
324
-
325
- 'xorshift64+': {
326
- globals: [ Valtype.i64 ],
327
- locals: [ Valtype.i64 ],
328
- returns: Valtype.i64,
329
- wasm: [
330
- // setup: s1 = state0
331
- [ Opcodes.global_get, 0 ], // state0
332
- [ Opcodes.local_tee, 0 ], // s1
333
-
334
- // s1 ^= s1 >> 12
335
- [ Opcodes.local_get, 0 ], // s1
336
- [ Opcodes.i64_const, 12 ],
337
- [ Opcodes.i64_shr_s ], // >>
338
- [ Opcodes.i64_xor ], // ^
339
- [ Opcodes.local_tee, 0 ], // s1
340
-
341
- // s1 ^= s1 << 25
342
- [ Opcodes.local_get, 0 ], // s1
343
- [ Opcodes.i64_const, 25 ],
344
- [ Opcodes.i64_shl ], // <<
345
- [ Opcodes.i64_xor ], // ^
346
- [ Opcodes.local_tee, 0 ], // s1
347
-
348
- // s1 ^= s1 >> 27
349
- [ Opcodes.local_get, 0 ], // s1
350
- [ Opcodes.i64_const, 27 ],
351
- [ Opcodes.i64_shr_s ], // >>
352
- [ Opcodes.i64_xor ], // ^
353
- [ Opcodes.local_tee, 0 ], // s1
354
-
355
- // state0 = s1
356
- [ Opcodes.global_set, 0 ],
357
-
358
- // s1
359
- [ Opcodes.local_get, 0 ],
360
- ],
361
- },
362
-
363
- 'xorshift128+': {
364
- globals: [ Valtype.i64, Valtype.i64 ],
365
- locals: [ Valtype.i64, Valtype.i64 ],
366
- returns: Valtype.i64,
367
- wasm: [
368
- // setup: s1 = state0, s0 = state1, state0 = s0
369
- [ Opcodes.global_get, 0 ], // state0
370
- [ Opcodes.local_tee, 0 ], // s1
371
- [ Opcodes.global_get, 1 ], // state1
372
- [ Opcodes.local_tee, 1, ], // s0
373
- [ Opcodes.global_set, 0 ], // state0
374
-
375
- // s1 ^= s1 << 23
376
- // [ Opcodes.local_get, 0 ], // s1
377
- [ Opcodes.local_get, 0 ], // s1
378
- [ Opcodes.i64_const, 23 ],
379
- [ Opcodes.i64_shl ], // <<
380
- [ Opcodes.i64_xor ], // ^
381
- [ Opcodes.local_set, 0 ], // s1
382
-
383
- // state1 = s1 ^ s0 ^ (s1 >> 17) ^ (s0 >> 26)
384
- // s1 ^ s0
385
- [ Opcodes.local_get, 0 ], // s1
386
- [ Opcodes.local_get, 1 ], // s0
387
- [ Opcodes.i64_xor ], // ^
388
-
389
- // ^ (s1 >> 17)
390
- [ Opcodes.local_get, 0 ], // s1
391
- [ Opcodes.i64_const, 17 ],
392
- [ Opcodes.i64_shr_u ], // >>
393
- [ Opcodes.i64_xor ], // ^
394
-
395
- // ^ (s0 >> 26)
396
- [ Opcodes.local_get, 1 ], // s0
397
- [ Opcodes.i64_const, 26 ],
398
- [ Opcodes.i64_shr_u ], // >>
399
- [ Opcodes.i64_xor ], // ^
400
-
401
- // state1 =
402
- [ Opcodes.global_set, 1 ],
403
-
404
- // state1 + s0
405
- [ Opcodes.global_get, 1 ], // state1
406
- [ Opcodes.local_get, 1 ], // s0
407
- [ Opcodes.i64_add ]
408
- ]
409
- },
410
-
411
- 'xoroshiro128+': {
412
- globals: [ Valtype.i64, Valtype.i64 ],
413
- locals: [ Valtype.i64, Valtype.i64, Valtype.i64 ],
414
- returns: Valtype.i64,
415
- wasm: [
416
- // setup: s1 = state1, s0 = state0
417
- [ Opcodes.global_get, 1 ], // state0
418
- [ Opcodes.local_tee, 0 ], // s1
419
- [ Opcodes.global_get, 0 ], // state1
420
- [ Opcodes.local_tee, 1, ], // s0
421
-
422
- // result = s0 + s1
423
- [ Opcodes.i64_add ],
424
- [ Opcodes.local_set, 2 ], // result
425
-
426
- // s1 ^= s0
427
- [ Opcodes.local_get, 0 ], // s1
428
- [ Opcodes.local_get, 1 ], // s0
429
- [ Opcodes.i64_xor ],
430
- [ Opcodes.local_set, 0 ], // s1
431
-
432
- // state0 = rotl(s0, 24) ^ s1 ^ (s1 << 16)
433
-
434
- // rotl(s0, 24) ^ s1
435
- [ Opcodes.local_get, 1 ], // s0
436
- number(24, Valtype.i64),
437
- [ Opcodes.i64_rotl ],
438
- [ Opcodes.local_get, 0 ], // s1
439
- [ Opcodes.i64_xor ],
440
-
441
- // ^ (s1 << 16)
442
- [ Opcodes.local_get, 0 ], // s1
443
- number(16, Valtype.i64),
444
- [ Opcodes.i64_shl ],
445
- [ Opcodes.i64_xor ],
446
-
447
- // state0 =
448
- [ Opcodes.global_set, 0 ], // state0
449
-
450
- // state1 = rotl(s1, 37)
451
- [ Opcodes.local_get, 0 ], // s1
452
- number(37, Valtype.i64),
453
- [ Opcodes.i64_rotl ],
454
- [ Opcodes.global_set, 1 ], // state1
455
-
456
- // result
457
- [ Opcodes.local_get, 2 ],
458
- ]
459
- },
460
-
461
- 'xoshiro128+': {
462
- globals: [ Valtype.i32, Valtype.i32, Valtype.i32, Valtype.i32 ],
463
- locals: [ Valtype.i32, Valtype.i32 ],
464
- returns: Valtype.i32,
465
- wasm: [
466
- // result = state0 + state3
467
- [ Opcodes.global_get, 0 ], // state0
468
- [ Opcodes.global_get, 3 ], // state0
469
- [ Opcodes.i32_add ],
470
- [ Opcodes.local_set, 0 ], // result
471
-
472
- // t = state1 << 9
473
- [ Opcodes.global_get, 1 ], // state1
474
- number(9, Valtype.i32),
475
- [ Opcodes.i32_shl ],
476
- [ Opcodes.local_set, 1 ], // t
477
-
478
- // state2 ^= state0
479
- [ Opcodes.global_get, 2 ], // state2
480
- [ Opcodes.global_get, 0 ], // state0
481
- [ Opcodes.i32_xor ],
482
- [ Opcodes.global_set, 2 ], // state2
483
-
484
- // state3 ^= state1
485
- [ Opcodes.global_get, 3 ], // state3
486
- [ Opcodes.global_get, 1 ], // state1
487
- [ Opcodes.i32_xor ],
488
- [ Opcodes.global_set, 3 ], // state3
489
-
490
- // state1 ^= state2
491
- [ Opcodes.global_get, 1 ], // state1
492
- [ Opcodes.global_get, 2 ], // state2
493
- [ Opcodes.i32_xor ],
494
- [ Opcodes.global_set, 1 ], // state1
495
-
496
- // state0 ^= state3
497
- [ Opcodes.global_get, 0 ], // state2
498
- [ Opcodes.global_get, 3 ], // state0
499
- [ Opcodes.i32_xor ],
500
- [ Opcodes.global_set, 0 ], // state2
501
-
502
- // state2 ^= t
503
- [ Opcodes.global_get, 2 ], // state2
504
- [ Opcodes.local_get, 1 ], // t
505
- [ Opcodes.i32_xor ],
506
- [ Opcodes.global_set, 2 ], // state2
507
-
508
- // state3 = rotl(state3, 11)
509
- [ Opcodes.global_get, 3 ], // state3
510
- number(11, Valtype.i32),
511
- [ Opcodes.i32_rotl ],
512
- [ Opcodes.global_set, 3 ], // state3
513
-
514
- // result
515
- [ Opcodes.local_get, 0 ],
516
- ]
517
- }
518
- })[Prefs.prng ?? 'xorshift128+'];
259
+ const prng = {
260
+ localNames: ['s1', 's0'],
261
+ ...({
262
+ 'xorshift32+': {
263
+ globalInits: { state0: prngSeed0 },
264
+ locals: [ Valtype.i32 ],
265
+ returns: Valtype.i32,
266
+ wasm: (scope, { glbl }) => [
267
+ // setup: s1 = state0
268
+ ...glbl(Opcodes.global_get, 'state0', Valtype.i32), // state0
269
+ [ Opcodes.local_tee, 0 ], // s1
270
+
271
+ // s1 ^= s1 << 13
272
+ [ Opcodes.local_get, 0 ], // s1
273
+ [ Opcodes.i32_const, 13 ],
274
+ [ Opcodes.i32_shl ], // <<
275
+ [ Opcodes.i32_xor ], // ^
276
+ [ Opcodes.local_tee, 0 ], // s1
277
+
278
+ // s1 ^= s1 >> 17
279
+ [ Opcodes.local_get, 0 ], // s1
280
+ [ Opcodes.i32_const, 17 ],
281
+ [ Opcodes.i32_shr_s ], // >>
282
+ [ Opcodes.i32_xor ], // ^
283
+ [ Opcodes.local_tee, 0 ], // s1
284
+
285
+ // s1 ^= s1 << 5
286
+ [ Opcodes.local_get, 0 ], // s1
287
+ [ Opcodes.i32_const, 5 ],
288
+ [ Opcodes.i32_shl ], // <<
289
+ [ Opcodes.i32_xor ], // ^
290
+ [ Opcodes.local_tee, 0 ], // s1
291
+
292
+ // state0 = s1
293
+ ...glbl(Opcodes.global_set, 'state0', Valtype.i32),
294
+
295
+ // s1
296
+ [ Opcodes.local_get, 0 ],
297
+ ],
298
+ },
299
+
300
+ 'xorshift64+': {
301
+ globalInits: { state0: prngSeed0 },
302
+ locals: [ Valtype.i64 ],
303
+ returns: Valtype.i64,
304
+ wasm: (scope, { glbl }) => [
305
+ // setup: s1 = state0
306
+ ...glbl(Opcodes.global_get, 'state0', Valtype.i64), // state0
307
+ [ Opcodes.local_tee, 0 ], // s1
308
+
309
+ // s1 ^= s1 >> 12
310
+ [ Opcodes.local_get, 0 ], // s1
311
+ [ Opcodes.i64_const, 12 ],
312
+ [ Opcodes.i64_shr_s ], // >>
313
+ [ Opcodes.i64_xor ], // ^
314
+ [ Opcodes.local_tee, 0 ], // s1
315
+
316
+ // s1 ^= s1 << 25
317
+ [ Opcodes.local_get, 0 ], // s1
318
+ [ Opcodes.i64_const, 25 ],
319
+ [ Opcodes.i64_shl ], // <<
320
+ [ Opcodes.i64_xor ], // ^
321
+ [ Opcodes.local_tee, 0 ], // s1
322
+
323
+ // s1 ^= s1 >> 27
324
+ [ Opcodes.local_get, 0 ], // s1
325
+ [ Opcodes.i64_const, 27 ],
326
+ [ Opcodes.i64_shr_s ], // >>
327
+ [ Opcodes.i64_xor ], // ^
328
+ [ Opcodes.local_tee, 0 ], // s1
329
+
330
+ // state0 = s1
331
+ ...glbl(Opcodes.global_set, 'state0', Valtype.i64),
332
+
333
+ // s1
334
+ [ Opcodes.local_get, 0 ],
335
+ ],
336
+ },
337
+
338
+ 'xorshift128+': {
339
+ globalInits: { state0: prngSeed0, state1: prngSeed1 },
340
+ locals: [ Valtype.i64, Valtype.i64 ],
341
+ returns: Valtype.i64,
342
+ wasm: (scope, { glbl }) => [
343
+ // setup: s1 = state0, s0 = state1, state0 = s0
344
+ ...glbl(Opcodes.global_get, 'state0', Valtype.i64), // state0
345
+ [ Opcodes.local_tee, 0 ], // s1
346
+ ...glbl(Opcodes.global_get, 'state1', Valtype.i64), // state1
347
+ [ Opcodes.local_tee, 1, ], // s0
348
+ ...glbl(Opcodes.global_set, 'state0', Valtype.i64), // state0
349
+
350
+ // s1 ^= s1 << 23
351
+ // [ Opcodes.local_get, 0 ], // s1
352
+ [ Opcodes.local_get, 0 ], // s1
353
+ [ Opcodes.i64_const, 23 ],
354
+ [ Opcodes.i64_shl ], // <<
355
+ [ Opcodes.i64_xor ], // ^
356
+ [ Opcodes.local_set, 0 ], // s1
357
+
358
+ // state1 = s1 ^ s0 ^ (s1 >> 17) ^ (s0 >> 26)
359
+ // s1 ^ s0
360
+ [ Opcodes.local_get, 0 ], // s1
361
+ [ Opcodes.local_get, 1 ], // s0
362
+ [ Opcodes.i64_xor ], // ^
363
+
364
+ // ^ (s1 >> 17)
365
+ [ Opcodes.local_get, 0 ], // s1
366
+ [ Opcodes.i64_const, 17 ],
367
+ [ Opcodes.i64_shr_u ], // >>
368
+ [ Opcodes.i64_xor ], // ^
369
+
370
+ // ^ (s0 >> 26)
371
+ [ Opcodes.local_get, 1 ], // s0
372
+ [ Opcodes.i64_const, 26 ],
373
+ [ Opcodes.i64_shr_u ], // >>
374
+ [ Opcodes.i64_xor ], // ^
375
+
376
+ // state1 =
377
+ ...glbl(Opcodes.global_set, 'state1', Valtype.i64),
378
+
379
+ // state1 + s0
380
+ ...glbl(Opcodes.global_get, 'state1', Valtype.i64), // state1
381
+ [ Opcodes.local_get, 1 ], // s0
382
+ [ Opcodes.i64_add ]
383
+ ]
384
+ },
385
+
386
+ 'xoroshiro128+': {
387
+ globalInits: { state0: prngSeed0, state1: prngSeed1 },
388
+ locals: [ Valtype.i64, Valtype.i64, Valtype.i64 ],
389
+ returns: Valtype.i64,
390
+ wasm: (scope, { glbl }) => [
391
+ // setup: s1 = state1, s0 = state0
392
+ ...glbl(Opcodes.global_get, 'state1', Valtype.i64), // state0
393
+ [ Opcodes.local_tee, 0 ], // s1
394
+ ...glbl(Opcodes.global_get, 'state0', Valtype.i64), // state1
395
+ [ Opcodes.local_tee, 1, ], // s0
396
+
397
+ // result = s0 + s1
398
+ [ Opcodes.i64_add ],
399
+ [ Opcodes.local_set, 2 ], // result
400
+
401
+ // s1 ^= s0
402
+ [ Opcodes.local_get, 0 ], // s1
403
+ [ Opcodes.local_get, 1 ], // s0
404
+ [ Opcodes.i64_xor ],
405
+ [ Opcodes.local_set, 0 ], // s1
406
+
407
+ // state0 = rotl(s0, 24) ^ s1 ^ (s1 << 16)
408
+
409
+ // rotl(s0, 24) ^ s1
410
+ [ Opcodes.local_get, 1 ], // s0
411
+ number(24, Valtype.i64),
412
+ [ Opcodes.i64_rotl ],
413
+ [ Opcodes.local_get, 0 ], // s1
414
+ [ Opcodes.i64_xor ],
415
+
416
+ // ^ (s1 << 16)
417
+ [ Opcodes.local_get, 0 ], // s1
418
+ number(16, Valtype.i64),
419
+ [ Opcodes.i64_shl ],
420
+ [ Opcodes.i64_xor ],
421
+
422
+ // state0 =
423
+ ...glbl(Opcodes.global_set, 'state0', Valtype.i64), // state0
424
+
425
+ // state1 = rotl(s1, 37)
426
+ [ Opcodes.local_get, 0 ], // s1
427
+ number(37, Valtype.i64),
428
+ [ Opcodes.i64_rotl ],
429
+ ...glbl(Opcodes.global_set, 'state1', Valtype.i64), // state1
430
+
431
+ // result
432
+ [ Opcodes.local_get, 2 ],
433
+ ]
434
+ },
435
+
436
+ 'xoshiro128+': {
437
+ globalInits: { state0: prngSeed0, state1: prngSeed1, state2: (prngSeed0 * 17) | 0, state3: (prngSeed1 * 31) | 0 },
438
+ locals: [ Valtype.i32, Valtype.i32 ],
439
+ returns: Valtype.i32,
440
+ wasm: (scope, { glbl }) => [
441
+ // result = state0 + state3
442
+ ...glbl(Opcodes.global_get, 'state0', Valtype.i32), // state0
443
+ ...glbl(Opcodes.global_get, 'state3', Valtype.i32), // state0
444
+ [ Opcodes.i32_add ],
445
+ [ Opcodes.local_set, 0 ], // result
446
+
447
+ // t = state1 << 9
448
+ ...glbl(Opcodes.global_get, 'state1', Valtype.i32), // state1
449
+ number(9, Valtype.i32),
450
+ [ Opcodes.i32_shl ],
451
+ [ Opcodes.local_set, 1 ], // t
452
+
453
+ // state2 ^= state0
454
+ ...glbl(Opcodes.global_get, 'state2', Valtype.i32), // state2
455
+ ...glbl(Opcodes.global_get, 'state0', Valtype.i32), // state0
456
+ [ Opcodes.i32_xor ],
457
+ ...glbl(Opcodes.global_set, 'state2', Valtype.i32), // state2
458
+
459
+ // state3 ^= state1
460
+ ...glbl(Opcodes.global_get, 'state3', Valtype.i32), // state3
461
+ ...glbl(Opcodes.global_get, 'state1', Valtype.i32), // state1
462
+ [ Opcodes.i32_xor ],
463
+ ...glbl(Opcodes.global_set, 'state3', Valtype.i32), // state3
464
+
465
+ // state1 ^= state2
466
+ ...glbl(Opcodes.global_get, 'state1', Valtype.i32), // state1
467
+ ...glbl(Opcodes.global_get, 'state2', Valtype.i32), // state2
468
+ [ Opcodes.i32_xor ],
469
+ ...glbl(Opcodes.global_set, 'state1', Valtype.i32), // state1
470
+
471
+ // state0 ^= state3
472
+ ...glbl(Opcodes.global_get, 'state0', Valtype.i32), // state2
473
+ ...glbl(Opcodes.global_get, 'state3', Valtype.i32), // state0
474
+ [ Opcodes.i32_xor ],
475
+ ...glbl(Opcodes.global_set, 'state0', Valtype.i32), // state2
476
+
477
+ // state2 ^= t
478
+ ...glbl(Opcodes.global_get, 'state2', Valtype.i32), // state2
479
+ [ Opcodes.local_get, 1 ], // t
480
+ [ Opcodes.i32_xor ],
481
+ ...glbl(Opcodes.global_set, 'state2', Valtype.i32), // state2
482
+
483
+ // state3 = rotl(state3, 11)
484
+ ...glbl(Opcodes.global_get, 'state3', Valtype.i32), // state3
485
+ number(11, Valtype.i32),
486
+ [ Opcodes.i32_rotl ],
487
+ ...glbl(Opcodes.global_set, 'state3', Valtype.i32), // state3
488
+
489
+ // result
490
+ [ Opcodes.local_get, 0 ],
491
+ ]
492
+ }
493
+ })[Prefs.prng ?? 'xorshift128+']
494
+ }
519
495
 
520
496
  if (!prng) throw new Error(`unknown prng algo: ${Prefs.prng}`);
521
497
 
522
498
  this.__Math_random = {
499
+ ...prng,
523
500
  params: [],
524
- locals: prng.locals,
525
- localNames: [ 's1', 's0' ],
526
- globals: prng.globals,
527
- globalNames: [ 'state0', 'state1' ],
528
- globalInits: [ prngSeed0, prngSeed1 ],
529
501
  returns: [ Valtype.f64 ],
530
502
  returnType: TYPES.number,
531
- wasm: [
532
- ...prng.wasm,
503
+ wasm: (scope, utils) => [
504
+ ...prng.wasm(scope, utils),
533
505
  ...(prng.returns === Valtype.i64 ? [
534
506
  number((1 << 53) - 1, Valtype.i64),
535
507
  [ Opcodes.i64_and ],
@@ -555,17 +527,12 @@ export const BuiltinFuncs = function() {
555
527
  };
556
528
 
557
529
  this.__Porffor_randomByte = {
530
+ ...prng,
558
531
  params: [],
559
- locals: prng.locals,
560
- localNames: [ 's1', 's0' ],
561
- globals: prng.globals,
562
- globalNames: [ 'state0', 'state1' ],
563
- globalInits: [ prngSeed0, prngSeed1 ],
564
532
  returns: [ Valtype.i32 ],
565
533
  returnType: TYPES.number,
566
- wasm: [
567
- ...prng.wasm,
568
-
534
+ wasm: (scope, utils) => [
535
+ ...prng.wasm(scope, utils),
569
536
  ...(prng.returns === Valtype.i64 ? [
570
537
  // the lowest bits of the output generated by xorshift128+ have low quality
571
538
  number(56, Valtype.i64),
@@ -584,7 +551,7 @@ export const BuiltinFuncs = function() {
584
551
  locals: [],
585
552
  returns: [ valtypeBinary ],
586
553
  returnType: TYPES.number,
587
- wasm: [
554
+ wasm: () => [
588
555
  [ Opcodes.local_get, 0 ],
589
556
  number(Math.PI / 180),
590
557
  [ Opcodes.f64_mul ]
@@ -596,7 +563,7 @@ export const BuiltinFuncs = function() {
596
563
  locals: [],
597
564
  returns: [ valtypeBinary ],
598
565
  returnType: TYPES.number,
599
- wasm: [
566
+ wasm: () => [
600
567
  [ Opcodes.local_get, 0 ],
601
568
  number(180 / Math.PI),
602
569
  [ Opcodes.f64_mul ]
@@ -609,7 +576,7 @@ export const BuiltinFuncs = function() {
609
576
  localNames: [ 'x', 'lower', 'upper' ],
610
577
  returns: [ valtypeBinary ],
611
578
  returnType: TYPES.number,
612
- wasm: [
579
+ wasm: () => [
613
580
  [ Opcodes.local_get, 0 ],
614
581
  [ Opcodes.local_get, 1 ],
615
582
  [ Opcodes.f64_max ],
@@ -624,7 +591,7 @@ export const BuiltinFuncs = function() {
624
591
  localNames: [ 'x', 'inLow', 'inHigh', 'outLow', 'outHigh' ],
625
592
  returns: [ valtypeBinary ],
626
593
  returnType: TYPES.number,
627
- wasm: [
594
+ wasm: () => [
628
595
  // (x − inLow) * (outHigh − outLow) / (inHigh - inLow) + outLow
629
596
  [ Opcodes.local_get, 0 ],
630
597
  [ Opcodes.local_get, 1 ],
@@ -653,7 +620,7 @@ export const BuiltinFuncs = function() {
653
620
  locals: [],
654
621
  returns: [ valtypeBinary ],
655
622
  returnType: TYPES.boolean,
656
- wasm: [
623
+ wasm: () => [
657
624
  [ Opcodes.local_get, 0 ],
658
625
  number(0),
659
626
  [ Opcodes.f64_le ],
@@ -667,7 +634,7 @@ export const BuiltinFuncs = function() {
667
634
  locals: [],
668
635
  returns: [ valtypeBinary ],
669
636
  returnType: TYPES.number,
670
- wasm: [
637
+ wasm: () => [
671
638
  [ Opcodes.call, importedFuncs.time ]
672
639
  ]
673
640
  };
@@ -694,7 +661,7 @@ export const BuiltinFuncs = function() {
694
661
  locals: [],
695
662
  returns: [],
696
663
  returnType: TYPES.undefined,
697
- wasm: [
664
+ wasm: () => [
698
665
  [ Opcodes.local_get, 1 ],
699
666
  [ Opcodes.local_get, 0 ],
700
667
  number(pageSize, Valtype.i32),
@@ -708,7 +675,7 @@ export const BuiltinFuncs = function() {
708
675
  locals: [],
709
676
  returns: [ Valtype.i32 ],
710
677
  returnType: TYPES.number,
711
- wasm: [
678
+ wasm: () => [
712
679
  number(1, Valtype.i32),
713
680
  [ Opcodes.memory_grow, 0 ],
714
681
  number(PageSize, Valtype.i32),
@@ -718,39 +685,37 @@ export const BuiltinFuncs = function() {
718
685
  chunk: {
719
686
  params: [],
720
687
  locals: [],
721
- globals: [ Valtype.i32, Valtype.i32 ],
722
- globalNames: [ 'chunkPtr', 'chunkOffset' ],
723
- globalInits: [ 0, 100 * PageSize ],
688
+ globalInits: { chunkPtr: 0, chunkOffset: 100 * PageSize },
724
689
  returns: [ Valtype.i32 ],
725
690
  returnType: TYPES.number,
726
- wasm: [
691
+ wasm: (scope, { glbl }) => [
727
692
  // if chunkOffset >= chunks:
728
- [ Opcodes.global_get, 1 ],
693
+ ...glbl(Opcodes.global_get, 'chunkOffset', Valtype.i32),
729
694
  number(PageSize * (Prefs.allocatorChunks ?? 16), Valtype.i32),
730
695
  [ Opcodes.i32_ge_s ],
731
696
  [ Opcodes.if, Valtype.i32 ],
732
697
  // chunkOffset = 1 page
733
698
  number(pageSize, Valtype.i32),
734
- [ Opcodes.global_set, 1 ],
699
+ ...glbl(Opcodes.global_set, 'chunkOffset', Valtype.i32),
735
700
 
736
701
  // return chunkPtr = allocated
737
702
  number(Prefs.allocatorChunks ?? 16, Valtype.i32),
738
703
  [ Opcodes.memory_grow, 0 ],
739
704
  number(PageSize, Valtype.i32),
740
705
  [ Opcodes.i32_mul ],
741
- [ Opcodes.global_set, 0 ],
742
- [ Opcodes.global_get, 0 ],
706
+ ...glbl(Opcodes.global_set, 'chunkPtr', Valtype.i32),
707
+ ...glbl(Opcodes.global_get, 'chunkPtr', Valtype.i32),
743
708
  [ Opcodes.else ],
744
709
  // return chunkPtr + chunkOffset
745
- [ Opcodes.global_get, 0 ],
746
- [ Opcodes.global_get, 1 ],
710
+ ...glbl(Opcodes.global_get, 'chunkPtr', Valtype.i32),
711
+ ...glbl(Opcodes.global_get, 'chunkOffset', Valtype.i32),
747
712
  [ Opcodes.i32_add ],
748
713
 
749
714
  // chunkOffset += 1 page
750
715
  number(pageSize, Valtype.i32),
751
- [ Opcodes.global_get, 1 ],
716
+ ...glbl(Opcodes.global_get, 'chunkOffset', Valtype.i32),
752
717
  [ Opcodes.i32_add ],
753
- [ Opcodes.global_set, 1 ],
718
+ ...glbl(Opcodes.global_set, 'chunkOffset', Valtype.i32),
754
719
  [ Opcodes.end ]
755
720
  ]
756
721
  }
@@ -759,36 +724,34 @@ export const BuiltinFuncs = function() {
759
724
  this.__Porffor_allocateBytes = {
760
725
  params: [ Valtype.i32 ],
761
726
  locals: [],
762
- globals: [ Valtype.i32, Valtype.i32 ],
763
- globalNames: [ 'currentPtr', 'bytesWritten' ],
764
- globalInits: [ 0, pageSize ], // init to pageSize so we always allocate on first call
727
+ globalInits: { currentPtr: 0, bytesWritten: pageSize }, // init to pageSize so we always allocate on first call
765
728
  returns: [ Valtype.i32 ],
766
729
  returnType: TYPES.number,
767
- wasm: (scope, { builtin }) => [
730
+ wasm: (scope, { builtin, glbl }) => [
768
731
  // if bytesWritten >= pageSize:
769
- [ Opcodes.global_get, 1 ],
732
+ ...glbl(Opcodes.global_get, 'bytesWritten', Valtype.i32),
770
733
  number(pageSize, Valtype.i32),
771
734
  [ Opcodes.i32_ge_s ],
772
735
  [ Opcodes.if, Valtype.i32 ],
773
736
  // bytesWritten = bytesToAllocate
774
737
  [ Opcodes.local_get, 0 ],
775
- [ Opcodes.global_set, 1 ],
738
+ ...glbl(Opcodes.global_set, 'bytesWritten', Valtype.i32),
776
739
 
777
740
  // return currentPtr = newly allocated page
778
741
  [ Opcodes.call, builtin('__Porffor_allocate') ],
779
- [ Opcodes.global_set, 0 ],
780
- [ Opcodes.global_get, 0 ],
742
+ ...glbl(Opcodes.global_set, 'currentPtr', Valtype.i32),
743
+ ...glbl(Opcodes.global_get, 'currentPtr', Valtype.i32),
781
744
  [ Opcodes.else ],
782
745
  // return currentPtr + bytesWritten
783
- [ Opcodes.global_get, 0 ],
784
- [ Opcodes.global_get, 1 ],
746
+ ...glbl(Opcodes.global_get, 'currentPtr', Valtype.i32),
747
+ ...glbl(Opcodes.global_get, 'bytesWritten', Valtype.i32),
785
748
  [ Opcodes.i32_add ],
786
749
 
787
750
  // bytesWritten += bytesToAllocate
788
751
  [ Opcodes.local_get, 0 ],
789
- [ Opcodes.global_get, 1 ],
752
+ ...glbl(Opcodes.global_get, 'bytesWritten', Valtype.i32),
790
753
  [ Opcodes.i32_add ],
791
- [ Opcodes.global_set, 1 ],
754
+ ...glbl(Opcodes.global_set, 'bytesWritten', Valtype.i32),
792
755
  [ Opcodes.end ]
793
756
  ]
794
757
  };
@@ -893,7 +856,7 @@ export const BuiltinFuncs = function() {
893
856
  params: [ Valtype.f64 ],
894
857
  returns: [ Valtype.i32 ],
895
858
  returnType: TYPES.number,
896
- wasm: [
859
+ wasm: () => [
897
860
  // extract exponent bits from f64 with bit manipulation
898
861
  [ Opcodes.local_get, 0 ],
899
862
  [ Opcodes.i64_reinterpret_f64 ],
@@ -2,7 +2,7 @@ import { Blocktype, Opcodes, Valtype } from './wasmSpec.js';
2
2
  import { TYPES } from './types.js';
3
3
  import { number } from './encoding.js';
4
4
 
5
- export default function({ builtinFuncs }, Prefs) {
5
+ export default function ({ builtinFuncs }, Prefs) {
6
6
  const makePrefix = name => (name.startsWith('__') ? '' : '__') + name + '_';
7
7
 
8
8
  const done = new Set();
@@ -72,16 +72,15 @@ export default function({ builtinFuncs }, Prefs) {
72
72
  continue;
73
73
  }
74
74
 
75
- let flags = 0b0000;
75
+ let add = true;
76
+ if (existingFunc && (x === 'prototype' || x === 'constructor')) add = false;
76
77
 
78
+ let flags = 0b0000;
77
79
  const d = props[x];
78
80
  if (d.configurable) flags |= 0b0010;
79
81
  if (d.enumerable) flags |= 0b0100;
80
82
  if (d.writable) flags |= 0b1000;
81
83
 
82
- // hack: do not generate objects inside of objects as it causes issues atm
83
- if (this[prefix + x]?.type === TYPES.object && this[prefix + x] !== this.null) value = { type: 'ObjectExpression', properties: [] };
84
-
85
84
  out.push(
86
85
  [ Opcodes.local_get, 0 ],
87
86
  number(TYPES.object, Valtype.i32),
@@ -96,7 +95,7 @@ export default function({ builtinFuncs }, Prefs) {
96
95
  number(flags, Valtype.i32),
97
96
  number(TYPES.number, Valtype.i32),
98
97
 
99
- [ Opcodes.call, builtin('__Porffor_object_fastAdd') ]
98
+ [ Opcodes.call, builtin(add ? '__Porffor_object_fastAdd' : '__Porffor_object_define') ]
100
99
  );
101
100
  }
102
101
 
@@ -170,11 +169,20 @@ export default function({ builtinFuncs }, Prefs) {
170
169
  const prefix = makePrefix(name);
171
170
  return builtinFuncKeys.filter(x => x.startsWith(prefix)).map(x => x.slice(prefix.length)).filter(x => !x.startsWith('prototype_'));
172
171
  };
173
- const autoFuncs = name => props({
174
- writable: true,
175
- enumerable: false,
176
- configurable: true
177
- }, autoFuncKeys(name));
172
+ const autoFuncs = name => ({
173
+ ...props({
174
+ writable: true,
175
+ enumerable: false,
176
+ configurable: true
177
+ }, autoFuncKeys(name)),
178
+ ...(this[`__${name}_prototype`] ? {
179
+ prototype: {
180
+ writable: false,
181
+ enumerable: false,
182
+ configurable: false
183
+ }
184
+ } : {})
185
+ });
178
186
 
179
187
  object('Math', {
180
188
  ...props({
@@ -248,28 +256,16 @@ export default function({ builtinFuncs }, Prefs) {
248
256
  NaN: NaN,
249
257
  POSITIVE_INFINITY: Infinity,
250
258
  NEGATIVE_INFINITY: -Infinity,
251
-
252
259
  MAX_VALUE: valtype === 'i32' ? 2147483647 : 1.7976931348623157e+308,
253
260
  MIN_VALUE: valtype === 'i32' ? -2147483648 : 5e-324,
254
-
255
261
  MAX_SAFE_INTEGER: valtype === 'i32' ? 2147483647 : 9007199254740991,
256
262
  MIN_SAFE_INTEGER: valtype === 'i32' ? -2147483648 : -9007199254740991,
257
-
258
263
  EPSILON: 2.220446049250313e-16
259
264
  }),
260
265
 
261
266
  ...autoFuncs('Number')
262
267
  });
263
268
 
264
- object('Reflect', autoFuncs('Reflect'));
265
- object('Object', autoFuncs('Object'));
266
- object('JSON', autoFuncs('JSON'));
267
- object('Promise', autoFuncs('Promise'));
268
- object('Array', autoFuncs('Array'));
269
- object('Symbol', autoFuncs('Symbol'));
270
- object('Date', autoFuncs('Date'));
271
- object('Atomics', autoFuncs('Atomics'));
272
-
273
269
  // these technically not spec compliant as it should be classes or non-enumerable but eh
274
270
  object('navigator', {
275
271
  ...props({
@@ -286,13 +282,15 @@ export default function({ builtinFuncs }, Prefs) {
286
282
  'crypto',
287
283
  'performance',
288
284
  ]) {
289
- object(x, {
290
- ...props({
291
- writable: true,
292
- enumerable: true,
293
- configurable: true
294
- }, autoFuncKeys(x).slice(0, 12))
295
- });
285
+ object(x, props({
286
+ writable: true,
287
+ enumerable: true,
288
+ configurable: true
289
+ }, autoFuncKeys(x).slice(0, 12)));
290
+ }
291
+
292
+ for (const x of [ 'Array', 'ArrayBuffer', 'Atomics', 'Date', 'Error', 'JSON', 'Object', 'Promise', 'Reflect', 'String', 'Symbol', 'Uint8Array', 'Int8Array', 'Uint8ClampedArray', 'Uint16Array', 'Int16Array', 'Uint32Array', 'Int32Array', 'Float32Array', 'Float64Array', 'BigInt64Array', 'BigUint64Array', 'SharedArrayBuffer', 'BigInt', 'Boolean', 'DataView', 'AggregateError', 'TypeError', 'ReferenceError', 'SyntaxError', 'RangeError', 'EvalError', 'URIError', 'Function', 'Map', 'RegExp', 'Set', 'WeakMap', 'WeakRef', 'WeakSet' ]) {
293
+ object(x, autoFuncs(x));
296
294
  }
297
295
 
298
296
  const enumerableGlobals = [ 'atob', 'btoa', 'performance', 'crypto', 'navigator' ];
@@ -334,7 +332,6 @@ export default function({ builtinFuncs }, Prefs) {
334
332
 
335
333
  if (Prefs.logMissingObjects) for (const x of Object.keys(builtinFuncs).concat(Object.keys(this))) {
336
334
  if (!x.startsWith('__')) continue;
337
-
338
335
  const name = x.split('_').slice(2, -1).join('_');
339
336
 
340
337
  let t = globalThis;
@@ -1631,7 +1631,7 @@ locals:[127,124],localNames:["#newtarget","#newtarget#type","#this","#this#type"
1631
1631
  constr:1,
1632
1632
  }
1633
1633
  this.__Error_prototype_constructor$get = {
1634
- wasm:(_,{funcRef})=>eval("[...funcRef('Error'),[65,6],[15]]"),
1634
+ wasm:(_,{builtin})=>eval("[[16,builtin('#get_Error')],[184],[65,6],[15]]"),
1635
1635
  params:[124,127],typedParams:1,returns:[124,127],
1636
1636
  locals:[],localNames:["_this","_this#type"],
1637
1637
  }
@@ -1657,7 +1657,7 @@ locals:[127,124],localNames:["#newtarget","#newtarget#type","#this","#this#type"
1657
1657
  constr:1,
1658
1658
  }
1659
1659
  this.__AggregateError_prototype_constructor$get = {
1660
- wasm:(_,{funcRef})=>eval("[...funcRef('AggregateError'),[65,6],[15]]"),
1660
+ wasm:(_,{builtin})=>eval("[[16,builtin('#get_AggregateError')],[184],[65,6],[15]]"),
1661
1661
  params:[124,127],typedParams:1,returns:[124,127],
1662
1662
  locals:[],localNames:["_this","_this#type"],
1663
1663
  }
@@ -1683,7 +1683,7 @@ locals:[127,124],localNames:["#newtarget","#newtarget#type","#this","#this#type"
1683
1683
  constr:1,
1684
1684
  }
1685
1685
  this.__TypeError_prototype_constructor$get = {
1686
- wasm:(_,{funcRef})=>eval("[...funcRef('TypeError'),[65,6],[15]]"),
1686
+ wasm:(_,{builtin})=>eval("[[16,builtin('#get_TypeError')],[184],[65,6],[15]]"),
1687
1687
  params:[124,127],typedParams:1,returns:[124,127],
1688
1688
  locals:[],localNames:["_this","_this#type"],
1689
1689
  }
@@ -1709,7 +1709,7 @@ locals:[127,124],localNames:["#newtarget","#newtarget#type","#this","#this#type"
1709
1709
  constr:1,
1710
1710
  }
1711
1711
  this.__ReferenceError_prototype_constructor$get = {
1712
- wasm:(_,{funcRef})=>eval("[...funcRef('ReferenceError'),[65,6],[15]]"),
1712
+ wasm:(_,{builtin})=>eval("[[16,builtin('#get_ReferenceError')],[184],[65,6],[15]]"),
1713
1713
  params:[124,127],typedParams:1,returns:[124,127],
1714
1714
  locals:[],localNames:["_this","_this#type"],
1715
1715
  }
@@ -1735,7 +1735,7 @@ locals:[127,124],localNames:["#newtarget","#newtarget#type","#this","#this#type"
1735
1735
  constr:1,
1736
1736
  }
1737
1737
  this.__SyntaxError_prototype_constructor$get = {
1738
- wasm:(_,{funcRef})=>eval("[...funcRef('SyntaxError'),[65,6],[15]]"),
1738
+ wasm:(_,{builtin})=>eval("[[16,builtin('#get_SyntaxError')],[184],[65,6],[15]]"),
1739
1739
  params:[124,127],typedParams:1,returns:[124,127],
1740
1740
  locals:[],localNames:["_this","_this#type"],
1741
1741
  }
@@ -1761,7 +1761,7 @@ locals:[127,124],localNames:["#newtarget","#newtarget#type","#this","#this#type"
1761
1761
  constr:1,
1762
1762
  }
1763
1763
  this.__RangeError_prototype_constructor$get = {
1764
- wasm:(_,{funcRef})=>eval("[...funcRef('RangeError'),[65,6],[15]]"),
1764
+ wasm:(_,{builtin})=>eval("[[16,builtin('#get_RangeError')],[184],[65,6],[15]]"),
1765
1765
  params:[124,127],typedParams:1,returns:[124,127],
1766
1766
  locals:[],localNames:["_this","_this#type"],
1767
1767
  }
@@ -1787,7 +1787,7 @@ locals:[127,124],localNames:["#newtarget","#newtarget#type","#this","#this#type"
1787
1787
  constr:1,
1788
1788
  }
1789
1789
  this.__EvalError_prototype_constructor$get = {
1790
- wasm:(_,{funcRef})=>eval("[...funcRef('EvalError'),[65,6],[15]]"),
1790
+ wasm:(_,{builtin})=>eval("[[16,builtin('#get_EvalError')],[184],[65,6],[15]]"),
1791
1791
  params:[124,127],typedParams:1,returns:[124,127],
1792
1792
  locals:[],localNames:["_this","_this#type"],
1793
1793
  }
@@ -1813,7 +1813,7 @@ locals:[127,124],localNames:["#newtarget","#newtarget#type","#this","#this#type"
1813
1813
  constr:1,
1814
1814
  }
1815
1815
  this.__URIError_prototype_constructor$get = {
1816
- wasm:(_,{funcRef})=>eval("[...funcRef('URIError'),[65,6],[15]]"),
1816
+ wasm:(_,{builtin})=>eval("[[16,builtin('#get_URIError')],[184],[65,6],[15]]"),
1817
1817
  params:[124,127],typedParams:1,returns:[124,127],
1818
1818
  locals:[],localNames:["_this","_this#type"],
1819
1819
  }
@@ -1294,15 +1294,21 @@ const asmFuncToAsm = (scope, func, extra) => func(scope, {
1294
1294
  scope.initedGlobals ??= new Set();
1295
1295
  if (!scope.initedGlobals.has(name)) {
1296
1296
  scope.initedGlobals.add(name);
1297
- if (scope.globalInits?.[name]) out.unshift(
1298
- [ Opcodes.global_get, globals[globalName + '#glbl_inited'].idx ],
1299
- [ Opcodes.i32_eqz ],
1300
- [ Opcodes.if, Blocktype.void ],
1301
- ...asmFuncToAsm(scope, scope.globalInits[name]),
1302
- number(1, Valtype.i32),
1303
- [ Opcodes.global_set, globals[globalName + '#glbl_inited'].idx ],
1304
- [ Opcodes.end ]
1305
- );
1297
+ if (scope.globalInits?.[name]) {
1298
+ if (typeof scope.globalInits[name] === 'function') {
1299
+ out.unshift(
1300
+ [ Opcodes.global_get, globals[globalName + '#glbl_inited'].idx ],
1301
+ [ Opcodes.i32_eqz ],
1302
+ [ Opcodes.if, Blocktype.void ],
1303
+ ...asmFuncToAsm(scope, scope.globalInits[name]),
1304
+ number(1, Valtype.i32),
1305
+ [ Opcodes.global_set, globals[globalName + '#glbl_inited'].idx ],
1306
+ [ Opcodes.end ]
1307
+ );
1308
+ } else {
1309
+ globals[globalName].init = scope.globalInits[name];
1310
+ }
1311
+ }
1306
1312
  }
1307
1313
 
1308
1314
  return out;
@@ -1332,7 +1338,7 @@ const asmFuncToAsm = (scope, func, extra) => func(scope, {
1332
1338
  allocPage: (scope, name) => allocPage({ scope, pages }, name)
1333
1339
  }, extra);
1334
1340
 
1335
- const asmFunc = (name, { wasm, params = [], typedParams = false, locals: localTypes = [], globals: globalTypes = [], globalInits = [], returns = [], returnType, localNames = [], globalNames = [], table = false, constr = false, hasRestArgument = false, usesTag = false, usesImports = false, returnTypes } = {}) => {
1341
+ const asmFunc = (name, { wasm, params = [], typedParams = false, locals: localTypes = [], globalInits = {}, returns = [], returnType, localNames = [], globalNames = [], table = false, constr = false, hasRestArgument = false, usesTag = false, usesImports = false, returnTypes } = {}) => {
1336
1342
  if (wasm == null) { // called with no built-in
1337
1343
  log.warning('codegen', `${name} has no built-in!`);
1338
1344
  wasm = [];
@@ -1364,28 +1370,8 @@ const asmFunc = (name, { wasm, params = [], typedParams = false, locals: localTy
1364
1370
  funcs.push(func);
1365
1371
  funcIndex[name] = func.index;
1366
1372
 
1367
- if (typeof wasm === 'function') {
1368
- if (globalThis.precompile) wasm = [];
1369
- else wasm = asmFuncToAsm(func, wasm);
1370
- }
1371
-
1372
- if (globalTypes.length !== 0) {
1373
- // offset global ops for base global idx
1374
- let baseGlobalIdx, i = 0;
1375
- for (const type of globalTypes) {
1376
- if (baseGlobalIdx === undefined) baseGlobalIdx = globals['#ind'];
1377
-
1378
- globals[globalNames[i] ?? `${name}_global_${i}`] = { idx: globals['#ind']++, type, init: globalInits[i] ?? 0 };
1379
- i++;
1380
- }
1381
-
1382
- for (let i = 0; i < wasm.length; i++) {
1383
- const inst = wasm[i];
1384
- if (inst[0] === Opcodes.global_get || inst[0] === Opcodes.global_set) {
1385
- inst[1] += baseGlobalIdx;
1386
- }
1387
- }
1388
- }
1373
+ if (globalThis.precompile) wasm = [];
1374
+ else wasm = asmFuncToAsm(func, wasm);
1389
1375
 
1390
1376
  if (table) funcs.table = true;
1391
1377
  if (usesTag) {
@@ -2546,14 +2532,13 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
2546
2532
  [ Opcodes.local_get, calleeLocal ],
2547
2533
  Opcodes.i32_to_u,
2548
2534
  [ Opcodes.call_indirect, args.length + 2, 0 ],
2549
- ...setLastType(scope),
2550
- ...(globalThis.precompile && valtypeBinary === Valtype.i32 ? [ Opcodes.i32_trunc_sat_f64_s ] : [])
2535
+ ...setLastType(scope)
2551
2536
  ],
2552
2537
 
2553
- default: decl.optional ? withType(scope, [ number(UNDEFINED) ], TYPES.undefined)
2538
+ default: decl.optional ? withType(scope, [ number(UNDEFINED, Valtype.f64) ], TYPES.undefined)
2554
2539
  : internalThrow(scope, 'TypeError', `${unhackName(name)} is not a function`, Valtype.f64)
2555
2540
  }, Valtype.f64),
2556
- ...(valtypeBinary === Valtype.i32 && scope.returns[0] !== Valtype.f64 ? [ [ Opcodes.f64_convert_i32_s ] ] : [])
2541
+ ...(valtypeBinary === Valtype.i32 ? [ Opcodes.i32_trunc_sat_f64_s ] : [])
2557
2542
  ];
2558
2543
  }
2559
2544
 
@@ -3639,6 +3624,71 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
3639
3624
 
3640
3625
  const op = decl.operator.slice(0, -1) || '=';
3641
3626
 
3627
+ // short-circuit behavior for logical assignment operators
3628
+ if (op === '||' || op === '&&' || op === '??') {
3629
+ // for logical assignment ops, it is not left @= right -> left = left @ right
3630
+ // instead, left @ (left = right)
3631
+ // eg, x &&= y -> x && (x = y)
3632
+ if (local !== undefined) {
3633
+ // fast path: just assigning to a local
3634
+ setInferred(scope, name, knownType(scope, getNodeType(scope, decl)), isGlobal);
3635
+ return [
3636
+ ...performOp(scope, op, [
3637
+ [ isGlobal ? Opcodes.global_get : Opcodes.local_get, local.idx ]
3638
+ ], [
3639
+ ...generate(scope, decl.right, isGlobal, name),
3640
+ [ isGlobal ? Opcodes.global_set : Opcodes.local_set, local.idx ],
3641
+ [ isGlobal ? Opcodes.global_get : Opcodes.local_get, local.idx ]
3642
+ ], getType(scope, name), getNodeType(scope, decl.right)),
3643
+ ...setType(scope, name, getLastType(scope), true)
3644
+ ];
3645
+ } else if (type === 'MemberExpression' && decl.left.computed) {
3646
+ // special path: cache properties for computed members so they are not evaluated twice
3647
+ // eg, x[y] &&= z -> (a = y, x[a] = (x[a] = z))
3648
+ const propTmp = localTmp(scope, '#logical_prop');
3649
+ const propTypeTmp = localTmp(scope, '#logical_prop#type', Valtype.i32);
3650
+
3651
+ const member = {
3652
+ type: 'MemberExpression',
3653
+ object: decl.left.object,
3654
+ property: { type: 'Identifier', name: '#logical_prop' },
3655
+ computed: true
3656
+ };
3657
+
3658
+ return [
3659
+ ...generate(scope, decl.left.property),
3660
+ [ Opcodes.local_set, propTmp ],
3661
+ ...getNodeType(scope, decl.left.property),
3662
+ [ Opcodes.local_set, propTypeTmp ],
3663
+
3664
+ ...generate(scope, {
3665
+ type: 'LogicalExpression',
3666
+ operator: op,
3667
+ left: member,
3668
+ right: {
3669
+ type: 'AssignmentExpression',
3670
+ operator: '=',
3671
+ left: member,
3672
+ right: decl.right
3673
+ }
3674
+ }, _global, _name, valueUnused)
3675
+ ];
3676
+ } else {
3677
+ // other: generate as LogicalExpression
3678
+ return generate(scope, {
3679
+ type: 'LogicalExpression',
3680
+ operator: op,
3681
+ left: decl.left,
3682
+ right: {
3683
+ type: 'AssignmentExpression',
3684
+ operator: '=',
3685
+ left: decl.left,
3686
+ right: decl.right
3687
+ }
3688
+ }, _global, _name, valueUnused);
3689
+ }
3690
+ }
3691
+
3642
3692
  // hack: .length setter
3643
3693
  if (type === 'MemberExpression' && decl.left.property.name === 'length' && !decl._internalAssign) {
3644
3694
  const newValueTmp = !valueUnused && localTmp(scope, '__length_setter_tmp');
@@ -4074,27 +4124,6 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
4074
4124
  return out;
4075
4125
  }
4076
4126
 
4077
- if (op === '||' || op === '&&' || op === '??') {
4078
- // todo: is this needed?
4079
- // for logical assignment ops, it is not left @= right ~= left = left @ right
4080
- // instead, left @ (left = right)
4081
- // eg, x &&= y ~= x && (x = y)
4082
-
4083
- setInferred(scope, name, knownType(scope, getNodeType(scope, decl)), isGlobal);
4084
-
4085
- return [
4086
- ...performOp(scope, op, [
4087
- [ isGlobal ? Opcodes.global_get : Opcodes.local_get, local.idx ]
4088
- ], [
4089
- ...generate(scope, decl.right, isGlobal, name),
4090
- [ isGlobal ? Opcodes.global_set : Opcodes.local_set, local.idx ],
4091
- [ isGlobal ? Opcodes.global_get : Opcodes.local_get, local.idx ]
4092
- ], getType(scope, name), getNodeType(scope, decl.right)),
4093
-
4094
- ...setType(scope, name, getLastType(scope), true)
4095
- ];
4096
- }
4097
-
4098
4127
  const out = setLocalWithType(
4099
4128
  scope, name, isGlobal,
4100
4129
  performOp(scope, op, [
@@ -7089,7 +7118,7 @@ const internalConstrs = {
7089
7118
  }
7090
7119
  };
7091
7120
 
7092
- let globals, tags, exceptions, funcs, indirectFuncs, funcIndex, currentFuncIndex, depth, pages, data, typeswitchDepth, usedTypes, coctc, globalInfer, builtinFuncs, builtinVars, prototypeFuncs;
7121
+ let globals, tags, exceptions, funcs, indirectFuncs, funcIndex, currentFuncIndex, depth, pages, data, typeswitchDepth, usedTypes, coctc, globalInfer, builtinFuncs, builtinVars, prototypeFuncs, lastValtype;
7093
7122
  export default program => {
7094
7123
  globals = { ['#ind']: 0 };
7095
7124
  tags = [];
@@ -7119,12 +7148,16 @@ export default program => {
7119
7148
  Opcodes.load = valtypeBinary === Valtype.i32 ? Opcodes.i32_load : Opcodes.f64_load;
7120
7149
  Opcodes.store = valtypeBinary === Valtype.i32 ? Opcodes.i32_store : Opcodes.f64_store;
7121
7150
 
7122
- builtinFuncs = new BuiltinFuncs();
7123
- builtinVars = new BuiltinVars({ builtinFuncs });
7124
- prototypeFuncs = new PrototypeFuncs();
7151
+ // keep builtins between compiles as much as possible
7152
+ if (lastValtype !== valtypeBinary) {
7153
+ lastValtype = valtypeBinary;
7154
+ builtinFuncs = new BuiltinFuncs();
7155
+ builtinVars = new BuiltinVars({ builtinFuncs });
7156
+ prototypeFuncs = new PrototypeFuncs();
7125
7157
 
7126
- const getObjectName = x => x.startsWith('__') && x.slice(2, x.indexOf('_', 2));
7127
- objectHackers = ['assert', 'compareArray', 'Test262Error', ...new Set(Object.keys(builtinFuncs).map(getObjectName).concat(Object.keys(builtinVars).map(getObjectName)).filter(x => x))];
7158
+ const getObjectName = x => x.startsWith('__') && x.slice(2, x.indexOf('_', 2));
7159
+ objectHackers = ['assert', 'compareArray', 'Test262Error', ...new Set(Object.keys(builtinFuncs).map(getObjectName).concat(Object.keys(builtinVars).map(getObjectName)).filter(x => x))];
7160
+ }
7128
7161
 
7129
7162
  const [ main ] = generateFunc({}, {
7130
7163
  type: 'Program',
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.57.32",
4
+ "version": "0.57.33",
5
5
  "author": "Oliver Medhurst <honk@goose.icu>",
6
6
  "license": "MIT",
7
7
  "scripts": {},
package/runtime/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import fs from 'node:fs';
3
- globalThis.version = '0.57.32';
3
+ globalThis.version = '0.57.33';
4
4
 
5
5
  // deno compat
6
6
  if (typeof process === 'undefined' && typeof Deno !== 'undefined') {
@@ -68,7 +68,7 @@ if (process.argv.includes('--help') || process.argv.includes('-h')) {
68
68
  'exception-mode': 'Exception mode to use (lut|\x1B[1mstack\x1B[0m)',
69
69
  'fast-length': 'Non-compliant optimization to make .length faster',
70
70
  'profile-compiler': 'Log general compiler performance (on by default when compiling to a file)',
71
- prng: 'PRNG algorithm to use (lcg32|xorshift32+|xorshift64+|\x1B[1mxorshift128+\x1B[0m|xoroshiro128+|xoshiro128+)'
71
+ prng: 'PRNG algorithm to use (xorshift32+|xorshift64+|\x1B[1mxorshift128+\x1B[0m|xoroshiro128+|xoshiro128+)'
72
72
  })) {
73
73
  flag = '-' + flag;
74
74
  if (flag.length > 3) flag = '-' + flag;