porffor 0.16.0-a7bc359af → 0.16.0-a8928b26c

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;
@@ -2230,11 +2178,11 @@ const allocVar = (scope, name, global = false, type = true) => {
2230
2178
  return target[name].idx;
2231
2179
  }
2232
2180
 
2233
- let idx = global ? globalInd++ : scope.localInd++;
2181
+ let idx = global ? globals['#ind']++ : scope.localInd++;
2234
2182
  target[name] = { idx, type: valtypeBinary };
2235
2183
 
2236
2184
  if (type) {
2237
- let typeIdx = global ? globalInd++ : scope.localInd++;
2185
+ let typeIdx = global ? globals['#ind']++ : scope.localInd++;
2238
2186
  target[name + '#type'] = { idx: typeIdx, type: Valtype.i32, name };
2239
2187
  }
2240
2188
 
@@ -2327,24 +2275,10 @@ const generateVar = (scope, decl) => {
2327
2275
  }
2328
2276
 
2329
2277
  if (x.init) {
2330
- // if (isFuncType(x.init.type)) {
2331
- // // let a = function () { ... }
2332
- // x.init.id = { name };
2333
-
2334
- // const func = generateFunc(scope, x.init);
2335
-
2336
- // out.push(
2337
- // ...number(func.index - importedFuncs.length),
2338
- // [ global ? Opcodes.global_set : Opcodes.local_set, idx ],
2339
-
2340
- // ...setType(scope, name, TYPES.function)
2341
- // );
2342
-
2343
- // continue;
2344
- // }
2278
+ const alreadyArray = scope.arrays?.get(name) != null;
2345
2279
 
2346
2280
  const generated = generate(scope, x.init, global, name);
2347
- if (scope.arrays?.get(name) != null) {
2281
+ if (!alreadyArray && scope.arrays?.get(name) != null) {
2348
2282
  // hack to set local as pointer before
2349
2283
  out.push(...number(scope.arrays.get(name)), [ global ? Opcodes.global_set : Opcodes.local_set, idx ]);
2350
2284
  if (generated.at(-1) == Opcodes.i32_from_u) generated.pop();
@@ -2396,19 +2330,12 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
2396
2330
 
2397
2331
  // hack: .length setter
2398
2332
  if (decl.left.type === 'MemberExpression' && decl.left.property.name === 'length') {
2399
- const name = decl.left.object.name;
2400
- const pointer = scope.arrays?.get(name);
2401
-
2402
- const aotPointer = Prefs.aotPointerOpt && pointer != null;
2403
-
2404
2333
  const newValueTmp = localTmp(scope, '__length_setter_tmp');
2405
2334
  const pointerTmp = op === '=' ? null : localTmp(scope, '__member_setter_ptr_tmp', Valtype.i32);
2406
2335
 
2407
2336
  return [
2408
- ...(aotPointer ? number(0, Valtype.i32) : [
2409
- ...generate(scope, decl.left.object),
2410
- Opcodes.i32_to_u
2411
- ]),
2337
+ ...generate(scope, decl.left.object),
2338
+ Opcodes.i32_to_u,
2412
2339
  ...(!pointerTmp ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
2413
2340
 
2414
2341
  ...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
@@ -2419,7 +2346,7 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
2419
2346
  [ Opcodes.local_tee, newValueTmp ],
2420
2347
 
2421
2348
  Opcodes.i32_to_u,
2422
- [ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, ...unsignedLEB128(aotPointer ? pointer : 0) ],
2349
+ [ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, 0 ],
2423
2350
 
2424
2351
  [ Opcodes.local_get, newValueTmp ]
2425
2352
  ];
@@ -2427,21 +2354,14 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
2427
2354
 
2428
2355
  // arr[i]
2429
2356
  if (decl.left.type === 'MemberExpression' && decl.left.computed) {
2430
- const name = decl.left.object.name;
2431
- const pointer = scope.arrays?.get(name);
2432
-
2433
- const aotPointer = Prefs.aotPointerOpt && pointer != null;
2434
-
2435
2357
  const newValueTmp = localTmp(scope, '__member_setter_val_tmp');
2436
2358
  const pointerTmp = op === '=' ? -1 : localTmp(scope, '__member_setter_ptr_tmp', Valtype.i32);
2437
2359
 
2438
2360
  return [
2439
2361
  ...typeSwitch(scope, getNodeType(scope, decl.left.object), {
2440
2362
  [TYPES.array]: [
2441
- ...(aotPointer ? [] : [
2442
- ...generate(scope, decl.left.object),
2443
- Opcodes.i32_to_u
2444
- ]),
2363
+ ...generate(scope, decl.left.object),
2364
+ Opcodes.i32_to_u,
2445
2365
 
2446
2366
  // get index as valtype
2447
2367
  ...generate(scope, decl.left.property),
@@ -2450,39 +2370,22 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
2450
2370
  // turn into byte offset by * valtypeSize (4 for i32, 8 for i64/f64)
2451
2371
  ...number(ValtypeSize[valtype] + 1, Valtype.i32),
2452
2372
  [ Opcodes.i32_mul ],
2453
- ...(aotPointer ? [] : [ [ Opcodes.i32_add ] ]),
2373
+ [ Opcodes.i32_add ],
2454
2374
  ...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
2455
2375
 
2456
2376
  ...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
2457
2377
  [ Opcodes.local_get, pointerTmp ],
2458
- [ Opcodes.load, 0, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ]
2378
+ [ Opcodes.load, 0, ValtypeSize.i32 ]
2459
2379
  ], generate(scope, decl.right), [
2460
2380
  [ Opcodes.local_get, pointerTmp ],
2461
- [ Opcodes.i32_load8_u, 0, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32 + ValtypeSize[valtype]) ]
2381
+ [ Opcodes.i32_load8_u, 0, ValtypeSize.i32 + ValtypeSize[valtype] ]
2462
2382
  ], getNodeType(scope, decl.right), false, name, true)),
2463
2383
  [ Opcodes.local_tee, newValueTmp ],
2464
2384
 
2465
- [ Opcodes.store, 0, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ]
2385
+ [ Opcodes.store, 0, ValtypeSize.i32 ]
2466
2386
  ],
2467
2387
 
2468
2388
  default: internalThrow(scope, 'TypeError', `Cannot assign member with non-array`)
2469
-
2470
- // [TYPES.string]: [
2471
- // // turn into byte offset by * sizeof i16
2472
- // ...number(ValtypeSize.i16, Valtype.i32),
2473
- // [ Opcodes.i32_mul ],
2474
- // ...(aotPointer ? [] : [ [ Opcodes.i32_add ] ]),
2475
- // ...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
2476
-
2477
- // ...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
2478
- // [ Opcodes.local_get, pointerTmp ],
2479
- // [ Opcodes.load, Math.log2(ValtypeSize[valtype]) - 1, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ]
2480
- // ], generate(scope, decl.right), number(TYPES.string, Valtype.i32), getNodeType(scope, decl.right))),
2481
- // [ Opcodes.local_tee, newValueTmp ],
2482
-
2483
- // Opcodes.i32_to_u,
2484
- // [ StoreOps.i16, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ]
2485
- // ]
2486
2389
  }, Blocktype.void),
2487
2390
 
2488
2391
  [ Opcodes.local_get, newValueTmp ]
@@ -2866,12 +2769,12 @@ const generateForOf = (scope, decl) => {
2866
2769
 
2867
2770
  // // todo: we should only do this for strings but we don't know at compile-time :(
2868
2771
  // hack: this is naughty and will break things!
2869
- let newOut = number(0, Valtype.f64), newPointer = -1;
2772
+ let newOut = number(0, Valtype.i32), newPointer = number(0, Valtype.i32);
2870
2773
  if (pages.hasAnyString) {
2871
2774
  // todo: we use i16 even for bytestrings which should not make a bad thing happen, just be confusing for debugging?
2872
2775
  0, [ newOut, newPointer ] = makeArray(scope, {
2873
- rawElements: new Array(1)
2874
- }, isGlobal, leftName, true, 'i16');
2776
+ rawElements: new Array(0)
2777
+ }, isGlobal, leftName, true, 'i16', true);
2875
2778
  }
2876
2779
 
2877
2780
  // set type for local
@@ -2918,23 +2821,28 @@ const generateForOf = (scope, decl) => {
2918
2821
  [TYPES.string]: [
2919
2822
  ...setType(scope, leftName, TYPES.string),
2920
2823
 
2921
- [ Opcodes.loop, Blocktype.void ],
2922
-
2923
2824
  // setup new/out array
2924
2825
  ...newOut,
2925
- [ Opcodes.drop ],
2926
2826
 
2927
- ...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,
2928
2835
 
2929
2836
  // load current string ind {arg}
2930
2837
  [ Opcodes.local_get, pointer ],
2931
- [ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128(ValtypeSize.i32) ],
2838
+ [ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],
2932
2839
 
2933
2840
  // store to new string ind 0
2934
- [ Opcodes.i32_store16, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128(newPointer + ValtypeSize.i32) ],
2841
+ [ Opcodes.i32_store16, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],
2935
2842
 
2936
2843
  // return new string (page)
2937
- ...number(newPointer),
2844
+ ...newPointer,
2845
+ Opcodes.i32_from_u,
2938
2846
 
2939
2847
  [ isGlobal ? Opcodes.global_set : Opcodes.local_set, local.idx ],
2940
2848
 
@@ -2966,25 +2874,30 @@ const generateForOf = (scope, decl) => {
2966
2874
  [TYPES.bytestring]: [
2967
2875
  ...setType(scope, leftName, TYPES.bytestring),
2968
2876
 
2969
- [ Opcodes.loop, Blocktype.void ],
2970
-
2971
2877
  // setup new/out array
2972
2878
  ...newOut,
2973
- [ Opcodes.drop ],
2974
2879
 
2975
- ...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,
2976
2888
 
2977
2889
  // load current string ind {arg}
2978
2890
  [ Opcodes.local_get, pointer ],
2979
2891
  [ Opcodes.local_get, counter ],
2980
2892
  [ Opcodes.i32_add ],
2981
- [ Opcodes.i32_load8_u, 0, ...unsignedLEB128(ValtypeSize.i32) ],
2893
+ [ Opcodes.i32_load8_u, 0, ValtypeSize.i32 ],
2982
2894
 
2983
2895
  // store to new string ind 0
2984
- [ Opcodes.i32_store8, 0, ...unsignedLEB128(newPointer + ValtypeSize.i32) ],
2896
+ [ Opcodes.i32_store8, 0, ValtypeSize.i32 ],
2985
2897
 
2986
2898
  // return new string (page)
2987
- ...number(newPointer),
2899
+ ...newPointer,
2900
+ Opcodes.i32_from_u,
2988
2901
 
2989
2902
  [ isGlobal ? Opcodes.global_set : Opcodes.local_set, local.idx ],
2990
2903
 
@@ -3199,18 +3112,6 @@ const allocPage = (scope, reason, type) => {
3199
3112
  scope.pages ??= new Map();
3200
3113
  scope.pages.set(reason, { ind, type });
3201
3114
 
3202
- if (Prefs.allocLog) log('alloc', `allocated new page of memory (${ind}) | ${reason} (type: ${type})`);
3203
-
3204
- return ind;
3205
- };
3206
-
3207
- // todo: add scope.pages
3208
- const freePage = reason => {
3209
- const { ind } = pages.get(reason);
3210
- pages.delete(reason);
3211
-
3212
- if (Prefs.allocLog) log('alloc', `freed page of memory (${ind}) | ${reason}`);
3213
-
3214
3115
  return ind;
3215
3116
  };
3216
3117
 
@@ -3248,39 +3149,58 @@ const compileBytes = (val, itemType) => {
3248
3149
  }
3249
3150
  };
3250
3151
 
3251
- const getAllocType = itemType => {
3252
- switch (itemType) {
3253
- case 'i8': return 'bytestring';
3254
- 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');
3255
3159
 
3256
- 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));
3257
3164
  }
3258
- };
3259
3165
 
3260
- const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty = false, itemType = valtype, typed = false) => {
3261
- const out = [];
3166
+ const obj = { bytes };
3167
+ if (offset != null) obj.offset = offset;
3262
3168
 
3263
- scope.arrays ??= new Map();
3169
+ const idx = data.push(obj) - 1;
3264
3170
 
3265
- let firstAssign = false;
3266
- if (!scope.arrays.has(name) || name === '$undeclared') {
3267
- firstAssign = true;
3171
+ scope.data ??= [];
3172
+ scope.data.push(idx);
3268
3173
 
3269
- // todo: can we just have 1 undeclared array? probably not? but this is not really memory efficient
3270
- const uniqueName = name === '$undeclared' ? name + randId() : 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
+ }
3271
3188
 
3272
- let page;
3273
- if (Prefs.scopedPageNames) page = allocPage(scope, `${getAllocType(itemType)}: ${scope.name}/${uniqueName}`, itemType);
3274
- else page = allocPage(scope, `${getAllocType(itemType)}: ${uniqueName}`, itemType);
3189
+ return out;
3190
+ };
3275
3191
 
3276
- // hack: use 1 for page 0 pointer for fast truthiness
3277
- const ptr = page === 0 ? 1 : (page * pageSize);
3278
- 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;
3279
3199
  }
3280
3200
 
3281
- const pointer = scope.arrays.get(name);
3201
+ const out = [];
3282
3202
 
3283
- const local = global ? globals[name] : scope.locals[name];
3203
+ const uniqueName = name === '$undeclared' ? name + randId() : name;
3284
3204
 
3285
3205
  const useRawElements = !!decl.rawElements;
3286
3206
  const elements = useRawElements ? decl.rawElements : decl.elements;
@@ -3288,46 +3208,81 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
3288
3208
  const valtype = itemTypeToValtype[itemType];
3289
3209
  const length = elements.length;
3290
3210
 
3291
- if (firstAssign && useRawElements && !Prefs.noData) {
3292
- // if length is 0 memory/data will just be 0000... anyway
3293
- if (length !== 0) {
3294
- 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}: `),
3295
3224
 
3296
- if (!initEmpty) for (let i = 0; i < length; i++) {
3297
- if (elements[i] == null) continue;
3225
+ [ Opcodes.local_get, tmp ],
3226
+ Opcodes.i32_from_u,
3227
+ [ Opcodes.call, 0 ],
3298
3228
 
3299
- 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
+ );
3300
3245
  }
3301
3246
 
3302
- const ind = data.push({
3303
- offset: pointer,
3304
- bytes
3305
- }) - 1;
3247
+ // return pointer in out
3248
+ out.push(
3249
+ ...pointer,
3250
+ ...(!intOut ? [ Opcodes.i32_from_u ] : [])
3251
+ );
3306
3252
 
3307
- scope.data ??= [];
3308
- scope.data.push(ind);
3253
+ return [ out, pointer ];
3309
3254
  }
3255
+ } else {
3256
+ const rawPtr = read_signedLEB128(pointer[0].slice(1));
3310
3257
 
3311
- // local value as pointer
3312
- out.push(...number(pointer));
3258
+ scope.arrays ??= new Map();
3259
+ const firstAssign = !scope.arrays.has(uniqueName);
3260
+ if (firstAssign) scope.arrays.set(uniqueName, rawPtr);
3313
3261
 
3314
- return [ out, pointer ];
3315
- }
3262
+ if (Prefs.data && firstAssign && useRawElements) {
3263
+ makeData(scope, elements, rawPtr, itemType, initEmpty);
3316
3264
 
3317
- const pointerTmp = local != null ? localTmp(scope, '#makearray_pointer_tmp', Valtype.i32) : null;
3318
- if (pointerTmp != null) {
3319
- out.push(
3320
- [ global ? Opcodes.global_get : Opcodes.local_get, local.idx ],
3321
- Opcodes.i32_to_u,
3322
- [ Opcodes.local_set, pointerTmp ]
3323
- );
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
+ }
3324
3280
  }
3325
3281
 
3326
- const pointerWasm = pointerTmp != null ? [ [ Opcodes.local_get, pointerTmp ] ] : number(pointer, Valtype.i32);
3327
3282
 
3328
3283
  // store length
3329
3284
  out.push(
3330
- ...pointerWasm,
3285
+ ...pointer,
3331
3286
  ...number(length, Valtype.i32),
3332
3287
  [ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, 0 ]
3333
3288
  );
@@ -3339,11 +3294,11 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
3339
3294
 
3340
3295
  const offset = ValtypeSize.i32 + i * sizePerEl;
3341
3296
  out.push(
3342
- ...pointerWasm,
3297
+ ...pointer,
3343
3298
  ...(useRawElements ? number(elements[i], Valtype[valtype]) : generate(scope, elements[i])),
3344
3299
  [ storeOp, 0, ...unsignedLEB128(offset) ],
3345
3300
  ...(!typed ? [] : [ // typed presumes !useRawElements
3346
- ...pointerWasm,
3301
+ ...pointer,
3347
3302
  ...getNodeType(scope, elements[i]),
3348
3303
  [ Opcodes.i32_store8, 0, ...unsignedLEB128(offset + ValtypeSize[itemType]) ]
3349
3304
  ])
@@ -3351,12 +3306,13 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
3351
3306
  }
3352
3307
 
3353
3308
  // local value as pointer
3354
- out.push(...pointerWasm, Opcodes.i32_from_u);
3309
+ out.push(...pointer);
3310
+ if (!intOut) out.push(Opcodes.i32_from_u);
3355
3311
 
3356
3312
  return [ out, pointer ];
3357
3313
  };
3358
3314
 
3359
- const storeArray = (scope, array, index, element, aotPointer = null) => {
3315
+ const storeArray = (scope, array, index, element) => {
3360
3316
  if (!Array.isArray(element)) element = generate(scope, element);
3361
3317
  if (typeof index === 'number') index = number(index);
3362
3318
 
@@ -3368,26 +3324,25 @@ const storeArray = (scope, array, index, element, aotPointer = null) => {
3368
3324
  Opcodes.i32_to_u,
3369
3325
  ...number(ValtypeSize[valtype] + 1, Valtype.i32),
3370
3326
  [ Opcodes.i32_mul ],
3371
- ...(aotPointer ? [] : [
3372
- ...array,
3373
- Opcodes.i32_to_u,
3374
- [ Opcodes.i32_add ],
3375
- ]),
3327
+
3328
+ ...array,
3329
+ Opcodes.i32_to_u,
3330
+ [ Opcodes.i32_add ],
3376
3331
  [ Opcodes.local_set, offset ],
3377
3332
 
3378
3333
  // store value
3379
3334
  [ Opcodes.local_get, offset ],
3380
3335
  ...generate(scope, element),
3381
- [ Opcodes.store, 0, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ],
3336
+ [ Opcodes.store, 0, ValtypeSize.i32 ],
3382
3337
 
3383
3338
  // store type
3384
3339
  [ Opcodes.local_get, offset ],
3385
3340
  ...getNodeType(scope, element),
3386
- [ Opcodes.i32_store8, 0, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32 + ValtypeSize[valtype]) ]
3341
+ [ Opcodes.i32_store8, 0, ValtypeSize.i32 + ValtypeSize[valtype] ]
3387
3342
  ];
3388
3343
  };
3389
3344
 
3390
- const loadArray = (scope, array, index, aotPointer = null) => {
3345
+ const loadArray = (scope, array, index) => {
3391
3346
  if (typeof index === 'number') index = number(index);
3392
3347
 
3393
3348
  const offset = localTmp(scope, '#loadArray_offset', Valtype.i32);
@@ -3398,20 +3353,19 @@ const loadArray = (scope, array, index, aotPointer = null) => {
3398
3353
  Opcodes.i32_to_u,
3399
3354
  ...number(ValtypeSize[valtype] + 1, Valtype.i32),
3400
3355
  [ Opcodes.i32_mul ],
3401
- ...(aotPointer ? [] : [
3402
- ...array,
3403
- Opcodes.i32_to_u,
3404
- [ Opcodes.i32_add ],
3405
- ]),
3356
+
3357
+ ...array,
3358
+ Opcodes.i32_to_u,
3359
+ [ Opcodes.i32_add ],
3406
3360
  [ Opcodes.local_set, offset ],
3407
3361
 
3408
3362
  // load value
3409
3363
  [ Opcodes.local_get, offset ],
3410
- [ Opcodes.load, 0, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ],
3364
+ [ Opcodes.load, 0, ValtypeSize.i32 ],
3411
3365
 
3412
3366
  // load type
3413
3367
  [ Opcodes.local_get, offset ],
3414
- [ Opcodes.i32_load8_u, 0, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32 + ValtypeSize[valtype]) ]
3368
+ [ Opcodes.i32_load8_u, 0, ValtypeSize.i32 + ValtypeSize[valtype] ]
3415
3369
  ];
3416
3370
  };
3417
3371
 
@@ -3443,7 +3397,7 @@ const makeString = (scope, str, global = false, name = '$undeclared', forceBytes
3443
3397
  };
3444
3398
 
3445
3399
  const generateArray = (scope, decl, global = false, name = '$undeclared', initEmpty = false) => {
3446
- return makeArray(scope, decl, global, name, initEmpty, valtype, true)[0];
3400
+ return makeArray(scope, decl, global, name, initEmpty, valtype, false, true)[0];
3447
3401
  };
3448
3402
 
3449
3403
  const generateObject = (scope, decl, global = false, name = '$undeclared') => {
@@ -3462,9 +3416,6 @@ const withType = (scope, wasm, type) => [
3462
3416
 
3463
3417
  const generateMember = (scope, decl, _global, _name) => {
3464
3418
  const name = decl.object.name;
3465
- const pointer = scope.arrays?.get(name);
3466
-
3467
- const aotPointer = Prefs.aotPointerOpt && pointer;
3468
3419
 
3469
3420
  // hack: .name
3470
3421
  if (decl.property.name === 'name') {
@@ -3505,12 +3456,10 @@ const generateMember = (scope, decl, _global, _name) => {
3505
3456
  if (Prefs.fastLength) {
3506
3457
  // presume valid length object
3507
3458
  return [
3508
- ...(aotPointer ? number(0, Valtype.i32) : [
3509
- ...generate(scope, decl.object),
3510
- Opcodes.i32_to_u
3511
- ]),
3459
+ ...generate(scope, decl.object),
3460
+ Opcodes.i32_to_u,
3512
3461
 
3513
- [ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, ...unsignedLEB128(aotPointer ? pointer : 0) ],
3462
+ [ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
3514
3463
  Opcodes.i32_from_u
3515
3464
  ];
3516
3465
  }
@@ -3519,12 +3468,10 @@ const generateMember = (scope, decl, _global, _name) => {
3519
3468
  const known = knownType(scope, type);
3520
3469
  if (known != null) {
3521
3470
  if ([ TYPES.string, TYPES.bytestring, TYPES.array ].includes(known)) return [
3522
- ...(aotPointer ? number(0, Valtype.i32) : [
3523
- ...generate(scope, decl.object),
3524
- Opcodes.i32_to_u
3525
- ]),
3471
+ ...generate(scope, decl.object),
3472
+ Opcodes.i32_to_u,
3526
3473
 
3527
- [ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, ...unsignedLEB128(aotPointer ? pointer : 0) ],
3474
+ [ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
3528
3475
  Opcodes.i32_from_u
3529
3476
  ];
3530
3477
 
@@ -3534,12 +3481,10 @@ const generateMember = (scope, decl, _global, _name) => {
3534
3481
  return [
3535
3482
  ...typeIsOneOf(getNodeType(scope, decl.object), [ TYPES.string, TYPES.bytestring, TYPES.array ]),
3536
3483
  [ Opcodes.if, valtypeBinary ],
3537
- ...(aotPointer ? number(0, Valtype.i32) : [
3538
- ...generate(scope, decl.object),
3539
- Opcodes.i32_to_u
3540
- ]),
3484
+ ...generate(scope, decl.object),
3485
+ Opcodes.i32_to_u,
3541
3486
 
3542
- [ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, ...unsignedLEB128(aotPointer ? pointer : 0) ],
3487
+ [ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
3543
3488
  Opcodes.i32_from_u,
3544
3489
 
3545
3490
  ...setLastType(scope, TYPES.number),
@@ -3582,25 +3527,29 @@ const generateMember = (scope, decl, _global, _name) => {
3582
3527
 
3583
3528
  // // todo: we should only do this for strings but we don't know at compile-time :(
3584
3529
  // hack: this is naughty and will break things!
3585
- let newOut = number(0, valtypeBinary), newPointer = -1;
3530
+ let newOut = number(0, Valtype.i32), newPointer = number(0, Valtype.i32);
3586
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?
3587
3533
  0, [ newOut, newPointer ] = makeArray(scope, {
3588
- rawElements: new Array(1)
3589
- }, _global, _name, true, 'i16');
3534
+ rawElements: new Array(0)
3535
+ }, _global, _name, true, 'i16', true);
3590
3536
  }
3591
3537
 
3592
3538
  return typeSwitch(scope, getNodeType(scope, decl.object), {
3593
3539
  [TYPES.array]: [
3594
- ...loadArray(scope, object, property, aotPointer),
3540
+ ...loadArray(scope, object, property),
3595
3541
  ...setLastType(scope)
3596
3542
  ],
3597
-
3598
3543
  [TYPES.string]: [
3599
3544
  // setup new/out array
3600
3545
  ...newOut,
3601
- [ Opcodes.drop ],
3602
3546
 
3603
- ...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,
3604
3553
 
3605
3554
  ...property,
3606
3555
  Opcodes.i32_to_u,
@@ -3608,46 +3557,48 @@ const generateMember = (scope, decl, _global, _name) => {
3608
3557
  ...number(ValtypeSize.i16, Valtype.i32),
3609
3558
  [ Opcodes.i32_mul ],
3610
3559
 
3611
- ...(aotPointer ? [] : [
3612
- ...object,
3613
- Opcodes.i32_to_u,
3614
- [ Opcodes.i32_add ]
3615
- ]),
3560
+ ...object,
3561
+ Opcodes.i32_to_u,
3562
+ [ Opcodes.i32_add ],
3616
3563
 
3617
3564
  // load current string ind {arg}
3618
- [ 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 ],
3619
3566
 
3620
3567
  // store to new string ind 0
3621
- [ Opcodes.i32_store16, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128(newPointer + ValtypeSize.i32) ],
3568
+ [ Opcodes.i32_store16, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],
3622
3569
 
3623
3570
  // return new string (page)
3624
- ...number(newPointer),
3571
+ ...newPointer,
3572
+ Opcodes.i32_from_u,
3625
3573
  ...setLastType(scope, TYPES.string)
3626
3574
  ],
3627
3575
  [TYPES.bytestring]: [
3628
3576
  // setup new/out array
3629
3577
  ...newOut,
3630
- [ Opcodes.drop ],
3631
3578
 
3632
- ...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,
3633
3585
 
3634
3586
  ...property,
3635
3587
  Opcodes.i32_to_u,
3636
3588
 
3637
- ...(aotPointer ? [] : [
3638
- ...object,
3639
- Opcodes.i32_to_u,
3640
- [ Opcodes.i32_add ]
3641
- ]),
3589
+ ...object,
3590
+ Opcodes.i32_to_u,
3591
+ [ Opcodes.i32_add ],
3642
3592
 
3643
3593
  // load current string ind {arg}
3644
- [ Opcodes.i32_load8_u, 0, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ],
3594
+ [ Opcodes.i32_load8_u, 0, ValtypeSize.i32 ],
3645
3595
 
3646
3596
  // store to new string ind 0
3647
- [ Opcodes.i32_store8, 0, ...unsignedLEB128(newPointer + ValtypeSize.i32) ],
3597
+ [ Opcodes.i32_store8, 0, ValtypeSize.i32 ],
3648
3598
 
3649
3599
  // return new string (page)
3650
- ...number(newPointer),
3600
+ ...newPointer,
3601
+ Opcodes.i32_from_u,
3651
3602
  ...setLastType(scope, TYPES.bytestring)
3652
3603
  ],
3653
3604
 
@@ -3792,9 +3743,9 @@ const internalConstrs = {
3792
3743
 
3793
3744
  // new Array(n)
3794
3745
 
3795
- const [ , pointer ] = makeArray(scope, {
3746
+ const [ out, pointer ] = makeArray(scope, {
3796
3747
  rawElements: new Array(0)
3797
- }, global, name, true);
3748
+ }, global, name, true, undefined, true);
3798
3749
 
3799
3750
  const arg = decl.arguments[0] ?? DEFAULT_VALUE;
3800
3751
 
@@ -3803,12 +3754,13 @@ const internalConstrs = {
3803
3754
  if (literalValue < 0 || !Number.isFinite(literalValue) || literalValue > 4294967295) return internalThrow(scope, 'RangeThrow', 'Invalid array length', true);
3804
3755
 
3805
3756
  return [
3806
- ...number(0, Valtype.i32),
3757
+ ...out,
3807
3758
  ...generate(scope, arg, global, name),
3808
3759
  Opcodes.i32_to_u,
3809
- [ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, ...unsignedLEB128(pointer) ],
3760
+ [ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, 0 ],
3810
3761
 
3811
- ...number(pointer)
3762
+ ...pointer,
3763
+ Opcodes.i32_from_u
3812
3764
  ];
3813
3765
  },
3814
3766
  type: TYPES.array,
@@ -3957,8 +3909,9 @@ const internalConstrs = {
3957
3909
  };
3958
3910
 
3959
3911
  export default program => {
3960
- globals = {};
3961
- globalInd = 0;
3912
+ globals = {
3913
+ ['#ind']: 0
3914
+ };
3962
3915
  tags = [];
3963
3916
  exceptions = [];
3964
3917
  funcs = [];
@@ -3991,6 +3944,7 @@ export default program => {
3991
3944
  builtinFuncs = new BuiltinFuncs();
3992
3945
  builtinVars = new BuiltinVars();
3993
3946
  prototypeFuncs = new PrototypeFuncs();
3947
+ allocator = makeAllocator(Prefs.allocator ?? 'static');
3994
3948
 
3995
3949
  program.id = { name: 'main' };
3996
3950
 
@@ -4033,6 +3987,8 @@ export default program => {
4033
3987
  else main.returns = [];
4034
3988
  }
4035
3989
 
3990
+ delete globals['#ind'];
3991
+
4036
3992
  // if blank main func and other exports, remove it
4037
3993
  if (main.wasm.length === 0 && funcs.reduce((acc, x) => acc + (x.export ? 1 : 0), 0) > 1) funcs.splice(main.index - importedFuncs.length, 1);
4038
3994