porffor 0.2.0-c6c8c81 → 0.2.0-dfa0583

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.
@@ -15,7 +15,7 @@ export default (wasm, name = '', ind = 0, locals = {}, params = [], returns = []
15
15
  if (name) out += `${makeSignature(params, returns)} ;; $${name} (${ind})\n`;
16
16
 
17
17
  const justLocals = Object.values(locals).sort((a, b) => a.idx - b.idx).slice(params.length);
18
- if (justLocals.length > 0) out += ` local ${justLocals.map(x => invValtype[x.type]).join(' ')}\n`;
18
+ if (name && justLocals.length > 0) out += ` local ${justLocals.map(x => invValtype[x.type]).join(' ')}\n`;
19
19
 
20
20
  let i = -1, lastInst;
21
21
  let byte = 0;
@@ -32,7 +32,7 @@ export default (wasm, name = '', ind = 0, locals = {}, params = [], returns = []
32
32
  inst = [ [ inst[0], inst[1] ], ...inst.slice(2) ];
33
33
  }
34
34
 
35
- if (inst[0] === Opcodes.end || inst[0] === Opcodes.else || inst[0] === Opcodes.catch_all) depth--;
35
+ if (depth > 0 && (inst[0] === Opcodes.end || inst[0] === Opcodes.else || inst[0] === Opcodes.catch_all)) depth--;
36
36
 
37
37
  out += ' '.repeat(Math.max(0, depth * 2));
38
38
 
@@ -116,13 +116,12 @@ export default (wasm, name = '', ind = 0, locals = {}, params = [], returns = []
116
116
  return highlightAsm(out);
117
117
  };
118
118
 
119
- export const highlightAsm = asm =>
120
- asm
121
- .replace(/(local|global|memory)\.[^\s]*/g, _ => `\x1B[31m${_}\x1B[0m`)
122
- .replace(/(i(8|16|32|64)x[0-9]+|v128)(\.[^\s]*)?/g, _ => `\x1B[34m${_}\x1B[0m`)
123
- .replace(/[^m](i32|i64|f32|f64|drop)(\.[^\s]*)?/g, _ => `${_[0]}\x1B[36m${_.slice(1)}\x1B[0m`)
124
- .replace(/(return_call|call|br_if|br|return|throw|rethrow)/g, _ => `\x1B[35m${_}\x1B[0m`)
125
- .replace(/(block|loop|if|end|else|try|catch_all|catch|delegate)/g, _ => `\x1B[95m${_}\x1B[0m`)
126
- .replace(/unreachable/g, _ => `\x1B[91m${_}\x1B[0m`)
127
- .replace(/ \-?[0-9\.]+/g, _ => ` \x1B[33m${_.slice(1)}\x1B[0m`)
128
- .replace(/ ;;.*$/gm, _ => `\x1B[90m${_.replaceAll(/\x1B\[[0-9]+m/g, '')}\x1B[0m`);
119
+ export const highlightAsm = asm => asm
120
+ .replace(/(local|global|memory)\.[^\s]*/g, _ => `\x1B[31m${_}\x1B[0m`)
121
+ .replace(/(i(8|16|32|64)x[0-9]+|v128)(\.[^\s]*)?/g, _ => `\x1B[34m${_}\x1B[0m`)
122
+ .replace(/(i32|i64|f32|f64|drop)(\.[^\s]*)?/g, _ => `\x1B[36m${_}\x1B[0m`)
123
+ .replace(/(return_call|call|br_if|br|return|rethrow|throw)/g, _ => `\x1B[35m${_}\x1B[0m`)
124
+ .replace(/(block|loop|if|end|else|try|catch_all|catch|delegate)/g, _ => `\x1B[95m${_}\x1B[0m`)
125
+ .replace(/unreachable/g, _ => `\x1B[91m${_}\x1B[0m`)
126
+ .replace(/ \-?[0-9\.]+/g, _ => ` \x1B[33m${_.slice(1)}\x1B[0m`)
127
+ .replace(/ ;;.*$/gm, _ => `\x1B[90m${_.replaceAll(/\x1B\[[0-9]+m/g, '')}\x1B[0m`);
@@ -105,119 +105,5 @@ export const read_unsignedLEB128 = _input => {
105
105
  };
106
106
 
107
107
  // ieee 754 binary64
108
-
109
- // from https://github.com/feross/ieee754
110
- // BSD 3-Clause. Copyright 2008 Fair Oaks Labs, Inc. (https://github.com/feross/ieee754/blob/master/LICENSE)
111
- export const ieee754_binary64 = value => {
112
- return [...new Uint8Array(new Float64Array([ value ]).buffer)];
113
-
114
- let isLE = true, mLen = 52, nBytes = 8, offset = 0;
115
- let buffer = new Array(nBytes).fill(0);
116
-
117
- let e, m, c
118
- let eLen = (nBytes * 8) - mLen - 1
119
- const eMax = (1 << eLen) - 1
120
- const eBias = eMax >> 1
121
- const rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0)
122
- let i = isLE ? 0 : (nBytes - 1)
123
- const d = isLE ? 1 : -1
124
- const s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0
125
-
126
- value = Math.abs(value)
127
-
128
- if (isNaN(value) || value === Infinity) {
129
- m = isNaN(value) ? 1 : 0
130
- e = eMax
131
- } else {
132
- e = Math.floor(Math.log(value) / Math.LN2)
133
- if (value * (c = Math.pow(2, -e)) < 1) {
134
- e--
135
- c *= 2
136
- }
137
- if (e + eBias >= 1) {
138
- value += rt / c
139
- } else {
140
- value += rt * Math.pow(2, 1 - eBias)
141
- }
142
- if (value * c >= 2) {
143
- e++
144
- c /= 2
145
- }
146
-
147
- if (e + eBias >= eMax) {
148
- m = 0
149
- e = eMax
150
- } else if (e + eBias >= 1) {
151
- m = ((value * c) - 1) * Math.pow(2, mLen)
152
- e = e + eBias
153
- } else {
154
- m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen)
155
- e = 0
156
- }
157
- }
158
-
159
- while (mLen >= 8) {
160
- buffer[offset + i] = m & 0xff
161
- i += d
162
- m /= 256
163
- mLen -= 8
164
- }
165
-
166
- e = (e << mLen) | m
167
- eLen += mLen
168
- while (eLen > 0) {
169
- buffer[offset + i] = e & 0xff
170
- i += d
171
- e /= 256
172
- eLen -= 8
173
- }
174
-
175
- buffer[offset + i - d] |= s * 128
176
-
177
- return buffer;
178
- };
179
-
180
- export const read_ieee754_binary64 = buffer => {
181
- return new Float64Array(new Uint8Array(buffer).buffer)[0];
182
-
183
- let isLE = true, mLen = 52, nBytes = 8, offset = 0;
184
-
185
- let e, m
186
- const eLen = (nBytes * 8) - mLen - 1
187
- const eMax = (1 << eLen) - 1
188
- const eBias = eMax >> 1
189
- let nBits = -7
190
- let i = isLE ? (nBytes - 1) : 0
191
- const d = isLE ? -1 : 1
192
- let s = buffer[offset + i]
193
-
194
- i += d
195
-
196
- e = s & ((1 << (-nBits)) - 1)
197
- s >>= (-nBits)
198
- nBits += eLen
199
- while (nBits > 0) {
200
- e = (e * 256) + buffer[offset + i]
201
- i += d
202
- nBits -= 8
203
- }
204
-
205
- m = e & ((1 << (-nBits)) - 1)
206
- e >>= (-nBits)
207
- nBits += mLen
208
- while (nBits > 0) {
209
- m = (m * 256) + buffer[offset + i]
210
- i += d
211
- nBits -= 8
212
- }
213
-
214
- if (e === 0) {
215
- e = 1 - eBias
216
- } else if (e === eMax) {
217
- return m ? NaN : ((s ? -1 : 1) * Infinity)
218
- } else {
219
- m = m + Math.pow(2, mLen)
220
- e = e - eBias
221
- }
222
- return (s ? -1 : 1) * m * Math.pow(2, e - mLen)
223
- };
108
+ export const ieee754_binary64 = value => [...new Uint8Array(new Float64Array([ value ]).buffer)];
109
+ export const read_ieee754_binary64 = buffer => new Float64Array(new Uint8Array(buffer).buffer)[0];
package/compiler/index.js CHANGED
@@ -28,8 +28,8 @@ const logFuncs = (funcs, globals, exceptions) => {
28
28
 
29
29
  const getArg = name => process.argv.find(x => x.startsWith(`-${name}=`))?.slice(name.length + 2);
30
30
 
31
- const writeFileSync = (typeof process !== 'undefined' ? (await import('node:fs')).writeFileSync : undefined);
32
- const execSync = (typeof process !== 'undefined' ? (await import('node:child_process')).execSync : undefined);
31
+ const writeFileSync = (typeof process?.version !== 'undefined' ? (await import('node:fs')).writeFileSync : undefined);
32
+ const execSync = (typeof process?.version !== 'undefined' ? (await import('node:child_process')).execSync : undefined);
33
33
 
34
34
  export default (code, flags) => {
35
35
  globalThis.optLog = process.argv.includes('-opt-log');
@@ -52,7 +52,7 @@ export default (code, flags) => {
52
52
  if (process.argv.includes('-funcs')) logFuncs(funcs, globals, exceptions);
53
53
 
54
54
  const t2 = performance.now();
55
- opt(funcs, globals, pages);
55
+ opt(funcs, globals, pages, tags);
56
56
  if (flags.includes('info')) console.log(`3. optimized code in ${(performance.now() - t2).toFixed(2)}ms`);
57
57
 
58
58
  if (process.argv.includes('-opt-funcs')) logFuncs(funcs, globals, exceptions);
@@ -75,6 +75,7 @@ export default (code, flags) => {
75
75
 
76
76
  if (target === 'c') {
77
77
  const c = toc(out);
78
+ out.c = c;
78
79
 
79
80
  if (outFile) {
80
81
  writeFileSync(outFile, c);
@@ -82,7 +83,7 @@ export default (code, flags) => {
82
83
  console.log(c);
83
84
  }
84
85
 
85
- process.exit();
86
+ if (process.version) process.exit();
86
87
  }
87
88
 
88
89
  if (target === 'native') {
@@ -98,7 +99,7 @@ export default (code, flags) => {
98
99
  // obvious command escape is obvious
99
100
  execSync(args.join(' '), { stdio: 'inherit' });
100
101
 
101
- process.exit();
102
+ if (process.version) process.exit();
102
103
  }
103
104
 
104
105
  return out;
package/compiler/opt.js CHANGED
@@ -11,7 +11,7 @@ const performWasmOp = (op, a, b) => {
11
11
  }
12
12
  };
13
13
 
14
- export default (funcs, globals, pages) => {
14
+ export default (funcs, globals, pages, tags) => {
15
15
  const optLevel = parseInt(process.argv.find(x => x.startsWith('-O'))?.[2] ?? 1);
16
16
  if (optLevel === 0) return;
17
17
 
@@ -99,10 +99,14 @@ export default (funcs, globals, pages) => {
99
99
 
100
100
  if (process.argv.includes('-opt-inline-only')) return;
101
101
 
102
+ const tagUse = tags.reduce((acc, x) => { acc[x.idx] = 0; return acc; }, {});
103
+
102
104
  // wasm transform pass
103
105
  for (const f of funcs) {
104
106
  const wasm = f.wasm;
105
107
 
108
+ const lastType = f.locals['#last_type'];
109
+
106
110
  let runs = 2; // how many by default? add arg?
107
111
  while (runs > 0) {
108
112
  runs--;
@@ -125,6 +129,8 @@ export default (funcs, globals, pages) => {
125
129
  if (inst[0] === Opcodes.local_get) getCount[inst[1]]++;
126
130
  if (inst[0] === Opcodes.local_set || inst[0] === Opcodes.local_tee) setCount[inst[1]]++;
127
131
 
132
+ if (inst[0] === Opcodes.throw) tagUse[inst[1]]++;
133
+
128
134
  if (inst[0] === Opcodes.block) {
129
135
  // remove unneeded blocks (no brs inside)
130
136
  // block
@@ -141,7 +147,7 @@ export default (funcs, globals, pages) => {
141
147
  depth--;
142
148
  if (depth <= 0) break;
143
149
  }
144
- if (op === Opcodes.br || op === Opcodes.br_if) {
150
+ if (op === Opcodes.br || op === Opcodes.br_if || op === Opcodes.br_table) {
145
151
  hasBranch = true;
146
152
  break;
147
153
  }
@@ -186,6 +192,7 @@ export default (funcs, globals, pages) => {
186
192
  let missing = false;
187
193
  if (type === 'Array') missing = !pages.hasArray;
188
194
  if (type === 'String') missing = !pages.hasString;
195
+ if (type === 'ByteString') missing = !pages.hasByteString;
189
196
 
190
197
  if (missing) {
191
198
  let j = i, depth = 0;
@@ -221,6 +228,7 @@ export default (funcs, globals, pages) => {
221
228
  }
222
229
 
223
230
  if (checks === 0) {
231
+ // todo: review indexes below
224
232
  wasm.splice(j - 1, 2, [ Opcodes.drop ]); // remove typeswitch start
225
233
  wasm.splice(i - 1, 1); // remove this inst
226
234
 
@@ -231,6 +239,13 @@ export default (funcs, globals, pages) => {
231
239
  }
232
240
  }
233
241
 
242
+ // remove setting last type if it is never gotten
243
+ if (!f.gotLastType && inst[0] === Opcodes.local_set && inst[1] === lastType?.idx) {
244
+ // replace this inst with drop
245
+ wasm.splice(i, 1, [ Opcodes.drop ]); // remove this and last inst
246
+ if (i > 0) i--;
247
+ }
248
+
234
249
  if (i < 1) continue;
235
250
  let lastInst = wasm[i - 1];
236
251
 
@@ -531,5 +546,12 @@ export default (funcs, globals, pages) => {
531
546
  }
532
547
  }
533
548
 
549
+ for (const x in tagUse) {
550
+ if (tagUse[x] === 0) {
551
+ const el = tags.find(y => y.idx === x);
552
+ tags.splice(tags.indexOf(el), 1);
553
+ }
554
+ }
555
+
534
556
  // return funcs;
535
557
  };
package/compiler/parse.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { log } from "./log.js";
2
+ // import { parse } from 'acorn';
2
3
 
3
4
  // deno compat
4
5
  if (typeof process === 'undefined' && typeof Deno !== 'undefined') {
@@ -6,26 +7,48 @@ if (typeof process === 'undefined' && typeof Deno !== 'undefined') {
6
7
  globalThis.process = { argv: ['', '', ...Deno.args], stdout: { write: str => Deno.writeAllSync(Deno.stdout, textEncoder.encode(str)) } };
7
8
  }
8
9
 
9
- // import { parse } from 'acorn';
10
+ // should we try to support types (while parsing)
11
+ const types = process.argv.includes('-parse-types');
12
+ globalThis.typedInput = types && process.argv.includes('-opt-types');
10
13
 
11
14
  // todo: review which to use by default
12
- const parser = process.argv.find(x => x.startsWith('-parser='))?.split('=')?.[1] ?? 'acorn';
13
- const { parse } = (await import((globalThis.document ? 'https://esm.sh/' : '') + parser));
14
-
15
15
  // supported parsers:
16
16
  // - acorn
17
17
  // - meriyah
18
18
  // - hermes-parser
19
19
  // - @babel/parser
20
20
 
21
- // should we try to support types (while parsing)
22
- const types = process.argv.includes('-types');
21
+ let parser, parse;
22
+ const loadParser = async (fallbackParser = 'acorn', forceParser) => {
23
+ parser = forceParser ?? process.argv.find(x => x.startsWith('-parser='))?.split('=')?.[1] ?? fallbackParser;
24
+ 0, { parse } = (await import((globalThis.document ? 'https://esm.sh/' : '') + parser));
25
+ };
26
+ globalThis._porf_loadParser = loadParser;
27
+ await loadParser(types ? '@babel/parser' : undefined);
23
28
 
24
29
  if (types && !['@babel/parser', 'hermes-parser'].includes(parser)) log.warning('parser', `passed -types with a parser (${parser}) which does not support`);
25
30
 
26
31
  export default (input, flags) => {
27
- return parse(input, {
32
+ const ast = parse(input, {
33
+ // acorn
28
34
  ecmaVersion: 'latest',
29
- sourceType: flags.includes('module') ? 'module' : 'script'
35
+
36
+ // meriyah
37
+ next: true,
38
+ module: flags.includes('module'),
39
+ webcompat: true,
40
+
41
+ // babel
42
+ plugins: types ? ['estree', 'typescript'] : ['estree'],
43
+
44
+ // multiple
45
+ sourceType: flags.includes('module') ? 'module' : 'script',
46
+ ranges: false,
47
+ tokens: false,
48
+ comments: false,
30
49
  });
50
+
51
+ if (ast.type === 'File') return ast.program;
52
+
53
+ return ast;
31
54
  };
@@ -16,7 +16,8 @@ const TYPES = {
16
16
 
17
17
  // these are not "typeof" types but tracked internally
18
18
  _array: 0x10,
19
- _regexp: 0x11
19
+ _regexp: 0x11,
20
+ _bytestring: 0x12
20
21
  };
21
22
 
22
23
  // todo: turn these into built-ins once arrays and these become less hacky
@@ -71,7 +72,7 @@ export const PrototypeFuncs = function() {
71
72
  ],
72
73
 
73
74
  // todo: only for 1 argument
74
- push: (pointer, length, wNewMember) => [
75
+ push: (pointer, length, wNewMember, _1, _2, _3, unusedValue) => [
75
76
  // get memory offset of array at last index (length)
76
77
  ...length.getCachedI32(),
77
78
  ...number(ValtypeSize[valtype], Valtype.i32),
@@ -92,22 +93,28 @@ export const PrototypeFuncs = function() {
92
93
  ...number(1, Valtype.i32),
93
94
  [ Opcodes.i32_add ],
94
95
 
95
- ...length.setCachedI32(),
96
- ...length.getCachedI32(),
96
+ ...(unusedValue() ? [] : [
97
+ ...length.setCachedI32(),
98
+ ...length.getCachedI32(),
99
+ ])
97
100
  ]),
98
101
 
99
- ...length.getCachedI32(),
100
- Opcodes.i32_from_u
102
+ ...(unusedValue() ? [] : [
103
+ ...length.getCachedI32(),
104
+ Opcodes.i32_from_u
105
+ ])
101
106
 
102
107
  // ...length.get()
103
108
  ],
104
109
 
105
- pop: (pointer, length) => [
110
+ pop: (pointer, length, _1, _2, _3, _4, unusedValue) => [
106
111
  // if length == 0, noop
107
112
  ...length.getCachedI32(),
108
113
  [ Opcodes.i32_eqz ],
109
114
  [ Opcodes.if, Blocktype.void ],
110
- ...number(UNDEFINED),
115
+ ...(unusedValue() ? [] : [
116
+ ...number(UNDEFINED),
117
+ ]),
111
118
  [ Opcodes.br, 1 ],
112
119
  [ Opcodes.end ],
113
120
 
@@ -119,19 +126,23 @@ export const PrototypeFuncs = function() {
119
126
  ...number(1, Valtype.i32),
120
127
  [ Opcodes.i32_sub ],
121
128
 
122
- ...length.setCachedI32(),
123
- ...length.getCachedI32(),
129
+ ...(unusedValue() ? [] : [
130
+ ...length.setCachedI32(),
131
+ ...length.getCachedI32(),
132
+ ])
124
133
  ]),
125
134
 
126
135
  // load last element
127
- ...length.getCachedI32(),
128
- ...number(ValtypeSize[valtype], Valtype.i32),
129
- [ Opcodes.i32_mul ],
136
+ ...(unusedValue() ? [] : [
137
+ ...length.getCachedI32(),
138
+ ...number(ValtypeSize[valtype], Valtype.i32),
139
+ [ Opcodes.i32_mul ],
130
140
 
131
- ...pointer,
132
- [ Opcodes.i32_add ],
141
+ ...pointer,
142
+ [ Opcodes.i32_add ],
133
143
 
134
- [ Opcodes.load, Math.log2(ValtypeSize[valtype]) - 1, ...unsignedLEB128(ValtypeSize.i32) ]
144
+ [ Opcodes.load, Math.log2(ValtypeSize[valtype]) - 1, ...unsignedLEB128(ValtypeSize.i32) ]
145
+ ])
135
146
  ],
136
147
 
137
148
  shift: (pointer, length) => [
@@ -472,8 +483,152 @@ export const PrototypeFuncs = function() {
472
483
  this[TYPES.string].at.returnType = TYPES.string;
473
484
  this[TYPES.string].charAt.returnType = TYPES.string;
474
485
  this[TYPES.string].charCodeAt.local = Valtype.i32;
486
+ this[TYPES.string].charCodeAt.noPointerCache = zeroChecks.charcodeat;
475
487
 
476
488
  this[TYPES.string].isWellFormed.local = Valtype.i32;
477
489
  this[TYPES.string].isWellFormed.local2 = Valtype.i32;
478
490
  this[TYPES.string].isWellFormed.returnType = TYPES.boolean;
491
+
492
+ if (process.argv.includes('-bytestring')) {
493
+ this[TYPES._bytestring] = {
494
+ at: (pointer, length, wIndex, iTmp, _, arrayShell) => {
495
+ const [ newOut, newPointer ] = arrayShell(1, 'i16');
496
+
497
+ return [
498
+ // setup new/out array
499
+ ...newOut,
500
+ [ Opcodes.drop ],
501
+
502
+ ...number(0, Valtype.i32), // base 0 for store later
503
+
504
+ ...wIndex,
505
+ Opcodes.i32_to_u,
506
+ [ Opcodes.local_tee, iTmp ],
507
+
508
+ // if index < 0: access index + array length
509
+ ...number(0, Valtype.i32),
510
+ [ Opcodes.i32_lt_s ],
511
+ [ Opcodes.if, Blocktype.void ],
512
+ [ Opcodes.local_get, iTmp ],
513
+ ...length.getCachedI32(),
514
+ [ Opcodes.i32_add ],
515
+ [ Opcodes.local_set, iTmp ],
516
+ [ Opcodes.end ],
517
+
518
+ // if still < 0 or >= length: return undefined
519
+ [ Opcodes.local_get, iTmp ],
520
+ ...number(0, Valtype.i32),
521
+ [ Opcodes.i32_lt_s ],
522
+
523
+ [ Opcodes.local_get, iTmp ],
524
+ ...length.getCachedI32(),
525
+ [ Opcodes.i32_ge_s ],
526
+ [ Opcodes.i32_or ],
527
+
528
+ [ Opcodes.if, Blocktype.void ],
529
+ ...number(UNDEFINED),
530
+ [ Opcodes.br, 1 ],
531
+ [ Opcodes.end ],
532
+
533
+ [ Opcodes.local_get, iTmp ],
534
+
535
+ ...pointer,
536
+ [ Opcodes.i32_add ],
537
+
538
+ // load current string ind {arg}
539
+ [ Opcodes.i32_load8_u, 0, ...unsignedLEB128(ValtypeSize.i32) ],
540
+
541
+ // store to new string ind 0
542
+ [ Opcodes.i32_store8, 0, ...unsignedLEB128(newPointer + ValtypeSize.i32) ],
543
+
544
+ // return new string (pointer)
545
+ ...number(newPointer)
546
+ ];
547
+ },
548
+
549
+ // todo: out of bounds properly
550
+ charAt: (pointer, length, wIndex, _1, _2, arrayShell) => {
551
+ const [ newOut, newPointer ] = arrayShell(1, 'i16');
552
+
553
+ return [
554
+ // setup new/out array
555
+ ...newOut,
556
+ [ Opcodes.drop ],
557
+
558
+ ...number(0, Valtype.i32), // base 0 for store later
559
+
560
+ ...wIndex,
561
+
562
+ Opcodes.i32_to,
563
+
564
+ ...pointer,
565
+ [ Opcodes.i32_add ],
566
+
567
+ // load current string ind {arg}
568
+ [ Opcodes.i32_load8_u, 0, ...unsignedLEB128(ValtypeSize.i32) ],
569
+
570
+ // store to new string ind 0
571
+ [ Opcodes.i32_store8, 0, ...unsignedLEB128(newPointer + ValtypeSize.i32) ],
572
+
573
+ // return new string (page)
574
+ ...number(newPointer)
575
+ ];
576
+ },
577
+
578
+ charCodeAt: (pointer, length, wIndex, iTmp) => {
579
+ return [
580
+ ...wIndex,
581
+ Opcodes.i32_to,
582
+
583
+ ...(zeroChecks.charcodeat ? [] : [
584
+ [ Opcodes.local_set, iTmp ],
585
+
586
+ // index < 0
587
+ ...(noUnlikelyChecks ? [] : [
588
+ [ Opcodes.local_get, iTmp ],
589
+ ...number(0, Valtype.i32),
590
+ [ Opcodes.i32_lt_s ],
591
+ ]),
592
+
593
+ // index >= length
594
+ [ Opcodes.local_get, iTmp ],
595
+ ...length.getCachedI32(),
596
+ [ Opcodes.i32_ge_s ],
597
+
598
+ ...(noUnlikelyChecks ? [] : [ [ Opcodes.i32_or ] ]),
599
+ [ Opcodes.if, Blocktype.void ],
600
+ ...number(NaN),
601
+ [ Opcodes.br, 1 ],
602
+ [ Opcodes.end ],
603
+
604
+ [ Opcodes.local_get, iTmp ],
605
+ ]),
606
+
607
+ ...pointer,
608
+ [ Opcodes.i32_add ],
609
+
610
+ // load current string ind {arg}
611
+ [ Opcodes.i32_load8_u, 0, ...unsignedLEB128(ValtypeSize.i32) ],
612
+ Opcodes.i32_from_u
613
+ ];
614
+ },
615
+
616
+ isWellFormed: () => {
617
+ return [
618
+ // we know it must be true as it is a bytestring lol
619
+ ...number(1)
620
+ ]
621
+ }
622
+ };
623
+
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;
629
+
630
+ this[TYPES._bytestring].isWellFormed.local = Valtype.i32;
631
+ this[TYPES._bytestring].isWellFormed.local2 = Valtype.i32;
632
+ this[TYPES._bytestring].isWellFormed.returnType = TYPES.boolean;
633
+ }
479
634
  };
@@ -150,7 +150,7 @@ export default (funcs, globals, tags, pages, data, flags) => {
150
150
 
151
151
  if (typeCount !== 0) localDecl.push(encodeLocal(typeCount, lastType));
152
152
 
153
- return encodeVector([ ...encodeVector(localDecl), ...x.wasm.flat().filter(x => x <= 0xff), Opcodes.end ]);
153
+ return encodeVector([ ...encodeVector(localDecl), ...x.wasm.flat().filter(x => x != null && x <= 0xff), Opcodes.end ]);
154
154
  }))
155
155
  );
156
156
 
@@ -32,8 +32,6 @@ export const Opcodes = {
32
32
  throw: 0x08,
33
33
  rethrow: 0x09,
34
34
 
35
- return: 0x0F,
36
-
37
35
  call: 0x10,
38
36
  call_indirect: 0x11,
39
37
  return_call: 0x12,
@@ -42,7 +40,10 @@ export const Opcodes = {
42
40
  end: 0x0b,
43
41
  br: 0x0c,
44
42
  br_if: 0x0d,
43
+ br_table: 0x0e,
44
+ return: 0x0f,
45
45
  call: 0x10,
46
+
46
47
  drop: 0x1a,
47
48
 
48
49
  local_get: 0x20,
@@ -56,9 +57,12 @@ export const Opcodes = {
56
57
  i64_load: 0x29,
57
58
  f64_load: 0x2b,
58
59
 
60
+ i32_load8_s: 0x2c,
61
+ i32_load8_u: 0x2d,
59
62
  i32_load16_s: 0x2e,
60
63
  i32_load16_u: 0x2f,
61
64
 
65
+ i32_store8: 0x3a,
62
66
  i32_store16: 0x3b,
63
67
 
64
68
  i32_store: 0x36,