porffor 0.16.0-6572d1c74 → 0.16.0-7143cc59c

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 makeAllocator from './allocators.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) {
@@ -32,11 +33,6 @@ const todo = (scope, msg, expectsValue = undefined) => {
32
33
 
33
34
  case 'runtime':
34
35
  return internalThrow(scope, 'TodoError', msg, expectsValue);
35
-
36
- // return [
37
- // ...debug(`todo! ${msg}`),
38
- // [ Opcodes.unreachable ]
39
- // ];
40
36
  }
41
37
  };
42
38
 
@@ -181,12 +177,6 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
181
177
  continue;
182
178
  }
183
179
 
184
- if (asm[0] === 'memory') {
185
- allocPage(scope, 'asm instrinsic');
186
- // todo: add to store/load offset insts
187
- continue;
188
- }
189
-
190
180
  let inst = Opcodes[asm[0].replace('.', '_')];
191
181
  if (inst == null) throw new Error(`inline asm: inst ${asm[0]} not found`);
192
182
 
@@ -433,63 +423,12 @@ const concatStrings = (scope, left, right, global, name, assign = false, bytestr
433
423
  const rightLength = localTmp(scope, 'concat_right_length', Valtype.i32);
434
424
  const leftLength = localTmp(scope, 'concat_left_length', Valtype.i32);
435
425
 
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
426
  const leftPointer = localTmp(scope, 'concat_left_pointer', Valtype.i32);
488
427
 
489
428
  // alloc/assign array
490
- const [ , pointer ] = makeArray(scope, {
429
+ const [ out, pointer ] = makeArray(scope, {
491
430
  rawElements: new Array(0)
492
- }, global, name, true, 'i16');
431
+ }, global, name, true, 'i16', true);
493
432
 
494
433
  return [
495
434
  // setup left
@@ -503,7 +442,7 @@ const concatStrings = (scope, left, right, global, name, assign = false, bytestr
503
442
  [ Opcodes.local_set, rightPointer ],
504
443
 
505
444
  // calculate length
506
- ...number(0, Valtype.i32), // base 0 for store later
445
+ ...out,
507
446
 
508
447
  [ Opcodes.local_get, leftPointer ],
509
448
  [ Opcodes.i32_load, 0, ...unsignedLEB128(0) ],
@@ -516,11 +455,13 @@ const concatStrings = (scope, left, right, global, name, assign = false, bytestr
516
455
  [ Opcodes.i32_add ],
517
456
 
518
457
  // store length
519
- [ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, ...unsignedLEB128(pointer) ],
458
+ [ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, 0 ],
520
459
 
521
460
  // copy left
522
461
  // dst = out pointer + length size
523
- ...number(pointer + ValtypeSize.i32, Valtype.i32),
462
+ ...pointer,
463
+ ...number(ValtypeSize.i32, Valtype.i32),
464
+ [ Opcodes.i32_add ],
524
465
 
525
466
  // src = left pointer + length size
526
467
  [ Opcodes.local_get, leftPointer ],
@@ -533,7 +474,9 @@ const concatStrings = (scope, left, right, global, name, assign = false, bytestr
533
474
 
534
475
  // copy right
535
476
  // dst = out pointer + length size + left length * sizeof valtype
536
- ...number(pointer + ValtypeSize.i32, Valtype.i32),
477
+ ...pointer,
478
+ ...number(ValtypeSize.i32, Valtype.i32),
479
+ [ Opcodes.i32_add ],
537
480
 
538
481
  [ Opcodes.local_get, leftLength ],
539
482
  ...number(bytestrings ? ValtypeSize.i8 : ValtypeSize.i16, Valtype.i32),
@@ -553,7 +496,8 @@ const concatStrings = (scope, left, right, global, name, assign = false, bytestr
553
496
  [ ...Opcodes.memory_copy, 0x00, 0x00 ],
554
497
 
555
498
  // return new string (page)
556
- ...number(pointer)
499
+ ...pointer,
500
+ Opcodes.i32_from_u
557
501
  ];
558
502
  };
559
503
 
@@ -669,10 +613,10 @@ const compareStrings = (scope, left, right, bytestrings = false) => {
669
613
  };
670
614
 
671
615
  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
- ];
616
+ // if (isIntToFloatOp(wasm[wasm.length - 1])) return [
617
+ // ...wasm,
618
+ // ...(!intIn && intOut ? [ Opcodes.i32_to_u ] : [])
619
+ // ];
676
620
  // if (isIntOp(wasm[wasm.length - 1])) return [ ...wasm ];
677
621
 
678
622
  // todo/perf: use knownType and custom bytecode here instead of typeSwitch
@@ -1054,7 +998,7 @@ const asmFuncToAsm = (func, scope) => {
1054
998
  });
1055
999
  };
1056
1000
 
1057
- const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes = [], globalInits, returns, returnType, localNames = [], globalNames = [], data: _data = [], table = false }) => {
1001
+ const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes = [], globalInits = [], returns, returnType, localNames = [], globalNames = [], data: _data = [], table = false }) => {
1058
1002
  const existing = funcs.find(x => x.name === name);
1059
1003
  if (existing) return existing;
1060
1004
 
@@ -1068,7 +1012,7 @@ const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes
1068
1012
 
1069
1013
  for (const x of _data) {
1070
1014
  const copy = { ...x };
1071
- copy.offset += pages.size * pageSize;
1015
+ if (copy.offset != null) copy.offset += pages.size * pageSize;
1072
1016
  data.push(copy);
1073
1017
  }
1074
1018
 
@@ -1091,9 +1035,9 @@ const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes
1091
1035
 
1092
1036
  let baseGlobalIdx, i = 0;
1093
1037
  for (const type of globalTypes) {
1094
- if (baseGlobalIdx === undefined) baseGlobalIdx = globalInd;
1038
+ if (baseGlobalIdx === undefined) baseGlobalIdx = globals['#ind'];
1095
1039
 
1096
- globals[globalNames[i] ?? `${name}_global_${i}`] = { idx: globalInd++, type, init: globalInits[i] ?? 0 };
1040
+ globals[globalNames[i] ?? `${name}_global_${i}`] = { idx: globals['#ind']++, type, init: globalInits[i] ?? 0 };
1097
1041
  i++;
1098
1042
  }
1099
1043
 
@@ -1106,11 +1050,15 @@ const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes
1106
1050
  }
1107
1051
  }
1108
1052
 
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));
1053
+ if (table) {
1054
+ for (const inst of wasm) {
1055
+ if (inst[0] === Opcodes.i32_load16_u && inst.at(-1) === 'read_argc') {
1056
+ inst.splice(2, 99);
1057
+ inst.push(...unsignedLEB128(allocPage({}, 'func argc lut') * pageSize));
1058
+ }
1113
1059
  }
1060
+
1061
+ funcs.table = true;
1114
1062
  }
1115
1063
 
1116
1064
  func.wasm = wasm;
@@ -1450,10 +1398,10 @@ const countLeftover = wasm => {
1450
1398
 
1451
1399
  if (depth === 0)
1452
1400
  if ([Opcodes.throw, Opcodes.drop, Opcodes.local_set, Opcodes.global_set].includes(inst[0])) count--;
1453
- else if ([null, Opcodes.i32_eqz, Opcodes.i64_eqz, Opcodes.f64_ceil, Opcodes.f64_floor, Opcodes.f64_trunc, Opcodes.f64_nearest, Opcodes.f64_sqrt, Opcodes.local_tee, Opcodes.i32_wrap_i64, Opcodes.i64_extend_i32_s, Opcodes.i64_extend_i32_u, Opcodes.f32_demote_f64, Opcodes.f64_promote_f32, Opcodes.f64_convert_i32_s, Opcodes.f64_convert_i32_u, Opcodes.i32_clz, Opcodes.i32_ctz, Opcodes.i32_popcnt, Opcodes.f64_neg, Opcodes.end, Opcodes.i32_trunc_sat_f64_s[0], Opcodes.i32x4_extract_lane, Opcodes.i16x8_extract_lane, Opcodes.i32_load, Opcodes.i64_load, Opcodes.f64_load, Opcodes.v128_load, Opcodes.i32_load16_u, Opcodes.i32_load16_s, Opcodes.i32_load8_u, Opcodes.i32_load8_s, Opcodes.memory_grow].includes(inst[0]) && (inst[0] !== 0xfc || inst[1] < 0x0a)) {}
1401
+ else if ([null, Opcodes.i32_eqz, Opcodes.i64_eqz, Opcodes.f64_ceil, Opcodes.f64_floor, Opcodes.f64_trunc, Opcodes.f64_nearest, Opcodes.f64_sqrt, Opcodes.local_tee, Opcodes.i32_wrap_i64, Opcodes.i64_extend_i32_s, Opcodes.i64_extend_i32_u, Opcodes.f32_demote_f64, Opcodes.f64_promote_f32, Opcodes.f64_convert_i32_s, Opcodes.f64_convert_i32_u, Opcodes.i32_clz, Opcodes.i32_ctz, Opcodes.i32_popcnt, Opcodes.f64_neg, Opcodes.end, Opcodes.i32_trunc_sat_f64_s[0], Opcodes.i32x4_extract_lane, Opcodes.i16x8_extract_lane, Opcodes.i32_load, Opcodes.i64_load, Opcodes.f64_load, Opcodes.v128_load, Opcodes.i32_load16_u, Opcodes.i32_load16_s, Opcodes.i32_load8_u, Opcodes.i32_load8_s, Opcodes.memory_grow].includes(inst[0]) && (inst[0] !== 0xfc || inst[1] < 0x04)) {}
1454
1402
  else if ([Opcodes.local_get, Opcodes.global_get, Opcodes.f64_const, Opcodes.i32_const, Opcodes.i64_const, Opcodes.v128_const, Opcodes.memory_size].includes(inst[0])) count++;
1455
1403
  else if ([Opcodes.i32_store, Opcodes.i64_store, Opcodes.f64_store, Opcodes.i32_store16, Opcodes.i32_store8].includes(inst[0])) count -= 2;
1456
- else if (Opcodes.memory_copy[0] === inst[0] && Opcodes.memory_copy[1] === inst[1]) count -= 3;
1404
+ else if (inst[0] === Opcodes.memory_copy[0] && (inst[1] === Opcodes.memory_copy[1] || inst[1] === Opcodes.memory_init[1])) count -= 3;
1457
1405
  else if (inst[0] === Opcodes.return) count = 0;
1458
1406
  else if (inst[0] === Opcodes.call) {
1459
1407
  let func = funcs.find(x => x.index === inst[1]);
@@ -1725,7 +1673,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
1725
1673
  }, generate(scope, decl.arguments[0] ?? DEFAULT_VALUE), getNodeType(scope, decl.arguments[0] ?? DEFAULT_VALUE), protoLocal, protoLocal2, (length, itemType) => {
1726
1674
  return makeArray(scope, {
1727
1675
  rawElements: new Array(length)
1728
- }, _global, _name, true, itemType);
1676
+ }, _global, _name, true, itemType, true);
1729
1677
  }, () => {
1730
1678
  optUnused = true;
1731
1679
  return unusedValue;
@@ -2115,7 +2063,6 @@ const brTable = (input, bc, returns) => {
2115
2063
  }
2116
2064
 
2117
2065
  for (let i = 0; i < count; i++) {
2118
- // if (i === 0) out.push([ Opcodes.block, returns, 'br table start' ]);
2119
2066
  if (i === 0) out.push([ Opcodes.block, returns ]);
2120
2067
  else out.push([ Opcodes.block, Blocktype.void ]);
2121
2068
  }
@@ -2149,10 +2096,8 @@ const brTable = (input, bc, returns) => {
2149
2096
  [ Opcodes.br_table, ...encodeVector(table), 0 ]
2150
2097
  );
2151
2098
 
2152
- // if you can guess why we sort the wrong way and then reverse
2153
- // (instead of just sorting the correct way)
2154
- // dm me and if you are correct and the first person
2155
- // I will somehow shout you out or something
2099
+ // sort the wrong way and then reverse
2100
+ // so strings ('default') are at the start before any numbers
2156
2101
  const orderedBc = keys.sort((a, b) => b - a).reverse();
2157
2102
 
2158
2103
  br = count - 1;
@@ -2178,7 +2123,7 @@ const typeSwitch = (scope, type, bc, returns = valtypeBinary) => {
2178
2123
  return bc[known] ?? bc.default;
2179
2124
  }
2180
2125
 
2181
- if (Prefs.typeswitchUseBrtable)
2126
+ if (Prefs.typeswitchBrtable)
2182
2127
  return brTable(type, bc, returns);
2183
2128
 
2184
2129
  const tmp = localTmp(scope, '#typeswitch_tmp' + (Prefs.typeswitchUniqueTmp ? randId() : ''), Valtype.i32);
@@ -2233,11 +2178,11 @@ const allocVar = (scope, name, global = false, type = true) => {
2233
2178
  return target[name].idx;
2234
2179
  }
2235
2180
 
2236
- let idx = global ? globalInd++ : scope.localInd++;
2181
+ let idx = global ? globals['#ind']++ : scope.localInd++;
2237
2182
  target[name] = { idx, type: valtypeBinary };
2238
2183
 
2239
2184
  if (type) {
2240
- let typeIdx = global ? globalInd++ : scope.localInd++;
2185
+ let typeIdx = global ? globals['#ind']++ : scope.localInd++;
2241
2186
  target[name + '#type'] = { idx: typeIdx, type: Valtype.i32, name };
2242
2187
  }
2243
2188
 
@@ -2330,24 +2275,10 @@ const generateVar = (scope, decl) => {
2330
2275
  }
2331
2276
 
2332
2277
  if (x.init) {
2333
- // if (isFuncType(x.init.type)) {
2334
- // // let a = function () { ... }
2335
- // x.init.id = { name };
2336
-
2337
- // const func = generateFunc(scope, x.init);
2338
-
2339
- // out.push(
2340
- // ...number(func.index - importedFuncs.length),
2341
- // [ global ? Opcodes.global_set : Opcodes.local_set, idx ],
2342
-
2343
- // ...setType(scope, name, TYPES.function)
2344
- // );
2345
-
2346
- // continue;
2347
- // }
2278
+ const alreadyArray = scope.arrays?.get(name) != null;
2348
2279
 
2349
2280
  const generated = generate(scope, x.init, global, name);
2350
- if (scope.arrays?.get(name) != null) {
2281
+ if (!alreadyArray && scope.arrays?.get(name) != null) {
2351
2282
  // hack to set local as pointer before
2352
2283
  out.push(...number(scope.arrays.get(name)), [ global ? Opcodes.global_set : Opcodes.local_set, idx ]);
2353
2284
  if (generated.at(-1) == Opcodes.i32_from_u) generated.pop();
@@ -2399,19 +2330,12 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
2399
2330
 
2400
2331
  // hack: .length setter
2401
2332
  if (decl.left.type === 'MemberExpression' && decl.left.property.name === 'length') {
2402
- const name = decl.left.object.name;
2403
- const pointer = scope.arrays?.get(name);
2404
-
2405
- const aotPointer = Prefs.aotPointerOpt && pointer != null;
2406
-
2407
2333
  const newValueTmp = localTmp(scope, '__length_setter_tmp');
2408
2334
  const pointerTmp = op === '=' ? null : localTmp(scope, '__member_setter_ptr_tmp', Valtype.i32);
2409
2335
 
2410
2336
  return [
2411
- ...(aotPointer ? number(0, Valtype.i32) : [
2412
- ...generate(scope, decl.left.object),
2413
- Opcodes.i32_to_u
2414
- ]),
2337
+ ...generate(scope, decl.left.object),
2338
+ Opcodes.i32_to_u,
2415
2339
  ...(!pointerTmp ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
2416
2340
 
2417
2341
  ...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
@@ -2422,7 +2346,7 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
2422
2346
  [ Opcodes.local_tee, newValueTmp ],
2423
2347
 
2424
2348
  Opcodes.i32_to_u,
2425
- [ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, ...unsignedLEB128(aotPointer ? pointer : 0) ],
2349
+ [ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, 0 ],
2426
2350
 
2427
2351
  [ Opcodes.local_get, newValueTmp ]
2428
2352
  ];
@@ -2430,21 +2354,14 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
2430
2354
 
2431
2355
  // arr[i]
2432
2356
  if (decl.left.type === 'MemberExpression' && decl.left.computed) {
2433
- const name = decl.left.object.name;
2434
- const pointer = scope.arrays?.get(name);
2435
-
2436
- const aotPointer = Prefs.aotPointerOpt && pointer != null;
2437
-
2438
2357
  const newValueTmp = localTmp(scope, '__member_setter_val_tmp');
2439
2358
  const pointerTmp = op === '=' ? -1 : localTmp(scope, '__member_setter_ptr_tmp', Valtype.i32);
2440
2359
 
2441
2360
  return [
2442
2361
  ...typeSwitch(scope, getNodeType(scope, decl.left.object), {
2443
2362
  [TYPES.array]: [
2444
- ...(aotPointer ? [] : [
2445
- ...generate(scope, decl.left.object),
2446
- Opcodes.i32_to_u
2447
- ]),
2363
+ ...generate(scope, decl.left.object),
2364
+ Opcodes.i32_to_u,
2448
2365
 
2449
2366
  // get index as valtype
2450
2367
  ...generate(scope, decl.left.property),
@@ -2453,39 +2370,22 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
2453
2370
  // turn into byte offset by * valtypeSize (4 for i32, 8 for i64/f64)
2454
2371
  ...number(ValtypeSize[valtype] + 1, Valtype.i32),
2455
2372
  [ Opcodes.i32_mul ],
2456
- ...(aotPointer ? [] : [ [ Opcodes.i32_add ] ]),
2373
+ [ Opcodes.i32_add ],
2457
2374
  ...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
2458
2375
 
2459
2376
  ...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
2460
2377
  [ Opcodes.local_get, pointerTmp ],
2461
- [ Opcodes.load, 0, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ]
2378
+ [ Opcodes.load, 0, ValtypeSize.i32 ]
2462
2379
  ], generate(scope, decl.right), [
2463
2380
  [ Opcodes.local_get, pointerTmp ],
2464
- [ Opcodes.i32_load8_u, 0, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32 + ValtypeSize[valtype]) ]
2381
+ [ Opcodes.i32_load8_u, 0, ValtypeSize.i32 + ValtypeSize[valtype] ]
2465
2382
  ], getNodeType(scope, decl.right), false, name, true)),
2466
2383
  [ Opcodes.local_tee, newValueTmp ],
2467
2384
 
2468
- [ Opcodes.store, 0, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ]
2385
+ [ Opcodes.store, 0, ValtypeSize.i32 ]
2469
2386
  ],
2470
2387
 
2471
2388
  default: internalThrow(scope, 'TypeError', `Cannot assign member with non-array`)
2472
-
2473
- // [TYPES.string]: [
2474
- // // turn into byte offset by * sizeof i16
2475
- // ...number(ValtypeSize.i16, Valtype.i32),
2476
- // [ Opcodes.i32_mul ],
2477
- // ...(aotPointer ? [] : [ [ Opcodes.i32_add ] ]),
2478
- // ...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
2479
-
2480
- // ...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
2481
- // [ Opcodes.local_get, pointerTmp ],
2482
- // [ Opcodes.load, Math.log2(ValtypeSize[valtype]) - 1, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ]
2483
- // ], generate(scope, decl.right), number(TYPES.string, Valtype.i32), getNodeType(scope, decl.right))),
2484
- // [ Opcodes.local_tee, newValueTmp ],
2485
-
2486
- // Opcodes.i32_to_u,
2487
- // [ StoreOps.i16, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ]
2488
- // ]
2489
2389
  }, Blocktype.void),
2490
2390
 
2491
2391
  [ Opcodes.local_get, newValueTmp ]
@@ -2869,12 +2769,12 @@ const generateForOf = (scope, decl) => {
2869
2769
 
2870
2770
  // // todo: we should only do this for strings but we don't know at compile-time :(
2871
2771
  // hack: this is naughty and will break things!
2872
- let newOut = number(0, Valtype.f64), newPointer = -1;
2772
+ let newOut = number(0, Valtype.i32), newPointer = number(0, Valtype.i32);
2873
2773
  if (pages.hasAnyString) {
2874
2774
  // todo: we use i16 even for bytestrings which should not make a bad thing happen, just be confusing for debugging?
2875
2775
  0, [ newOut, newPointer ] = makeArray(scope, {
2876
- rawElements: new Array(1)
2877
- }, isGlobal, leftName, true, 'i16');
2776
+ rawElements: new Array(0)
2777
+ }, isGlobal, leftName, true, 'i16', true);
2878
2778
  }
2879
2779
 
2880
2780
  // set type for local
@@ -2921,23 +2821,28 @@ const generateForOf = (scope, decl) => {
2921
2821
  [TYPES.string]: [
2922
2822
  ...setType(scope, leftName, TYPES.string),
2923
2823
 
2924
- [ Opcodes.loop, Blocktype.void ],
2925
-
2926
2824
  // setup new/out array
2927
2825
  ...newOut,
2928
- [ Opcodes.drop ],
2929
2826
 
2930
- ...number(0, Valtype.i32), // base 0 for store after
2827
+ // set length to 1
2828
+ ...number(1, Valtype.i32),
2829
+ [ Opcodes.i32_store, 0, 0 ],
2830
+
2831
+ [ Opcodes.loop, Blocktype.void ],
2832
+
2833
+ // use as pointer for store later
2834
+ ...newPointer,
2931
2835
 
2932
2836
  // load current string ind {arg}
2933
2837
  [ Opcodes.local_get, pointer ],
2934
- [ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128(ValtypeSize.i32) ],
2838
+ [ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],
2935
2839
 
2936
2840
  // store to new string ind 0
2937
- [ Opcodes.i32_store16, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128(newPointer + ValtypeSize.i32) ],
2841
+ [ Opcodes.i32_store16, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],
2938
2842
 
2939
2843
  // return new string (page)
2940
- ...number(newPointer),
2844
+ ...newPointer,
2845
+ Opcodes.i32_from_u,
2941
2846
 
2942
2847
  [ isGlobal ? Opcodes.global_set : Opcodes.local_set, local.idx ],
2943
2848
 
@@ -2969,25 +2874,30 @@ const generateForOf = (scope, decl) => {
2969
2874
  [TYPES.bytestring]: [
2970
2875
  ...setType(scope, leftName, TYPES.bytestring),
2971
2876
 
2972
- [ Opcodes.loop, Blocktype.void ],
2973
-
2974
2877
  // setup new/out array
2975
2878
  ...newOut,
2976
- [ Opcodes.drop ],
2977
2879
 
2978
- ...number(0, Valtype.i32), // base 0 for store after
2880
+ // set length to 1
2881
+ ...number(1, Valtype.i32),
2882
+ [ Opcodes.i32_store, 0, 0 ],
2883
+
2884
+ [ Opcodes.loop, Blocktype.void ],
2885
+
2886
+ // use as pointer for store later
2887
+ ...newPointer,
2979
2888
 
2980
2889
  // load current string ind {arg}
2981
2890
  [ Opcodes.local_get, pointer ],
2982
2891
  [ Opcodes.local_get, counter ],
2983
2892
  [ Opcodes.i32_add ],
2984
- [ Opcodes.i32_load8_u, 0, ...unsignedLEB128(ValtypeSize.i32) ],
2893
+ [ Opcodes.i32_load8_u, 0, ValtypeSize.i32 ],
2985
2894
 
2986
2895
  // store to new string ind 0
2987
- [ Opcodes.i32_store8, 0, ...unsignedLEB128(newPointer + ValtypeSize.i32) ],
2896
+ [ Opcodes.i32_store8, 0, ValtypeSize.i32 ],
2988
2897
 
2989
2898
  // return new string (page)
2990
- ...number(newPointer),
2899
+ ...newPointer,
2900
+ Opcodes.i32_from_u,
2991
2901
 
2992
2902
  [ isGlobal ? Opcodes.global_set : Opcodes.local_set, local.idx ],
2993
2903
 
@@ -3202,18 +3112,6 @@ const allocPage = (scope, reason, type) => {
3202
3112
  scope.pages ??= new Map();
3203
3113
  scope.pages.set(reason, { ind, type });
3204
3114
 
3205
- if (Prefs.allocLog) log('alloc', `allocated new page of memory (${ind}) | ${reason} (type: ${type})`);
3206
-
3207
- return ind;
3208
- };
3209
-
3210
- // todo: add scope.pages
3211
- const freePage = reason => {
3212
- const { ind } = pages.get(reason);
3213
- pages.delete(reason);
3214
-
3215
- if (Prefs.allocLog) log('alloc', `freed page of memory (${ind}) | ${reason}`);
3216
-
3217
3115
  return ind;
3218
3116
  };
3219
3117
 
@@ -3251,39 +3149,58 @@ const compileBytes = (val, itemType) => {
3251
3149
  }
3252
3150
  };
3253
3151
 
3254
- const getAllocType = itemType => {
3255
- switch (itemType) {
3256
- case 'i8': return 'bytestring';
3257
- case 'i16': return 'string';
3152
+ const makeData = (scope, elements, offset = null, itemType, initEmpty) => {
3153
+ const length = elements.length;
3154
+
3155
+ // if length is 0 memory/data will just be 0000... anyway
3156
+ if (length === 0) return false;
3157
+
3158
+ let bytes = compileBytes(length, 'i32');
3258
3159
 
3259
- default: return 'array';
3160
+ if (!initEmpty) for (let i = 0; i < length; i++) {
3161
+ if (elements[i] == null) continue;
3162
+
3163
+ bytes.push(...compileBytes(elements[i], itemType));
3260
3164
  }
3261
- };
3262
3165
 
3263
- const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty = false, itemType = valtype, typed = false) => {
3264
- const out = [];
3166
+ const obj = { bytes };
3167
+ if (offset != null) obj.offset = offset;
3265
3168
 
3266
- scope.arrays ??= new Map();
3169
+ const idx = data.push(obj) - 1;
3267
3170
 
3268
- let firstAssign = false;
3269
- if (!scope.arrays.has(name) || name === '$undeclared') {
3270
- firstAssign = true;
3171
+ scope.data ??= [];
3172
+ scope.data.push(idx);
3271
3173
 
3272
- // todo: can we just have 1 undeclared array? probably not? but this is not really memory efficient
3273
- const uniqueName = name === '$undeclared' ? name + Math.random().toString().slice(2) : name;
3174
+ return { idx, size: bytes.length };
3175
+ };
3176
+
3177
+ const printStaticStr = str => {
3178
+ const out = [];
3179
+
3180
+ for (let i = 0; i < str.length; i++) {
3181
+ out.push(
3182
+ // ...number(str.charCodeAt(i)),
3183
+ ...number(str.charCodeAt(i), Valtype.i32),
3184
+ Opcodes.i32_from_u,
3185
+ [ Opcodes.call, importedFuncs.printChar ]
3186
+ );
3187
+ }
3274
3188
 
3275
- let page;
3276
- if (Prefs.scopedPageNames) page = allocPage(scope, `${getAllocType(itemType)}: ${scope.name}/${uniqueName}`, itemType);
3277
- else page = allocPage(scope, `${getAllocType(itemType)}: ${uniqueName}`, itemType);
3189
+ return out;
3190
+ };
3278
3191
 
3279
- // hack: use 1 for page 0 pointer for fast truthiness
3280
- const ptr = page === 0 ? 1 : (page * pageSize);
3281
- scope.arrays.set(name, ptr);
3192
+ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty = false, itemType = valtype, intOut = false, typed = false) => {
3193
+ if (itemType !== 'i16' && itemType !== 'i8') {
3194
+ pages.hasArray = true;
3195
+ } else {
3196
+ pages.hasAnyString = true;
3197
+ if (itemType === 'i8') pages.hasByteString = true;
3198
+ else pages.hasString = true;
3282
3199
  }
3283
3200
 
3284
- const pointer = scope.arrays.get(name);
3201
+ const out = [];
3285
3202
 
3286
- const local = global ? globals[name] : scope.locals[name];
3203
+ const uniqueName = name === '$undeclared' ? name + randId() : name;
3287
3204
 
3288
3205
  const useRawElements = !!decl.rawElements;
3289
3206
  const elements = useRawElements ? decl.rawElements : decl.elements;
@@ -3291,46 +3208,81 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
3291
3208
  const valtype = itemTypeToValtype[itemType];
3292
3209
  const length = elements.length;
3293
3210
 
3294
- if (firstAssign && useRawElements && !Prefs.noData) {
3295
- // if length is 0 memory/data will just be 0000... anyway
3296
- if (length !== 0) {
3297
- let bytes = compileBytes(length, 'i32');
3211
+ const allocated = allocator.alloc({ scope, pages, globals, asmFunc, funcIndex }, uniqueName, { itemType });
3212
+
3213
+ let pointer = allocated;
3214
+ if (allocator.constructor.name !== 'StaticAllocator') {
3215
+ // const tmp = localTmp(scope, '#makearray_pointer' + uniqueName, Valtype.i32);
3216
+ const tmp = localTmp(scope, '#makearray_pointer' + name, Valtype.i32);
3217
+ out.push(
3218
+ ...allocated,
3219
+ [ Opcodes.local_set, tmp ]
3220
+ );
3221
+
3222
+ if (Prefs.runtimeAllocLog) out.push(
3223
+ ...printStaticStr(`${name}: `),
3298
3224
 
3299
- if (!initEmpty) for (let i = 0; i < length; i++) {
3300
- if (elements[i] == null) continue;
3225
+ [ Opcodes.local_get, tmp ],
3226
+ Opcodes.i32_from_u,
3227
+ [ Opcodes.call, 0 ],
3301
3228
 
3302
- bytes.push(...compileBytes(elements[i], itemType));
3229
+ ...number(10),
3230
+ [ Opcodes.call, 1 ]
3231
+ );
3232
+
3233
+ pointer = [ [ Opcodes.local_get, tmp ] ];
3234
+
3235
+ if (Prefs.data && useRawElements) {
3236
+ const data = makeData(scope, elements, null, itemType, initEmpty);
3237
+ if (data) {
3238
+ // init data
3239
+ out.push(
3240
+ ...pointer,
3241
+ ...number(0, Valtype.i32),
3242
+ ...number(data.size, Valtype.i32),
3243
+ [ ...Opcodes.memory_init, ...unsignedLEB128(data.idx), 0 ]
3244
+ );
3303
3245
  }
3304
3246
 
3305
- const ind = data.push({
3306
- offset: pointer,
3307
- bytes
3308
- }) - 1;
3247
+ // return pointer in out
3248
+ out.push(
3249
+ ...pointer,
3250
+ ...(!intOut ? [ Opcodes.i32_from_u ] : [])
3251
+ );
3309
3252
 
3310
- scope.data ??= [];
3311
- scope.data.push(ind);
3253
+ return [ out, pointer ];
3312
3254
  }
3255
+ } else {
3256
+ const rawPtr = read_signedLEB128(pointer[0].slice(1));
3313
3257
 
3314
- // local value as pointer
3315
- out.push(...number(pointer));
3258
+ scope.arrays ??= new Map();
3259
+ const firstAssign = !scope.arrays.has(uniqueName);
3260
+ if (firstAssign) scope.arrays.set(uniqueName, rawPtr);
3316
3261
 
3317
- return [ out, pointer ];
3318
- }
3262
+ if (Prefs.data && firstAssign && useRawElements) {
3263
+ makeData(scope, elements, rawPtr, itemType, initEmpty);
3319
3264
 
3320
- const pointerTmp = local != null ? localTmp(scope, '#makearray_pointer_tmp', Valtype.i32) : null;
3321
- if (pointerTmp != null) {
3322
- out.push(
3323
- [ global ? Opcodes.global_get : Opcodes.local_get, local.idx ],
3324
- Opcodes.i32_to_u,
3325
- [ Opcodes.local_set, pointerTmp ]
3326
- );
3265
+ // local value as pointer
3266
+ return [ number(rawPtr, intOut ? Valtype.i32 : valtypeBinary), pointer ];
3267
+ }
3268
+
3269
+ const local = global ? globals[name] : scope.locals[name];
3270
+ const pointerTmp = local != null ? localTmp(scope, '#makearray_pointer_tmp', Valtype.i32) : null;
3271
+ if (pointerTmp != null) {
3272
+ out.push(
3273
+ [ global ? Opcodes.global_get : Opcodes.local_get, local.idx ],
3274
+ Opcodes.i32_to_u,
3275
+ [ Opcodes.local_set, pointerTmp ]
3276
+ );
3277
+
3278
+ pointer = [ [ Opcodes.local_get, pointerTmp ] ];
3279
+ }
3327
3280
  }
3328
3281
 
3329
- const pointerWasm = pointerTmp != null ? [ [ Opcodes.local_get, pointerTmp ] ] : number(pointer, Valtype.i32);
3330
3282
 
3331
3283
  // store length
3332
3284
  out.push(
3333
- ...pointerWasm,
3285
+ ...pointer,
3334
3286
  ...number(length, Valtype.i32),
3335
3287
  [ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, 0 ]
3336
3288
  );
@@ -3342,11 +3294,11 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
3342
3294
 
3343
3295
  const offset = ValtypeSize.i32 + i * sizePerEl;
3344
3296
  out.push(
3345
- ...pointerWasm,
3297
+ ...pointer,
3346
3298
  ...(useRawElements ? number(elements[i], Valtype[valtype]) : generate(scope, elements[i])),
3347
3299
  [ storeOp, 0, ...unsignedLEB128(offset) ],
3348
3300
  ...(!typed ? [] : [ // typed presumes !useRawElements
3349
- ...pointerWasm,
3301
+ ...pointer,
3350
3302
  ...getNodeType(scope, elements[i]),
3351
3303
  [ Opcodes.i32_store8, 0, ...unsignedLEB128(offset + ValtypeSize[itemType]) ]
3352
3304
  ])
@@ -3354,12 +3306,13 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
3354
3306
  }
3355
3307
 
3356
3308
  // local value as pointer
3357
- out.push(...pointerWasm, Opcodes.i32_from_u);
3309
+ out.push(...pointer);
3310
+ if (!intOut) out.push(Opcodes.i32_from_u);
3358
3311
 
3359
3312
  return [ out, pointer ];
3360
3313
  };
3361
3314
 
3362
- const storeArray = (scope, array, index, element, aotPointer = null) => {
3315
+ const storeArray = (scope, array, index, element) => {
3363
3316
  if (!Array.isArray(element)) element = generate(scope, element);
3364
3317
  if (typeof index === 'number') index = number(index);
3365
3318
 
@@ -3371,26 +3324,25 @@ const storeArray = (scope, array, index, element, aotPointer = null) => {
3371
3324
  Opcodes.i32_to_u,
3372
3325
  ...number(ValtypeSize[valtype] + 1, Valtype.i32),
3373
3326
  [ Opcodes.i32_mul ],
3374
- ...(aotPointer ? [] : [
3375
- ...array,
3376
- Opcodes.i32_to_u,
3377
- [ Opcodes.i32_add ],
3378
- ]),
3327
+
3328
+ ...array,
3329
+ Opcodes.i32_to_u,
3330
+ [ Opcodes.i32_add ],
3379
3331
  [ Opcodes.local_set, offset ],
3380
3332
 
3381
3333
  // store value
3382
3334
  [ Opcodes.local_get, offset ],
3383
3335
  ...generate(scope, element),
3384
- [ Opcodes.store, 0, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ],
3336
+ [ Opcodes.store, 0, ValtypeSize.i32 ],
3385
3337
 
3386
3338
  // store type
3387
3339
  [ Opcodes.local_get, offset ],
3388
3340
  ...getNodeType(scope, element),
3389
- [ Opcodes.i32_store8, 0, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32 + ValtypeSize[valtype]) ]
3341
+ [ Opcodes.i32_store8, 0, ValtypeSize.i32 + ValtypeSize[valtype] ]
3390
3342
  ];
3391
3343
  };
3392
3344
 
3393
- const loadArray = (scope, array, index, aotPointer = null) => {
3345
+ const loadArray = (scope, array, index) => {
3394
3346
  if (typeof index === 'number') index = number(index);
3395
3347
 
3396
3348
  const offset = localTmp(scope, '#loadArray_offset', Valtype.i32);
@@ -3401,20 +3353,19 @@ const loadArray = (scope, array, index, aotPointer = null) => {
3401
3353
  Opcodes.i32_to_u,
3402
3354
  ...number(ValtypeSize[valtype] + 1, Valtype.i32),
3403
3355
  [ Opcodes.i32_mul ],
3404
- ...(aotPointer ? [] : [
3405
- ...array,
3406
- Opcodes.i32_to_u,
3407
- [ Opcodes.i32_add ],
3408
- ]),
3356
+
3357
+ ...array,
3358
+ Opcodes.i32_to_u,
3359
+ [ Opcodes.i32_add ],
3409
3360
  [ Opcodes.local_set, offset ],
3410
3361
 
3411
3362
  // load value
3412
3363
  [ Opcodes.local_get, offset ],
3413
- [ Opcodes.load, 0, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ],
3364
+ [ Opcodes.load, 0, ValtypeSize.i32 ],
3414
3365
 
3415
3366
  // load type
3416
3367
  [ Opcodes.local_get, offset ],
3417
- [ Opcodes.i32_load8_u, 0, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32 + ValtypeSize[valtype]) ]
3368
+ [ Opcodes.i32_load8_u, 0, ValtypeSize.i32 + ValtypeSize[valtype] ]
3418
3369
  ];
3419
3370
  };
3420
3371
 
@@ -3446,7 +3397,7 @@ const makeString = (scope, str, global = false, name = '$undeclared', forceBytes
3446
3397
  };
3447
3398
 
3448
3399
  const generateArray = (scope, decl, global = false, name = '$undeclared', initEmpty = false) => {
3449
- return makeArray(scope, decl, global, name, initEmpty, valtype, true)[0];
3400
+ return makeArray(scope, decl, global, name, initEmpty, valtype, false, true)[0];
3450
3401
  };
3451
3402
 
3452
3403
  const generateObject = (scope, decl, global = false, name = '$undeclared') => {
@@ -3465,9 +3416,6 @@ const withType = (scope, wasm, type) => [
3465
3416
 
3466
3417
  const generateMember = (scope, decl, _global, _name) => {
3467
3418
  const name = decl.object.name;
3468
- const pointer = scope.arrays?.get(name);
3469
-
3470
- const aotPointer = Prefs.aotPointerOpt && pointer;
3471
3419
 
3472
3420
  // hack: .name
3473
3421
  if (decl.property.name === 'name') {
@@ -3508,12 +3456,10 @@ const generateMember = (scope, decl, _global, _name) => {
3508
3456
  if (Prefs.fastLength) {
3509
3457
  // presume valid length object
3510
3458
  return [
3511
- ...(aotPointer ? number(0, Valtype.i32) : [
3512
- ...generate(scope, decl.object),
3513
- Opcodes.i32_to_u
3514
- ]),
3459
+ ...generate(scope, decl.object),
3460
+ Opcodes.i32_to_u,
3515
3461
 
3516
- [ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, ...unsignedLEB128(aotPointer ? pointer : 0) ],
3462
+ [ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
3517
3463
  Opcodes.i32_from_u
3518
3464
  ];
3519
3465
  }
@@ -3522,12 +3468,10 @@ const generateMember = (scope, decl, _global, _name) => {
3522
3468
  const known = knownType(scope, type);
3523
3469
  if (known != null) {
3524
3470
  if ([ TYPES.string, TYPES.bytestring, TYPES.array ].includes(known)) return [
3525
- ...(aotPointer ? number(0, Valtype.i32) : [
3526
- ...generate(scope, decl.object),
3527
- Opcodes.i32_to_u
3528
- ]),
3471
+ ...generate(scope, decl.object),
3472
+ Opcodes.i32_to_u,
3529
3473
 
3530
- [ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, ...unsignedLEB128(aotPointer ? pointer : 0) ],
3474
+ [ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
3531
3475
  Opcodes.i32_from_u
3532
3476
  ];
3533
3477
 
@@ -3537,12 +3481,10 @@ const generateMember = (scope, decl, _global, _name) => {
3537
3481
  return [
3538
3482
  ...typeIsOneOf(getNodeType(scope, decl.object), [ TYPES.string, TYPES.bytestring, TYPES.array ]),
3539
3483
  [ Opcodes.if, valtypeBinary ],
3540
- ...(aotPointer ? number(0, Valtype.i32) : [
3541
- ...generate(scope, decl.object),
3542
- Opcodes.i32_to_u
3543
- ]),
3484
+ ...generate(scope, decl.object),
3485
+ Opcodes.i32_to_u,
3544
3486
 
3545
- [ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, ...unsignedLEB128(aotPointer ? pointer : 0) ],
3487
+ [ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
3546
3488
  Opcodes.i32_from_u,
3547
3489
 
3548
3490
  ...setLastType(scope, TYPES.number),
@@ -3585,25 +3527,29 @@ const generateMember = (scope, decl, _global, _name) => {
3585
3527
 
3586
3528
  // // todo: we should only do this for strings but we don't know at compile-time :(
3587
3529
  // hack: this is naughty and will break things!
3588
- let newOut = number(0, valtypeBinary), newPointer = -1;
3530
+ let newOut = number(0, Valtype.i32), newPointer = number(0, Valtype.i32);
3589
3531
  if (pages.hasAnyString) {
3532
+ // todo: we use i16 even for bytestrings which should not make a bad thing happen, just be confusing for debugging?
3590
3533
  0, [ newOut, newPointer ] = makeArray(scope, {
3591
- rawElements: new Array(1)
3592
- }, _global, _name, true, 'i16');
3534
+ rawElements: new Array(0)
3535
+ }, _global, _name, true, 'i16', true);
3593
3536
  }
3594
3537
 
3595
3538
  return typeSwitch(scope, getNodeType(scope, decl.object), {
3596
3539
  [TYPES.array]: [
3597
- ...loadArray(scope, object, property, aotPointer),
3540
+ ...loadArray(scope, object, property),
3598
3541
  ...setLastType(scope)
3599
3542
  ],
3600
-
3601
3543
  [TYPES.string]: [
3602
3544
  // setup new/out array
3603
3545
  ...newOut,
3604
- [ Opcodes.drop ],
3605
3546
 
3606
- ...number(0, Valtype.i32), // base 0 for store later
3547
+ // set length to 1
3548
+ ...number(1, Valtype.i32),
3549
+ [ Opcodes.i32_store, 0, 0 ],
3550
+
3551
+ // use as pointer for store later
3552
+ ...newPointer,
3607
3553
 
3608
3554
  ...property,
3609
3555
  Opcodes.i32_to_u,
@@ -3611,46 +3557,48 @@ const generateMember = (scope, decl, _global, _name) => {
3611
3557
  ...number(ValtypeSize.i16, Valtype.i32),
3612
3558
  [ Opcodes.i32_mul ],
3613
3559
 
3614
- ...(aotPointer ? [] : [
3615
- ...object,
3616
- Opcodes.i32_to_u,
3617
- [ Opcodes.i32_add ]
3618
- ]),
3560
+ ...object,
3561
+ Opcodes.i32_to_u,
3562
+ [ Opcodes.i32_add ],
3619
3563
 
3620
3564
  // load current string ind {arg}
3621
- [ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ],
3565
+ [ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],
3622
3566
 
3623
3567
  // store to new string ind 0
3624
- [ Opcodes.i32_store16, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128(newPointer + ValtypeSize.i32) ],
3568
+ [ Opcodes.i32_store16, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],
3625
3569
 
3626
3570
  // return new string (page)
3627
- ...number(newPointer),
3571
+ ...newPointer,
3572
+ Opcodes.i32_from_u,
3628
3573
  ...setLastType(scope, TYPES.string)
3629
3574
  ],
3630
3575
  [TYPES.bytestring]: [
3631
3576
  // setup new/out array
3632
3577
  ...newOut,
3633
- [ Opcodes.drop ],
3634
3578
 
3635
- ...number(0, Valtype.i32), // base 0 for store later
3579
+ // set length to 1
3580
+ ...number(1, Valtype.i32),
3581
+ [ Opcodes.i32_store, 0, 0 ],
3582
+
3583
+ // use as pointer for store later
3584
+ ...newPointer,
3636
3585
 
3637
3586
  ...property,
3638
3587
  Opcodes.i32_to_u,
3639
3588
 
3640
- ...(aotPointer ? [] : [
3641
- ...object,
3642
- Opcodes.i32_to_u,
3643
- [ Opcodes.i32_add ]
3644
- ]),
3589
+ ...object,
3590
+ Opcodes.i32_to_u,
3591
+ [ Opcodes.i32_add ],
3645
3592
 
3646
3593
  // load current string ind {arg}
3647
- [ Opcodes.i32_load8_u, 0, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ],
3594
+ [ Opcodes.i32_load8_u, 0, ValtypeSize.i32 ],
3648
3595
 
3649
3596
  // store to new string ind 0
3650
- [ Opcodes.i32_store8, 0, ...unsignedLEB128(newPointer + ValtypeSize.i32) ],
3597
+ [ Opcodes.i32_store8, 0, ValtypeSize.i32 ],
3651
3598
 
3652
3599
  // return new string (page)
3653
- ...number(newPointer),
3600
+ ...newPointer,
3601
+ Opcodes.i32_from_u,
3654
3602
  ...setLastType(scope, TYPES.bytestring)
3655
3603
  ],
3656
3604
 
@@ -3658,7 +3606,7 @@ const generateMember = (scope, decl, _global, _name) => {
3658
3606
  });
3659
3607
  };
3660
3608
 
3661
- const randId = () => Math.random().toString(16).slice(0, -4);
3609
+ const randId = () => Math.random().toString(16).slice(1, -2).padEnd(12, '0');
3662
3610
 
3663
3611
  const objectHack = node => {
3664
3612
  if (!node) return node;
@@ -3710,7 +3658,7 @@ const generateFunc = (scope, decl) => {
3710
3658
  if (decl.async) return todo(scope, 'async functions are not supported');
3711
3659
  if (decl.generator) return todo(scope, 'generator functions are not supported');
3712
3660
 
3713
- const name = decl.id ? decl.id.name : `anonymous_${randId()}`;
3661
+ const name = decl.id ? decl.id.name : `anonymous${randId()}`;
3714
3662
  const params = decl.params ?? [];
3715
3663
 
3716
3664
  // TODO: share scope/locals between !!!
@@ -3795,9 +3743,9 @@ const internalConstrs = {
3795
3743
 
3796
3744
  // new Array(n)
3797
3745
 
3798
- const [ , pointer ] = makeArray(scope, {
3746
+ const [ out, pointer ] = makeArray(scope, {
3799
3747
  rawElements: new Array(0)
3800
- }, global, name, true);
3748
+ }, global, name, true, undefined, true);
3801
3749
 
3802
3750
  const arg = decl.arguments[0] ?? DEFAULT_VALUE;
3803
3751
 
@@ -3806,12 +3754,13 @@ const internalConstrs = {
3806
3754
  if (literalValue < 0 || !Number.isFinite(literalValue) || literalValue > 4294967295) return internalThrow(scope, 'RangeThrow', 'Invalid array length', true);
3807
3755
 
3808
3756
  return [
3809
- ...number(0, Valtype.i32),
3757
+ ...out,
3810
3758
  ...generate(scope, arg, global, name),
3811
3759
  Opcodes.i32_to_u,
3812
- [ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, ...unsignedLEB128(pointer) ],
3760
+ [ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, 0 ],
3813
3761
 
3814
- ...number(pointer)
3762
+ ...pointer,
3763
+ Opcodes.i32_from_u
3815
3764
  ];
3816
3765
  },
3817
3766
  type: TYPES.array,
@@ -3960,8 +3909,9 @@ const internalConstrs = {
3960
3909
  };
3961
3910
 
3962
3911
  export default program => {
3963
- globals = {};
3964
- globalInd = 0;
3912
+ globals = {
3913
+ ['#ind']: 0
3914
+ };
3965
3915
  tags = [];
3966
3916
  exceptions = [];
3967
3917
  funcs = [];
@@ -3994,6 +3944,7 @@ export default program => {
3994
3944
  builtinFuncs = new BuiltinFuncs();
3995
3945
  builtinVars = new BuiltinVars();
3996
3946
  prototypeFuncs = new PrototypeFuncs();
3947
+ allocator = makeAllocator(Prefs.allocator ?? 'static');
3997
3948
 
3998
3949
  program.id = { name: 'main' };
3999
3950
 
@@ -4036,6 +3987,8 @@ export default program => {
4036
3987
  else main.returns = [];
4037
3988
  }
4038
3989
 
3990
+ delete globals['#ind'];
3991
+
4039
3992
  // if blank main func and other exports, remove it
4040
3993
  if (main.wasm.length === 0 && funcs.reduce((acc, x) => acc + (x.export ? 1 : 0), 0) > 1) funcs.splice(main.index - importedFuncs.length, 1);
4041
3994