porffor 0.14.0-eca486960 → 0.16.0-053a03e10
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/CONTRIBUTING.md +15 -9
- package/README.md +9 -13
- package/asur/index.js +1 -1
- package/compiler/2c.js +104 -51
- package/compiler/assemble.js +18 -3
- package/compiler/builtins/annexb_string.ts +1 -0
- package/compiler/builtins/array.ts +84 -4
- package/compiler/builtins/base64.ts +1 -0
- package/compiler/builtins/boolean.ts +2 -0
- package/compiler/builtins/console.ts +6 -0
- package/compiler/builtins/crypto.ts +1 -0
- package/compiler/builtins/date.ts +2 -0
- package/compiler/builtins/error.js +22 -0
- package/compiler/builtins/escape.ts +1 -2
- package/compiler/builtins/function.ts +2 -0
- package/compiler/builtins/int.ts +2 -0
- package/compiler/builtins/math.ts +410 -0
- package/compiler/builtins/number.ts +2 -0
- package/compiler/builtins/object.ts +2 -0
- package/compiler/builtins/porffor.d.ts +11 -0
- package/compiler/builtins/set.ts +15 -1
- package/compiler/builtins/string.ts +1 -0
- package/compiler/builtins/symbol.ts +8 -7
- package/compiler/builtins.js +46 -10
- package/compiler/codegen.js +384 -192
- package/compiler/cyclone.js +535 -0
- package/compiler/decompile.js +6 -0
- package/compiler/generated_builtins.js +503 -53
- package/compiler/havoc.js +93 -0
- package/compiler/index.js +78 -7
- package/compiler/opt.js +3 -39
- package/compiler/parse.js +2 -2
- package/compiler/pgo.js +206 -0
- package/compiler/precompile.js +5 -4
- package/compiler/prefs.js +7 -2
- package/compiler/prototype.js +180 -157
- package/compiler/wrap.js +71 -16
- package/no_pgo.txt +923 -0
- package/package.json +1 -1
- package/pgo.txt +916 -0
- package/runner/index.js +18 -12
- package/runner/repl.js +18 -2
- /package/runner/{profiler.js → profile.js} +0 -0
package/compiler/prototype.js
CHANGED
@@ -16,7 +16,7 @@ export const PrototypeFuncs = function() {
|
|
16
16
|
|
17
17
|
this[TYPES.array] = {
|
18
18
|
// lX = local accessor of X ({ get, set }), iX = local index of X, wX = wasm ops of X
|
19
|
-
at: (pointer, length, wIndex, iTmp) => [
|
19
|
+
at: (pointer, length, wIndex, wType, iTmp) => [
|
20
20
|
...wIndex,
|
21
21
|
Opcodes.i32_to,
|
22
22
|
[ Opcodes.local_tee, iTmp ],
|
@@ -47,31 +47,39 @@ export const PrototypeFuncs = function() {
|
|
47
47
|
[ Opcodes.end ],
|
48
48
|
|
49
49
|
[ Opcodes.local_get, iTmp ],
|
50
|
-
...number(ValtypeSize[valtype], Valtype.i32),
|
50
|
+
...number(ValtypeSize[valtype] + 1, Valtype.i32),
|
51
51
|
[ Opcodes.i32_mul ],
|
52
|
-
|
53
52
|
...pointer,
|
54
53
|
[ Opcodes.i32_add ],
|
54
|
+
[ Opcodes.local_set, iTmp ],
|
55
55
|
|
56
56
|
// read from memory
|
57
|
-
[ Opcodes.
|
57
|
+
[ Opcodes.local_get, iTmp ],
|
58
|
+
[ Opcodes.load, 0, ...unsignedLEB128(ValtypeSize.i32) ],
|
59
|
+
|
60
|
+
[ Opcodes.local_get, iTmp ],
|
61
|
+
[ Opcodes.i32_load8_u, 0, ...unsignedLEB128(ValtypeSize.i32 + ValtypeSize[valtype]) ]
|
58
62
|
],
|
59
63
|
|
60
64
|
// todo: only for 1 argument
|
61
|
-
push: (pointer, length, wNewMember,
|
65
|
+
push: (pointer, length, wNewMember, wType, iTmp, _2, _3, unusedValue) => [
|
62
66
|
// get memory offset of array at last index (length)
|
63
67
|
...length.getCachedI32(),
|
64
|
-
...number(ValtypeSize[valtype], Valtype.i32),
|
68
|
+
...number(ValtypeSize[valtype] + 1, Valtype.i32),
|
65
69
|
[ Opcodes.i32_mul ],
|
66
|
-
|
67
70
|
...pointer,
|
68
71
|
[ Opcodes.i32_add ],
|
72
|
+
[ Opcodes.local_set, iTmp ],
|
69
73
|
|
70
|
-
//
|
74
|
+
// store value
|
75
|
+
[ Opcodes.local_get, iTmp ],
|
71
76
|
...wNewMember,
|
77
|
+
[ Opcodes.store, 0, ...unsignedLEB128(ValtypeSize.i32) ],
|
72
78
|
|
73
|
-
// store
|
74
|
-
[ Opcodes.
|
79
|
+
// store type
|
80
|
+
[ Opcodes.local_get, iTmp ],
|
81
|
+
...wType,
|
82
|
+
[ Opcodes.i32_store8, 0, ...unsignedLEB128(ValtypeSize.i32 + ValtypeSize[valtype]) ],
|
75
83
|
|
76
84
|
// bump array length by 1 and return it
|
77
85
|
...length.setI32([
|
@@ -93,7 +101,7 @@ export const PrototypeFuncs = function() {
|
|
93
101
|
// ...length.get()
|
94
102
|
],
|
95
103
|
|
96
|
-
pop: (pointer, length, _1, _2, _3, _4, unusedValue) => [
|
104
|
+
pop: (pointer, length, _1, _2, iTmp, _3, _4, unusedValue) => [
|
97
105
|
// if length == 0, noop
|
98
106
|
...length.getCachedI32(),
|
99
107
|
[ Opcodes.i32_eqz ],
|
@@ -121,13 +129,18 @@ export const PrototypeFuncs = function() {
|
|
121
129
|
// load last element
|
122
130
|
...(unusedValue() ? [] : [
|
123
131
|
...length.getCachedI32(),
|
124
|
-
...number(ValtypeSize[valtype], Valtype.i32),
|
132
|
+
...number(ValtypeSize[valtype] + 1, Valtype.i32),
|
125
133
|
[ Opcodes.i32_mul ],
|
126
134
|
|
127
135
|
...pointer,
|
128
136
|
[ Opcodes.i32_add ],
|
137
|
+
[ Opcodes.local_set, iTmp ],
|
129
138
|
|
130
|
-
[ Opcodes.
|
139
|
+
[ Opcodes.local_get, iTmp ],
|
140
|
+
[ Opcodes.load, 0, ...unsignedLEB128(ValtypeSize.i32) ],
|
141
|
+
|
142
|
+
[ Opcodes.local_get, iTmp ],
|
143
|
+
[ Opcodes.i32_load8_u, 0, ...unsignedLEB128(ValtypeSize.i32 + ValtypeSize[valtype]) ]
|
131
144
|
])
|
132
145
|
],
|
133
146
|
|
@@ -153,8 +166,12 @@ export const PrototypeFuncs = function() {
|
|
153
166
|
]),
|
154
167
|
|
155
168
|
// load first element
|
169
|
+
// todo/perf: unusedValue opt
|
156
170
|
...pointer,
|
157
|
-
[ Opcodes.load,
|
171
|
+
[ Opcodes.load, 0, ...unsignedLEB128(ValtypeSize.i32) ],
|
172
|
+
|
173
|
+
...pointer,
|
174
|
+
[ Opcodes.i32_load8_u, 0, ...unsignedLEB128(ValtypeSize.i32 + ValtypeSize[valtype]) ],
|
158
175
|
|
159
176
|
// offset page by -1 ind
|
160
177
|
// ...number(pointer + ValtypeSize.i32, Valtype.i32), // dst = base array index + length size
|
@@ -170,13 +187,13 @@ export const PrototypeFuncs = function() {
|
|
170
187
|
[ Opcodes.i32_add ],
|
171
188
|
|
172
189
|
// src = base array index + length size + an index
|
173
|
-
...number(ValtypeSize.i32 + ValtypeSize[valtype], Valtype.i32),
|
190
|
+
...number(ValtypeSize.i32 + ValtypeSize[valtype] + 1, Valtype.i32),
|
174
191
|
...pointer,
|
175
192
|
[ Opcodes.i32_add ],
|
176
193
|
|
177
194
|
// size = new length * sizeof element
|
178
195
|
...length.getCachedI32(),
|
179
|
-
...number(ValtypeSize[valtype], Valtype.i32),
|
196
|
+
...number(ValtypeSize[valtype] + 1, Valtype.i32),
|
180
197
|
[ Opcodes.i32_mul ],
|
181
198
|
[ ...Opcodes.memory_copy, 0x00, 0x00 ]
|
182
199
|
|
@@ -194,7 +211,7 @@ export const PrototypeFuncs = function() {
|
|
194
211
|
// ]),
|
195
212
|
],
|
196
213
|
|
197
|
-
fill: (pointer, length, wElement, iTmp) => [
|
214
|
+
fill: (pointer, length, wElement, wType, iTmp, iTmp2) => [
|
198
215
|
...wElement,
|
199
216
|
[ Opcodes.local_set, iTmp ],
|
200
217
|
|
@@ -206,7 +223,7 @@ export const PrototypeFuncs = function() {
|
|
206
223
|
[ Opcodes.i32_sub ],
|
207
224
|
|
208
225
|
// * sizeof value
|
209
|
-
...number(ValtypeSize[valtype], Valtype.i32),
|
226
|
+
...number(ValtypeSize[valtype] + 1, Valtype.i32),
|
210
227
|
[ Opcodes.i32_mul ],
|
211
228
|
|
212
229
|
...length.setCachedI32(),
|
@@ -224,17 +241,25 @@ export const PrototypeFuncs = function() {
|
|
224
241
|
|
225
242
|
[ Opcodes.loop, Blocktype.void ],
|
226
243
|
|
227
|
-
//
|
244
|
+
// calculate offset
|
228
245
|
...length.getCachedI32(),
|
229
246
|
...pointer,
|
230
247
|
[ Opcodes.i32_add ],
|
248
|
+
[ Opcodes.local_set, iTmp2 ],
|
231
249
|
|
250
|
+
// store value
|
251
|
+
[ Opcodes.local_get, iTmp2 ],
|
232
252
|
[ Opcodes.local_get, iTmp ],
|
233
|
-
[ Opcodes.store,
|
253
|
+
[ Opcodes.store, 0, ...unsignedLEB128(ValtypeSize.i32) ],
|
254
|
+
|
255
|
+
// store type
|
256
|
+
[ Opcodes.local_get, iTmp2 ],
|
257
|
+
...wType,
|
258
|
+
[ Opcodes.i32_store8, 0, ...unsignedLEB128(ValtypeSize.i32 + ValtypeSize[valtype]) ],
|
234
259
|
|
235
260
|
// pointer - sizeof value
|
236
261
|
...length.getCachedI32(),
|
237
|
-
...number(ValtypeSize[valtype], Valtype.i32),
|
262
|
+
...number(ValtypeSize[valtype] + 1, Valtype.i32),
|
238
263
|
[ Opcodes.i32_sub ],
|
239
264
|
|
240
265
|
...length.setCachedI32(),
|
@@ -254,12 +279,16 @@ export const PrototypeFuncs = function() {
|
|
254
279
|
};
|
255
280
|
|
256
281
|
this[TYPES.array].at.local = Valtype.i32;
|
282
|
+
this[TYPES.array].push.returnType = TYPES.number;
|
257
283
|
this[TYPES.array].push.noArgRetLength = true;
|
284
|
+
this[TYPES.array].push.local = Valtype.i32;
|
285
|
+
this[TYPES.array].pop.local = Valtype.i32;
|
258
286
|
this[TYPES.array].fill.local = valtypeBinary;
|
287
|
+
this[TYPES.array].fill.local2 = Valtype.i32;
|
259
288
|
this[TYPES.array].fill.returnType = TYPES.array;
|
260
289
|
|
261
290
|
this[TYPES.string] = {
|
262
|
-
at: (pointer, length, wIndex, iTmp, _, arrayShell) => {
|
291
|
+
at: (pointer, length, wIndex, wType, iTmp, _, arrayShell) => {
|
263
292
|
const [ newOut, newPointer ] = arrayShell(1, 'i16');
|
264
293
|
|
265
294
|
return [
|
@@ -317,7 +346,7 @@ export const PrototypeFuncs = function() {
|
|
317
346
|
},
|
318
347
|
|
319
348
|
// todo: out of bounds properly
|
320
|
-
charAt: (pointer, length, wIndex, _1, _2, arrayShell) => {
|
349
|
+
charAt: (pointer, length, wIndex, wType, _1, _2, arrayShell) => {
|
321
350
|
const [ newOut, newPointer ] = arrayShell(1, 'i16');
|
322
351
|
|
323
352
|
return [
|
@@ -347,127 +376,124 @@ export const PrototypeFuncs = function() {
|
|
347
376
|
];
|
348
377
|
},
|
349
378
|
|
350
|
-
charCodeAt: (pointer, length, wIndex, iTmp) =>
|
351
|
-
|
352
|
-
|
353
|
-
Opcodes.i32_to,
|
354
|
-
|
355
|
-
...(zeroChecks.charcodeat ? [] : [
|
356
|
-
[ Opcodes.local_set, iTmp ],
|
379
|
+
charCodeAt: (pointer, length, wIndex, wType, iTmp) => [
|
380
|
+
...wIndex,
|
381
|
+
Opcodes.i32_to,
|
357
382
|
|
358
|
-
|
359
|
-
|
360
|
-
[ Opcodes.local_get, iTmp ],
|
361
|
-
...number(0, Valtype.i32),
|
362
|
-
[ Opcodes.i32_lt_s ],
|
363
|
-
]),
|
383
|
+
...(zeroChecks.charcodeat ? [] : [
|
384
|
+
[ Opcodes.local_set, iTmp ],
|
364
385
|
|
365
|
-
|
386
|
+
// index < 0
|
387
|
+
...(noUnlikelyChecks ? [] : [
|
366
388
|
[ Opcodes.local_get, iTmp ],
|
367
|
-
...
|
368
|
-
[ Opcodes.
|
389
|
+
...number(0, Valtype.i32),
|
390
|
+
[ Opcodes.i32_lt_s ],
|
391
|
+
]),
|
369
392
|
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
[ Opcodes.end ],
|
393
|
+
// index >= length
|
394
|
+
[ Opcodes.local_get, iTmp ],
|
395
|
+
...length.getCachedI32(),
|
396
|
+
[ Opcodes.i32_ge_s ],
|
375
397
|
|
376
|
-
|
377
|
-
]
|
398
|
+
...(noUnlikelyChecks ? [] : [ [ Opcodes.i32_or ] ]),
|
399
|
+
[ Opcodes.if, Blocktype.void ],
|
400
|
+
...number(valtype === 'i32' ? -1 : NaN),
|
401
|
+
[ Opcodes.br, 1 ],
|
402
|
+
[ Opcodes.end ],
|
378
403
|
|
379
|
-
|
380
|
-
|
404
|
+
[ Opcodes.local_get, iTmp ],
|
405
|
+
]),
|
381
406
|
|
382
|
-
|
383
|
-
|
407
|
+
...number(ValtypeSize.i16, Valtype.i32),
|
408
|
+
[ Opcodes.i32_mul ],
|
384
409
|
|
385
|
-
|
386
|
-
|
387
|
-
Opcodes.i32_from_u
|
388
|
-
];
|
389
|
-
},
|
410
|
+
...pointer,
|
411
|
+
[ Opcodes.i32_add ],
|
390
412
|
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
[ Opcodes.local_set, iTmp ],
|
413
|
+
// load current string ind {arg}
|
414
|
+
[ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128(ValtypeSize.i32) ],
|
415
|
+
Opcodes.i32_from_u
|
416
|
+
],
|
396
417
|
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
418
|
+
isWellFormed: (pointer, length, _1, _2, iTmp, iTmp2) => [
|
419
|
+
// note: we cannot presume it begins as 0 in case it was used previously
|
420
|
+
...pointer,
|
421
|
+
[ Opcodes.local_set, iTmp ],
|
422
|
+
|
423
|
+
// use cached length as end pointer
|
424
|
+
...length.getCachedI32(),
|
425
|
+
...number(ValtypeSize.i16, Valtype.i32),
|
426
|
+
[ Opcodes.i32_mul ],
|
427
|
+
...pointer,
|
428
|
+
[ Opcodes.i32_add ],
|
429
|
+
...length.setCachedI32(),
|
404
430
|
|
405
|
-
|
431
|
+
[ Opcodes.loop, Blocktype.void ],
|
406
432
|
|
407
|
-
|
433
|
+
[ Opcodes.block, Blocktype.void ],
|
408
434
|
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
// if not leading surrogate, return false
|
422
|
-
[ Opcodes.local_get, iTmp2 ],
|
423
|
-
...number(0xDC00, Valtype.i32),
|
424
|
-
[ Opcodes.i32_ge_s ],
|
425
|
-
[ Opcodes.if, Blocktype.void ],
|
426
|
-
...number(0),
|
427
|
-
[ Opcodes.br, 3 ],
|
428
|
-
[ Opcodes.end ],
|
435
|
+
[ Opcodes.local_get, iTmp ],
|
436
|
+
[ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128(ValtypeSize.i32) ],
|
437
|
+
[ Opcodes.local_set, iTmp2 ],
|
438
|
+
|
439
|
+
// if not surrogate, continue
|
440
|
+
[ Opcodes.local_get, iTmp2 ],
|
441
|
+
...number(0xF800, Valtype.i32),
|
442
|
+
[ Opcodes.i32_and ],
|
443
|
+
...number(0xD800, Valtype.i32),
|
444
|
+
[ Opcodes.i32_ne ],
|
445
|
+
[ Opcodes.br_if, 0 ],
|
429
446
|
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
...number(0),
|
439
|
-
[ Opcodes.br, 3 ],
|
440
|
-
[ Opcodes.end ],
|
447
|
+
// if not leading surrogate, return false
|
448
|
+
[ Opcodes.local_get, iTmp2 ],
|
449
|
+
...number(0xDC00, Valtype.i32),
|
450
|
+
[ Opcodes.i32_ge_s ],
|
451
|
+
[ Opcodes.if, Blocktype.void ],
|
452
|
+
...number(0),
|
453
|
+
[ Opcodes.br, 3 ],
|
454
|
+
[ Opcodes.end ],
|
441
455
|
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
456
|
+
// if not followed by trailing surrogate, return false
|
457
|
+
[ Opcodes.local_get, iTmp ],
|
458
|
+
[ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128(ValtypeSize.i32 + ValtypeSize.i16) ],
|
459
|
+
...number(0xFC00, Valtype.i32),
|
460
|
+
[ Opcodes.i32_and ],
|
461
|
+
...number(0xDC00, Valtype.i32),
|
462
|
+
[ Opcodes.i32_ne ],
|
463
|
+
[ Opcodes.if, Blocktype.void ],
|
464
|
+
...number(0),
|
465
|
+
[ Opcodes.br, 3 ],
|
466
|
+
[ Opcodes.end ],
|
447
467
|
|
448
|
-
|
468
|
+
// bump index again since gone through two valid chars
|
469
|
+
[ Opcodes.local_get, iTmp ],
|
470
|
+
...number(ValtypeSize.i16, Valtype.i32),
|
471
|
+
[ Opcodes.i32_add ],
|
472
|
+
[ Opcodes.local_set, iTmp ],
|
449
473
|
|
450
|
-
|
451
|
-
[ Opcodes.local_get, iTmp ],
|
452
|
-
...number(ValtypeSize.i16, Valtype.i32),
|
453
|
-
[ Opcodes.i32_add ],
|
454
|
-
[ Opcodes.local_tee, iTmp ],
|
474
|
+
[ Opcodes.end ],
|
455
475
|
|
456
|
-
|
457
|
-
|
458
|
-
|
476
|
+
// bump pointer and loop if not at the end
|
477
|
+
[ Opcodes.local_get, iTmp ],
|
478
|
+
...number(ValtypeSize.i16, Valtype.i32),
|
479
|
+
[ Opcodes.i32_add ],
|
480
|
+
[ Opcodes.local_tee, iTmp ],
|
459
481
|
|
460
|
-
|
482
|
+
...length.getCachedI32(), // end pointer
|
483
|
+
[ Opcodes.i32_ne ],
|
484
|
+
[ Opcodes.br_if, 0 ],
|
461
485
|
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
486
|
+
[ Opcodes.end ],
|
487
|
+
|
488
|
+
// return true
|
489
|
+
...number(1)
|
490
|
+
]
|
466
491
|
};
|
467
492
|
|
468
493
|
this[TYPES.string].at.local = Valtype.i32;
|
469
494
|
this[TYPES.string].at.returnType = TYPES.string;
|
470
495
|
this[TYPES.string].charAt.returnType = TYPES.string;
|
496
|
+
this[TYPES.string].charCodeAt.returnType = TYPES.number;
|
471
497
|
this[TYPES.string].charCodeAt.local = Valtype.i32;
|
472
498
|
this[TYPES.string].charCodeAt.noPointerCache = zeroChecks.charcodeat;
|
473
499
|
|
@@ -477,7 +503,7 @@ export const PrototypeFuncs = function() {
|
|
477
503
|
|
478
504
|
if (Prefs.bytestring) {
|
479
505
|
this[TYPES.bytestring] = {
|
480
|
-
at: (pointer, length, wIndex, iTmp, _, arrayShell) => {
|
506
|
+
at: (pointer, length, wIndex, wType, iTmp, _, arrayShell) => {
|
481
507
|
const [ newOut, newPointer ] = arrayShell(1, 'i8');
|
482
508
|
|
483
509
|
return [
|
@@ -533,7 +559,7 @@ export const PrototypeFuncs = function() {
|
|
533
559
|
},
|
534
560
|
|
535
561
|
// todo: out of bounds properly
|
536
|
-
charAt: (pointer, length, wIndex, _1, _2, arrayShell) => {
|
562
|
+
charAt: (pointer, length, wIndex, wType, _1, _2, arrayShell) => {
|
537
563
|
const [ newOut, newPointer ] = arrayShell(1, 'i8');
|
538
564
|
|
539
565
|
return [
|
@@ -560,55 +586,52 @@ export const PrototypeFuncs = function() {
|
|
560
586
|
];
|
561
587
|
},
|
562
588
|
|
563
|
-
charCodeAt: (pointer, length, wIndex, iTmp) =>
|
564
|
-
|
565
|
-
|
566
|
-
Opcodes.i32_to,
|
567
|
-
|
568
|
-
...(zeroChecks.charcodeat ? [] : [
|
569
|
-
[ Opcodes.local_set, iTmp ],
|
589
|
+
charCodeAt: (pointer, length, wIndex, wType, iTmp) => [
|
590
|
+
...wIndex,
|
591
|
+
Opcodes.i32_to,
|
570
592
|
|
571
|
-
|
572
|
-
|
573
|
-
[ Opcodes.local_get, iTmp ],
|
574
|
-
...number(0, Valtype.i32),
|
575
|
-
[ Opcodes.i32_lt_s ],
|
576
|
-
]),
|
593
|
+
...(zeroChecks.charcodeat ? [] : [
|
594
|
+
[ Opcodes.local_set, iTmp ],
|
577
595
|
|
578
|
-
|
596
|
+
// index < 0
|
597
|
+
...(noUnlikelyChecks ? [] : [
|
579
598
|
[ Opcodes.local_get, iTmp ],
|
580
|
-
...
|
581
|
-
[ Opcodes.
|
599
|
+
...number(0, Valtype.i32),
|
600
|
+
[ Opcodes.i32_lt_s ],
|
601
|
+
]),
|
582
602
|
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
[ Opcodes.end ],
|
603
|
+
// index >= length
|
604
|
+
[ Opcodes.local_get, iTmp ],
|
605
|
+
...length.getCachedI32(),
|
606
|
+
[ Opcodes.i32_ge_s ],
|
588
607
|
|
589
|
-
|
590
|
-
]
|
608
|
+
...(noUnlikelyChecks ? [] : [ [ Opcodes.i32_or ] ]),
|
609
|
+
[ Opcodes.if, Blocktype.void ],
|
610
|
+
...number(valtype === 'i32' ? -1 : NaN),
|
611
|
+
[ Opcodes.br, 1 ],
|
612
|
+
[ Opcodes.end ],
|
591
613
|
|
592
|
-
|
593
|
-
|
614
|
+
[ Opcodes.local_get, iTmp ],
|
615
|
+
]),
|
594
616
|
|
595
|
-
|
596
|
-
|
597
|
-
Opcodes.i32_from_u
|
598
|
-
];
|
599
|
-
},
|
617
|
+
...pointer,
|
618
|
+
[ Opcodes.i32_add ],
|
600
619
|
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
620
|
+
// load current string ind {arg}
|
621
|
+
[ Opcodes.i32_load8_u, 0, ...unsignedLEB128(ValtypeSize.i32) ],
|
622
|
+
Opcodes.i32_from_u
|
623
|
+
],
|
624
|
+
|
625
|
+
isWellFormed: () => [
|
626
|
+
// we know it must be true as it is a bytestring lol
|
627
|
+
...number(1)
|
628
|
+
]
|
607
629
|
};
|
608
630
|
|
609
631
|
this[TYPES.bytestring].at.local = Valtype.i32;
|
610
632
|
this[TYPES.bytestring].at.returnType = TYPES.bytestring;
|
611
633
|
this[TYPES.bytestring].charAt.returnType = TYPES.bytestring;
|
634
|
+
this[TYPES.bytestring].charCodeAt.returnType = TYPES.number;
|
612
635
|
this[TYPES.bytestring].charCodeAt.local = Valtype.i32;
|
613
636
|
this[TYPES.bytestring].charCodeAt.noPointerCache = zeroChecks.charcodeat;
|
614
637
|
|
package/compiler/wrap.js
CHANGED
@@ -6,8 +6,25 @@ import { TYPES } from './types.js';
|
|
6
6
|
import { log } from './log.js';
|
7
7
|
import Prefs from './prefs.js';
|
8
8
|
|
9
|
+
const fs = (typeof process?.version !== 'undefined' ? (await import('node:fs')) : undefined);
|
10
|
+
|
9
11
|
const bold = x => `\u001b[1m${x}\u001b[0m`;
|
10
12
|
|
13
|
+
export const readByteStr = (memory, ptr) => {
|
14
|
+
const length = (new Int32Array(memory.buffer, ptr, 1))[0];
|
15
|
+
return Array.from(new Uint8Array(memory.buffer, ptr + 4, length)).map(x => String.fromCharCode(x)).join('');
|
16
|
+
};
|
17
|
+
|
18
|
+
export const writeByteStr = (memory, ptr, str) => {
|
19
|
+
const length = str.length;
|
20
|
+
(new Int32Array(memory.buffer, ptr, 1))[0] = length;
|
21
|
+
|
22
|
+
const arr = new Uint8Array(memory.buffer, ptr + 4, length);
|
23
|
+
for (let i = 0; i < length; i++) {
|
24
|
+
arr[i] = str.charCodeAt(i);
|
25
|
+
}
|
26
|
+
};
|
27
|
+
|
11
28
|
const porfToJSValue = ({ memory, funcs, pages }, value, type) => {
|
12
29
|
switch (type) {
|
13
30
|
case TYPES.boolean: return Boolean(value);
|
@@ -41,9 +58,22 @@ const porfToJSValue = ({ memory, funcs, pages }, value, type) => {
|
|
41
58
|
case TYPES.array: {
|
42
59
|
const length = (new Int32Array(memory.buffer, value, 1))[0];
|
43
60
|
|
44
|
-
|
45
|
-
|
46
|
-
|
61
|
+
const out = [];
|
62
|
+
for (let i = 0; i < length; i++) {
|
63
|
+
const offset = value + 4 + (i * 9);
|
64
|
+
|
65
|
+
// have to slice because of memory alignment (?)
|
66
|
+
const v = (new Float64Array(memory.buffer.slice(offset, offset + 8), 0, 1))[0];
|
67
|
+
const t = (new Uint8Array(memory.buffer, offset + 8, 1))[0];
|
68
|
+
|
69
|
+
// console.log(`reading value at index ${i}...`)
|
70
|
+
// console.log(' memory:', Array.from(new Uint8Array(memory.buffer, offset, 9)).map(x => x.toString(16).padStart(2, '0')).join(' '));
|
71
|
+
// console.log(' read:', { value: v, type: t }, '\n');
|
72
|
+
|
73
|
+
out.push(porfToJSValue({ memory, funcs, pages }, v, t));
|
74
|
+
}
|
75
|
+
|
76
|
+
return out;
|
47
77
|
}
|
48
78
|
|
49
79
|
case TYPES.date: {
|
@@ -88,28 +118,31 @@ const porfToJSValue = ({ memory, funcs, pages }, value, type) => {
|
|
88
118
|
}
|
89
119
|
};
|
90
120
|
|
91
|
-
export default
|
121
|
+
export default (source, flags = [ 'module' ], customImports = {}, print = str => process.stdout.write(str)) => {
|
92
122
|
const times = [];
|
93
123
|
|
94
124
|
const t1 = performance.now();
|
95
|
-
const { wasm, funcs, globals, tags, exceptions, pages, c } = compile(source, flags);
|
125
|
+
const { wasm, funcs, globals, tags, exceptions, pages, c } = typeof source === 'object' ? source : compile(source, flags);
|
96
126
|
|
97
127
|
globalThis.porfDebugInfo = { funcs, globals };
|
98
128
|
|
99
|
-
if (source.includes('export
|
129
|
+
if (source.includes?.('export ')) flags.push('module');
|
100
130
|
|
101
|
-
|
131
|
+
fs.writeFileSync('out.wasm', Buffer.from(wasm));
|
102
132
|
|
103
133
|
times.push(performance.now() - t1);
|
104
134
|
if (Prefs.profileCompiler) console.log(bold(`compiled in ${times[0].toFixed(2)}ms`));
|
105
135
|
|
106
136
|
const backtrace = (funcInd, blobOffset) => {
|
107
|
-
if (funcInd == null || blobOffset == null
|
137
|
+
if (funcInd == null || blobOffset == null ||
|
138
|
+
Number.isNaN(funcInd) || Number.isNaN(blobOffset)) return false;
|
108
139
|
|
109
140
|
// convert blob offset -> function wasm offset.
|
110
141
|
// this is not good code and is somewhat duplicated
|
111
142
|
// I just want it to work for debugging, I don't care about perf/yes
|
112
143
|
const func = funcs.find(x => x.index === funcInd);
|
144
|
+
if (!func) return false;
|
145
|
+
|
113
146
|
const locals = Object.values(func.locals).sort((a, b) => a.idx - b.idx).slice(func.params.length).sort((a, b) => a.idx - b.idx);
|
114
147
|
|
115
148
|
let localDecl = [], typeCount = 0, lastType;
|
@@ -184,13 +217,15 @@ export default async (source, flags = [ 'module' ], customImports = {}, print =
|
|
184
217
|
|
185
218
|
let instance;
|
186
219
|
try {
|
187
|
-
let wasmEngine = WebAssembly;
|
188
|
-
if (Prefs.asur) {
|
189
|
-
|
190
|
-
|
191
|
-
}
|
192
|
-
|
193
|
-
0, { instance } = await wasmEngine.instantiate(wasm, {
|
220
|
+
// let wasmEngine = WebAssembly;
|
221
|
+
// if (Prefs.asur) {
|
222
|
+
// log.warning('wrap', 'using our !experimental! asur wasm engine instead of host to run');
|
223
|
+
// wasmEngine = await import('../asur/index.js');
|
224
|
+
// }
|
225
|
+
|
226
|
+
// 0, { instance } = await wasmEngine.instantiate(wasm, {
|
227
|
+
const module = new WebAssembly.Module(wasm);
|
228
|
+
instance = new WebAssembly.Instance(module, {
|
194
229
|
'': {
|
195
230
|
p: valtype === 'i64' ? i => print(Number(i).toString()) : i => print(i.toString()),
|
196
231
|
c: valtype === 'i64' ? i => print(String.fromCharCode(Number(i))) : i => print(String.fromCharCode(i)),
|
@@ -198,12 +233,31 @@ export default async (source, flags = [ 'module' ], customImports = {}, print =
|
|
198
233
|
u: () => performance.timeOrigin,
|
199
234
|
y: () => {},
|
200
235
|
z: () => {},
|
236
|
+
w: (ind, outPtr) => { // readArgv
|
237
|
+
const args = process.argv.slice(2).filter(x => !x.startsWith('-'));
|
238
|
+
const str = args[ind];
|
239
|
+
if (!str) return -1;
|
240
|
+
|
241
|
+
writeByteStr(memory, outPtr, str);
|
242
|
+
return str.length;
|
243
|
+
},
|
244
|
+
q: (pathPtr, outPtr) => { // readFile
|
245
|
+
try {
|
246
|
+
const path = readByteStr(memory, pathPtr);
|
247
|
+
const contents = fs.readFileSync(path, 'utf8');
|
248
|
+
writeByteStr(memory, outPtr, contents);
|
249
|
+
return contents.length;
|
250
|
+
} catch {
|
251
|
+
return -1;
|
252
|
+
}
|
253
|
+
},
|
201
254
|
...customImports
|
202
255
|
}
|
203
256
|
});
|
204
257
|
} catch (e) {
|
205
258
|
// only backtrace for runner, not test262/etc
|
206
259
|
if (!process.argv[1].includes('/runner')) throw e;
|
260
|
+
if (!(e instanceof WebAssembly.CompileError)) throw e;
|
207
261
|
|
208
262
|
const funcInd = parseInt(e.message.match(/function #([0-9]+) /)?.[1]);
|
209
263
|
const blobOffset = parseInt(e.message.split('@')?.[1]);
|
@@ -216,6 +270,7 @@ export default async (source, flags = [ 'module' ], customImports = {}, print =
|
|
216
270
|
if (Prefs.profileCompiler) console.log(`instantiated in ${times[1].toFixed(2)}ms`);
|
217
271
|
|
218
272
|
const exports = {};
|
273
|
+
const rawValues = process.argv.includes('-i');
|
219
274
|
|
220
275
|
const exceptTag = instance.exports['0'], memory = instance.exports['$'];
|
221
276
|
for (const x in instance.exports) {
|
@@ -236,7 +291,7 @@ export default async (source, flags = [ 'module' ], customImports = {}, print =
|
|
236
291
|
const ret = exp.apply(this, arguments);
|
237
292
|
if (ret == null) return undefined;
|
238
293
|
|
239
|
-
if (
|
294
|
+
if (rawValues) return { value: ret[0], type: ret[1], js: porfToJSValue({ memory, funcs, pages }, ret[0], ret[1]) };
|
240
295
|
|
241
296
|
return porfToJSValue({ memory, funcs, pages }, ret[0], ret[1]);
|
242
297
|
} catch (e) {
|