porffor 0.16.0-79cd8c0c8 → 0.16.0-8107e135a

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
- const [ , pointer ] = makeArray(scope, {
434
+ const [ out, 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
+ ...out,
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
@@ -1068,7 +1017,7 @@ const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes
1068
1017
 
1069
1018
  for (const x of _data) {
1070
1019
  const copy = { ...x };
1071
- copy.offset += pages.size * pageSize;
1020
+ if (copy.offset != null) copy.offset += pages.size * pageSize;
1072
1021
  data.push(copy);
1073
1022
  }
1074
1023
 
@@ -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;
@@ -1450,10 +1403,10 @@ const countLeftover = wasm => {
1450
1403
 
1451
1404
  if (depth === 0)
1452
1405
  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)) {}
1406
+ 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
1407
  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
1408
  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;
1409
+ else if (inst[0] === Opcodes.memory_copy[0] && (inst[1] === Opcodes.memory_copy[1] || inst[1] === Opcodes.memory_init[1])) count -= 3;
1457
1410
  else if (inst[0] === Opcodes.return) count = 0;
1458
1411
  else if (inst[0] === Opcodes.call) {
1459
1412
  let func = funcs.find(x => x.index === inst[1]);
@@ -1725,7 +1678,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
1725
1678
  }, generate(scope, decl.arguments[0] ?? DEFAULT_VALUE), getNodeType(scope, decl.arguments[0] ?? DEFAULT_VALUE), protoLocal, protoLocal2, (length, itemType) => {
1726
1679
  return makeArray(scope, {
1727
1680
  rawElements: new Array(length)
1728
- }, _global, _name, true, itemType);
1681
+ }, _global, _name, true, itemType, true);
1729
1682
  }, () => {
1730
1683
  optUnused = true;
1731
1684
  return unusedValue;
@@ -2115,7 +2068,6 @@ const brTable = (input, bc, returns) => {
2115
2068
  }
2116
2069
 
2117
2070
  for (let i = 0; i < count; i++) {
2118
- // if (i === 0) out.push([ Opcodes.block, returns, 'br table start' ]);
2119
2071
  if (i === 0) out.push([ Opcodes.block, returns ]);
2120
2072
  else out.push([ Opcodes.block, Blocktype.void ]);
2121
2073
  }
@@ -2149,10 +2101,8 @@ const brTable = (input, bc, returns) => {
2149
2101
  [ Opcodes.br_table, ...encodeVector(table), 0 ]
2150
2102
  );
2151
2103
 
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
2104
+ // sort the wrong way and then reverse
2105
+ // so strings ('default') are at the start before any numbers
2156
2106
  const orderedBc = keys.sort((a, b) => b - a).reverse();
2157
2107
 
2158
2108
  br = count - 1;
@@ -2178,7 +2128,7 @@ const typeSwitch = (scope, type, bc, returns = valtypeBinary) => {
2178
2128
  return bc[known] ?? bc.default;
2179
2129
  }
2180
2130
 
2181
- if (Prefs.typeswitchUseBrtable)
2131
+ if (Prefs.typeswitchBrtable)
2182
2132
  return brTable(type, bc, returns);
2183
2133
 
2184
2134
  const tmp = localTmp(scope, '#typeswitch_tmp' + (Prefs.typeswitchUniqueTmp ? randId() : ''), Valtype.i32);
@@ -2233,11 +2183,11 @@ const allocVar = (scope, name, global = false, type = true) => {
2233
2183
  return target[name].idx;
2234
2184
  }
2235
2185
 
2236
- let idx = global ? globalInd++ : scope.localInd++;
2186
+ let idx = global ? globals['#ind']++ : scope.localInd++;
2237
2187
  target[name] = { idx, type: valtypeBinary };
2238
2188
 
2239
2189
  if (type) {
2240
- let typeIdx = global ? globalInd++ : scope.localInd++;
2190
+ let typeIdx = global ? globals['#ind']++ : scope.localInd++;
2241
2191
  target[name + '#type'] = { idx: typeIdx, type: Valtype.i32, name };
2242
2192
  }
2243
2193
 
@@ -2330,24 +2280,10 @@ const generateVar = (scope, decl) => {
2330
2280
  }
2331
2281
 
2332
2282
  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
- // }
2283
+ const alreadyArray = scope.arrays?.get(name) != null;
2348
2284
 
2349
2285
  const generated = generate(scope, x.init, global, name);
2350
- if (scope.arrays?.get(name) != null) {
2286
+ if (!alreadyArray && scope.arrays?.get(name) != null) {
2351
2287
  // hack to set local as pointer before
2352
2288
  out.push(...number(scope.arrays.get(name)), [ global ? Opcodes.global_set : Opcodes.local_set, idx ]);
2353
2289
  if (generated.at(-1) == Opcodes.i32_from_u) generated.pop();
@@ -2399,19 +2335,12 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
2399
2335
 
2400
2336
  // hack: .length setter
2401
2337
  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
2338
  const newValueTmp = localTmp(scope, '__length_setter_tmp');
2408
2339
  const pointerTmp = op === '=' ? null : localTmp(scope, '__member_setter_ptr_tmp', Valtype.i32);
2409
2340
 
2410
2341
  return [
2411
- ...(aotPointer ? number(0, Valtype.i32) : [
2412
- ...generate(scope, decl.left.object),
2413
- Opcodes.i32_to_u
2414
- ]),
2342
+ ...generate(scope, decl.left.object),
2343
+ Opcodes.i32_to_u,
2415
2344
  ...(!pointerTmp ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
2416
2345
 
2417
2346
  ...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
@@ -2422,7 +2351,7 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
2422
2351
  [ Opcodes.local_tee, newValueTmp ],
2423
2352
 
2424
2353
  Opcodes.i32_to_u,
2425
- [ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, ...unsignedLEB128(aotPointer ? pointer : 0) ],
2354
+ [ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, 0 ],
2426
2355
 
2427
2356
  [ Opcodes.local_get, newValueTmp ]
2428
2357
  ];
@@ -2430,21 +2359,14 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
2430
2359
 
2431
2360
  // arr[i]
2432
2361
  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
2362
  const newValueTmp = localTmp(scope, '__member_setter_val_tmp');
2439
2363
  const pointerTmp = op === '=' ? -1 : localTmp(scope, '__member_setter_ptr_tmp', Valtype.i32);
2440
2364
 
2441
2365
  return [
2442
2366
  ...typeSwitch(scope, getNodeType(scope, decl.left.object), {
2443
2367
  [TYPES.array]: [
2444
- ...(aotPointer ? [] : [
2445
- ...generate(scope, decl.left.object),
2446
- Opcodes.i32_to_u
2447
- ]),
2368
+ ...generate(scope, decl.left.object),
2369
+ Opcodes.i32_to_u,
2448
2370
 
2449
2371
  // get index as valtype
2450
2372
  ...generate(scope, decl.left.property),
@@ -2453,39 +2375,22 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
2453
2375
  // turn into byte offset by * valtypeSize (4 for i32, 8 for i64/f64)
2454
2376
  ...number(ValtypeSize[valtype] + 1, Valtype.i32),
2455
2377
  [ Opcodes.i32_mul ],
2456
- ...(aotPointer ? [] : [ [ Opcodes.i32_add ] ]),
2378
+ [ Opcodes.i32_add ],
2457
2379
  ...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
2458
2380
 
2459
2381
  ...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
2460
2382
  [ Opcodes.local_get, pointerTmp ],
2461
- [ Opcodes.load, 0, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ]
2383
+ [ Opcodes.load, 0, ValtypeSize.i32 ]
2462
2384
  ], generate(scope, decl.right), [
2463
2385
  [ Opcodes.local_get, pointerTmp ],
2464
- [ Opcodes.i32_load8_u, 0, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32 + ValtypeSize[valtype]) ]
2386
+ [ Opcodes.i32_load8_u, 0, ValtypeSize.i32 + ValtypeSize[valtype] ]
2465
2387
  ], getNodeType(scope, decl.right), false, name, true)),
2466
2388
  [ Opcodes.local_tee, newValueTmp ],
2467
2389
 
2468
- [ Opcodes.store, 0, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ]
2390
+ [ Opcodes.store, 0, ValtypeSize.i32 ]
2469
2391
  ],
2470
2392
 
2471
2393
  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
2394
  }, Blocktype.void),
2490
2395
 
2491
2396
  [ Opcodes.local_get, newValueTmp ]
@@ -2869,12 +2774,12 @@ const generateForOf = (scope, decl) => {
2869
2774
 
2870
2775
  // // todo: we should only do this for strings but we don't know at compile-time :(
2871
2776
  // hack: this is naughty and will break things!
2872
- let newOut = number(0, Valtype.f64), newPointer = -1;
2777
+ let newOut = number(0, Valtype.i32), newPointer = number(0, Valtype.i32);
2873
2778
  if (pages.hasAnyString) {
2874
2779
  // todo: we use i16 even for bytestrings which should not make a bad thing happen, just be confusing for debugging?
2875
2780
  0, [ newOut, newPointer ] = makeArray(scope, {
2876
- rawElements: new Array(1)
2877
- }, isGlobal, leftName, true, 'i16');
2781
+ rawElements: new Array(0)
2782
+ }, isGlobal, leftName, true, 'i16', true);
2878
2783
  }
2879
2784
 
2880
2785
  // set type for local
@@ -2921,23 +2826,28 @@ const generateForOf = (scope, decl) => {
2921
2826
  [TYPES.string]: [
2922
2827
  ...setType(scope, leftName, TYPES.string),
2923
2828
 
2924
- [ Opcodes.loop, Blocktype.void ],
2925
-
2926
2829
  // setup new/out array
2927
2830
  ...newOut,
2928
- [ Opcodes.drop ],
2929
2831
 
2930
- ...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,
2931
2840
 
2932
2841
  // load current string ind {arg}
2933
2842
  [ Opcodes.local_get, pointer ],
2934
- [ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128(ValtypeSize.i32) ],
2843
+ [ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],
2935
2844
 
2936
2845
  // store to new string ind 0
2937
- [ Opcodes.i32_store16, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128(newPointer + ValtypeSize.i32) ],
2846
+ [ Opcodes.i32_store16, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],
2938
2847
 
2939
2848
  // return new string (page)
2940
- ...number(newPointer),
2849
+ ...newPointer,
2850
+ Opcodes.i32_from_u,
2941
2851
 
2942
2852
  [ isGlobal ? Opcodes.global_set : Opcodes.local_set, local.idx ],
2943
2853
 
@@ -2969,25 +2879,30 @@ const generateForOf = (scope, decl) => {
2969
2879
  [TYPES.bytestring]: [
2970
2880
  ...setType(scope, leftName, TYPES.bytestring),
2971
2881
 
2972
- [ Opcodes.loop, Blocktype.void ],
2973
-
2974
2882
  // setup new/out array
2975
2883
  ...newOut,
2976
- [ Opcodes.drop ],
2977
2884
 
2978
- ...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,
2979
2893
 
2980
2894
  // load current string ind {arg}
2981
2895
  [ Opcodes.local_get, pointer ],
2982
2896
  [ Opcodes.local_get, counter ],
2983
2897
  [ Opcodes.i32_add ],
2984
- [ Opcodes.i32_load8_u, 0, ...unsignedLEB128(ValtypeSize.i32) ],
2898
+ [ Opcodes.i32_load8_u, 0, ValtypeSize.i32 ],
2985
2899
 
2986
2900
  // store to new string ind 0
2987
- [ Opcodes.i32_store8, 0, ...unsignedLEB128(newPointer + ValtypeSize.i32) ],
2901
+ [ Opcodes.i32_store8, 0, ValtypeSize.i32 ],
2988
2902
 
2989
2903
  // return new string (page)
2990
- ...number(newPointer),
2904
+ ...newPointer,
2905
+ Opcodes.i32_from_u,
2991
2906
 
2992
2907
  [ isGlobal ? Opcodes.global_set : Opcodes.local_set, local.idx ],
2993
2908
 
@@ -3207,16 +3122,6 @@ const allocPage = (scope, reason, type) => {
3207
3122
  return ind;
3208
3123
  };
3209
3124
 
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
- return ind;
3218
- };
3219
-
3220
3125
  const itemTypeToValtype = {
3221
3126
  i32: 'i32',
3222
3127
  i64: 'i64',
@@ -3251,39 +3156,43 @@ const compileBytes = (val, itemType) => {
3251
3156
  }
3252
3157
  };
3253
3158
 
3254
- const getAllocType = itemType => {
3255
- switch (itemType) {
3256
- case 'i8': return 'bytestring';
3257
- case 'i16': return 'string';
3159
+ const makeData = (scope, elements, offset = null, itemType, initEmpty) => {
3160
+ const length = elements.length;
3258
3161
 
3259
- default: return 'array';
3260
- }
3261
- };
3162
+ // if length is 0 memory/data will just be 0000... anyway
3163
+ if (length === 0) return false;
3262
3164
 
3263
- const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty = false, itemType = valtype, typed = false) => {
3264
- const out = [];
3165
+ let bytes = compileBytes(length, 'i32');
3166
+
3167
+ if (!initEmpty) for (let i = 0; i < length; i++) {
3168
+ if (elements[i] == null) continue;
3265
3169
 
3266
- scope.arrays ??= new Map();
3170
+ bytes.push(...compileBytes(elements[i], itemType));
3171
+ }
3172
+
3173
+ const obj = { bytes };
3174
+ if (offset != null) obj.offset = offset;
3267
3175
 
3268
- let firstAssign = false;
3269
- if (!scope.arrays.has(name) || name === '$undeclared') {
3270
- firstAssign = true;
3176
+ const idx = data.push(obj) - 1;
3271
3177
 
3272
- // todo: can we just have 1 undeclared array? probably not? but this is not really memory efficient
3273
- const uniqueName = name === '$undeclared' ? name + randId() : name;
3178
+ scope.data ??= [];
3179
+ scope.data.push(idx);
3274
3180
 
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);
3181
+ return { idx, size: bytes.length };
3182
+ };
3278
3183
 
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);
3184
+ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty = false, itemType = valtype, intOut = false, typed = false) => {
3185
+ if (itemType !== 'i16' && itemType !== 'i8') {
3186
+ pages.hasArray = true;
3187
+ } else {
3188
+ pages.hasAnyString = true;
3189
+ if (itemType === 'i8') pages.hasByteString = true;
3190
+ else pages.hasString = true;
3282
3191
  }
3283
3192
 
3284
- const pointer = scope.arrays.get(name);
3193
+ const out = [];
3285
3194
 
3286
- const local = global ? globals[name] : scope.locals[name];
3195
+ const uniqueName = name === '$undeclared' ? name + randId() : name;
3287
3196
 
3288
3197
  const useRawElements = !!decl.rawElements;
3289
3198
  const elements = useRawElements ? decl.rawElements : decl.elements;
@@ -3291,46 +3200,70 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
3291
3200
  const valtype = itemTypeToValtype[itemType];
3292
3201
  const length = elements.length;
3293
3202
 
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');
3203
+ const allocated = allocator.alloc({ scope, pages, globals }, uniqueName, { itemType });
3298
3204
 
3299
- if (!initEmpty) for (let i = 0; i < length; i++) {
3300
- if (elements[i] == null) continue;
3205
+ let pointer = allocated;
3206
+ if (allocator.constructor.name !== 'StaticAllocator') {
3207
+ // const tmp = localTmp(scope, '#makearray_pointer' + uniqueName, Valtype.i32);
3208
+ const tmp = localTmp(scope, '#makearray_pointer' + name, Valtype.i32);
3209
+ out.push(
3210
+ ...allocated,
3211
+ [ Opcodes.local_set, tmp ]
3212
+ );
3213
+
3214
+ pointer = [ [ Opcodes.local_get, tmp ] ];
3301
3215
 
3302
- bytes.push(...compileBytes(elements[i], itemType));
3216
+ if (Prefs.data && useRawElements) {
3217
+ const data = makeData(scope, elements, null, itemType, initEmpty);
3218
+ if (data) {
3219
+ // init data
3220
+ out.push(
3221
+ ...pointer,
3222
+ ...number(0, Valtype.i32),
3223
+ ...number(data.size, Valtype.i32),
3224
+ [ ...Opcodes.memory_init, ...unsignedLEB128(data.idx), 0 ]
3225
+ );
3303
3226
  }
3304
3227
 
3305
- const ind = data.push({
3306
- offset: pointer,
3307
- bytes
3308
- }) - 1;
3228
+ // return pointer in out
3229
+ out.push(
3230
+ ...pointer,
3231
+ ...(!intOut ? [ Opcodes.i32_from_u ] : [])
3232
+ );
3309
3233
 
3310
- scope.data ??= [];
3311
- scope.data.push(ind);
3234
+ return [ out, pointer ];
3312
3235
  }
3236
+ } else {
3237
+ const rawPtr = read_signedLEB128(pointer[0].slice(1));
3313
3238
 
3314
- // local value as pointer
3315
- out.push(...number(pointer));
3239
+ scope.arrays ??= new Map();
3240
+ const firstAssign = !scope.arrays.has(uniqueName);
3241
+ if (firstAssign) scope.arrays.set(uniqueName, rawPtr);
3316
3242
 
3317
- return [ out, pointer ];
3318
- }
3243
+ if (Prefs.data && firstAssign && useRawElements) {
3244
+ makeData(scope, elements, rawPtr, itemType, initEmpty);
3319
3245
 
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
- );
3246
+ // local value as pointer
3247
+ return [ number(rawPtr, intOut ? Valtype.i32 : valtypeBinary), pointer ];
3248
+ }
3249
+
3250
+ const local = global ? globals[name] : scope.locals[name];
3251
+ const pointerTmp = local != null ? localTmp(scope, '#makearray_pointer_tmp', Valtype.i32) : null;
3252
+ if (pointerTmp != null) {
3253
+ out.push(
3254
+ [ global ? Opcodes.global_get : Opcodes.local_get, local.idx ],
3255
+ Opcodes.i32_to_u,
3256
+ [ Opcodes.local_set, pointerTmp ]
3257
+ );
3258
+
3259
+ pointer = [ [ Opcodes.local_get, pointerTmp ] ];
3260
+ }
3327
3261
  }
3328
3262
 
3329
- const pointerWasm = pointerTmp != null ? [ [ Opcodes.local_get, pointerTmp ] ] : number(pointer, Valtype.i32);
3330
3263
 
3331
3264
  // store length
3332
3265
  out.push(
3333
- ...pointerWasm,
3266
+ ...pointer,
3334
3267
  ...number(length, Valtype.i32),
3335
3268
  [ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, 0 ]
3336
3269
  );
@@ -3342,11 +3275,11 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
3342
3275
 
3343
3276
  const offset = ValtypeSize.i32 + i * sizePerEl;
3344
3277
  out.push(
3345
- ...pointerWasm,
3278
+ ...pointer,
3346
3279
  ...(useRawElements ? number(elements[i], Valtype[valtype]) : generate(scope, elements[i])),
3347
3280
  [ storeOp, 0, ...unsignedLEB128(offset) ],
3348
3281
  ...(!typed ? [] : [ // typed presumes !useRawElements
3349
- ...pointerWasm,
3282
+ ...pointer,
3350
3283
  ...getNodeType(scope, elements[i]),
3351
3284
  [ Opcodes.i32_store8, 0, ...unsignedLEB128(offset + ValtypeSize[itemType]) ]
3352
3285
  ])
@@ -3354,12 +3287,13 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
3354
3287
  }
3355
3288
 
3356
3289
  // local value as pointer
3357
- out.push(...pointerWasm, Opcodes.i32_from_u);
3290
+ out.push(...pointer);
3291
+ if (!intOut) out.push(Opcodes.i32_from_u);
3358
3292
 
3359
3293
  return [ out, pointer ];
3360
3294
  };
3361
3295
 
3362
- const storeArray = (scope, array, index, element, aotPointer = null) => {
3296
+ const storeArray = (scope, array, index, element) => {
3363
3297
  if (!Array.isArray(element)) element = generate(scope, element);
3364
3298
  if (typeof index === 'number') index = number(index);
3365
3299
 
@@ -3371,26 +3305,25 @@ const storeArray = (scope, array, index, element, aotPointer = null) => {
3371
3305
  Opcodes.i32_to_u,
3372
3306
  ...number(ValtypeSize[valtype] + 1, Valtype.i32),
3373
3307
  [ Opcodes.i32_mul ],
3374
- ...(aotPointer ? [] : [
3375
- ...array,
3376
- Opcodes.i32_to_u,
3377
- [ Opcodes.i32_add ],
3378
- ]),
3308
+
3309
+ ...array,
3310
+ Opcodes.i32_to_u,
3311
+ [ Opcodes.i32_add ],
3379
3312
  [ Opcodes.local_set, offset ],
3380
3313
 
3381
3314
  // store value
3382
3315
  [ Opcodes.local_get, offset ],
3383
3316
  ...generate(scope, element),
3384
- [ Opcodes.store, 0, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ],
3317
+ [ Opcodes.store, 0, ValtypeSize.i32 ],
3385
3318
 
3386
3319
  // store type
3387
3320
  [ Opcodes.local_get, offset ],
3388
3321
  ...getNodeType(scope, element),
3389
- [ Opcodes.i32_store8, 0, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32 + ValtypeSize[valtype]) ]
3322
+ [ Opcodes.i32_store8, 0, ValtypeSize.i32 + ValtypeSize[valtype] ]
3390
3323
  ];
3391
3324
  };
3392
3325
 
3393
- const loadArray = (scope, array, index, aotPointer = null) => {
3326
+ const loadArray = (scope, array, index) => {
3394
3327
  if (typeof index === 'number') index = number(index);
3395
3328
 
3396
3329
  const offset = localTmp(scope, '#loadArray_offset', Valtype.i32);
@@ -3401,20 +3334,19 @@ const loadArray = (scope, array, index, aotPointer = null) => {
3401
3334
  Opcodes.i32_to_u,
3402
3335
  ...number(ValtypeSize[valtype] + 1, Valtype.i32),
3403
3336
  [ Opcodes.i32_mul ],
3404
- ...(aotPointer ? [] : [
3405
- ...array,
3406
- Opcodes.i32_to_u,
3407
- [ Opcodes.i32_add ],
3408
- ]),
3337
+
3338
+ ...array,
3339
+ Opcodes.i32_to_u,
3340
+ [ Opcodes.i32_add ],
3409
3341
  [ Opcodes.local_set, offset ],
3410
3342
 
3411
3343
  // load value
3412
3344
  [ Opcodes.local_get, offset ],
3413
- [ Opcodes.load, 0, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ],
3345
+ [ Opcodes.load, 0, ValtypeSize.i32 ],
3414
3346
 
3415
3347
  // load type
3416
3348
  [ Opcodes.local_get, offset ],
3417
- [ Opcodes.i32_load8_u, 0, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32 + ValtypeSize[valtype]) ]
3349
+ [ Opcodes.i32_load8_u, 0, ValtypeSize.i32 + ValtypeSize[valtype] ]
3418
3350
  ];
3419
3351
  };
3420
3352
 
@@ -3446,7 +3378,7 @@ const makeString = (scope, str, global = false, name = '$undeclared', forceBytes
3446
3378
  };
3447
3379
 
3448
3380
  const generateArray = (scope, decl, global = false, name = '$undeclared', initEmpty = false) => {
3449
- return makeArray(scope, decl, global, name, initEmpty, valtype, true)[0];
3381
+ return makeArray(scope, decl, global, name, initEmpty, valtype, false, true)[0];
3450
3382
  };
3451
3383
 
3452
3384
  const generateObject = (scope, decl, global = false, name = '$undeclared') => {
@@ -3465,9 +3397,6 @@ const withType = (scope, wasm, type) => [
3465
3397
 
3466
3398
  const generateMember = (scope, decl, _global, _name) => {
3467
3399
  const name = decl.object.name;
3468
- const pointer = scope.arrays?.get(name);
3469
-
3470
- const aotPointer = Prefs.aotPointerOpt && pointer;
3471
3400
 
3472
3401
  // hack: .name
3473
3402
  if (decl.property.name === 'name') {
@@ -3508,12 +3437,10 @@ const generateMember = (scope, decl, _global, _name) => {
3508
3437
  if (Prefs.fastLength) {
3509
3438
  // presume valid length object
3510
3439
  return [
3511
- ...(aotPointer ? number(0, Valtype.i32) : [
3512
- ...generate(scope, decl.object),
3513
- Opcodes.i32_to_u
3514
- ]),
3440
+ ...generate(scope, decl.object),
3441
+ Opcodes.i32_to_u,
3515
3442
 
3516
- [ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, ...unsignedLEB128(aotPointer ? pointer : 0) ],
3443
+ [ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
3517
3444
  Opcodes.i32_from_u
3518
3445
  ];
3519
3446
  }
@@ -3522,12 +3449,10 @@ const generateMember = (scope, decl, _global, _name) => {
3522
3449
  const known = knownType(scope, type);
3523
3450
  if (known != null) {
3524
3451
  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
- ]),
3452
+ ...generate(scope, decl.object),
3453
+ Opcodes.i32_to_u,
3529
3454
 
3530
- [ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, ...unsignedLEB128(aotPointer ? pointer : 0) ],
3455
+ [ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
3531
3456
  Opcodes.i32_from_u
3532
3457
  ];
3533
3458
 
@@ -3537,12 +3462,10 @@ const generateMember = (scope, decl, _global, _name) => {
3537
3462
  return [
3538
3463
  ...typeIsOneOf(getNodeType(scope, decl.object), [ TYPES.string, TYPES.bytestring, TYPES.array ]),
3539
3464
  [ Opcodes.if, valtypeBinary ],
3540
- ...(aotPointer ? number(0, Valtype.i32) : [
3541
- ...generate(scope, decl.object),
3542
- Opcodes.i32_to_u
3543
- ]),
3465
+ ...generate(scope, decl.object),
3466
+ Opcodes.i32_to_u,
3544
3467
 
3545
- [ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, ...unsignedLEB128(aotPointer ? pointer : 0) ],
3468
+ [ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
3546
3469
  Opcodes.i32_from_u,
3547
3470
 
3548
3471
  ...setLastType(scope, TYPES.number),
@@ -3585,25 +3508,29 @@ const generateMember = (scope, decl, _global, _name) => {
3585
3508
 
3586
3509
  // // todo: we should only do this for strings but we don't know at compile-time :(
3587
3510
  // hack: this is naughty and will break things!
3588
- let newOut = number(0, valtypeBinary), newPointer = -1;
3511
+ let newOut = number(0, Valtype.i32), newPointer = number(0, Valtype.i32);
3589
3512
  if (pages.hasAnyString) {
3513
+ // todo: we use i16 even for bytestrings which should not make a bad thing happen, just be confusing for debugging?
3590
3514
  0, [ newOut, newPointer ] = makeArray(scope, {
3591
- rawElements: new Array(1)
3592
- }, _global, _name, true, 'i16');
3515
+ rawElements: new Array(0)
3516
+ }, _global, _name, true, 'i16', true);
3593
3517
  }
3594
3518
 
3595
3519
  return typeSwitch(scope, getNodeType(scope, decl.object), {
3596
3520
  [TYPES.array]: [
3597
- ...loadArray(scope, object, property, aotPointer),
3521
+ ...loadArray(scope, object, property),
3598
3522
  ...setLastType(scope)
3599
3523
  ],
3600
-
3601
3524
  [TYPES.string]: [
3602
3525
  // setup new/out array
3603
3526
  ...newOut,
3604
- [ Opcodes.drop ],
3605
3527
 
3606
- ...number(0, Valtype.i32), // base 0 for store later
3528
+ // set length to 1
3529
+ ...number(1, Valtype.i32),
3530
+ [ Opcodes.i32_store, 0, 0 ],
3531
+
3532
+ // use as pointer for store later
3533
+ ...newPointer,
3607
3534
 
3608
3535
  ...property,
3609
3536
  Opcodes.i32_to_u,
@@ -3611,46 +3538,48 @@ const generateMember = (scope, decl, _global, _name) => {
3611
3538
  ...number(ValtypeSize.i16, Valtype.i32),
3612
3539
  [ Opcodes.i32_mul ],
3613
3540
 
3614
- ...(aotPointer ? [] : [
3615
- ...object,
3616
- Opcodes.i32_to_u,
3617
- [ Opcodes.i32_add ]
3618
- ]),
3541
+ ...object,
3542
+ Opcodes.i32_to_u,
3543
+ [ Opcodes.i32_add ],
3619
3544
 
3620
3545
  // load current string ind {arg}
3621
- [ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ],
3546
+ [ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],
3622
3547
 
3623
3548
  // store to new string ind 0
3624
- [ Opcodes.i32_store16, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128(newPointer + ValtypeSize.i32) ],
3549
+ [ Opcodes.i32_store16, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],
3625
3550
 
3626
3551
  // return new string (page)
3627
- ...number(newPointer),
3552
+ ...newPointer,
3553
+ Opcodes.i32_from_u,
3628
3554
  ...setLastType(scope, TYPES.string)
3629
3555
  ],
3630
3556
  [TYPES.bytestring]: [
3631
3557
  // setup new/out array
3632
3558
  ...newOut,
3633
- [ Opcodes.drop ],
3634
3559
 
3635
- ...number(0, Valtype.i32), // base 0 for store later
3560
+ // set length to 1
3561
+ ...number(1, Valtype.i32),
3562
+ [ Opcodes.i32_store, 0, 0 ],
3563
+
3564
+ // use as pointer for store later
3565
+ ...newPointer,
3636
3566
 
3637
3567
  ...property,
3638
3568
  Opcodes.i32_to_u,
3639
3569
 
3640
- ...(aotPointer ? [] : [
3641
- ...object,
3642
- Opcodes.i32_to_u,
3643
- [ Opcodes.i32_add ]
3644
- ]),
3570
+ ...object,
3571
+ Opcodes.i32_to_u,
3572
+ [ Opcodes.i32_add ],
3645
3573
 
3646
3574
  // load current string ind {arg}
3647
- [ Opcodes.i32_load8_u, 0, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ],
3575
+ [ Opcodes.i32_load8_u, 0, ValtypeSize.i32 ],
3648
3576
 
3649
3577
  // store to new string ind 0
3650
- [ Opcodes.i32_store8, 0, ...unsignedLEB128(newPointer + ValtypeSize.i32) ],
3578
+ [ Opcodes.i32_store8, 0, ValtypeSize.i32 ],
3651
3579
 
3652
3580
  // return new string (page)
3653
- ...number(newPointer),
3581
+ ...newPointer,
3582
+ Opcodes.i32_from_u,
3654
3583
  ...setLastType(scope, TYPES.bytestring)
3655
3584
  ],
3656
3585
 
@@ -3795,9 +3724,9 @@ const internalConstrs = {
3795
3724
 
3796
3725
  // new Array(n)
3797
3726
 
3798
- const [ , pointer ] = makeArray(scope, {
3727
+ const [ out, pointer ] = makeArray(scope, {
3799
3728
  rawElements: new Array(0)
3800
- }, global, name, true);
3729
+ }, global, name, true, undefined, true);
3801
3730
 
3802
3731
  const arg = decl.arguments[0] ?? DEFAULT_VALUE;
3803
3732
 
@@ -3806,12 +3735,13 @@ const internalConstrs = {
3806
3735
  if (literalValue < 0 || !Number.isFinite(literalValue) || literalValue > 4294967295) return internalThrow(scope, 'RangeThrow', 'Invalid array length', true);
3807
3736
 
3808
3737
  return [
3809
- ...number(0, Valtype.i32),
3738
+ ...out,
3810
3739
  ...generate(scope, arg, global, name),
3811
3740
  Opcodes.i32_to_u,
3812
- [ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, ...unsignedLEB128(pointer) ],
3741
+ [ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, 0 ],
3813
3742
 
3814
- ...number(pointer)
3743
+ ...pointer,
3744
+ Opcodes.i32_from_u
3815
3745
  ];
3816
3746
  },
3817
3747
  type: TYPES.array,
@@ -3960,8 +3890,9 @@ const internalConstrs = {
3960
3890
  };
3961
3891
 
3962
3892
  export default program => {
3963
- globals = {};
3964
- globalInd = 0;
3893
+ globals = {
3894
+ ['#ind']: 0
3895
+ };
3965
3896
  tags = [];
3966
3897
  exceptions = [];
3967
3898
  funcs = [];
@@ -3994,6 +3925,7 @@ export default program => {
3994
3925
  builtinFuncs = new BuiltinFuncs();
3995
3926
  builtinVars = new BuiltinVars();
3996
3927
  prototypeFuncs = new PrototypeFuncs();
3928
+ allocator = Allocator(Prefs.allocator ?? 'static');
3997
3929
 
3998
3930
  program.id = { name: 'main' };
3999
3931
 
@@ -4036,6 +3968,8 @@ export default program => {
4036
3968
  else main.returns = [];
4037
3969
  }
4038
3970
 
3971
+ delete globals['#ind'];
3972
+
4039
3973
  // if blank main func and other exports, remove it
4040
3974
  if (main.wasm.length === 0 && funcs.reduce((acc, x) => acc + (x.export ? 1 : 0), 0) > 1) funcs.splice(main.index - importedFuncs.length, 1);
4041
3975