porffor 0.16.0-594397507 → 0.16.0-688a50c13

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.
@@ -1,5 +1,5 @@
1
- import { Blocktype, Opcodes, Valtype, PageSize, ValtypeSize } from './wasmSpec.js';
2
- import { ieee754_binary64, signedLEB128, unsignedLEB128, encodeVector } from './encoding.js';
1
+ import { Blocktype, Opcodes, Valtype, ValtypeSize } from './wasmSpec.js';
2
+ import { 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
5
  import { PrototypeFuncs } from './prototype.js';
@@ -9,15 +9,16 @@ import * as Rhemyn from '../rhemyn/compile.js';
9
9
  import parse from './parse.js';
10
10
  import { log } from './log.js';
11
11
  import Prefs from './prefs.js';
12
+ import Allocator from './allocators/index.js';
12
13
 
13
14
  let globals = {};
14
- let globalInd = 0;
15
15
  let tags = [];
16
16
  let funcs = [];
17
17
  let exceptions = [];
18
18
  let funcIndex = {};
19
19
  let currentFuncIndex = importedFuncs.length;
20
20
  let builtinFuncs = {}, builtinVars = {}, prototypeFuncs = {};
21
+ let allocator;
21
22
 
22
23
  class TodoError extends Error {
23
24
  constructor(message) {
@@ -181,12 +182,6 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
181
182
  continue;
182
183
  }
183
184
 
184
- if (asm[0] === 'memory') {
185
- allocPage(scope, 'asm instrinsic');
186
- // todo: add to store/load offset insts
187
- continue;
188
- }
189
-
190
185
  let inst = Opcodes[asm[0].replace('.', '_')];
191
186
  if (inst == null) throw new Error(`inline asm: inst ${asm[0]} not found`);
192
187
 
@@ -433,63 +428,12 @@ const concatStrings = (scope, left, right, global, name, assign = false, bytestr
433
428
  const rightLength = localTmp(scope, 'concat_right_length', Valtype.i32);
434
429
  const leftLength = localTmp(scope, 'concat_left_length', Valtype.i32);
435
430
 
436
- if (assign && Prefs.aotPointerOpt) {
437
- const pointer = scope.arrays?.get(name ?? '$undeclared');
438
-
439
- return [
440
- // setup right
441
- ...right,
442
- Opcodes.i32_to_u,
443
- [ Opcodes.local_set, rightPointer ],
444
-
445
- // calculate length
446
- ...number(0, Valtype.i32), // base 0 for store later
447
-
448
- ...number(pointer, Valtype.i32),
449
- [ Opcodes.i32_load, 0, ...unsignedLEB128(0) ],
450
- [ Opcodes.local_tee, leftLength ],
451
-
452
- [ Opcodes.local_get, rightPointer ],
453
- [ Opcodes.i32_load, 0, ...unsignedLEB128(0) ],
454
- [ Opcodes.local_tee, rightLength ],
455
-
456
- [ Opcodes.i32_add ],
457
-
458
- // store length
459
- [ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, ...unsignedLEB128(pointer) ],
460
-
461
- // copy right
462
- // dst = out pointer + length size + current length * sizeof valtype
463
- ...number(pointer + ValtypeSize.i32, Valtype.i32),
464
-
465
- [ Opcodes.local_get, leftLength ],
466
- ...number(bytestrings ? ValtypeSize.i8 : ValtypeSize.i16, Valtype.i32),
467
- [ Opcodes.i32_mul ],
468
- [ Opcodes.i32_add ],
469
-
470
- // src = right pointer + length size
471
- [ Opcodes.local_get, rightPointer ],
472
- ...number(ValtypeSize.i32, Valtype.i32),
473
- [ Opcodes.i32_add ],
474
-
475
- // size = right length * sizeof valtype
476
- [ Opcodes.local_get, rightLength ],
477
- ...number(bytestrings ? ValtypeSize.i8 : ValtypeSize.i16, Valtype.i32),
478
- [ Opcodes.i32_mul ],
479
-
480
- [ ...Opcodes.memory_copy, 0x00, 0x00 ],
481
-
482
- // return new string (page)
483
- ...number(pointer)
484
- ];
485
- }
486
-
487
431
  const leftPointer = localTmp(scope, 'concat_left_pointer', Valtype.i32);
488
432
 
489
433
  // alloc/assign array
490
434
  const [ , pointer ] = makeArray(scope, {
491
435
  rawElements: new Array(0)
492
- }, global, name, true, 'i16');
436
+ }, global, name, true, 'i16', true);
493
437
 
494
438
  return [
495
439
  // setup left
@@ -503,7 +447,7 @@ const concatStrings = (scope, left, right, global, name, assign = false, bytestr
503
447
  [ Opcodes.local_set, rightPointer ],
504
448
 
505
449
  // calculate length
506
- ...number(0, Valtype.i32), // base 0 for store later
450
+ ...pointer, // base 0 for store later
507
451
 
508
452
  [ Opcodes.local_get, leftPointer ],
509
453
  [ Opcodes.i32_load, 0, ...unsignedLEB128(0) ],
@@ -516,11 +460,13 @@ const concatStrings = (scope, left, right, global, name, assign = false, bytestr
516
460
  [ Opcodes.i32_add ],
517
461
 
518
462
  // store length
519
- [ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, ...unsignedLEB128(pointer) ],
463
+ [ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, 0 ],
520
464
 
521
465
  // copy left
522
466
  // dst = out pointer + length size
523
- ...number(pointer + ValtypeSize.i32, Valtype.i32),
467
+ ...pointer,
468
+ ...number(ValtypeSize.i32, Valtype.i32),
469
+ [ Opcodes.i32_add ],
524
470
 
525
471
  // src = left pointer + length size
526
472
  [ Opcodes.local_get, leftPointer ],
@@ -533,7 +479,9 @@ const concatStrings = (scope, left, right, global, name, assign = false, bytestr
533
479
 
534
480
  // copy right
535
481
  // dst = out pointer + length size + left length * sizeof valtype
536
- ...number(pointer + ValtypeSize.i32, Valtype.i32),
482
+ ...pointer,
483
+ ...number(ValtypeSize.i32, Valtype.i32),
484
+ [ Opcodes.i32_add ],
537
485
 
538
486
  [ Opcodes.local_get, leftLength ],
539
487
  ...number(bytestrings ? ValtypeSize.i8 : ValtypeSize.i16, Valtype.i32),
@@ -553,7 +501,8 @@ const concatStrings = (scope, left, right, global, name, assign = false, bytestr
553
501
  [ ...Opcodes.memory_copy, 0x00, 0x00 ],
554
502
 
555
503
  // return new string (page)
556
- ...number(pointer)
504
+ ...pointer,
505
+ Opcodes.i32_from_u
557
506
  ];
558
507
  };
559
508
 
@@ -669,10 +618,10 @@ const compareStrings = (scope, left, right, bytestrings = false) => {
669
618
  };
670
619
 
671
620
  const truthy = (scope, wasm, type, intIn = false, intOut = false, forceTruthyMode = undefined) => {
672
- if (isIntToFloatOp(wasm[wasm.length - 1])) return [
673
- ...wasm,
674
- ...(!intIn && intOut ? [ Opcodes.i32_to_u ] : [])
675
- ];
621
+ // if (isIntToFloatOp(wasm[wasm.length - 1])) return [
622
+ // ...wasm,
623
+ // ...(!intIn && intOut ? [ Opcodes.i32_to_u ] : [])
624
+ // ];
676
625
  // if (isIntOp(wasm[wasm.length - 1])) return [ ...wasm ];
677
626
 
678
627
  // todo/perf: use knownType and custom bytecode here instead of typeSwitch
@@ -1078,7 +1027,7 @@ const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes
1078
1027
  locals,
1079
1028
  localInd: allLocals.length,
1080
1029
  returns,
1081
- returnType: returnType ?? TYPES.number,
1030
+ returnType,
1082
1031
  internal: true,
1083
1032
  index: currentFuncIndex++,
1084
1033
  table
@@ -1091,9 +1040,9 @@ const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes
1091
1040
 
1092
1041
  let baseGlobalIdx, i = 0;
1093
1042
  for (const type of globalTypes) {
1094
- if (baseGlobalIdx === undefined) baseGlobalIdx = globalInd;
1043
+ if (baseGlobalIdx === undefined) baseGlobalIdx = globals['#ind'];
1095
1044
 
1096
- globals[globalNames[i] ?? `${name}_global_${i}`] = { idx: globalInd++, type, init: globalInits[i] ?? 0 };
1045
+ globals[globalNames[i] ?? `${name}_global_${i}`] = { idx: globals['#ind']++, type, init: globalInits[i] ?? 0 };
1097
1046
  i++;
1098
1047
  }
1099
1048
 
@@ -1106,11 +1055,15 @@ const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes
1106
1055
  }
1107
1056
  }
1108
1057
 
1109
- if (table) for (const inst of wasm) {
1110
- if (inst[0] === Opcodes.i32_load16_u && inst.at(-1) === 'read_argc') {
1111
- inst.splice(2, 99);
1112
- inst.push(...unsignedLEB128(allocPage({}, 'func argc lut') * pageSize));
1058
+ if (table) {
1059
+ for (const inst of wasm) {
1060
+ if (inst[0] === Opcodes.i32_load16_u && inst.at(-1) === 'read_argc') {
1061
+ inst.splice(2, 99);
1062
+ inst.push(...unsignedLEB128(allocPage({}, 'func argc lut') * pageSize));
1063
+ }
1113
1064
  }
1065
+
1066
+ funcs.table = true;
1114
1067
  }
1115
1068
 
1116
1069
  func.wasm = wasm;
@@ -1254,7 +1207,7 @@ const getNodeType = (scope, node) => {
1254
1207
  const func = funcs.find(x => x.name === name);
1255
1208
 
1256
1209
  if (func) {
1257
- if (func.returnType) return func.returnType;
1210
+ if (func.returnType != null) return func.returnType;
1258
1211
  }
1259
1212
 
1260
1213
  if (builtinFuncs[name] && !builtinFuncs[name].typedReturns) return builtinFuncs[name].returnType ?? TYPES.number;
@@ -1270,15 +1223,7 @@ const getNodeType = (scope, node) => {
1270
1223
  const func = spl[spl.length - 1];
1271
1224
  const protoFuncs = Object.keys(prototypeFuncs).filter(x => x != TYPES.bytestring && prototypeFuncs[x][func] != null);
1272
1225
  if (protoFuncs.length === 1) {
1273
- if (protoFuncs[0].returnType) return protoFuncs[0].returnType;
1274
- }
1275
-
1276
- if (protoFuncs.length > 0) {
1277
- if (scope.locals['#last_type']) return getLastType(scope);
1278
-
1279
- // presume
1280
- // todo: warn here?
1281
- return TYPES.number;
1226
+ if (protoFuncs[0].returnType != null) return protoFuncs[0].returnType;
1282
1227
  }
1283
1228
  }
1284
1229
 
@@ -1733,7 +1678,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
1733
1678
  }, generate(scope, decl.arguments[0] ?? DEFAULT_VALUE), getNodeType(scope, decl.arguments[0] ?? DEFAULT_VALUE), protoLocal, protoLocal2, (length, itemType) => {
1734
1679
  return makeArray(scope, {
1735
1680
  rawElements: new Array(length)
1736
- }, _global, _name, true, itemType);
1681
+ }, _global, _name, true, itemType, true);
1737
1682
  }, () => {
1738
1683
  optUnused = true;
1739
1684
  return unusedValue;
@@ -1815,7 +1760,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
1815
1760
  f64_store: { imms: 2, args: [ true, false ], returns: 0 },
1816
1761
 
1817
1762
  // value
1818
- i32_const: { imms: 1, args: [], returns: 1 },
1763
+ i32_const: { imms: 1, args: [], returns: 0 },
1819
1764
  };
1820
1765
 
1821
1766
  const opName = name.slice('__Porffor_wasm_'.length);
@@ -1978,7 +1923,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
1978
1923
  const func = funcs[idx - importedFuncs.length]; // idx === scope.index ? scope : funcs.find(x => x.index === idx);
1979
1924
  const userFunc = func && !func.internal;
1980
1925
  const typedParams = userFunc || builtinFuncs[name]?.typedParams;
1981
- const typedReturns = (func && func.returnType == null) || builtinFuncs[name]?.typedReturns;
1926
+ const typedReturns = (userFunc && func.returnType == null) || builtinFuncs[name]?.typedReturns;
1982
1927
  const paramCount = func && (typedParams ? func.params.length / 2 : func.params.length);
1983
1928
 
1984
1929
  let args = decl.arguments;
@@ -2007,8 +1952,8 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
2007
1952
  }
2008
1953
 
2009
1954
  if (valtypeBinary !== Valtype.i32 && (
2010
- (builtinFuncs[name] && builtinFuncs[name].params[i * (typedParams ? 2 : 1)] === Valtype.i32) ||
2011
- (importedFuncs[name] && name.startsWith('profile'))
1955
+ (builtinFuncs[name] && builtinFuncs[name].params[i * (typedParams ? 2 : 1)] === Valtype.i32)
1956
+ // (importedFuncs[name] && name.startsWith('profile'))
2012
1957
  )) {
2013
1958
  out.push(Opcodes.i32_to);
2014
1959
  }
@@ -2123,7 +2068,6 @@ const brTable = (input, bc, returns) => {
2123
2068
  }
2124
2069
 
2125
2070
  for (let i = 0; i < count; i++) {
2126
- // if (i === 0) out.push([ Opcodes.block, returns, 'br table start' ]);
2127
2071
  if (i === 0) out.push([ Opcodes.block, returns ]);
2128
2072
  else out.push([ Opcodes.block, Blocktype.void ]);
2129
2073
  }
@@ -2157,10 +2101,8 @@ const brTable = (input, bc, returns) => {
2157
2101
  [ Opcodes.br_table, ...encodeVector(table), 0 ]
2158
2102
  );
2159
2103
 
2160
- // if you can guess why we sort the wrong way and then reverse
2161
- // (instead of just sorting the correct way)
2162
- // dm me and if you are correct and the first person
2163
- // I will somehow shout you out or something
2104
+ // sort the wrong way and then reverse
2105
+ // so strings ('default') are at the start before any numbers
2164
2106
  const orderedBc = keys.sort((a, b) => b - a).reverse();
2165
2107
 
2166
2108
  br = count - 1;
@@ -2186,10 +2128,10 @@ const typeSwitch = (scope, type, bc, returns = valtypeBinary) => {
2186
2128
  return bc[known] ?? bc.default;
2187
2129
  }
2188
2130
 
2189
- if (Prefs.typeswitchUseBrtable)
2131
+ if (Prefs.typeswitchBrtable)
2190
2132
  return brTable(type, bc, returns);
2191
2133
 
2192
- const tmp = localTmp(scope, '#typeswitch_tmp', Valtype.i32);
2134
+ const tmp = localTmp(scope, '#typeswitch_tmp' + (Prefs.typeswitchUniqueTmp ? randId() : ''), Valtype.i32);
2193
2135
  const out = [
2194
2136
  ...type,
2195
2137
  [ Opcodes.local_set, tmp ],
@@ -2241,11 +2183,11 @@ const allocVar = (scope, name, global = false, type = true) => {
2241
2183
  return target[name].idx;
2242
2184
  }
2243
2185
 
2244
- let idx = global ? globalInd++ : scope.localInd++;
2186
+ let idx = global ? globals['#ind']++ : scope.localInd++;
2245
2187
  target[name] = { idx, type: valtypeBinary };
2246
2188
 
2247
2189
  if (type) {
2248
- let typeIdx = global ? globalInd++ : scope.localInd++;
2190
+ let typeIdx = global ? globals['#ind']++ : scope.localInd++;
2249
2191
  target[name + '#type'] = { idx: typeIdx, type: Valtype.i32, name };
2250
2192
  }
2251
2193
 
@@ -2338,24 +2280,10 @@ const generateVar = (scope, decl) => {
2338
2280
  }
2339
2281
 
2340
2282
  if (x.init) {
2341
- // if (isFuncType(x.init.type)) {
2342
- // // let a = function () { ... }
2343
- // x.init.id = { name };
2344
-
2345
- // const func = generateFunc(scope, x.init);
2346
-
2347
- // out.push(
2348
- // ...number(func.index - importedFuncs.length),
2349
- // [ global ? Opcodes.global_set : Opcodes.local_set, idx ],
2350
-
2351
- // ...setType(scope, name, TYPES.function)
2352
- // );
2353
-
2354
- // continue;
2355
- // }
2283
+ const alreadyArray = scope.arrays?.get(name) != null;
2356
2284
 
2357
2285
  const generated = generate(scope, x.init, global, name);
2358
- if (scope.arrays?.get(name) != null) {
2286
+ if (!alreadyArray && scope.arrays?.get(name) != null) {
2359
2287
  // hack to set local as pointer before
2360
2288
  out.push(...number(scope.arrays.get(name)), [ global ? Opcodes.global_set : Opcodes.local_set, idx ]);
2361
2289
  if (generated.at(-1) == Opcodes.i32_from_u) generated.pop();
@@ -2407,19 +2335,12 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
2407
2335
 
2408
2336
  // hack: .length setter
2409
2337
  if (decl.left.type === 'MemberExpression' && decl.left.property.name === 'length') {
2410
- const name = decl.left.object.name;
2411
- const pointer = scope.arrays?.get(name);
2412
-
2413
- const aotPointer = Prefs.aotPointerOpt && pointer != null;
2414
-
2415
2338
  const newValueTmp = localTmp(scope, '__length_setter_tmp');
2416
2339
  const pointerTmp = op === '=' ? null : localTmp(scope, '__member_setter_ptr_tmp', Valtype.i32);
2417
2340
 
2418
2341
  return [
2419
- ...(aotPointer ? number(0, Valtype.i32) : [
2420
- ...generate(scope, decl.left.object),
2421
- Opcodes.i32_to_u
2422
- ]),
2342
+ ...generate(scope, decl.left.object),
2343
+ Opcodes.i32_to_u,
2423
2344
  ...(!pointerTmp ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
2424
2345
 
2425
2346
  ...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
@@ -2430,7 +2351,7 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
2430
2351
  [ Opcodes.local_tee, newValueTmp ],
2431
2352
 
2432
2353
  Opcodes.i32_to_u,
2433
- [ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, ...unsignedLEB128(aotPointer ? pointer : 0) ],
2354
+ [ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, 0 ],
2434
2355
 
2435
2356
  [ Opcodes.local_get, newValueTmp ]
2436
2357
  ];
@@ -2438,21 +2359,14 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
2438
2359
 
2439
2360
  // arr[i]
2440
2361
  if (decl.left.type === 'MemberExpression' && decl.left.computed) {
2441
- const name = decl.left.object.name;
2442
- const pointer = scope.arrays?.get(name);
2443
-
2444
- const aotPointer = Prefs.aotPointerOpt && pointer != null;
2445
-
2446
2362
  const newValueTmp = localTmp(scope, '__member_setter_val_tmp');
2447
2363
  const pointerTmp = op === '=' ? -1 : localTmp(scope, '__member_setter_ptr_tmp', Valtype.i32);
2448
2364
 
2449
2365
  return [
2450
2366
  ...typeSwitch(scope, getNodeType(scope, decl.left.object), {
2451
2367
  [TYPES.array]: [
2452
- ...(aotPointer ? [] : [
2453
- ...generate(scope, decl.left.object),
2454
- Opcodes.i32_to_u
2455
- ]),
2368
+ ...generate(scope, decl.left.object),
2369
+ Opcodes.i32_to_u,
2456
2370
 
2457
2371
  // get index as valtype
2458
2372
  ...generate(scope, decl.left.property),
@@ -2461,39 +2375,22 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
2461
2375
  // turn into byte offset by * valtypeSize (4 for i32, 8 for i64/f64)
2462
2376
  ...number(ValtypeSize[valtype] + 1, Valtype.i32),
2463
2377
  [ Opcodes.i32_mul ],
2464
- ...(aotPointer ? [] : [ [ Opcodes.i32_add ] ]),
2378
+ [ Opcodes.i32_add ],
2465
2379
  ...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
2466
2380
 
2467
2381
  ...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
2468
2382
  [ Opcodes.local_get, pointerTmp ],
2469
- [ Opcodes.load, 0, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ]
2383
+ [ Opcodes.load, 0, ValtypeSize.i32 ]
2470
2384
  ], generate(scope, decl.right), [
2471
2385
  [ Opcodes.local_get, pointerTmp ],
2472
- [ Opcodes.i32_load8_u, 0, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32 + ValtypeSize[valtype]) ]
2386
+ [ Opcodes.i32_load8_u, 0, ValtypeSize.i32 + ValtypeSize[valtype] ]
2473
2387
  ], getNodeType(scope, decl.right), false, name, true)),
2474
2388
  [ Opcodes.local_tee, newValueTmp ],
2475
2389
 
2476
- [ Opcodes.store, 0, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ]
2390
+ [ Opcodes.store, 0, ValtypeSize.i32 ]
2477
2391
  ],
2478
2392
 
2479
2393
  default: internalThrow(scope, 'TypeError', `Cannot assign member with non-array`)
2480
-
2481
- // [TYPES.string]: [
2482
- // // turn into byte offset by * sizeof i16
2483
- // ...number(ValtypeSize.i16, Valtype.i32),
2484
- // [ Opcodes.i32_mul ],
2485
- // ...(aotPointer ? [] : [ [ Opcodes.i32_add ] ]),
2486
- // ...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
2487
-
2488
- // ...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
2489
- // [ Opcodes.local_get, pointerTmp ],
2490
- // [ Opcodes.load, Math.log2(ValtypeSize[valtype]) - 1, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ]
2491
- // ], generate(scope, decl.right), number(TYPES.string, Valtype.i32), getNodeType(scope, decl.right))),
2492
- // [ Opcodes.local_tee, newValueTmp ],
2493
-
2494
- // Opcodes.i32_to_u,
2495
- // [ StoreOps.i16, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ]
2496
- // ]
2497
2394
  }, Blocktype.void),
2498
2395
 
2499
2396
  [ Opcodes.local_get, newValueTmp ]
@@ -2571,7 +2468,7 @@ const generateUnary = (scope, decl) => {
2571
2468
  // * -1
2572
2469
 
2573
2470
  if (decl.prefix && decl.argument.type === 'Literal' && typeof decl.argument.value === 'number') {
2574
- // if -<N>, just return that
2471
+ // if -n, just return that as a const
2575
2472
  return number(-1 * decl.argument.value);
2576
2473
  }
2577
2474
 
@@ -2583,14 +2480,14 @@ const generateUnary = (scope, decl) => {
2583
2480
  case '!':
2584
2481
  const arg = decl.argument;
2585
2482
  if (arg.type === 'UnaryExpression' && arg.operator === '!') {
2586
- // !!x -> is x truthy
2483
+ // opt: !!x -> is x truthy
2587
2484
  return truthy(scope, generate(scope, arg.argument), getNodeType(scope, arg.argument), false, false);
2588
2485
  }
2486
+
2589
2487
  // !=
2590
- return falsy(scope, generate(scope, decl.argument), getNodeType(scope, decl.argument), false, false);
2488
+ return falsy(scope, generate(scope, arg), getNodeType(scope, arg), false, false);
2591
2489
 
2592
2490
  case '~':
2593
- // todo: does not handle Infinity properly (should convert to 0) (but opt const converting saves us sometimes)
2594
2491
  return [
2595
2492
  ...generate(scope, decl.argument),
2596
2493
  Opcodes.i32_to,
@@ -2877,12 +2774,12 @@ const generateForOf = (scope, decl) => {
2877
2774
 
2878
2775
  // // todo: we should only do this for strings but we don't know at compile-time :(
2879
2776
  // hack: this is naughty and will break things!
2880
- let newOut = number(0, Valtype.f64), newPointer = -1;
2777
+ let newOut = number(0, Valtype.i32), newPointer = number(0, Valtype.i32);
2881
2778
  if (pages.hasAnyString) {
2882
2779
  // todo: we use i16 even for bytestrings which should not make a bad thing happen, just be confusing for debugging?
2883
2780
  0, [ newOut, newPointer ] = makeArray(scope, {
2884
- rawElements: new Array(1)
2885
- }, isGlobal, leftName, true, 'i16');
2781
+ rawElements: new Array(0)
2782
+ }, isGlobal, leftName, true, 'i16', true);
2886
2783
  }
2887
2784
 
2888
2785
  // set type for local
@@ -2929,23 +2826,28 @@ const generateForOf = (scope, decl) => {
2929
2826
  [TYPES.string]: [
2930
2827
  ...setType(scope, leftName, TYPES.string),
2931
2828
 
2932
- [ Opcodes.loop, Blocktype.void ],
2933
-
2934
2829
  // setup new/out array
2935
2830
  ...newOut,
2936
- [ Opcodes.drop ],
2937
2831
 
2938
- ...number(0, Valtype.i32), // base 0 for store after
2832
+ // set length to 1
2833
+ ...number(1, Valtype.i32),
2834
+ [ Opcodes.i32_store, 0, 0 ],
2835
+
2836
+ [ Opcodes.loop, Blocktype.void ],
2837
+
2838
+ // use as pointer for store later
2839
+ ...newPointer,
2939
2840
 
2940
2841
  // load current string ind {arg}
2941
2842
  [ Opcodes.local_get, pointer ],
2942
- [ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128(ValtypeSize.i32) ],
2843
+ [ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],
2943
2844
 
2944
2845
  // store to new string ind 0
2945
- [ Opcodes.i32_store16, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128(newPointer + ValtypeSize.i32) ],
2846
+ [ Opcodes.i32_store16, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],
2946
2847
 
2947
2848
  // return new string (page)
2948
- ...number(newPointer),
2849
+ ...newPointer,
2850
+ Opcodes.i32_from_u,
2949
2851
 
2950
2852
  [ isGlobal ? Opcodes.global_set : Opcodes.local_set, local.idx ],
2951
2853
 
@@ -2977,25 +2879,30 @@ const generateForOf = (scope, decl) => {
2977
2879
  [TYPES.bytestring]: [
2978
2880
  ...setType(scope, leftName, TYPES.bytestring),
2979
2881
 
2980
- [ Opcodes.loop, Blocktype.void ],
2981
-
2982
2882
  // setup new/out array
2983
2883
  ...newOut,
2984
- [ Opcodes.drop ],
2985
2884
 
2986
- ...number(0, Valtype.i32), // base 0 for store after
2885
+ // set length to 1
2886
+ ...number(1, Valtype.i32),
2887
+ [ Opcodes.i32_store, 0, 0 ],
2888
+
2889
+ [ Opcodes.loop, Blocktype.void ],
2890
+
2891
+ // use as pointer for store later
2892
+ ...newPointer,
2987
2893
 
2988
2894
  // load current string ind {arg}
2989
2895
  [ Opcodes.local_get, pointer ],
2990
2896
  [ Opcodes.local_get, counter ],
2991
2897
  [ Opcodes.i32_add ],
2992
- [ Opcodes.i32_load8_u, 0, ...unsignedLEB128(ValtypeSize.i32) ],
2898
+ [ Opcodes.i32_load8_u, 0, ValtypeSize.i32 ],
2993
2899
 
2994
2900
  // store to new string ind 0
2995
- [ Opcodes.i32_store8, 0, ...unsignedLEB128(newPointer + ValtypeSize.i32) ],
2901
+ [ Opcodes.i32_store8, 0, ValtypeSize.i32 ],
2996
2902
 
2997
2903
  // return new string (page)
2998
- ...number(newPointer),
2904
+ ...newPointer,
2905
+ Opcodes.i32_from_u,
2999
2906
 
3000
2907
  [ isGlobal ? Opcodes.global_set : Opcodes.local_set, local.idx ],
3001
2908
 
@@ -3215,16 +3122,6 @@ const allocPage = (scope, reason, type) => {
3215
3122
  return ind;
3216
3123
  };
3217
3124
 
3218
- // todo: add scope.pages
3219
- const freePage = reason => {
3220
- const { ind } = pages.get(reason);
3221
- pages.delete(reason);
3222
-
3223
- if (Prefs.allocLog) log('alloc', `freed page of memory (${ind}) | ${reason}`);
3224
-
3225
- return ind;
3226
- };
3227
-
3228
3125
  const itemTypeToValtype = {
3229
3126
  i32: 'i32',
3230
3127
  i64: 'i64',
@@ -3259,86 +3156,84 @@ const compileBytes = (val, itemType) => {
3259
3156
  }
3260
3157
  };
3261
3158
 
3262
- const getAllocType = itemType => {
3263
- switch (itemType) {
3264
- case 'i8': return 'bytestring';
3265
- case 'i16': return 'string';
3266
-
3267
- default: return 'array';
3159
+ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty = false, itemType = valtype, intOut = false, typed = false) => {
3160
+ if (itemType !== 'i16' && itemType !== 'i8') {
3161
+ pages.hasArray = true;
3162
+ } else {
3163
+ pages.hasAnyString = true;
3164
+ if (itemType === 'i8') pages.hasByteString = true;
3165
+ else pages.hasString = true;
3268
3166
  }
3269
- };
3270
3167
 
3271
- const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty = false, itemType = valtype, typed = false) => {
3272
3168
  const out = [];
3273
3169
 
3274
- scope.arrays ??= new Map();
3170
+ const uniqueName = name === '$undeclared' ? name + randId() : name;
3275
3171
 
3276
- let firstAssign = false;
3277
- if (!scope.arrays.has(name) || name === '$undeclared') {
3278
- firstAssign = true;
3172
+ const useRawElements = !!decl.rawElements;
3173
+ const elements = useRawElements ? decl.rawElements : decl.elements;
3279
3174
 
3280
- // todo: can we just have 1 undeclared array? probably not? but this is not really memory efficient
3281
- const uniqueName = name === '$undeclared' ? name + Math.random().toString().slice(2) : name;
3175
+ const valtype = itemTypeToValtype[itemType];
3176
+ const length = elements.length;
3282
3177
 
3283
- let page;
3284
- if (Prefs.scopedPageNames) page = allocPage(scope, `${getAllocType(itemType)}: ${scope.name}/${uniqueName}`, itemType);
3285
- else page = allocPage(scope, `${getAllocType(itemType)}: ${uniqueName}`, itemType);
3178
+ const allocated = allocator.alloc({ scope, pages, globals }, uniqueName, { itemType });
3286
3179
 
3287
- // hack: use 1 for page 0 pointer for fast truthiness
3288
- const ptr = page === 0 ? 1 : (page * pageSize);
3289
- scope.arrays.set(name, ptr);
3290
- }
3180
+ let pointer = allocated;
3181
+ if (allocator.constructor.name !== 'StaticAllocator') {
3182
+ const tmp = localTmp(scope, '#makearray_pointer' + uniqueName, Valtype.i32);
3183
+ out.push(
3184
+ ...allocated,
3185
+ [ Opcodes.local_set, tmp ]
3186
+ );
3291
3187
 
3292
- const pointer = scope.arrays.get(name);
3188
+ pointer = [ [ Opcodes.local_get, tmp ] ];
3189
+ } else {
3190
+ const rawPtr = read_signedLEB128(pointer[0].slice(1));
3293
3191
 
3294
- const local = global ? globals[name] : scope.locals[name];
3192
+ scope.arrays ??= new Map();
3193
+ const firstAssign = !scope.arrays.has(uniqueName);
3194
+ if (firstAssign) scope.arrays.set(uniqueName, rawPtr);
3295
3195
 
3296
- const useRawElements = !!decl.rawElements;
3297
- const elements = useRawElements ? decl.rawElements : decl.elements;
3196
+ if (Prefs.data && firstAssign && useRawElements) {
3197
+ // if length is 0 memory/data will just be 0000... anyway
3198
+ if (length !== 0) {
3199
+ let bytes = compileBytes(length, 'i32');
3298
3200
 
3299
- const valtype = itemTypeToValtype[itemType];
3300
- const length = elements.length;
3201
+ if (!initEmpty) for (let i = 0; i < length; i++) {
3202
+ if (elements[i] == null) continue;
3301
3203
 
3302
- if (firstAssign && useRawElements && !Prefs.noData) {
3303
- // if length is 0 memory/data will just be 0000... anyway
3304
- if (length !== 0) {
3305
- let bytes = compileBytes(length, 'i32');
3204
+ bytes.push(...compileBytes(elements[i], itemType));
3205
+ }
3306
3206
 
3307
- if (!initEmpty) for (let i = 0; i < length; i++) {
3308
- if (elements[i] == null) continue;
3207
+ const ind = data.push({
3208
+ offset: rawPtr,
3209
+ bytes
3210
+ }) - 1;
3309
3211
 
3310
- bytes.push(...compileBytes(elements[i], itemType));
3212
+ scope.data ??= [];
3213
+ scope.data.push(ind);
3311
3214
  }
3312
3215
 
3313
- const ind = data.push({
3314
- offset: pointer,
3315
- bytes
3316
- }) - 1;
3317
-
3318
- scope.data ??= [];
3319
- scope.data.push(ind);
3216
+ // local value as pointer
3217
+ return [ number(rawPtr, intOut ? Valtype.i32 : valtypeBinary), pointer ];
3320
3218
  }
3321
3219
 
3322
- // local value as pointer
3323
- out.push(...number(pointer));
3324
-
3325
- return [ out, pointer ];
3326
- }
3220
+ const local = global ? globals[name] : scope.locals[name];
3221
+ const pointerTmp = local != null ? localTmp(scope, '#makearray_pointer_tmp', Valtype.i32) : null;
3222
+ if (pointerTmp != null) {
3223
+ out.push(
3224
+ [ global ? Opcodes.global_get : Opcodes.local_get, local.idx ],
3225
+ Opcodes.i32_to_u,
3226
+ [ Opcodes.local_set, pointerTmp ]
3227
+ );
3327
3228
 
3328
- const pointerTmp = local != null ? localTmp(scope, '#makearray_pointer_tmp', Valtype.i32) : null;
3329
- if (pointerTmp != null) {
3330
- out.push(
3331
- [ global ? Opcodes.global_get : Opcodes.local_get, local.idx ],
3332
- Opcodes.i32_to_u,
3333
- [ Opcodes.local_set, pointerTmp ]
3334
- );
3229
+ pointer = [ [ Opcodes.local_get, pointerTmp ] ];
3230
+ }
3335
3231
  }
3336
3232
 
3337
- const pointerWasm = pointerTmp != null ? [ [ Opcodes.local_get, pointerTmp ] ] : number(pointer, Valtype.i32);
3338
3233
 
3339
3234
  // store length
3340
3235
  out.push(
3341
- ...pointerWasm,
3236
+ ...pointer,
3342
3237
  ...number(length, Valtype.i32),
3343
3238
  [ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, 0 ]
3344
3239
  );
@@ -3350,11 +3245,11 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
3350
3245
 
3351
3246
  const offset = ValtypeSize.i32 + i * sizePerEl;
3352
3247
  out.push(
3353
- ...pointerWasm,
3248
+ ...pointer,
3354
3249
  ...(useRawElements ? number(elements[i], Valtype[valtype]) : generate(scope, elements[i])),
3355
3250
  [ storeOp, 0, ...unsignedLEB128(offset) ],
3356
3251
  ...(!typed ? [] : [ // typed presumes !useRawElements
3357
- ...pointerWasm,
3252
+ ...pointer,
3358
3253
  ...getNodeType(scope, elements[i]),
3359
3254
  [ Opcodes.i32_store8, 0, ...unsignedLEB128(offset + ValtypeSize[itemType]) ]
3360
3255
  ])
@@ -3362,12 +3257,13 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
3362
3257
  }
3363
3258
 
3364
3259
  // local value as pointer
3365
- out.push(...pointerWasm, Opcodes.i32_from_u);
3260
+ out.push(...pointer);
3261
+ if (!intOut) out.push(Opcodes.i32_from_u);
3366
3262
 
3367
3263
  return [ out, pointer ];
3368
3264
  };
3369
3265
 
3370
- const storeArray = (scope, array, index, element, aotPointer = null) => {
3266
+ const storeArray = (scope, array, index, element) => {
3371
3267
  if (!Array.isArray(element)) element = generate(scope, element);
3372
3268
  if (typeof index === 'number') index = number(index);
3373
3269
 
@@ -3379,26 +3275,25 @@ const storeArray = (scope, array, index, element, aotPointer = null) => {
3379
3275
  Opcodes.i32_to_u,
3380
3276
  ...number(ValtypeSize[valtype] + 1, Valtype.i32),
3381
3277
  [ Opcodes.i32_mul ],
3382
- ...(aotPointer ? [] : [
3383
- ...array,
3384
- Opcodes.i32_to_u,
3385
- [ Opcodes.i32_add ],
3386
- ]),
3278
+
3279
+ ...array,
3280
+ Opcodes.i32_to_u,
3281
+ [ Opcodes.i32_add ],
3387
3282
  [ Opcodes.local_set, offset ],
3388
3283
 
3389
3284
  // store value
3390
3285
  [ Opcodes.local_get, offset ],
3391
3286
  ...generate(scope, element),
3392
- [ Opcodes.store, 0, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ],
3287
+ [ Opcodes.store, 0, ValtypeSize.i32 ],
3393
3288
 
3394
3289
  // store type
3395
3290
  [ Opcodes.local_get, offset ],
3396
3291
  ...getNodeType(scope, element),
3397
- [ Opcodes.i32_store8, 0, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32 + ValtypeSize[valtype]) ]
3292
+ [ Opcodes.i32_store8, 0, ValtypeSize.i32 + ValtypeSize[valtype] ]
3398
3293
  ];
3399
3294
  };
3400
3295
 
3401
- const loadArray = (scope, array, index, aotPointer = null) => {
3296
+ const loadArray = (scope, array, index) => {
3402
3297
  if (typeof index === 'number') index = number(index);
3403
3298
 
3404
3299
  const offset = localTmp(scope, '#loadArray_offset', Valtype.i32);
@@ -3409,20 +3304,19 @@ const loadArray = (scope, array, index, aotPointer = null) => {
3409
3304
  Opcodes.i32_to_u,
3410
3305
  ...number(ValtypeSize[valtype] + 1, Valtype.i32),
3411
3306
  [ Opcodes.i32_mul ],
3412
- ...(aotPointer ? [] : [
3413
- ...array,
3414
- Opcodes.i32_to_u,
3415
- [ Opcodes.i32_add ],
3416
- ]),
3307
+
3308
+ ...array,
3309
+ Opcodes.i32_to_u,
3310
+ [ Opcodes.i32_add ],
3417
3311
  [ Opcodes.local_set, offset ],
3418
3312
 
3419
3313
  // load value
3420
3314
  [ Opcodes.local_get, offset ],
3421
- [ Opcodes.load, 0, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ],
3315
+ [ Opcodes.load, 0, ValtypeSize.i32 ],
3422
3316
 
3423
3317
  // load type
3424
3318
  [ Opcodes.local_get, offset ],
3425
- [ Opcodes.i32_load8_u, 0, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32 + ValtypeSize[valtype]) ]
3319
+ [ Opcodes.i32_load8_u, 0, ValtypeSize.i32 + ValtypeSize[valtype] ]
3426
3320
  ];
3427
3321
  };
3428
3322
 
@@ -3454,7 +3348,7 @@ const makeString = (scope, str, global = false, name = '$undeclared', forceBytes
3454
3348
  };
3455
3349
 
3456
3350
  const generateArray = (scope, decl, global = false, name = '$undeclared', initEmpty = false) => {
3457
- return makeArray(scope, decl, global, name, initEmpty, valtype, true)[0];
3351
+ return makeArray(scope, decl, global, name, initEmpty, valtype, false, true)[0];
3458
3352
  };
3459
3353
 
3460
3354
  const generateObject = (scope, decl, global = false, name = '$undeclared') => {
@@ -3473,9 +3367,6 @@ const withType = (scope, wasm, type) => [
3473
3367
 
3474
3368
  const generateMember = (scope, decl, _global, _name) => {
3475
3369
  const name = decl.object.name;
3476
- const pointer = scope.arrays?.get(name);
3477
-
3478
- const aotPointer = Prefs.aotPointerOpt && pointer;
3479
3370
 
3480
3371
  // hack: .name
3481
3372
  if (decl.property.name === 'name') {
@@ -3510,18 +3401,16 @@ const generateMember = (scope, decl, _global, _name) => {
3510
3401
  }
3511
3402
 
3512
3403
  if (builtinFuncs[name]) return withType(scope, number(builtinFuncs[name].typedParams ? (builtinFuncs[name].params.length / 2) : builtinFuncs[name].params.length), TYPES.number);
3513
- if (importedFuncs[name]) return withType(scope, number(importedFuncs[name].params), TYPES.number);
3404
+ if (importedFuncs[name]) return withType(scope, number(importedFuncs[name].params.length ?? importedFuncs[name].params), TYPES.number);
3514
3405
  if (internalConstrs[name]) return withType(scope, number(internalConstrs[name].length ?? 0), TYPES.number);
3515
3406
 
3516
3407
  if (Prefs.fastLength) {
3517
3408
  // presume valid length object
3518
3409
  return [
3519
- ...(aotPointer ? number(0, Valtype.i32) : [
3520
- ...generate(scope, decl.object),
3521
- Opcodes.i32_to_u
3522
- ]),
3410
+ ...generate(scope, decl.object),
3411
+ Opcodes.i32_to_u,
3523
3412
 
3524
- [ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, ...unsignedLEB128(aotPointer ? pointer : 0) ],
3413
+ [ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
3525
3414
  Opcodes.i32_from_u
3526
3415
  ];
3527
3416
  }
@@ -3530,12 +3419,10 @@ const generateMember = (scope, decl, _global, _name) => {
3530
3419
  const known = knownType(scope, type);
3531
3420
  if (known != null) {
3532
3421
  if ([ TYPES.string, TYPES.bytestring, TYPES.array ].includes(known)) return [
3533
- ...(aotPointer ? number(0, Valtype.i32) : [
3534
- ...generate(scope, decl.object),
3535
- Opcodes.i32_to_u
3536
- ]),
3422
+ ...generate(scope, decl.object),
3423
+ Opcodes.i32_to_u,
3537
3424
 
3538
- [ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, ...unsignedLEB128(aotPointer ? pointer : 0) ],
3425
+ [ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
3539
3426
  Opcodes.i32_from_u
3540
3427
  ];
3541
3428
 
@@ -3545,12 +3432,10 @@ const generateMember = (scope, decl, _global, _name) => {
3545
3432
  return [
3546
3433
  ...typeIsOneOf(getNodeType(scope, decl.object), [ TYPES.string, TYPES.bytestring, TYPES.array ]),
3547
3434
  [ Opcodes.if, valtypeBinary ],
3548
- ...(aotPointer ? number(0, Valtype.i32) : [
3549
- ...generate(scope, decl.object),
3550
- Opcodes.i32_to_u
3551
- ]),
3435
+ ...generate(scope, decl.object),
3436
+ Opcodes.i32_to_u,
3552
3437
 
3553
- [ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, ...unsignedLEB128(aotPointer ? pointer : 0) ],
3438
+ [ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
3554
3439
  Opcodes.i32_from_u,
3555
3440
 
3556
3441
  ...setLastType(scope, TYPES.number),
@@ -3593,25 +3478,29 @@ const generateMember = (scope, decl, _global, _name) => {
3593
3478
 
3594
3479
  // // todo: we should only do this for strings but we don't know at compile-time :(
3595
3480
  // hack: this is naughty and will break things!
3596
- let newOut = number(0, valtypeBinary), newPointer = -1;
3481
+ let newOut = number(0, Valtype.i32), newPointer = number(0, Valtype.i32);
3597
3482
  if (pages.hasAnyString) {
3483
+ // todo: we use i16 even for bytestrings which should not make a bad thing happen, just be confusing for debugging?
3598
3484
  0, [ newOut, newPointer ] = makeArray(scope, {
3599
- rawElements: new Array(1)
3600
- }, _global, _name, true, 'i16');
3485
+ rawElements: new Array(0)
3486
+ }, _global, _name, true, 'i16', true);
3601
3487
  }
3602
3488
 
3603
3489
  return typeSwitch(scope, getNodeType(scope, decl.object), {
3604
3490
  [TYPES.array]: [
3605
- ...loadArray(scope, object, property, aotPointer),
3491
+ ...loadArray(scope, object, property),
3606
3492
  ...setLastType(scope)
3607
3493
  ],
3608
-
3609
3494
  [TYPES.string]: [
3610
3495
  // setup new/out array
3611
3496
  ...newOut,
3612
- [ Opcodes.drop ],
3613
3497
 
3614
- ...number(0, Valtype.i32), // base 0 for store later
3498
+ // set length to 1
3499
+ ...number(1, Valtype.i32),
3500
+ [ Opcodes.i32_store, 0, 0 ],
3501
+
3502
+ // use as pointer for store later
3503
+ ...newPointer,
3615
3504
 
3616
3505
  ...property,
3617
3506
  Opcodes.i32_to_u,
@@ -3619,46 +3508,48 @@ const generateMember = (scope, decl, _global, _name) => {
3619
3508
  ...number(ValtypeSize.i16, Valtype.i32),
3620
3509
  [ Opcodes.i32_mul ],
3621
3510
 
3622
- ...(aotPointer ? [] : [
3623
- ...object,
3624
- Opcodes.i32_to_u,
3625
- [ Opcodes.i32_add ]
3626
- ]),
3511
+ ...object,
3512
+ Opcodes.i32_to_u,
3513
+ [ Opcodes.i32_add ],
3627
3514
 
3628
3515
  // load current string ind {arg}
3629
- [ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ],
3516
+ [ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],
3630
3517
 
3631
3518
  // store to new string ind 0
3632
- [ Opcodes.i32_store16, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128(newPointer + ValtypeSize.i32) ],
3519
+ [ Opcodes.i32_store16, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],
3633
3520
 
3634
3521
  // return new string (page)
3635
- ...number(newPointer),
3522
+ ...newPointer,
3523
+ Opcodes.i32_from_u,
3636
3524
  ...setLastType(scope, TYPES.string)
3637
3525
  ],
3638
3526
  [TYPES.bytestring]: [
3639
3527
  // setup new/out array
3640
3528
  ...newOut,
3641
- [ Opcodes.drop ],
3642
3529
 
3643
- ...number(0, Valtype.i32), // base 0 for store later
3530
+ // set length to 1
3531
+ ...number(1, Valtype.i32),
3532
+ [ Opcodes.i32_store, 0, 0 ],
3533
+
3534
+ // use as pointer for store later
3535
+ ...newPointer,
3644
3536
 
3645
3537
  ...property,
3646
3538
  Opcodes.i32_to_u,
3647
3539
 
3648
- ...(aotPointer ? [] : [
3649
- ...object,
3650
- Opcodes.i32_to_u,
3651
- [ Opcodes.i32_add ]
3652
- ]),
3540
+ ...object,
3541
+ Opcodes.i32_to_u,
3542
+ [ Opcodes.i32_add ],
3653
3543
 
3654
3544
  // load current string ind {arg}
3655
- [ Opcodes.i32_load8_u, 0, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ],
3545
+ [ Opcodes.i32_load8_u, 0, ValtypeSize.i32 ],
3656
3546
 
3657
3547
  // store to new string ind 0
3658
- [ Opcodes.i32_store8, 0, ...unsignedLEB128(newPointer + ValtypeSize.i32) ],
3548
+ [ Opcodes.i32_store8, 0, ValtypeSize.i32 ],
3659
3549
 
3660
3550
  // return new string (page)
3661
- ...number(newPointer),
3551
+ ...newPointer,
3552
+ Opcodes.i32_from_u,
3662
3553
  ...setLastType(scope, TYPES.bytestring)
3663
3554
  ],
3664
3555
 
@@ -3666,7 +3557,7 @@ const generateMember = (scope, decl, _global, _name) => {
3666
3557
  });
3667
3558
  };
3668
3559
 
3669
- const randId = () => Math.random().toString(16).slice(0, -4);
3560
+ const randId = () => Math.random().toString(16).slice(1, -2).padEnd(12, '0');
3670
3561
 
3671
3562
  const objectHack = node => {
3672
3563
  if (!node) return node;
@@ -3718,7 +3609,7 @@ const generateFunc = (scope, decl) => {
3718
3609
  if (decl.async) return todo(scope, 'async functions are not supported');
3719
3610
  if (decl.generator) return todo(scope, 'generator functions are not supported');
3720
3611
 
3721
- const name = decl.id ? decl.id.name : `anonymous_${randId()}`;
3612
+ const name = decl.id ? decl.id.name : `anonymous${randId()}`;
3722
3613
  const params = decl.params ?? [];
3723
3614
 
3724
3615
  // TODO: share scope/locals between !!!
@@ -3814,12 +3705,13 @@ const internalConstrs = {
3814
3705
  if (literalValue < 0 || !Number.isFinite(literalValue) || literalValue > 4294967295) return internalThrow(scope, 'RangeThrow', 'Invalid array length', true);
3815
3706
 
3816
3707
  return [
3817
- ...number(0, Valtype.i32),
3708
+ ...pointer,
3818
3709
  ...generate(scope, arg, global, name),
3819
3710
  Opcodes.i32_to_u,
3820
- [ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, ...unsignedLEB128(pointer) ],
3711
+ [ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, 0 ],
3821
3712
 
3822
- ...number(pointer)
3713
+ ...pointer,
3714
+ Opcodes.i32_from_u
3823
3715
  ];
3824
3716
  },
3825
3717
  type: TYPES.array,
@@ -3968,8 +3860,9 @@ const internalConstrs = {
3968
3860
  };
3969
3861
 
3970
3862
  export default program => {
3971
- globals = {};
3972
- globalInd = 0;
3863
+ globals = {
3864
+ ['#ind']: 0
3865
+ };
3973
3866
  tags = [];
3974
3867
  exceptions = [];
3975
3868
  funcs = [];
@@ -3979,19 +3872,8 @@ export default program => {
3979
3872
  data = [];
3980
3873
  currentFuncIndex = importedFuncs.length;
3981
3874
 
3982
- globalThis.valtype = 'f64';
3983
-
3984
- const valtypeOpt = process.argv.find(x => x.startsWith('--valtype='));
3985
- if (valtypeOpt) valtype = valtypeOpt.split('=')[1];
3986
-
3987
- globalThis.valtypeBinary = Valtype[valtype];
3988
-
3989
3875
  const valtypeInd = ['i32', 'i64', 'f64'].indexOf(valtype);
3990
3876
 
3991
- globalThis.pageSize = PageSize;
3992
- const pageSizeOpt = process.argv.find(x => x.startsWith('--page-size='));
3993
- if (pageSizeOpt) pageSize = parseInt(pageSizeOpt.split('=')[1]) * 1024;
3994
-
3995
3877
  // set generic opcodes for current valtype
3996
3878
  Opcodes.const = [ Opcodes.i32_const, Opcodes.i64_const, Opcodes.f64_const ][valtypeInd];
3997
3879
  Opcodes.eq = [ Opcodes.i32_eq, Opcodes.i64_eq, Opcodes.f64_eq ][valtypeInd];
@@ -4013,6 +3895,7 @@ export default program => {
4013
3895
  builtinFuncs = new BuiltinFuncs();
4014
3896
  builtinVars = new BuiltinVars();
4015
3897
  prototypeFuncs = new PrototypeFuncs();
3898
+ allocator = Allocator(Prefs.allocator ?? 'static');
4016
3899
 
4017
3900
  program.id = { name: 'main' };
4018
3901
 
@@ -4055,6 +3938,8 @@ export default program => {
4055
3938
  else main.returns = [];
4056
3939
  }
4057
3940
 
3941
+ delete globals['#ind'];
3942
+
4058
3943
  // if blank main func and other exports, remove it
4059
3944
  if (main.wasm.length === 0 && funcs.reduce((acc, x) => acc + (x.export ? 1 : 0), 0) > 1) funcs.splice(main.index - importedFuncs.length, 1);
4060
3945