porffor 0.2.0-fde989a → 0.14.0-032e4ad08

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.
Files changed (64) hide show
  1. package/CONTRIBUTING.md +262 -0
  2. package/LICENSE +20 -20
  3. package/README.md +135 -94
  4. package/asur/README.md +2 -0
  5. package/asur/index.js +1262 -0
  6. package/byg/index.js +216 -0
  7. package/compiler/2c.js +66 -54
  8. package/compiler/{sections.js → assemble.js} +109 -21
  9. package/compiler/builtins/annexb_string.js +72 -0
  10. package/compiler/builtins/annexb_string.ts +19 -0
  11. package/compiler/builtins/array.ts +225 -0
  12. package/compiler/builtins/base64.ts +77 -0
  13. package/compiler/builtins/boolean.ts +20 -0
  14. package/compiler/builtins/crypto.ts +121 -0
  15. package/compiler/builtins/date.ts +2069 -0
  16. package/compiler/builtins/error.js +22 -0
  17. package/compiler/builtins/escape.ts +140 -0
  18. package/compiler/builtins/function.ts +7 -0
  19. package/compiler/builtins/int.ts +147 -0
  20. package/compiler/builtins/math.ts +410 -0
  21. package/compiler/builtins/number.ts +531 -0
  22. package/compiler/builtins/object.ts +6 -0
  23. package/compiler/builtins/porffor.d.ts +60 -0
  24. package/compiler/builtins/set.ts +199 -0
  25. package/compiler/builtins/string.ts +1081 -0
  26. package/compiler/builtins/symbol.ts +62 -0
  27. package/compiler/builtins.js +466 -284
  28. package/compiler/{codeGen.js → codegen.js} +1573 -656
  29. package/compiler/decompile.js +3 -4
  30. package/compiler/embedding.js +22 -22
  31. package/compiler/encoding.js +94 -10
  32. package/compiler/expression.js +1 -1
  33. package/compiler/generated_builtins.js +2110 -0
  34. package/compiler/index.js +29 -44
  35. package/compiler/log.js +6 -3
  36. package/compiler/opt.js +55 -41
  37. package/compiler/parse.js +38 -30
  38. package/compiler/precompile.js +121 -0
  39. package/compiler/prefs.js +31 -0
  40. package/compiler/prototype.js +209 -201
  41. package/compiler/types.js +38 -0
  42. package/compiler/wasmSpec.js +33 -8
  43. package/compiler/wrap.js +154 -89
  44. package/package.json +9 -5
  45. package/porf +2 -0
  46. package/porffor_tmp.c +202 -0
  47. package/rhemyn/compile.js +46 -27
  48. package/rhemyn/parse.js +322 -320
  49. package/rhemyn/test/parse.js +58 -58
  50. package/runner/compare.js +33 -34
  51. package/runner/debug.js +117 -0
  52. package/runner/index.js +80 -12
  53. package/runner/profiler.js +75 -0
  54. package/runner/repl.js +58 -15
  55. package/runner/sizes.js +37 -37
  56. package/runner/version.js +10 -8
  57. package/compiler/builtins/base64.js +0 -92
  58. package/filesize.cmd +0 -2
  59. package/runner/info.js +0 -89
  60. package/runner/profile.js +0 -46
  61. package/runner/results.json +0 -1
  62. package/runner/transform.js +0 -15
  63. package/tmp.c +0 -661
  64. package/util/enum.js +0 -20
@@ -0,0 +1,31 @@
1
+ const onByDefault = [ 'bytestring', 'treeshakeWasmImports', 'alwaysMemory', 'indirectCalls', 'optUnused' ];
2
+
3
+ let cache = {};
4
+ const obj = new Proxy({}, {
5
+ get(_, p) {
6
+ // intentionally misses with undefined values cached
7
+ if (cache[p]) return cache[p];
8
+
9
+ const ret = (() => {
10
+ // fooBar -> foo-bar
11
+ const name = p[0] === '_' ? p : p.replace(/[A-Z]/g, c => `-${c.toLowerCase()}`);
12
+ const prefix = name.length === 1 ? '-' : '--';
13
+ if (process.argv.includes(prefix + name)) return true;
14
+ if (process.argv.includes(prefix + 'no-' + name)) return false;
15
+
16
+ const valArg = process.argv.find(x => x.startsWith(`${prefix}${name}=`));
17
+ if (valArg) return valArg.slice(name.length + 1 + prefix.length);
18
+
19
+ if (onByDefault.includes(p)) return true;
20
+ return undefined;
21
+ })();
22
+
23
+ // do not cache in web demo as args are changed live
24
+ if (!globalThis.document) cache[p] = ret;
25
+ return ret;
26
+ }
27
+ });
28
+
29
+ obj.uncache = () => cache = {};
30
+
31
+ export default obj;
@@ -1,36 +1,22 @@
1
- import { Opcodes, Blocktype, Valtype, ValtypeSize, PageSize } from "./wasmSpec.js";
2
- import { number } from "./embedding.js";
3
- import { unsignedLEB128 } from "./encoding.js";
4
- import { UNDEFINED } from "./builtins.js";
5
-
6
- // todo: do not duplicate this
7
- const TYPES = {
8
- number: 0x00,
9
- boolean: 0x01,
10
- string: 0x02,
11
- undefined: 0x03,
12
- object: 0x04,
13
- function: 0x05,
14
- symbol: 0x06,
15
- bigint: 0x07,
16
-
17
- // these are not "typeof" types but tracked internally
18
- _array: 0x10,
19
- _regexp: 0x11,
20
- _bytestring: 0x12
21
- };
1
+ import { Opcodes, Blocktype, Valtype, ValtypeSize } from './wasmSpec.js';
2
+ import { number } from './embedding.js';
3
+ import { unsignedLEB128 } from './encoding.js';
4
+ import { UNDEFINED } from './builtins.js';
5
+ import { TYPES } from './types.js';
6
+ import Prefs from './prefs.js';
22
7
 
23
8
  // todo: turn these into built-ins once arrays and these become less hacky
24
9
 
25
10
  export const PrototypeFuncs = function() {
26
- const noUnlikelyChecks = process.argv.includes('-funsafe-no-unlikely-proto-checks');
27
- let zeroChecks = process.argv.find(x => x.startsWith('-funsafe-zero-proto-checks='));
28
- if (zeroChecks) zeroChecks = zeroChecks.split('=')[1].split(',').reduce((acc, x) => { acc[x.toLowerCase()] = true; return acc; }, {});
11
+ const noUnlikelyChecks = Prefs.funsafeNoUnlikelyProtoChecks;
12
+
13
+ let zeroChecks;
14
+ if (Prefs.zeroChecks) zeroChecks = Prefs.zeroChecks.split('=')[1].split(',').reduce((acc, x) => { acc[x.toLowerCase()] = true; return acc; }, {});
29
15
  else zeroChecks = {};
30
16
 
31
- this[TYPES._array] = {
17
+ this[TYPES.array] = {
32
18
  // lX = local accessor of X ({ get, set }), iX = local index of X, wX = wasm ops of X
33
- at: (pointer, length, wIndex, iTmp) => [
19
+ at: (pointer, length, wIndex, wType, iTmp) => [
34
20
  ...wIndex,
35
21
  Opcodes.i32_to,
36
22
  [ Opcodes.local_tee, iTmp ],
@@ -61,31 +47,39 @@ export const PrototypeFuncs = function() {
61
47
  [ Opcodes.end ],
62
48
 
63
49
  [ Opcodes.local_get, iTmp ],
64
- ...number(ValtypeSize[valtype], Valtype.i32),
50
+ ...number(ValtypeSize[valtype] + 1, Valtype.i32),
65
51
  [ Opcodes.i32_mul ],
66
-
67
52
  ...pointer,
68
53
  [ Opcodes.i32_add ],
54
+ [ Opcodes.local_set, iTmp ],
69
55
 
70
56
  // read from memory
71
- [ Opcodes.load, Math.log2(ValtypeSize[valtype]) - 1, ...unsignedLEB128(ValtypeSize.i32) ]
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]) ]
72
62
  ],
73
63
 
74
64
  // todo: only for 1 argument
75
- push: (pointer, length, wNewMember, _1, _2, _3, unusedValue) => [
65
+ push: (pointer, length, wNewMember, wType, iTmp, _2, _3, unusedValue) => [
76
66
  // get memory offset of array at last index (length)
77
67
  ...length.getCachedI32(),
78
- ...number(ValtypeSize[valtype], Valtype.i32),
68
+ ...number(ValtypeSize[valtype] + 1, Valtype.i32),
79
69
  [ Opcodes.i32_mul ],
80
-
81
70
  ...pointer,
82
71
  [ Opcodes.i32_add ],
72
+ [ Opcodes.local_set, iTmp ],
83
73
 
84
- // generated wasm for new member
74
+ // store value
75
+ [ Opcodes.local_get, iTmp ],
85
76
  ...wNewMember,
77
+ [ Opcodes.store, 0, ...unsignedLEB128(ValtypeSize.i32) ],
86
78
 
87
- // store in memory
88
- [ Opcodes.store, Math.log2(ValtypeSize[valtype]) - 1, ...unsignedLEB128(ValtypeSize.i32) ],
79
+ // store type
80
+ [ Opcodes.local_get, iTmp ],
81
+ ...wType,
82
+ [ Opcodes.i32_store8, 0, ...unsignedLEB128(ValtypeSize.i32 + ValtypeSize[valtype]) ],
89
83
 
90
84
  // bump array length by 1 and return it
91
85
  ...length.setI32([
@@ -107,7 +101,7 @@ export const PrototypeFuncs = function() {
107
101
  // ...length.get()
108
102
  ],
109
103
 
110
- pop: (pointer, length, _1, _2, _3, _4, unusedValue) => [
104
+ pop: (pointer, length, _1, _2, iTmp, _3, _4, unusedValue) => [
111
105
  // if length == 0, noop
112
106
  ...length.getCachedI32(),
113
107
  [ Opcodes.i32_eqz ],
@@ -135,20 +129,25 @@ export const PrototypeFuncs = function() {
135
129
  // load last element
136
130
  ...(unusedValue() ? [] : [
137
131
  ...length.getCachedI32(),
138
- ...number(ValtypeSize[valtype], Valtype.i32),
132
+ ...number(ValtypeSize[valtype] + 1, Valtype.i32),
139
133
  [ Opcodes.i32_mul ],
140
134
 
141
135
  ...pointer,
142
136
  [ Opcodes.i32_add ],
137
+ [ Opcodes.local_set, iTmp ],
143
138
 
144
- [ Opcodes.load, Math.log2(ValtypeSize[valtype]) - 1, ...unsignedLEB128(ValtypeSize.i32) ]
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]) ]
145
144
  ])
146
145
  ],
147
146
 
148
147
  shift: (pointer, length) => [
149
148
  // if length == 0, noop
150
149
  ...length.getCachedI32(),
151
- Opcodes.i32_eqz,
150
+ [ Opcodes.i32_eqz ],
152
151
  [ Opcodes.if, Blocktype.void ],
153
152
  ...number(UNDEFINED),
154
153
  [ Opcodes.br, 1 ],
@@ -167,8 +166,12 @@ export const PrototypeFuncs = function() {
167
166
  ]),
168
167
 
169
168
  // load first element
169
+ // todo/perf: unusedValue opt
170
+ ...pointer,
171
+ [ Opcodes.load, 0, ...unsignedLEB128(ValtypeSize.i32) ],
172
+
170
173
  ...pointer,
171
- [ Opcodes.load, Math.log2(ValtypeSize[valtype]) - 1, ...unsignedLEB128(ValtypeSize.i32) ],
174
+ [ Opcodes.i32_load8_u, 0, ...unsignedLEB128(ValtypeSize.i32 + ValtypeSize[valtype]) ],
172
175
 
173
176
  // offset page by -1 ind
174
177
  // ...number(pointer + ValtypeSize.i32, Valtype.i32), // dst = base array index + length size
@@ -184,13 +187,13 @@ export const PrototypeFuncs = function() {
184
187
  [ Opcodes.i32_add ],
185
188
 
186
189
  // src = base array index + length size + an index
187
- ...number(ValtypeSize.i32 + ValtypeSize[valtype], Valtype.i32),
190
+ ...number(ValtypeSize.i32 + ValtypeSize[valtype] + 1, Valtype.i32),
188
191
  ...pointer,
189
192
  [ Opcodes.i32_add ],
190
193
 
191
194
  // size = new length * sizeof element
192
195
  ...length.getCachedI32(),
193
- ...number(ValtypeSize[valtype], Valtype.i32),
196
+ ...number(ValtypeSize[valtype] + 1, Valtype.i32),
194
197
  [ Opcodes.i32_mul ],
195
198
  [ ...Opcodes.memory_copy, 0x00, 0x00 ]
196
199
 
@@ -208,7 +211,7 @@ export const PrototypeFuncs = function() {
208
211
  // ]),
209
212
  ],
210
213
 
211
- fill: (pointer, length, wElement, iTmp) => [
214
+ fill: (pointer, length, wElement, wType, iTmp, iTmp2) => [
212
215
  ...wElement,
213
216
  [ Opcodes.local_set, iTmp ],
214
217
 
@@ -220,7 +223,7 @@ export const PrototypeFuncs = function() {
220
223
  [ Opcodes.i32_sub ],
221
224
 
222
225
  // * sizeof value
223
- ...number(ValtypeSize[valtype], Valtype.i32),
226
+ ...number(ValtypeSize[valtype] + 1, Valtype.i32),
224
227
  [ Opcodes.i32_mul ],
225
228
 
226
229
  ...length.setCachedI32(),
@@ -238,17 +241,25 @@ export const PrototypeFuncs = function() {
238
241
 
239
242
  [ Opcodes.loop, Blocktype.void ],
240
243
 
241
- // set element using pointer
244
+ // calculate offset
242
245
  ...length.getCachedI32(),
243
246
  ...pointer,
244
247
  [ Opcodes.i32_add ],
248
+ [ Opcodes.local_set, iTmp2 ],
245
249
 
250
+ // store value
251
+ [ Opcodes.local_get, iTmp2 ],
246
252
  [ Opcodes.local_get, iTmp ],
247
- [ Opcodes.store, Math.log2(ValtypeSize[valtype]) - 1, ...unsignedLEB128( ValtypeSize.i32) ],
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]) ],
248
259
 
249
260
  // pointer - sizeof value
250
261
  ...length.getCachedI32(),
251
- ...number(ValtypeSize[valtype], Valtype.i32),
262
+ ...number(ValtypeSize[valtype] + 1, Valtype.i32),
252
263
  [ Opcodes.i32_sub ],
253
264
 
254
265
  ...length.setCachedI32(),
@@ -267,13 +278,17 @@ export const PrototypeFuncs = function() {
267
278
  ]
268
279
  };
269
280
 
270
- this[TYPES._array].at.local = Valtype.i32;
271
- this[TYPES._array].push.noArgRetLength = true;
272
- this[TYPES._array].fill.local = valtypeBinary;
273
- this[TYPES._array].fill.returnType = TYPES._array;
281
+ this[TYPES.array].at.local = Valtype.i32;
282
+ this[TYPES.array].push.returnType = TYPES.number;
283
+ this[TYPES.array].push.noArgRetLength = true;
284
+ this[TYPES.array].push.local = Valtype.i32;
285
+ this[TYPES.array].pop.local = Valtype.i32;
286
+ this[TYPES.array].fill.local = valtypeBinary;
287
+ this[TYPES.array].fill.local2 = Valtype.i32;
288
+ this[TYPES.array].fill.returnType = TYPES.array;
274
289
 
275
290
  this[TYPES.string] = {
276
- at: (pointer, length, wIndex, iTmp, _, arrayShell) => {
291
+ at: (pointer, length, wIndex, wType, iTmp, _, arrayShell) => {
277
292
  const [ newOut, newPointer ] = arrayShell(1, 'i16');
278
293
 
279
294
  return [
@@ -331,7 +346,7 @@ export const PrototypeFuncs = function() {
331
346
  },
332
347
 
333
348
  // todo: out of bounds properly
334
- charAt: (pointer, length, wIndex, _1, _2, arrayShell) => {
349
+ charAt: (pointer, length, wIndex, wType, _1, _2, arrayShell) => {
335
350
  const [ newOut, newPointer ] = arrayShell(1, 'i16');
336
351
 
337
352
  return [
@@ -342,8 +357,8 @@ export const PrototypeFuncs = function() {
342
357
  ...number(0, Valtype.i32), // base 0 for store later
343
358
 
344
359
  ...wIndex,
345
-
346
360
  Opcodes.i32_to,
361
+
347
362
  ...number(ValtypeSize.i16, Valtype.i32),
348
363
  [ Opcodes.i32_mul ],
349
364
 
@@ -361,127 +376,124 @@ export const PrototypeFuncs = function() {
361
376
  ];
362
377
  },
363
378
 
364
- charCodeAt: (pointer, length, wIndex, iTmp) => {
365
- return [
366
- ...wIndex,
367
- Opcodes.i32_to,
368
-
369
- ...(zeroChecks.charcodeat ? [] : [
370
- [ Opcodes.local_set, iTmp ],
379
+ charCodeAt: (pointer, length, wIndex, wType, iTmp) => [
380
+ ...wIndex,
381
+ Opcodes.i32_to,
371
382
 
372
- // index < 0
373
- ...(noUnlikelyChecks ? [] : [
374
- [ Opcodes.local_get, iTmp ],
375
- ...number(0, Valtype.i32),
376
- [ Opcodes.i32_lt_s ],
377
- ]),
383
+ ...(zeroChecks.charcodeat ? [] : [
384
+ [ Opcodes.local_set, iTmp ],
378
385
 
379
- // index >= length
386
+ // index < 0
387
+ ...(noUnlikelyChecks ? [] : [
380
388
  [ Opcodes.local_get, iTmp ],
381
- ...length.getCachedI32(),
382
- [ Opcodes.i32_ge_s ],
389
+ ...number(0, Valtype.i32),
390
+ [ Opcodes.i32_lt_s ],
391
+ ]),
383
392
 
384
- ...(noUnlikelyChecks ? [] : [ [ Opcodes.i32_or ] ]),
385
- [ Opcodes.if, Blocktype.void ],
386
- ...number(NaN),
387
- [ Opcodes.br, 1 ],
388
- [ Opcodes.end ],
393
+ // index >= length
394
+ [ Opcodes.local_get, iTmp ],
395
+ ...length.getCachedI32(),
396
+ [ Opcodes.i32_ge_s ],
389
397
 
390
- [ Opcodes.local_get, iTmp ],
391
- ]),
398
+ ...(noUnlikelyChecks ? [] : [ [ Opcodes.i32_or ] ]),
399
+ [ Opcodes.if, Blocktype.void ],
400
+ ...number(valtype === 'i32' ? -1 : NaN),
401
+ [ Opcodes.br, 1 ],
402
+ [ Opcodes.end ],
392
403
 
393
- ...number(ValtypeSize.i16, Valtype.i32),
394
- [ Opcodes.i32_mul ],
404
+ [ Opcodes.local_get, iTmp ],
405
+ ]),
395
406
 
396
- ...pointer,
397
- [ Opcodes.i32_add ],
407
+ ...number(ValtypeSize.i16, Valtype.i32),
408
+ [ Opcodes.i32_mul ],
398
409
 
399
- // load current string ind {arg}
400
- [ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128(ValtypeSize.i32) ],
401
- Opcodes.i32_from_u
402
- ];
403
- },
410
+ ...pointer,
411
+ [ Opcodes.i32_add ],
404
412
 
405
- isWellFormed: (pointer, length, wIndex, iTmp, iTmp2) => {
406
- return [
407
- // note: we cannot presume it begins as 0 in case it was used previously
408
- ...pointer,
409
- [ 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
+ ],
410
417
 
411
- // use cached length as end pointer
412
- ...length.getCachedI32(),
413
- ...number(ValtypeSize.i16, Valtype.i32),
414
- [ Opcodes.i32_mul ],
415
- ...pointer,
416
- [ Opcodes.i32_add ],
417
- ...length.setCachedI32(),
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 ],
418
422
 
419
- [ Opcodes.loop, Blocktype.void ],
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(),
420
430
 
421
- [ Opcodes.block, Blocktype.void ],
431
+ [ Opcodes.loop, Blocktype.void ],
422
432
 
423
- [ Opcodes.local_get, iTmp ],
424
- [ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128(ValtypeSize.i32) ],
425
- [ Opcodes.local_set, iTmp2 ],
426
-
427
- // if not surrogate, continue
428
- [ Opcodes.local_get, iTmp2 ],
429
- ...number(0xF800, Valtype.i32),
430
- [ Opcodes.i32_and ],
431
- ...number(0xD800, Valtype.i32),
432
- [ Opcodes.i32_ne ],
433
- [ Opcodes.br_if, 0 ],
434
-
435
- // if not leading surrogate, return false
436
- [ Opcodes.local_get, iTmp2 ],
437
- ...number(0xDC00, Valtype.i32),
438
- [ Opcodes.i32_ge_s ],
439
- [ Opcodes.if, Blocktype.void ],
440
- ...number(0),
441
- [ Opcodes.br, 3 ],
442
- [ Opcodes.end ],
433
+ [ Opcodes.block, Blocktype.void ],
443
434
 
444
- // if not followed by trailing surrogate, return false
445
- [ Opcodes.local_get, iTmp ],
446
- [ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128(ValtypeSize.i32 + ValtypeSize.i16) ],
447
- ...number(0xFC00, Valtype.i32),
448
- [ Opcodes.i32_and ],
449
- ...number(0xDC00, Valtype.i32),
450
- [ Opcodes.i32_ne ],
451
- [ Opcodes.if, Blocktype.void ],
452
- ...number(0),
453
- [ Opcodes.br, 3 ],
454
- [ 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 ],
455
446
 
456
- // bump index again since gone through two valid chars
457
- [ Opcodes.local_get, iTmp ],
458
- ...number(ValtypeSize.i16, Valtype.i32),
459
- [ Opcodes.i32_add ],
460
- [ Opcodes.local_set, iTmp ],
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 ],
461
455
 
462
- [ Opcodes.end ],
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 ],
463
467
 
464
- // bump pointer and loop if not at the end
465
- [ Opcodes.local_get, iTmp ],
466
- ...number(ValtypeSize.i16, Valtype.i32),
467
- [ Opcodes.i32_add ],
468
- [ Opcodes.local_tee, iTmp ],
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 ],
473
+
474
+ [ Opcodes.end ],
469
475
 
470
- ...length.getCachedI32(), // end pointer
471
- [ Opcodes.i32_ne ],
472
- [ Opcodes.br_if, 0 ],
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 ],
473
481
 
474
- [ Opcodes.end ],
482
+ ...length.getCachedI32(), // end pointer
483
+ [ Opcodes.i32_ne ],
484
+ [ Opcodes.br_if, 0 ],
475
485
 
476
- // return true
477
- ...number(1)
478
- ]
479
- }
486
+ [ Opcodes.end ],
487
+
488
+ // return true
489
+ ...number(1)
490
+ ]
480
491
  };
481
492
 
482
493
  this[TYPES.string].at.local = Valtype.i32;
483
494
  this[TYPES.string].at.returnType = TYPES.string;
484
495
  this[TYPES.string].charAt.returnType = TYPES.string;
496
+ this[TYPES.string].charCodeAt.returnType = TYPES.number;
485
497
  this[TYPES.string].charCodeAt.local = Valtype.i32;
486
498
  this[TYPES.string].charCodeAt.noPointerCache = zeroChecks.charcodeat;
487
499
 
@@ -489,10 +501,10 @@ export const PrototypeFuncs = function() {
489
501
  this[TYPES.string].isWellFormed.local2 = Valtype.i32;
490
502
  this[TYPES.string].isWellFormed.returnType = TYPES.boolean;
491
503
 
492
- if (process.argv.includes('-bytestring')) {
493
- this[TYPES._bytestring] = {
494
- at: (pointer, length, wIndex, iTmp, _, arrayShell) => {
495
- const [ newOut, newPointer ] = arrayShell(1, 'i16');
504
+ if (Prefs.bytestring) {
505
+ this[TYPES.bytestring] = {
506
+ at: (pointer, length, wIndex, wType, iTmp, _, arrayShell) => {
507
+ const [ newOut, newPointer ] = arrayShell(1, 'i8');
496
508
 
497
509
  return [
498
510
  // setup new/out array
@@ -547,8 +559,8 @@ export const PrototypeFuncs = function() {
547
559
  },
548
560
 
549
561
  // todo: out of bounds properly
550
- charAt: (pointer, length, wIndex, _1, _2, arrayShell) => {
551
- const [ newOut, newPointer ] = arrayShell(1, 'i16');
562
+ charAt: (pointer, length, wIndex, wType, _1, _2, arrayShell) => {
563
+ const [ newOut, newPointer ] = arrayShell(1, 'i8');
552
564
 
553
565
  return [
554
566
  // setup new/out array
@@ -558,7 +570,6 @@ export const PrototypeFuncs = function() {
558
570
  ...number(0, Valtype.i32), // base 0 for store later
559
571
 
560
572
  ...wIndex,
561
-
562
573
  Opcodes.i32_to,
563
574
 
564
575
  ...pointer,
@@ -575,60 +586,57 @@ export const PrototypeFuncs = function() {
575
586
  ];
576
587
  },
577
588
 
578
- charCodeAt: (pointer, length, wIndex, iTmp) => {
579
- return [
580
- ...wIndex,
581
- Opcodes.i32_to,
582
-
583
- ...(zeroChecks.charcodeat ? [] : [
584
- [ Opcodes.local_set, iTmp ],
589
+ charCodeAt: (pointer, length, wIndex, wType, iTmp) => [
590
+ ...wIndex,
591
+ Opcodes.i32_to,
585
592
 
586
- // index < 0
587
- ...(noUnlikelyChecks ? [] : [
588
- [ Opcodes.local_get, iTmp ],
589
- ...number(0, Valtype.i32),
590
- [ Opcodes.i32_lt_s ],
591
- ]),
593
+ ...(zeroChecks.charcodeat ? [] : [
594
+ [ Opcodes.local_set, iTmp ],
592
595
 
593
- // index >= length
596
+ // index < 0
597
+ ...(noUnlikelyChecks ? [] : [
594
598
  [ Opcodes.local_get, iTmp ],
595
- ...length.getCachedI32(),
596
- [ Opcodes.i32_ge_s ],
599
+ ...number(0, Valtype.i32),
600
+ [ Opcodes.i32_lt_s ],
601
+ ]),
597
602
 
598
- ...(noUnlikelyChecks ? [] : [ [ Opcodes.i32_or ] ]),
599
- [ Opcodes.if, Blocktype.void ],
600
- ...number(NaN),
601
- [ Opcodes.br, 1 ],
602
- [ Opcodes.end ],
603
+ // index >= length
604
+ [ Opcodes.local_get, iTmp ],
605
+ ...length.getCachedI32(),
606
+ [ Opcodes.i32_ge_s ],
603
607
 
604
- [ Opcodes.local_get, iTmp ],
605
- ]),
608
+ ...(noUnlikelyChecks ? [] : [ [ Opcodes.i32_or ] ]),
609
+ [ Opcodes.if, Blocktype.void ],
610
+ ...number(valtype === 'i32' ? -1 : NaN),
611
+ [ Opcodes.br, 1 ],
612
+ [ Opcodes.end ],
606
613
 
607
- ...pointer,
608
- [ Opcodes.i32_add ],
614
+ [ Opcodes.local_get, iTmp ],
615
+ ]),
609
616
 
610
- // load current string ind {arg}
611
- [ Opcodes.i32_load8_u, 0, ...unsignedLEB128(ValtypeSize.i32) ],
612
- Opcodes.i32_from_u
613
- ];
614
- },
617
+ ...pointer,
618
+ [ Opcodes.i32_add ],
615
619
 
616
- isWellFormed: () => {
617
- return [
618
- // we know it must be true as it is a bytestring lol
619
- ...number(1)
620
- ]
621
- }
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
+ ]
622
629
  };
623
630
 
624
- this[TYPES._bytestring].at.local = Valtype.i32;
625
- this[TYPES._bytestring].at.returnType = TYPES._bytestring;
626
- this[TYPES._bytestring].charAt.returnType = TYPES._bytestring;
627
- this[TYPES._bytestring].charCodeAt.local = Valtype.i32;
628
- this[TYPES._bytestring].charCodeAt.noPointerCache = zeroChecks.charcodeat;
631
+ this[TYPES.bytestring].at.local = Valtype.i32;
632
+ this[TYPES.bytestring].at.returnType = TYPES.bytestring;
633
+ this[TYPES.bytestring].charAt.returnType = TYPES.bytestring;
634
+ this[TYPES.bytestring].charCodeAt.returnType = TYPES.number;
635
+ this[TYPES.bytestring].charCodeAt.local = Valtype.i32;
636
+ this[TYPES.bytestring].charCodeAt.noPointerCache = zeroChecks.charcodeat;
629
637
 
630
- this[TYPES._bytestring].isWellFormed.local = Valtype.i32;
631
- this[TYPES._bytestring].isWellFormed.local2 = Valtype.i32;
632
- this[TYPES._bytestring].isWellFormed.returnType = TYPES.boolean;
638
+ this[TYPES.bytestring].isWellFormed.local = Valtype.i32;
639
+ this[TYPES.bytestring].isWellFormed.local2 = Valtype.i32;
640
+ this[TYPES.bytestring].isWellFormed.returnType = TYPES.boolean;
633
641
  }
634
642
  };
@@ -0,0 +1,38 @@
1
+ export const TYPES = {
2
+ number: 0x00,
3
+ boolean: 0x01,
4
+ string: 0x02,
5
+ undefined: 0x03,
6
+ object: 0x04,
7
+ function: 0x05,
8
+ symbol: 0x06,
9
+ bigint: 0x07
10
+ };
11
+
12
+ export const TYPE_NAMES = {
13
+ [TYPES.number]: 'Number',
14
+ [TYPES.boolean]: 'Boolean',
15
+ [TYPES.string]: 'String',
16
+ [TYPES.undefined]: 'undefined',
17
+ [TYPES.object]: 'Object',
18
+ [TYPES.function]: 'Function',
19
+ [TYPES.symbol]: 'Symbol',
20
+ [TYPES.bigint]: 'BigInt'
21
+ };
22
+
23
+ export const INTERNAL_TYPE_BASE = 0x10;
24
+ let internalTypeIndex = INTERNAL_TYPE_BASE;
25
+ const registerInternalType = name => {
26
+ const n = internalTypeIndex++;
27
+ TYPES[name.toLowerCase()] = n;
28
+ TYPE_NAMES[n] = name;
29
+ };
30
+
31
+ // note: when adding a new internal type, please also add a deserializer to wrap.js
32
+ // (it is okay to add a throw todo deserializer for wips)
33
+
34
+ registerInternalType('Array');
35
+ registerInternalType('RegExp');
36
+ registerInternalType('ByteString');
37
+ registerInternalType('Date');
38
+ registerInternalType('Set');