porffor 0.0.0-579ef36

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.
@@ -0,0 +1,770 @@
1
+ import { Blocktype, Opcodes, Valtype } from "./wasmSpec.js";
2
+ import { number, i32x4 } from "./embedding.js";
3
+ import { signedLEB128 } from "./encoding.js";
4
+
5
+ export const importedFuncs = [
6
+ {
7
+ name: 'print',
8
+ import: 'p',
9
+ params: 1,
10
+ returns: 0
11
+ },
12
+ {
13
+ name: 'printChar',
14
+ import: 'c',
15
+ params: 1,
16
+ returns: 0
17
+ },
18
+ {
19
+ name: 'assert',
20
+ import: 'a',
21
+ params: 1,
22
+ returns: 0
23
+ },
24
+ {
25
+ name: 'time',
26
+ import: 't',
27
+ params: 0,
28
+ returns: 1
29
+ }
30
+ ];
31
+
32
+ for (let i = 0; i < importedFuncs.length; i++) {
33
+ const f = importedFuncs[i];
34
+ importedFuncs[f.name] = i;
35
+ }
36
+
37
+ const char = c => number(c.charCodeAt(0));
38
+
39
+ // todo: somehow diff between these (undefined != null) while remaining falsey in wasm as a number value
40
+ export const UNDEFINED = 0;
41
+ export const NULL = 0;
42
+
43
+ export const BuiltinVars = function() {
44
+ this.undefined = number(UNDEFINED);
45
+ this.undefined.type = 'undefined';
46
+
47
+ this.null = number(NULL);
48
+ this.null.type = 'object';
49
+
50
+ this.NaN = number(NaN);
51
+ this.NaN.floatOnly = true;
52
+
53
+ this.Infinity = number(Infinity);
54
+ this.Infinity.floatOnly = true;
55
+
56
+ this.__Number_NaN = number(NaN);
57
+ this.__Number_NaN.floatOnly = true;
58
+
59
+ this.__Number_POSITIVE_INFINITY = number(Infinity);
60
+ this.__Number_POSITIVE_INFINITY.floatOnly = true;
61
+
62
+ this.__Number_NEGATIVE_INFINITY = number(-Infinity);
63
+ this.__Number_NEGATIVE_INFINITY.floatOnly = true;
64
+
65
+ switch (valtype) {
66
+ case 'i32':
67
+ this.__Number_MAX_VALUE = number(2147483647);
68
+ this.__Number_MIN_VALUE = number(-2147483648);
69
+
70
+ this.__Number_MAX_SAFE_INTEGER = this.__Number_MAX_VALUE;
71
+ this.__Number_MIN_SAFE_INTEGER = this.__Number_MIN_VALUE;
72
+
73
+ break;
74
+
75
+ case 'i64':
76
+ // todo: we use 32 bit limits here as we cannot encode 64 bit integers yet
77
+ this.__Number_MAX_VALUE = number(2147483647);
78
+ this.__Number_MIN_VALUE = number(-2147483648);
79
+
80
+ this.__Number_MAX_SAFE_INTEGER = this.__Number_MAX_VALUE;
81
+ this.__Number_MIN_SAFE_INTEGER = this.__Number_MIN_VALUE;
82
+
83
+ break;
84
+
85
+ case 'f64':
86
+ this.__Number_MAX_VALUE = number(1.7976931348623157e+308);
87
+ this.__Number_MIN_VALUE = number(5e-324);
88
+
89
+ this.__Number_MAX_SAFE_INTEGER = number(9007199254740991);
90
+ this.__Number_MIN_SAFE_INTEGER = number(-9007199254740991);
91
+
92
+ this.__Number_EPSILON = number(2.220446049250313e-16);
93
+
94
+ this.__Math_E = number(Math.E);
95
+ this.__Math_LN10 = number(Math.LN10);
96
+ this.__Math_LN2 = number(Math.LN2);
97
+ this.__Math_LOG10E = number(Math.LOG10E);
98
+ this.__Math_LOG2E = number(Math.LOG2E);
99
+ this.__Math_PI = number(Math.PI);
100
+ this.__Math_SQRT1_2 = number(Math.SQRT1_2);
101
+ this.__Math_SQRT2 = number(Math.SQRT2);
102
+
103
+ // https://github.com/rwaldron/proposal-math-extensions/issues/10
104
+ this.__Math_RAD_PER_DEG = number(Math.PI / 180);
105
+ this.__Math_DEG_PER_RAD = number(180 / Math.PI);
106
+
107
+ break;
108
+ }
109
+
110
+ // stubs just so that parent objects exist
111
+ this.Math = number(1);
112
+ };
113
+
114
+ export const BuiltinFuncs = function() {
115
+ this['f64_%'] = {
116
+ params: [ valtypeBinary, valtypeBinary ],
117
+ locals: [],
118
+ returns: [ valtypeBinary ],
119
+ wasm: [ // x - truncf(x / y) * y
120
+ [ Opcodes.local_get, 0 ], // x
121
+
122
+ [ Opcodes.local_get, 0 ], // x
123
+ [ Opcodes.local_get, 1 ], // y
124
+
125
+ [ Opcodes.f64_div ],
126
+ [ Opcodes.f64_trunc ],
127
+
128
+ [ Opcodes.local_get, 1 ], // y
129
+ [ Opcodes.f64_mul ],
130
+
131
+ [ Opcodes.f64_sub ]
132
+ ]
133
+ };
134
+
135
+ // add bitwise ops by converting operands to i32 first
136
+ for (const [ char, op ] of [ ['&', Opcodes.i32_and], ['|', Opcodes.i32_or], ['^', Opcodes.i32_xor], ['<<', Opcodes.i32_shl], ['>>', Opcodes.i32_shr_s], ['>>>', Opcodes.i32_shr_u] ]) {
137
+ this[`f64_${char}`] = {
138
+ params: [ valtypeBinary, valtypeBinary ],
139
+ locals: [],
140
+ returns: [ valtypeBinary ],
141
+ wasm: [
142
+ [ Opcodes.local_get, 0 ],
143
+ Opcodes.i32_to,
144
+
145
+ [ Opcodes.local_get, 1 ],
146
+ Opcodes.i32_to,
147
+
148
+ [ op ],
149
+ Opcodes.i32_from
150
+ ]
151
+ };
152
+ }
153
+
154
+
155
+ // just echo given for now, for type constructors
156
+ this.Number = {
157
+ params: [ valtypeBinary ],
158
+ locals: [],
159
+ returns: [ valtypeBinary ],
160
+ wasm: [
161
+ [ Opcodes.local_get, 0 ]
162
+ ]
163
+ };
164
+
165
+ // todo: return false for NaN
166
+ this.Boolean = {
167
+ params: [ valtypeBinary ],
168
+ locals: [],
169
+ returns: [ valtypeBinary ],
170
+ returnType: 'boolean',
171
+ wasm: [
172
+ [ Opcodes.local_get, 0 ],
173
+ ...(valtype === 'f64' ? [
174
+ ...number(0),
175
+ [ Opcodes.f64_ne ]
176
+ ] : [
177
+ ...Opcodes.eqz,
178
+ [ Opcodes.i32_eqz ]
179
+ ]),
180
+ Opcodes.i32_from
181
+ ]
182
+ };
183
+
184
+ // just return given (default 0) for (new) Object() as we somewhat supports object just not constructor
185
+ this.Object = {
186
+ params: [ valtypeBinary ],
187
+ locals: [],
188
+ returns: [ valtypeBinary ],
189
+ returnType: 'object',
190
+ wasm: [
191
+ [ Opcodes.local_get, 0 ]
192
+ ]
193
+ };
194
+
195
+
196
+ this.__console_log = {
197
+ params: [ valtypeBinary ],
198
+ locals: [],
199
+ returns: [],
200
+ wasm: [
201
+ [ Opcodes.local_get, 0 ],
202
+ [ Opcodes.call, importedFuncs.print ],
203
+ ...char('\n'),
204
+ [ Opcodes.call, importedFuncs.printChar ]
205
+ ]
206
+ };
207
+
208
+ // todo: add more console funcs
209
+
210
+
211
+ this.isNaN = {
212
+ floatOnly: true,
213
+ params: [ valtypeBinary ],
214
+ locals: [],
215
+ returns: [ valtypeBinary ],
216
+ returnType: 'boolean',
217
+ wasm: [
218
+ [ Opcodes.local_get, 0 ],
219
+ [ Opcodes.local_get, 0 ],
220
+ [ Opcodes.f64_ne ],
221
+ Opcodes.i32_from
222
+ ]
223
+ };
224
+ this.__Number_isNaN = this.isNaN;
225
+
226
+ this.isFinite = {
227
+ floatOnly: true,
228
+ params: [ valtypeBinary ],
229
+ locals: [ valtypeBinary ],
230
+ returns: [ valtypeBinary ],
231
+ returnType: 'boolean',
232
+ wasm: [
233
+ [ Opcodes.local_get, 0 ],
234
+ [ Opcodes.local_get, 0 ],
235
+ [ Opcodes.f64_sub ],
236
+ [ Opcodes.local_tee, 1 ],
237
+ [ Opcodes.local_get, 1 ],
238
+ [ Opcodes.f64_eq ],
239
+ Opcodes.i32_from
240
+ ]
241
+ };
242
+ this.__Number_isFinite = this.isFinite;
243
+
244
+ // todo: should be false for +-Infinity
245
+ this.__Number_isInteger = {
246
+ floatOnly: true,
247
+ params: [ valtypeBinary ],
248
+ locals: [],
249
+ returns: [ valtypeBinary ],
250
+ returnType: 'boolean',
251
+ wasm: [
252
+ [ Opcodes.local_get, 0 ],
253
+ [ Opcodes.local_get, 0 ],
254
+ [ Opcodes.f64_trunc ],
255
+ [ Opcodes.f64_eq ],
256
+ Opcodes.i32_from
257
+ ]
258
+ };
259
+
260
+ this.__Number_isSafeInteger = {
261
+ floatOnly: true,
262
+ params: [ valtypeBinary ],
263
+ locals: [],
264
+ returns: [ valtypeBinary ],
265
+ returnType: 'boolean',
266
+ wasm: [
267
+ [ Opcodes.local_get, 0 ],
268
+ [ Opcodes.local_get, 0 ],
269
+ [ Opcodes.f64_trunc ],
270
+ [ Opcodes.f64_ne ],
271
+ [ Opcodes.if, Blocktype.void ],
272
+ ...number(0),
273
+ [ Opcodes.return ],
274
+ [ Opcodes.end ],
275
+ [ Opcodes.local_get, 0 ],
276
+ [ Opcodes.f64_abs ],
277
+ ...number(9007199254740991),
278
+ [ Opcodes.f64_le ],
279
+ Opcodes.i32_from
280
+ ]
281
+ };
282
+
283
+
284
+ this.__Math_sqrt = {
285
+ floatOnly: true,
286
+ params: [ valtypeBinary ],
287
+ locals: [],
288
+ returns: [ valtypeBinary ],
289
+ wasm: [
290
+ [ Opcodes.local_get, 0 ],
291
+ [ Opcodes.f64_sqrt ]
292
+ ]
293
+ };
294
+
295
+ this.__Math_abs = {
296
+ floatOnly: true,
297
+ params: [ valtypeBinary ],
298
+ locals: [],
299
+ returns: [ valtypeBinary ],
300
+ wasm: [
301
+ [ Opcodes.local_get, 0 ],
302
+ [ Opcodes.f64_abs ]
303
+ ]
304
+ };
305
+
306
+ this.__Math_sign = {
307
+ floatOnly: true,
308
+ params: [ valtypeBinary ],
309
+ locals: [],
310
+ returns: [ valtypeBinary ],
311
+ wasm: [
312
+ ...number(1),
313
+ [ Opcodes.local_get, 0 ],
314
+ [ Opcodes.f64_copysign ]
315
+ ]
316
+ };
317
+
318
+ this.__Math_floor = {
319
+ floatOnly: true,
320
+ params: [ valtypeBinary ],
321
+ locals: [],
322
+ returns: [ valtypeBinary ],
323
+ wasm: [
324
+ [ Opcodes.local_get, 0 ],
325
+ [ Opcodes.f64_floor ]
326
+ ]
327
+ };
328
+
329
+ this.__Math_ceil = {
330
+ floatOnly: true,
331
+ params: [ valtypeBinary ],
332
+ locals: [],
333
+ returns: [ valtypeBinary ],
334
+ wasm: [
335
+ [ Opcodes.local_get, 0 ],
336
+ [ Opcodes.f64_ceil ]
337
+ ]
338
+ };
339
+
340
+ this.__Math_round = {
341
+ floatOnly: true,
342
+ params: [ valtypeBinary ],
343
+ locals: [],
344
+ returns: [ valtypeBinary ],
345
+ wasm: [
346
+ [ Opcodes.local_get, 0 ],
347
+ [ Opcodes.f64_nearest ]
348
+ ]
349
+ };
350
+
351
+ this.__Math_trunc = {
352
+ floatOnly: true,
353
+ params: [ valtypeBinary ],
354
+ locals: [],
355
+ returns: [ valtypeBinary ],
356
+ wasm: [
357
+ [ Opcodes.local_get, 0 ],
358
+ [ Opcodes.f64_trunc ]
359
+ ]
360
+ };
361
+
362
+ // todo: does not follow spec with +-Infinity and values >2**32
363
+ this.__Math_clz32 = {
364
+ params: [ valtypeBinary ],
365
+ locals: [],
366
+ returns: [ valtypeBinary ],
367
+ wasm: [
368
+ [ Opcodes.local_get, 0 ],
369
+ Opcodes.i32_trunc_sat_f64_u,
370
+ [ Opcodes.i32_clz ],
371
+ Opcodes.i32_from
372
+ ]
373
+ };
374
+
375
+ this.__Math_fround = {
376
+ floatOnly: true,
377
+ params: [ valtypeBinary ],
378
+ locals: [],
379
+ returns: [ valtypeBinary ],
380
+ wasm: [
381
+ [ Opcodes.local_get, 0 ],
382
+ [ Opcodes.f32_demote_f64 ],
383
+ [ Opcodes.f64_promote_f32 ]
384
+ ]
385
+ };
386
+
387
+ // todo: this does not overflow correctly
388
+ this.__Math_imul = {
389
+ floatOnly: true,
390
+ params: [ valtypeBinary, valtypeBinary ],
391
+ locals: [],
392
+ returns: [ valtypeBinary ],
393
+ wasm: [
394
+ [ Opcodes.local_get, 0 ],
395
+ Opcodes.i32_trunc_sat_f64_s,
396
+ [ Opcodes.local_get, 1 ],
397
+ Opcodes.i32_trunc_sat_f64_s,
398
+ [ Opcodes.i32_mul ],
399
+ Opcodes.i32_from
400
+ ]
401
+ };
402
+
403
+ // this is an implementation of xorshift128+ (in wasm bytecode)
404
+ // fun fact: v8, SM, JSC also use this (you will need this fun fact to maintain your sanity reading this code)
405
+ const prngSeed0 = Math.floor(Math.random() * (2 ** 30)), prngSeed1 = Math.floor(Math.random() * (2 ** 30));
406
+
407
+ this.__Math_random = {
408
+ floatOnly: true,
409
+ params: [],
410
+ locals: [ Valtype.i64, Valtype.i64 ],
411
+ localNames: [ 's1', 's0' ],
412
+ globals: [ Valtype.i64, Valtype.i64 ],
413
+ globalNames: [ 'state0', 'state1' ],
414
+ globalInits: [ prngSeed0, prngSeed1 ],
415
+ returns: [ Valtype.f64 ],
416
+ wasm: [
417
+ // setup: s1 = state0, s0 = state1, state0 = s0
418
+ [ Opcodes.global_get, 0 ], // state0
419
+ [ Opcodes.local_set, 0 ], // s1
420
+ [ Opcodes.global_get, 1 ], // state1
421
+ [ Opcodes.local_tee, 1, ], // s0
422
+ [ Opcodes.global_set, 0 ], // state0
423
+
424
+ // s1 ^= s1 << 23
425
+ [ Opcodes.local_get, 0 ], // s1
426
+ [ Opcodes.local_get, 0 ], // s1
427
+ [ Opcodes.i64_const, 23 ],
428
+ [ Opcodes.i64_shl ], // <<
429
+ [ Opcodes.i64_xor ], // ^
430
+ [ Opcodes.local_set, 0 ], // s1
431
+
432
+ // state1 = s1 ^ s0 ^ (s1 >> 17) ^ (s0 >> 26)
433
+ // s1 ^ s0
434
+ [ Opcodes.local_get, 0 ], // s1
435
+ [ Opcodes.local_get, 1 ], // s0
436
+ [ Opcodes.i64_xor ], // ^
437
+
438
+ // ^ (s1 >> 17)
439
+ [ Opcodes.local_get, 0 ], // s1
440
+ [ Opcodes.i64_const, 17 ],
441
+ [ Opcodes.i64_shr_u ], // >>
442
+ [ Opcodes.i64_xor ], // ^
443
+
444
+ // ^ (s0 >> 26)
445
+ [ Opcodes.local_get, 1 ], // s0
446
+ [ Opcodes.i64_const, 26 ],
447
+ [ Opcodes.i64_shr_u ], // >>
448
+ [ Opcodes.i64_xor ], // ^
449
+
450
+ // state1 =
451
+ [ Opcodes.global_set, 1 ],
452
+
453
+ // you thought it was over? now we need the result as a f64 between 0-1 :)
454
+
455
+ // mantissa = (state1 + s0) & ((1 << 53) - 1)
456
+ [ Opcodes.global_get, 1 ], // state1
457
+ [ Opcodes.local_get, 1 ], // s0
458
+ [ Opcodes.i64_add ],
459
+
460
+ [ Opcodes.i64_const, ...signedLEB128((1 << 53) - 1) ],
461
+ [ Opcodes.i64_and ],
462
+
463
+ // double(mantissa)
464
+ [ Opcodes.f64_convert_i64_u ],
465
+
466
+ // / (1 << 53)
467
+ ...number(1 << 53),
468
+ [ Opcodes.f64_div ]
469
+ ]
470
+ };
471
+
472
+ this.__Math_radians = {
473
+ floatOnly: true,
474
+ params: [ valtypeBinary ],
475
+ locals: [],
476
+ returns: [ valtypeBinary ],
477
+ wasm: [
478
+ [ Opcodes.local_get, 0 ],
479
+ ...number(Math.PI / 180),
480
+ [ Opcodes.f64_mul ]
481
+ ]
482
+ };
483
+
484
+ this.__Math_degrees = {
485
+ floatOnly: true,
486
+ params: [ valtypeBinary ],
487
+ locals: [],
488
+ returns: [ valtypeBinary ],
489
+ wasm: [
490
+ [ Opcodes.local_get, 0 ],
491
+ ...number(180 / Math.PI),
492
+ [ Opcodes.f64_mul ]
493
+ ]
494
+ };
495
+
496
+ this.__Math_clamp = {
497
+ floatOnly: true,
498
+ params: [ valtypeBinary, valtypeBinary, valtypeBinary ],
499
+ locals: [],
500
+ localNames: [ 'x', 'lower', 'upper' ],
501
+ returns: [ valtypeBinary ],
502
+ wasm: [
503
+ [ Opcodes.local_get, 0 ],
504
+ [ Opcodes.local_get, 1 ],
505
+ [ Opcodes.f64_max ],
506
+ [ Opcodes.local_get, 2 ],
507
+ [ Opcodes.f64_min ]
508
+ ]
509
+ };
510
+
511
+ this.__Math_scale = {
512
+ floatOnly: true,
513
+ params: [ valtypeBinary, valtypeBinary, valtypeBinary, valtypeBinary, valtypeBinary ],
514
+ locals: [],
515
+ localNames: [ 'x', 'inLow', 'inHigh', 'outLow', 'outHigh' ],
516
+ returns: [ valtypeBinary ],
517
+ wasm: [
518
+ // (x − inLow) * (outHigh − outLow) / (inHigh - inLow) + outLow
519
+
520
+ [ Opcodes.local_get, 0 ],
521
+ [ Opcodes.local_get, 1 ],
522
+ [ Opcodes.f64_sub ],
523
+
524
+ [ Opcodes.local_get, 4 ],
525
+ [ Opcodes.local_get, 3 ],
526
+ [ Opcodes.f64_sub ],
527
+
528
+ [ Opcodes.f64_mul ],
529
+
530
+ [ Opcodes.local_get, 2 ],
531
+ [ Opcodes.local_get, 1 ],
532
+ [ Opcodes.f64_sub ],
533
+
534
+ [ Opcodes.f64_div ],
535
+
536
+ [ Opcodes.local_get, 3 ],
537
+ [ Opcodes.f64_add ]
538
+ ]
539
+ };
540
+
541
+ // todo: fix for -0
542
+ this.__Math_signbit = {
543
+ floatOnly: true,
544
+ params: [ valtypeBinary ],
545
+ locals: [],
546
+ returns: [ valtypeBinary ],
547
+ returnType: 'boolean',
548
+ wasm: [
549
+ [ Opcodes.local_get, 0 ],
550
+ ...number(0),
551
+ [ Opcodes.f64_le ],
552
+ Opcodes.i32_from
553
+ ]
554
+ };
555
+
556
+
557
+ this.__performance_now = {
558
+ params: [],
559
+ locals: [],
560
+ returns: [ valtypeBinary ],
561
+ wasm: [
562
+ [ Opcodes.call, importedFuncs.time ]
563
+ ]
564
+ };
565
+
566
+
567
+ this.__SIMD_i32x4_load = {
568
+ params: [ Valtype.i32 ],
569
+ locals: [],
570
+ returns: [ Valtype.v128 ],
571
+ memory: true,
572
+ wasm: [
573
+ [ Opcodes.local_get, 0 ],
574
+ [ ...Opcodes.v128_load, 0, 0 ]
575
+ ]
576
+ };
577
+
578
+ this.__SIMD_i32x4_splat = {
579
+ params: [ Valtype.i32 ],
580
+ locals: [],
581
+ returns: [ Valtype.v128 ],
582
+ wasm: [
583
+ [ Opcodes.local_get, 0 ],
584
+ [ ...Opcodes.i32x4_splat ],
585
+ ]
586
+ };
587
+
588
+ this.__SIMD_i16x8_create = {
589
+ params: [ Valtype.i32, Valtype.i32, Valtype.i32, Valtype.i32, Valtype.i32, Valtype.i32, Valtype.i32, Valtype.i32 ],
590
+ locals: [],
591
+ returns: [ Valtype.v128 ],
592
+ wasm: [
593
+ ...i32x4(0, 0, 0, 0),
594
+ [ Opcodes.local_get, 0 ],
595
+ [ ...Opcodes.i16x8_replace_lane, 0 ],
596
+ [ Opcodes.local_get, 1 ],
597
+ [ ...Opcodes.i16x8_replace_lane, 1 ],
598
+ [ Opcodes.local_get, 2 ],
599
+ [ ...Opcodes.i16x8_replace_lane, 2 ],
600
+ [ Opcodes.local_get, 3 ],
601
+ [ ...Opcodes.i16x8_replace_lane, 3 ],
602
+ [ Opcodes.local_get, 4 ],
603
+ [ ...Opcodes.i16x8_replace_lane, 4 ],
604
+ [ Opcodes.local_get, 5 ],
605
+ [ ...Opcodes.i16x8_replace_lane, 5 ],
606
+ [ Opcodes.local_get, 6 ],
607
+ [ ...Opcodes.i16x8_replace_lane, 6 ],
608
+ [ Opcodes.local_get, 7 ],
609
+ [ ...Opcodes.i16x8_replace_lane, 7 ],
610
+ ]
611
+ };
612
+
613
+ this.__SIMD_i32x4_dot_i16x8 = {
614
+ params: [ Valtype.v128, Valtype.v128 ],
615
+ locals: [],
616
+ returns: [ Valtype.v128 ],
617
+ wasm: [
618
+ [ Opcodes.local_get, 0 ],
619
+ [ Opcodes.local_get, 1 ],
620
+ [ ...Opcodes.i32x4_dot_i16x8_s ]
621
+ ]
622
+ };
623
+
624
+ this.__SIMD_i32x4_create = {
625
+ params: [ Valtype.i32, Valtype.i32, Valtype.i32, Valtype.i32 ],
626
+ locals: [],
627
+ returns: [ Valtype.v128 ],
628
+ wasm: [
629
+ ...i32x4(0, 0, 0, 0),
630
+ [ Opcodes.local_get, 0 ],
631
+ [ ...Opcodes.i32x4_replace_lane, 0 ],
632
+ [ Opcodes.local_get, 1 ],
633
+ [ ...Opcodes.i32x4_replace_lane, 1 ],
634
+ [ Opcodes.local_get, 2 ],
635
+ [ ...Opcodes.i32x4_replace_lane, 2 ],
636
+ [ Opcodes.local_get, 3 ],
637
+ [ ...Opcodes.i32x4_replace_lane, 3 ],
638
+ ]
639
+ };
640
+
641
+ this.__SIMD_i32x4_add = {
642
+ params: [ Valtype.v128, Valtype.v128 ],
643
+ locals: [],
644
+ returns: [ Valtype.v128 ],
645
+ wasm: [
646
+ [ Opcodes.local_get, 0 ],
647
+ [ Opcodes.local_get, 1 ],
648
+ [ ...Opcodes.i32x4_add ]
649
+ ]
650
+ };
651
+
652
+ this.__SIMD_i32x4_sub = {
653
+ params: [ Valtype.v128, Valtype.v128 ],
654
+ locals: [],
655
+ returns: [ Valtype.v128 ],
656
+ wasm: [
657
+ [ Opcodes.local_get, 0 ],
658
+ [ Opcodes.local_get, 1 ],
659
+ [ ...Opcodes.i32x4_sub ]
660
+ ]
661
+ };
662
+
663
+ this.__SIMD_i32x4_mul = {
664
+ params: [ Valtype.v128, Valtype.v128 ],
665
+ locals: [],
666
+ returns: [ Valtype.v128 ],
667
+ wasm: [
668
+ [ Opcodes.local_get, 0 ],
669
+ [ Opcodes.local_get, 1 ],
670
+ [ ...Opcodes.i32x4_mul ]
671
+ ]
672
+ };
673
+
674
+ this.__SIMD_i32x4_get0 = {
675
+ params: [ Valtype.v128 ],
676
+ locals: [],
677
+ returns: [ Valtype.i32 ],
678
+ wasm: [
679
+ [ Opcodes.local_get, 0 ],
680
+ [ ...Opcodes.i32x4_extract_lane, 0 ],
681
+ ],
682
+ },
683
+
684
+ this.__SIMD_i32x4_get1 = {
685
+ params: [ Valtype.v128 ],
686
+ locals: [],
687
+ returns: [ Valtype.i32 ],
688
+ wasm: [
689
+ [ Opcodes.local_get, 0 ],
690
+ [ ...Opcodes.i32x4_extract_lane, 1 ],
691
+ ],
692
+ };
693
+
694
+ this.__SIMD_i32x4_get2 = {
695
+ params: [ Valtype.v128 ],
696
+ locals: [],
697
+ returns: [ Valtype.i32 ],
698
+ wasm: [
699
+ [ Opcodes.local_get, 0 ],
700
+ [ ...Opcodes.i32x4_extract_lane, 2 ],
701
+ ],
702
+ };
703
+
704
+ this.__SIMD_i32x4_get3 = {
705
+ params: [ Valtype.v128 ],
706
+ locals: [],
707
+ returns: [ Valtype.i32 ],
708
+ wasm: [
709
+ [ Opcodes.local_get, 0 ],
710
+ [ ...Opcodes.i32x4_extract_lane, 3 ],
711
+ ],
712
+ };
713
+
714
+ this.__SIMD_i32x4_shuffle_000c = {
715
+ params: [ Valtype.v128 ],
716
+ locals: [],
717
+ returns: [ Valtype.v128 ],
718
+ wasm: [
719
+ [ Opcodes.local_get, 0 ],
720
+ ...i32x4(0, 0, 0, 0),
721
+ [ ...Opcodes.i8x16_shuffle, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 8, 9, 10, 11 ], // i32x4 (a, b, c, d) -> i32x4 (0, 0, 0, c)
722
+ ]
723
+ };
724
+
725
+ this.__SIMD_i32x4_shuffle_00ab = {
726
+ params: [ Valtype.v128 ],
727
+ locals: [],
728
+ returns: [ Valtype.v128 ],
729
+ wasm: [
730
+ [ Opcodes.local_get, 0 ],
731
+ ...i32x4(0, 0, 0, 0),
732
+ [ ...Opcodes.i8x16_shuffle, 16, 16, 16, 16, 16, 16, 16, 16, 0, 1, 2, 3, 4, 5, 6, 7 ], // i32x4 (a, b, c, d) -> i32x4 (0, 0, a, b)
733
+ ]
734
+ };
735
+ };
736
+
737
+ export const BuiltinPreludes = {
738
+ btoa: `var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
739
+ var btoa = function (input) {
740
+ // todo: throw invalid character for unicode
741
+
742
+ let output = "";
743
+ let chr1, chr2, chr3, enc1, enc2, enc3, enc4;
744
+ let i = 0;
745
+
746
+ while (i < input.length) {
747
+ chr1 = input.charCodeAt(i++);
748
+ chr2 = input.charCodeAt(i++);
749
+ chr3 = input.charCodeAt(i++);
750
+
751
+ enc1 = chr1 >> 2;
752
+ enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
753
+ enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
754
+ enc4 = chr3 & 63;
755
+
756
+ if (isNaN(chr2)) {
757
+ enc3 = enc4 = 64;
758
+ } else if (isNaN(chr3)) {
759
+ enc4 = 64;
760
+ }
761
+
762
+ output += keyStr.charAt(enc1);
763
+ output += keyStr.charAt(enc2);
764
+ output += keyStr.charAt(enc3);
765
+ output += keyStr.charAt(enc4);
766
+ }
767
+
768
+ return output;
769
+ };`
770
+ };