porffor 0.58.18 → 0.58.19

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.
@@ -2,7 +2,6 @@ import { Blocktype, Opcodes, Valtype, ValtypeSize } from './wasmSpec.js';
2
2
  import { number, ieee754_binary64, signedLEB128, unsignedLEB128, encodeVector, read_signedLEB128 } from './encoding.js';
3
3
  import { operatorOpcode } from './expression.js';
4
4
  import { BuiltinFuncs, BuiltinVars, importedFuncs, NULL, UNDEFINED } from './builtins.js';
5
- import { PrototypeFuncs } from './prototype.js';
6
5
  import { TYPES, TYPE_FLAGS, TYPE_NAMES } from './types.js';
7
6
  import parse from './parse.js';
8
7
  import { log } from './log.js';
@@ -556,7 +555,7 @@ const lookup = (scope, name, failEarly = false) => {
556
555
  includeBuiltin(scope, name);
557
556
  }
558
557
 
559
- if (isExistingProtoFunc(name) || Object.hasOwn(internalConstrs, name)) {
558
+ if (Object.hasOwn(internalConstrs, name)) {
560
559
  // todo: return an actual something
561
560
  return [ number(1) ];
562
561
  }
@@ -1520,13 +1519,6 @@ const includeBuiltin = (scope, builtin) => {
1520
1519
  const generateLogicExp = (scope, decl) =>
1521
1520
  performLogicOp(scope, decl.operator, generate(scope, decl.left), generate(scope, decl.right), getNodeType(scope, decl.left), getNodeType(scope, decl.right));
1522
1521
 
1523
- const isExistingProtoFunc = name => {
1524
- if (name.startsWith('__Array_prototype')) return Object.hasOwn(prototypeFuncs[TYPES.array], name.slice(18));
1525
- if (name.startsWith('__String_prototype_')) return Object.hasOwn(prototypeFuncs[TYPES.string], name.slice(19));
1526
-
1527
- return false;
1528
- };
1529
-
1530
1522
  const getInferred = (scope, name, global = false) => {
1531
1523
  if (global) {
1532
1524
  if (globalInfer.has(name) && inferLoopPrev.length === 0) return globalInfer.get(name);
@@ -1595,7 +1587,7 @@ const getType = (scope, name, failEarly = false) => {
1595
1587
  [ global ? Opcodes.global_get : Opcodes.local_get, typeLocal.idx ]
1596
1588
  ];
1597
1589
 
1598
- if (hasFuncWithName(name) || isExistingProtoFunc(name)) {
1590
+ if (hasFuncWithName(name)) {
1599
1591
  return [ number(TYPES.function, Valtype.i32) ];
1600
1592
  }
1601
1593
 
@@ -2294,9 +2286,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
2294
2286
  });
2295
2287
  }
2296
2288
 
2297
- const protoBC = {};
2298
2289
  const builtinProtoCands = Object.keys(builtinFuncs).filter(x => x.startsWith('__') && x.endsWith('_prototype_' + protoName));
2299
-
2300
2290
  if (!decl._protoInternalCall && builtinProtoCands.length > 0) {
2301
2291
  out.push(
2302
2292
  ...generate(scope, target),
@@ -2315,6 +2305,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
2315
2305
  );
2316
2306
  }
2317
2307
 
2308
+ const protoBC = {};
2318
2309
  for (const x of builtinProtoCands) {
2319
2310
  const name = x.split('_prototype_')[0].toLowerCase();
2320
2311
  const type = TYPES[name.slice(2)] ?? TYPES[name];
@@ -2338,88 +2329,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
2338
2329
  _protoInternalCall: true
2339
2330
  });
2340
2331
  }
2341
- }
2342
-
2343
- const protoCands = Object.keys(prototypeFuncs).reduce((acc, x) => {
2344
- if (Object.hasOwn(prototypeFuncs[x], protoName)) acc[x] = prototypeFuncs[x][protoName];
2345
- return acc;
2346
- }, {});
2347
-
2348
- if (Object.keys(protoCands).length > 0) {
2349
- // use local for cached i32 length as commonly used
2350
- const lengthLocal = localTmp(scope, '__proto_length_cache', Valtype.i32);
2351
- const pointerLocal = localTmp(scope, '__proto_pointer_cache', Valtype.i32);
2352
-
2353
- if (out.length === 0) {
2354
- out.push(
2355
- ...generate(scope, target),
2356
- Opcodes.i32_to_u,
2357
- [ Opcodes.local_set, pointerLocal ]
2358
- );
2359
- } else {
2360
- out.push(
2361
- [ Opcodes.local_get, localTmp(scope, '#proto_target') ],
2362
- Opcodes.i32_to_u,
2363
- [ Opcodes.local_set, pointerLocal ]
2364
- );
2365
- }
2366
-
2367
- for (const x in protoCands) {
2368
- const protoFunc = protoCands[x];
2369
- const getPointer = [ [ Opcodes.local_get, pointerLocal ] ];
2370
-
2371
- if (protoFunc.noArgRetLength && decl.arguments.length === 0) {
2372
- protoBC[x] = [
2373
- ...ArrayUtil.getLength(getPointer),
2374
- ...setLastType(scope, TYPES.number)
2375
- ];
2376
- continue;
2377
- }
2378
-
2379
- protoBC[x] = () => {
2380
- const protoLocal = protoFunc.local ? localTmp(scope, `__${protoName}_tmp`, protoFunc.local) : -1;
2381
- const protoLocal2 = protoFunc.local2 ? localTmp(scope, `__${protoName}_tmp2`, protoFunc.local2) : -1;
2382
-
2383
- let optUnused = false;
2384
- const protoOut = protoFunc({
2385
- pointer: getPointer,
2386
- length: {
2387
- getCachedI32: () => [ [ Opcodes.local_get, lengthLocal ] ],
2388
- setCachedI32: () => [ [ Opcodes.local_set, lengthLocal ] ],
2389
- get: () => ArrayUtil.getLength(getPointer),
2390
- getI32: () => ArrayUtil.getLengthI32(getPointer),
2391
- set: value => ArrayUtil.setLength(getPointer, value),
2392
- setI32: value => ArrayUtil.setLengthI32(getPointer, value)
2393
- },
2394
- arg: generate(scope, decl.arguments[0] ?? DEFAULT_VALUE()),
2395
- argType: getNodeType(scope, decl.arguments[0] ?? DEFAULT_VALUE()),
2396
- iTmp: protoLocal,
2397
- iTmp2: protoLocal2,
2398
- alloc: bytes => [
2399
- number(bytes, Valtype.i32),
2400
- [ Opcodes.call, includeBuiltin(scope, '__Porffor_allocateBytes').index ]
2401
- ],
2402
- unusedValue: () => {
2403
- optUnused = true;
2404
- return unusedValue;
2405
- },
2406
- setType: type => setLastType(scope, type)
2407
- });
2408
-
2409
- return [
2410
- ...ArrayUtil.getLengthI32(getPointer),
2411
- [ Opcodes.local_set, lengthLocal ],
2412
-
2413
- [ Opcodes.block, unusedValue && optUnused ? Blocktype.void : valtypeBinary ],
2414
- ...protoOut,
2415
- [ Opcodes.end ],
2416
- ...(unusedValue && optUnused ? [ number(UNDEFINED) ] : [])
2417
- ];
2418
- };
2419
- }
2420
- }
2421
2332
 
2422
- if (Object.keys(protoBC).length > 0) {
2423
2333
  protoBC.default = decl.optional ?
2424
2334
  withType(scope, [ number(UNDEFINED) ], TYPES.undefined) :
2425
2335
  internalThrow(scope, 'TypeError', `'${protoName}' proto func tried to be called on a type without an impl`, true);
@@ -6717,7 +6627,7 @@ const objectHack = node => {
6717
6627
  if (objectName !== 'Object_prototype' && (node.property.name === 'propertyIsEnumerable' || node.property.name === 'hasOwnProperty' || node.property.name === 'isPrototypeOf')) return abortOut;
6718
6628
 
6719
6629
  const name = '__' + objectName + '_' + node.property.name;
6720
- if ((!hasFuncWithName(name) && !Object.hasOwn(builtinVars, name) && !isExistingProtoFunc(name) && !hasFuncWithName(name + '$get')) && (hasFuncWithName(objectName) || Object.hasOwn(builtinVars, objectName) || hasFuncWithName('__' + objectName) || Object.hasOwn(builtinVars, '__' + objectName))) return abortOut;
6630
+ if ((!hasFuncWithName(name) && !Object.hasOwn(builtinVars, name) && !hasFuncWithName(name + '$get')) && (hasFuncWithName(objectName) || Object.hasOwn(builtinVars, objectName) || hasFuncWithName('__' + objectName) || Object.hasOwn(builtinVars, '__' + objectName))) return abortOut;
6721
6631
 
6722
6632
  if (Prefs.codeLog) log('codegen', `object hack! ${node.object.name}.${node.property.name} -> ${name}`);
6723
6633
 
@@ -7294,7 +7204,7 @@ const internalConstrs = {
7294
7204
  }
7295
7205
  };
7296
7206
 
7297
- let globals, tags, exceptions, funcs, indirectFuncs, funcIndex, currentFuncIndex, depth, pages, data, typeswitchDepth, usedTypes, coctc, globalInfer, builtinFuncs, builtinVars, prototypeFuncs, lastValtype;
7207
+ let globals, tags, exceptions, funcs, indirectFuncs, funcIndex, currentFuncIndex, depth, pages, data, typeswitchDepth, usedTypes, coctc, globalInfer, builtinFuncs, builtinVars, lastValtype;
7298
7208
  export default program => {
7299
7209
  globals = { ['#ind']: 0 };
7300
7210
  tags = [];
@@ -7333,7 +7243,6 @@ export default program => {
7333
7243
  lastValtype = valtypeBinary;
7334
7244
  builtinFuncs = new BuiltinFuncs();
7335
7245
  builtinVars = new BuiltinVars({ builtinFuncs });
7336
- prototypeFuncs = new PrototypeFuncs();
7337
7246
 
7338
7247
  const getObjectName = x => x.startsWith('__') && x.slice(2, x.indexOf('_', 2));
7339
7248
  objectHackers = ['assert', 'compareArray', 'Test262Error', ...new Set(Object.keys(builtinFuncs).map(getObjectName).concat(Object.keys(builtinVars).map(getObjectName)).filter(x => x))];
@@ -57,7 +57,7 @@ const compile = async (file, _funcs) => {
57
57
  first = source.slice(0, source.indexOf('\n'));
58
58
  }
59
59
 
60
- let args = ['--module', '--todo-time=compile', '--truthy=no_nan_negative', '--no-rm-unused-types', '--scoped-page-names', '--funsafe-no-unlikely-proto-checks', '--zero-checks=charCodeAt', '--fast-length', '--parse-types', '--opt-types', '--no-passive-data', '--active-data', '--no-treeshake-wasm-imports', '--no-coctc'];
60
+ let args = ['--module', '--todo-time=compile', '--truthy=no_nan_negative', '--no-rm-unused-types', '--scoped-page-names', '--fast-length', '--parse-types', '--opt-types', '--no-passive-data', '--active-data', '--no-treeshake-wasm-imports', '--no-coctc'];
61
61
  if (first.startsWith('// @porf')) {
62
62
  args = first.slice('// @porf '.length).split(' ').concat(args);
63
63
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "porffor",
3
3
  "description": "An ahead-of-time JavaScript compiler",
4
- "version": "0.58.18",
4
+ "version": "0.58.19",
5
5
  "author": "Oliver Medhurst <honk@goose.icu>",
6
6
  "license": "MIT",
7
7
  "scripts": {},
package/runtime/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import fs from 'node:fs';
3
- globalThis.version = '0.58.18';
3
+ globalThis.version = '0.58.19';
4
4
 
5
5
  // deno compat
6
6
  if (typeof process === 'undefined' && typeof Deno !== 'undefined') {
package/wow.js ADDED
@@ -0,0 +1 @@
1
+ (false ? 42 : 42) + (false ? null : 'G9vBsCA4GzkqlZN')
@@ -1,407 +0,0 @@
1
- import { Opcodes, Blocktype, Valtype, ValtypeSize } from './wasmSpec.js';
2
- import { number } from './encoding.js';
3
- import { UNDEFINED } from './builtins.js';
4
- import { TYPES } from './types.js';
5
- import './prefs.js';
6
-
7
- // todo: turn these into built-ins once arrays and these become less hacky
8
-
9
- export const PrototypeFuncs = function() {
10
- const noUnlikelyChecks = Prefs.funsafeNoUnlikelyProtoChecks;
11
-
12
- let zeroChecks;
13
- if (Prefs.zeroChecks) zeroChecks = Prefs.zeroChecks.split(',').reduce((acc, x) => { acc[x.toLowerCase()] = true; return acc; }, {});
14
- else zeroChecks = {};
15
-
16
- this[TYPES.array] = {
17
- pop: ({ pointer, length, iTmp, unusedValue, setType }) => [
18
- // if length == 0, noop
19
- ...length.getCachedI32(),
20
- [ Opcodes.i32_eqz ],
21
- [ Opcodes.if, Blocktype.void ],
22
- ...(unusedValue() ? [] : [
23
- number(UNDEFINED),
24
- ...setType(TYPES.undefined)
25
- ]),
26
- [ Opcodes.br, 1 ],
27
- [ Opcodes.end ],
28
-
29
- // todo: should we store 0/undefined in "removed" element?
30
-
31
- // decrement length by 1
32
- ...length.setI32([
33
- ...length.getCachedI32(),
34
- number(1, Valtype.i32),
35
- [ Opcodes.i32_sub ],
36
-
37
- ...(unusedValue() ? [] : [
38
- ...length.setCachedI32(),
39
- ...length.getCachedI32(),
40
- ])
41
- ]),
42
-
43
- // load last element
44
- ...(unusedValue() ? [] : [
45
- ...length.getCachedI32(),
46
- number(ValtypeSize[valtype] + 1, Valtype.i32),
47
- [ Opcodes.i32_mul ],
48
-
49
- ...pointer,
50
- [ Opcodes.i32_add ],
51
- [ Opcodes.local_set, iTmp ],
52
-
53
- [ Opcodes.local_get, iTmp ],
54
- [ Opcodes.load, 0, ValtypeSize.i32 ],
55
-
56
- [ Opcodes.local_get, iTmp ],
57
- [ Opcodes.i32_load8_u, 0, ValtypeSize.i32 + ValtypeSize[valtype] ],
58
- ...setType()
59
- ])
60
- ],
61
-
62
- shift: ({ pointer, length, setType }) => [
63
- // if length == 0, noop
64
- ...length.getCachedI32(),
65
- [ Opcodes.i32_eqz ],
66
- [ Opcodes.if, Blocktype.void ],
67
- number(UNDEFINED),
68
- ...setType(TYPES.undefined),
69
- [ Opcodes.br, 1 ],
70
- [ Opcodes.end ],
71
-
72
- // todo: should we store 0/undefined in "removed" element?
73
-
74
- // decrement length by 1
75
- ...length.setI32([
76
- ...length.getCachedI32(),
77
- number(1, Valtype.i32),
78
- [ Opcodes.i32_sub ],
79
-
80
- ...length.setCachedI32(),
81
- ...length.getCachedI32(),
82
- ]),
83
-
84
- // load first element
85
- // todo/perf: unusedValue opt
86
- ...pointer,
87
- [ Opcodes.load, 0, ValtypeSize.i32 ],
88
-
89
- ...pointer,
90
- [ Opcodes.i32_load8_u, 0, ValtypeSize.i32 + ValtypeSize[valtype] ],
91
- ...setType(),
92
-
93
- // offset page by -1 ind
94
- // number(pointer + ValtypeSize.i32, Valtype.i32), // dst = base array index + length size
95
- // number(pointer + ValtypeSize.i32 + ValtypeSize[valtype], Valtype.i32), // src = base array index + length size + an index
96
- // number(pageSize - ValtypeSize.i32 - ValtypeSize[valtype], Valtype.i32), // size = PageSize - length size - an index
97
- // [ ...Opcodes.memory_copy, 0x00, 0x00 ]
98
-
99
- // offset all elements by -1 ind
100
-
101
- // dst = base array index + length size
102
- number(ValtypeSize.i32, Valtype.i32),
103
- ...pointer,
104
- [ Opcodes.i32_add ],
105
-
106
- // src = base array index + length size + an index
107
- number(ValtypeSize.i32 + ValtypeSize[valtype] + 1, Valtype.i32),
108
- ...pointer,
109
- [ Opcodes.i32_add ],
110
-
111
- // size = new length * sizeof element
112
- ...length.getCachedI32(),
113
- number(ValtypeSize[valtype] + 1, Valtype.i32),
114
- [ Opcodes.i32_mul ],
115
- [ ...Opcodes.memory_copy, 0x00, 0x00 ]
116
-
117
- // move pointer + sizeof element
118
- // ...pointer.get(),
119
- // number(ValtypeSize[valtype], Valtype.i32),
120
- // [ Opcodes.i32_add ],
121
- // ...pointer.set(),
122
-
123
- // // write length - 1 in new address
124
- // ...length.setI32([
125
- // ...length.getCachedI32(),
126
- // number(1, Valtype.i32),
127
- // [ Opcodes.i32_sub ]
128
- // ]),
129
- ]
130
- };
131
-
132
- this[TYPES.array].pop.local = Valtype.i32;
133
-
134
- this[TYPES.string] = {
135
- at: ({ pointer, length, arg, iTmp, iTmp2, alloc, setType }) => [
136
- // setup out string and use pointer for store
137
- ...alloc(8),
138
- [ Opcodes.local_tee, iTmp2 ],
139
-
140
- // out.length = 1
141
- [ Opcodes.local_get, iTmp2 ],
142
- number(1, Valtype.i32),
143
- [ Opcodes.i32_store, 0, 0 ],
144
-
145
- ...arg,
146
- Opcodes.i32_to_u,
147
- [ Opcodes.local_tee, iTmp ],
148
-
149
- // if index < 0: access index + array length
150
- number(0, Valtype.i32),
151
- [ Opcodes.i32_lt_s ],
152
- [ Opcodes.if, Blocktype.void ],
153
- [ Opcodes.local_get, iTmp ],
154
- ...length.getCachedI32(),
155
- [ Opcodes.i32_add ],
156
- [ Opcodes.local_set, iTmp ],
157
- [ Opcodes.end ],
158
-
159
- // if still < 0 or >= length: return undefined
160
- [ Opcodes.local_get, iTmp ],
161
- number(0, Valtype.i32),
162
- [ Opcodes.i32_lt_s ],
163
-
164
- [ Opcodes.local_get, iTmp ],
165
- ...length.getCachedI32(),
166
- [ Opcodes.i32_ge_s ],
167
- [ Opcodes.i32_or ],
168
-
169
- [ Opcodes.if, Blocktype.void ],
170
- number(UNDEFINED),
171
- ...setType(TYPES.undefined),
172
- [ Opcodes.br, 1 ],
173
- [ Opcodes.end ],
174
-
175
- [ Opcodes.local_get, iTmp ],
176
- number(ValtypeSize.i16, Valtype.i32),
177
- [ Opcodes.i32_mul ],
178
-
179
- ...pointer,
180
- [ Opcodes.i32_add ],
181
-
182
- // load current string ind {arg}
183
- [ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],
184
-
185
- // store to new string ind 0
186
- [ Opcodes.i32_store16, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],
187
-
188
- // return new string (pointer)
189
- [ Opcodes.local_get, iTmp2 ],
190
- Opcodes.i32_from_u,
191
-
192
- ...setType(TYPES.string)
193
- ],
194
-
195
- // todo: out of bounds properly
196
- charAt: ({ pointer, arg, iTmp, alloc, setType }) => [
197
- // setup out string and use as pointer for store
198
- ...alloc(8),
199
- [ Opcodes.local_tee, iTmp ],
200
-
201
- // out.length = 1
202
- [ Opcodes.local_get, iTmp ],
203
- number(1, Valtype.i32),
204
- [ Opcodes.i32_store, 0, 0 ],
205
-
206
- ...arg,
207
- Opcodes.i32_to,
208
-
209
- number(ValtypeSize.i16, Valtype.i32),
210
- [ Opcodes.i32_mul ],
211
-
212
- ...pointer,
213
- [ Opcodes.i32_add ],
214
-
215
- // load current string ind {arg}
216
- [ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],
217
-
218
- // store to new string ind 0
219
- [ Opcodes.i32_store16, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],
220
-
221
- // return new string (page)
222
- [ Opcodes.local_get, iTmp ],
223
- Opcodes.i32_from_u,
224
-
225
- ...setType(TYPES.string)
226
- ],
227
-
228
- charCodeAt: ({ pointer, length, arg, iTmp, setType }) => [
229
- ...setType(TYPES.number),
230
-
231
- ...arg,
232
- Opcodes.i32_to,
233
-
234
- ...(zeroChecks.charcodeat ? [] : [
235
- [ Opcodes.local_set, iTmp ],
236
-
237
- // index < 0
238
- ...(noUnlikelyChecks ? [] : [
239
- [ Opcodes.local_get, iTmp ],
240
- number(0, Valtype.i32),
241
- [ Opcodes.i32_lt_s ],
242
- ]),
243
-
244
- // index >= length
245
- [ Opcodes.local_get, iTmp ],
246
- ...length.getCachedI32(),
247
- [ Opcodes.i32_ge_s ],
248
-
249
- ...(noUnlikelyChecks ? [] : [ [ Opcodes.i32_or ] ]),
250
- [ Opcodes.if, Blocktype.void ],
251
- number(valtype === 'i32' ? -1 : NaN),
252
- [ Opcodes.br, 1 ],
253
- [ Opcodes.end ],
254
-
255
- [ Opcodes.local_get, iTmp ],
256
- ]),
257
-
258
- number(ValtypeSize.i16, Valtype.i32),
259
- [ Opcodes.i32_mul ],
260
-
261
- ...pointer,
262
- [ Opcodes.i32_add ],
263
-
264
- // load current string ind {arg}
265
- [ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],
266
- Opcodes.i32_from_u
267
- ]
268
- };
269
-
270
- this[TYPES.string].at.local = Valtype.i32;
271
- this[TYPES.string].at.local2 = Valtype.i32;
272
- this[TYPES.string].charAt.local = Valtype.i32;
273
- this[TYPES.string].charCodeAt.local = Valtype.i32;
274
-
275
- this[TYPES.bytestring] = {
276
- at: ({ pointer, length, arg, iTmp, iTmp2, alloc, setType }) => [
277
- // setup out string and use pointer for store
278
- ...alloc(8),
279
- [ Opcodes.local_tee, iTmp2 ],
280
-
281
- // out.length = 1
282
- [ Opcodes.local_get, iTmp2 ],
283
- number(1, Valtype.i32),
284
- [ Opcodes.i32_store, 0, 0 ],
285
-
286
- ...arg,
287
- Opcodes.i32_to_u,
288
- [ Opcodes.local_tee, iTmp ],
289
-
290
- // if index < 0: access index + array length
291
- number(0, Valtype.i32),
292
- [ Opcodes.i32_lt_s ],
293
- [ Opcodes.if, Blocktype.void ],
294
- [ Opcodes.local_get, iTmp ],
295
- ...length.getCachedI32(),
296
- [ Opcodes.i32_add ],
297
- [ Opcodes.local_set, iTmp ],
298
- [ Opcodes.end ],
299
-
300
- // if still < 0 or >= length: return undefined
301
- [ Opcodes.local_get, iTmp ],
302
- number(0, Valtype.i32),
303
- [ Opcodes.i32_lt_s ],
304
-
305
- [ Opcodes.local_get, iTmp ],
306
- ...length.getCachedI32(),
307
- [ Opcodes.i32_ge_s ],
308
- [ Opcodes.i32_or ],
309
-
310
- [ Opcodes.if, Blocktype.void ],
311
- number(UNDEFINED),
312
- ...setType(TYPES.undefined),
313
- [ Opcodes.br, 1 ],
314
- [ Opcodes.end ],
315
-
316
- [ Opcodes.local_get, iTmp ],
317
-
318
- ...pointer,
319
- [ Opcodes.i32_add ],
320
-
321
- // load current string ind {arg}
322
- [ Opcodes.i32_load8_u, 0, ValtypeSize.i32 ],
323
-
324
- // store to new string ind 0
325
- [ Opcodes.i32_store8, 0, ValtypeSize.i32 ],
326
-
327
- // return new string (pointer)
328
- [ Opcodes.local_get, iTmp2 ],
329
- Opcodes.i32_from_u,
330
-
331
- ...setType(TYPES.bytestring)
332
- ],
333
-
334
- // todo: out of bounds properly
335
- charAt: ({ pointer, arg, iTmp, alloc, setType }) => [
336
- // setup out string and use as pointer for store
337
- ...alloc(8),
338
- [ Opcodes.local_tee, iTmp ],
339
-
340
- // out.length = 1
341
- [ Opcodes.local_get, iTmp ],
342
- number(1, Valtype.i32),
343
- [ Opcodes.i32_store, 0, 0 ],
344
-
345
- ...arg,
346
- Opcodes.i32_to,
347
-
348
- ...pointer,
349
- [ Opcodes.i32_add ],
350
-
351
- // load current string ind {arg}
352
- [ Opcodes.i32_load8_u, 0, ValtypeSize.i32 ],
353
-
354
- // store to new string ind 0
355
- [ Opcodes.i32_store8, 0, ValtypeSize.i32 ],
356
-
357
- // return new string (page)
358
- [ Opcodes.local_get, iTmp ],
359
- Opcodes.i32_from_u,
360
-
361
- ...setType(TYPES.bytestring)
362
- ],
363
-
364
- charCodeAt: ({ pointer, length, arg, iTmp, setType }) => [
365
- ...setType(TYPES.number),
366
-
367
- ...arg,
368
- Opcodes.i32_to,
369
-
370
- ...(zeroChecks.charcodeat ? [] : [
371
- [ Opcodes.local_set, iTmp ],
372
-
373
- // index < 0
374
- ...(noUnlikelyChecks ? [] : [
375
- [ Opcodes.local_get, iTmp ],
376
- number(0, Valtype.i32),
377
- [ Opcodes.i32_lt_s ],
378
- ]),
379
-
380
- // index >= length
381
- [ Opcodes.local_get, iTmp ],
382
- ...length.getCachedI32(),
383
- [ Opcodes.i32_ge_s ],
384
-
385
- ...(noUnlikelyChecks ? [] : [ [ Opcodes.i32_or ] ]),
386
- [ Opcodes.if, Blocktype.void ],
387
- number(valtype === 'i32' ? -1 : NaN),
388
- [ Opcodes.br, 1 ],
389
- [ Opcodes.end ],
390
-
391
- [ Opcodes.local_get, iTmp ],
392
- ]),
393
-
394
- ...pointer,
395
- [ Opcodes.i32_add ],
396
-
397
- // load current string ind {arg}
398
- [ Opcodes.i32_load8_u, 0, ValtypeSize.i32 ],
399
- Opcodes.i32_from_u
400
- ]
401
- };
402
-
403
- this[TYPES.bytestring].at.local = Valtype.i32;
404
- this[TYPES.bytestring].at.local2 = Valtype.i32;
405
- this[TYPES.bytestring].charAt.local = Valtype.i32;
406
- this[TYPES.bytestring].charCodeAt.local = Valtype.i32;
407
- };