porffor 0.0.0-05f898f

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,769 @@
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
+ wasm: [
572
+ [ Opcodes.local_get, 0 ],
573
+ [ ...Opcodes.v128_load, 0, 0 ]
574
+ ]
575
+ };
576
+
577
+ this.__SIMD_i32x4_splat = {
578
+ params: [ Valtype.i32 ],
579
+ locals: [],
580
+ returns: [ Valtype.v128 ],
581
+ wasm: [
582
+ [ Opcodes.local_get, 0 ],
583
+ [ ...Opcodes.i32x4_splat ],
584
+ ]
585
+ };
586
+
587
+ this.__SIMD_i16x8_create = {
588
+ params: [ Valtype.i32, Valtype.i32, Valtype.i32, Valtype.i32, Valtype.i32, Valtype.i32, Valtype.i32, Valtype.i32 ],
589
+ locals: [],
590
+ returns: [ Valtype.v128 ],
591
+ wasm: [
592
+ ...i32x4(0, 0, 0, 0),
593
+ [ Opcodes.local_get, 0 ],
594
+ [ ...Opcodes.i16x8_replace_lane, 0 ],
595
+ [ Opcodes.local_get, 1 ],
596
+ [ ...Opcodes.i16x8_replace_lane, 1 ],
597
+ [ Opcodes.local_get, 2 ],
598
+ [ ...Opcodes.i16x8_replace_lane, 2 ],
599
+ [ Opcodes.local_get, 3 ],
600
+ [ ...Opcodes.i16x8_replace_lane, 3 ],
601
+ [ Opcodes.local_get, 4 ],
602
+ [ ...Opcodes.i16x8_replace_lane, 4 ],
603
+ [ Opcodes.local_get, 5 ],
604
+ [ ...Opcodes.i16x8_replace_lane, 5 ],
605
+ [ Opcodes.local_get, 6 ],
606
+ [ ...Opcodes.i16x8_replace_lane, 6 ],
607
+ [ Opcodes.local_get, 7 ],
608
+ [ ...Opcodes.i16x8_replace_lane, 7 ],
609
+ ]
610
+ };
611
+
612
+ this.__SIMD_i32x4_dot_i16x8 = {
613
+ params: [ Valtype.v128, Valtype.v128 ],
614
+ locals: [],
615
+ returns: [ Valtype.v128 ],
616
+ wasm: [
617
+ [ Opcodes.local_get, 0 ],
618
+ [ Opcodes.local_get, 1 ],
619
+ [ ...Opcodes.i32x4_dot_i16x8_s ]
620
+ ]
621
+ };
622
+
623
+ this.__SIMD_i32x4_create = {
624
+ params: [ Valtype.i32, Valtype.i32, Valtype.i32, Valtype.i32 ],
625
+ locals: [],
626
+ returns: [ Valtype.v128 ],
627
+ wasm: [
628
+ ...i32x4(0, 0, 0, 0),
629
+ [ Opcodes.local_get, 0 ],
630
+ [ ...Opcodes.i32x4_replace_lane, 0 ],
631
+ [ Opcodes.local_get, 1 ],
632
+ [ ...Opcodes.i32x4_replace_lane, 1 ],
633
+ [ Opcodes.local_get, 2 ],
634
+ [ ...Opcodes.i32x4_replace_lane, 2 ],
635
+ [ Opcodes.local_get, 3 ],
636
+ [ ...Opcodes.i32x4_replace_lane, 3 ],
637
+ ]
638
+ };
639
+
640
+ this.__SIMD_i32x4_add = {
641
+ params: [ Valtype.v128, Valtype.v128 ],
642
+ locals: [],
643
+ returns: [ Valtype.v128 ],
644
+ wasm: [
645
+ [ Opcodes.local_get, 0 ],
646
+ [ Opcodes.local_get, 1 ],
647
+ [ ...Opcodes.i32x4_add ]
648
+ ]
649
+ };
650
+
651
+ this.__SIMD_i32x4_sub = {
652
+ params: [ Valtype.v128, Valtype.v128 ],
653
+ locals: [],
654
+ returns: [ Valtype.v128 ],
655
+ wasm: [
656
+ [ Opcodes.local_get, 0 ],
657
+ [ Opcodes.local_get, 1 ],
658
+ [ ...Opcodes.i32x4_sub ]
659
+ ]
660
+ };
661
+
662
+ this.__SIMD_i32x4_mul = {
663
+ params: [ Valtype.v128, Valtype.v128 ],
664
+ locals: [],
665
+ returns: [ Valtype.v128 ],
666
+ wasm: [
667
+ [ Opcodes.local_get, 0 ],
668
+ [ Opcodes.local_get, 1 ],
669
+ [ ...Opcodes.i32x4_mul ]
670
+ ]
671
+ };
672
+
673
+ this.__SIMD_i32x4_get0 = {
674
+ params: [ Valtype.v128 ],
675
+ locals: [],
676
+ returns: [ Valtype.i32 ],
677
+ wasm: [
678
+ [ Opcodes.local_get, 0 ],
679
+ [ ...Opcodes.i32x4_extract_lane, 0 ],
680
+ ],
681
+ },
682
+
683
+ this.__SIMD_i32x4_get1 = {
684
+ params: [ Valtype.v128 ],
685
+ locals: [],
686
+ returns: [ Valtype.i32 ],
687
+ wasm: [
688
+ [ Opcodes.local_get, 0 ],
689
+ [ ...Opcodes.i32x4_extract_lane, 1 ],
690
+ ],
691
+ };
692
+
693
+ this.__SIMD_i32x4_get2 = {
694
+ params: [ Valtype.v128 ],
695
+ locals: [],
696
+ returns: [ Valtype.i32 ],
697
+ wasm: [
698
+ [ Opcodes.local_get, 0 ],
699
+ [ ...Opcodes.i32x4_extract_lane, 2 ],
700
+ ],
701
+ };
702
+
703
+ this.__SIMD_i32x4_get3 = {
704
+ params: [ Valtype.v128 ],
705
+ locals: [],
706
+ returns: [ Valtype.i32 ],
707
+ wasm: [
708
+ [ Opcodes.local_get, 0 ],
709
+ [ ...Opcodes.i32x4_extract_lane, 3 ],
710
+ ],
711
+ };
712
+
713
+ this.__SIMD_i32x4_shuffle_000c = {
714
+ params: [ Valtype.v128 ],
715
+ locals: [],
716
+ returns: [ Valtype.v128 ],
717
+ wasm: [
718
+ [ Opcodes.local_get, 0 ],
719
+ ...i32x4(0, 0, 0, 0),
720
+ [ ...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)
721
+ ]
722
+ };
723
+
724
+ this.__SIMD_i32x4_shuffle_00ab = {
725
+ params: [ Valtype.v128 ],
726
+ locals: [],
727
+ returns: [ Valtype.v128 ],
728
+ wasm: [
729
+ [ Opcodes.local_get, 0 ],
730
+ ...i32x4(0, 0, 0, 0),
731
+ [ ...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)
732
+ ]
733
+ };
734
+ };
735
+
736
+ export const BuiltinPreludes = {
737
+ btoa: `var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
738
+ var btoa = function (input) {
739
+ // todo: throw invalid character for unicode
740
+
741
+ let output = "";
742
+ let chr1, chr2, chr3, enc1, enc2, enc3, enc4;
743
+ let i = 0;
744
+
745
+ while (i < input.length) {
746
+ chr1 = input.charCodeAt(i++);
747
+ chr2 = input.charCodeAt(i++);
748
+ chr3 = input.charCodeAt(i++);
749
+
750
+ enc1 = chr1 >> 2;
751
+ enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
752
+ enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
753
+ enc4 = chr3 & 63;
754
+
755
+ if (isNaN(chr2)) {
756
+ enc3 = enc4 = 64;
757
+ } else if (isNaN(chr3)) {
758
+ enc4 = 64;
759
+ }
760
+
761
+ output += keyStr.charAt(enc1);
762
+ output += keyStr.charAt(enc2);
763
+ output += keyStr.charAt(enc3);
764
+ output += keyStr.charAt(enc4);
765
+ }
766
+
767
+ return output;
768
+ };`
769
+ };