porffor 0.16.0-594397507 → 0.16.0-5c5338783

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
 
@@ -1078,7 +1022,7 @@ const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes
1078
1022
  locals,
1079
1023
  localInd: allLocals.length,
1080
1024
  returns,
1081
- returnType: returnType ?? TYPES.number,
1025
+ returnType,
1082
1026
  internal: true,
1083
1027
  index: currentFuncIndex++,
1084
1028
  table
@@ -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;
@@ -1254,7 +1202,7 @@ const getNodeType = (scope, node) => {
1254
1202
  const func = funcs.find(x => x.name === name);
1255
1203
 
1256
1204
  if (func) {
1257
- if (func.returnType) return func.returnType;
1205
+ if (func.returnType != null) return func.returnType;
1258
1206
  }
1259
1207
 
1260
1208
  if (builtinFuncs[name] && !builtinFuncs[name].typedReturns) return builtinFuncs[name].returnType ?? TYPES.number;
@@ -1270,15 +1218,7 @@ const getNodeType = (scope, node) => {
1270
1218
  const func = spl[spl.length - 1];
1271
1219
  const protoFuncs = Object.keys(prototypeFuncs).filter(x => x != TYPES.bytestring && prototypeFuncs[x][func] != null);
1272
1220
  if (protoFuncs.length === 1) {
1273
- if (protoFuncs[0].returnType) return protoFuncs[0].returnType;
1274
- }
1275
-
1276
- if (protoFuncs.length > 0) {
1277
- if (scope.locals['#last_type']) return getLastType(scope);
1278
-
1279
- // presume
1280
- // todo: warn here?
1281
- return TYPES.number;
1221
+ if (protoFuncs[0].returnType != null) return protoFuncs[0].returnType;
1282
1222
  }
1283
1223
  }
1284
1224
 
@@ -1458,10 +1398,10 @@ const countLeftover = wasm => {
1458
1398
 
1459
1399
  if (depth === 0)
1460
1400
  if ([Opcodes.throw, Opcodes.drop, Opcodes.local_set, Opcodes.global_set].includes(inst[0])) count--;
1461
- 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)) {}
1462
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++;
1463
1403
  else if ([Opcodes.i32_store, Opcodes.i64_store, Opcodes.f64_store, Opcodes.i32_store16, Opcodes.i32_store8].includes(inst[0])) count -= 2;
1464
- 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;
1465
1405
  else if (inst[0] === Opcodes.return) count = 0;
1466
1406
  else if (inst[0] === Opcodes.call) {
1467
1407
  let func = funcs.find(x => x.index === inst[1]);
@@ -1733,7 +1673,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
1733
1673
  }, generate(scope, decl.arguments[0] ?? DEFAULT_VALUE), getNodeType(scope, decl.arguments[0] ?? DEFAULT_VALUE), protoLocal, protoLocal2, (length, itemType) => {
1734
1674
  return makeArray(scope, {
1735
1675
  rawElements: new Array(length)
1736
- }, _global, _name, true, itemType);
1676
+ }, _global, _name, true, itemType, true);
1737
1677
  }, () => {
1738
1678
  optUnused = true;
1739
1679
  return unusedValue;
@@ -1815,7 +1755,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
1815
1755
  f64_store: { imms: 2, args: [ true, false ], returns: 0 },
1816
1756
 
1817
1757
  // value
1818
- i32_const: { imms: 1, args: [], returns: 1 },
1758
+ i32_const: { imms: 1, args: [], returns: 0 },
1819
1759
  };
1820
1760
 
1821
1761
  const opName = name.slice('__Porffor_wasm_'.length);
@@ -1978,7 +1918,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
1978
1918
  const func = funcs[idx - importedFuncs.length]; // idx === scope.index ? scope : funcs.find(x => x.index === idx);
1979
1919
  const userFunc = func && !func.internal;
1980
1920
  const typedParams = userFunc || builtinFuncs[name]?.typedParams;
1981
- const typedReturns = (func && func.returnType == null) || builtinFuncs[name]?.typedReturns;
1921
+ const typedReturns = (userFunc && func.returnType == null) || builtinFuncs[name]?.typedReturns;
1982
1922
  const paramCount = func && (typedParams ? func.params.length / 2 : func.params.length);
1983
1923
 
1984
1924
  let args = decl.arguments;
@@ -2007,8 +1947,8 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
2007
1947
  }
2008
1948
 
2009
1949
  if (valtypeBinary !== Valtype.i32 && (
2010
- (builtinFuncs[name] && builtinFuncs[name].params[i * (typedParams ? 2 : 1)] === Valtype.i32) ||
2011
- (importedFuncs[name] && name.startsWith('profile'))
1950
+ (builtinFuncs[name] && builtinFuncs[name].params[i * (typedParams ? 2 : 1)] === Valtype.i32)
1951
+ // (importedFuncs[name] && name.startsWith('profile'))
2012
1952
  )) {
2013
1953
  out.push(Opcodes.i32_to);
2014
1954
  }
@@ -2123,7 +2063,6 @@ const brTable = (input, bc, returns) => {
2123
2063
  }
2124
2064
 
2125
2065
  for (let i = 0; i < count; i++) {
2126
- // if (i === 0) out.push([ Opcodes.block, returns, 'br table start' ]);
2127
2066
  if (i === 0) out.push([ Opcodes.block, returns ]);
2128
2067
  else out.push([ Opcodes.block, Blocktype.void ]);
2129
2068
  }
@@ -2157,10 +2096,8 @@ const brTable = (input, bc, returns) => {
2157
2096
  [ Opcodes.br_table, ...encodeVector(table), 0 ]
2158
2097
  );
2159
2098
 
2160
- // if you can guess why we sort the wrong way and then reverse
2161
- // (instead of just sorting the correct way)
2162
- // dm me and if you are correct and the first person
2163
- // I will somehow shout you out or something
2099
+ // sort the wrong way and then reverse
2100
+ // so strings ('default') are at the start before any numbers
2164
2101
  const orderedBc = keys.sort((a, b) => b - a).reverse();
2165
2102
 
2166
2103
  br = count - 1;
@@ -2186,10 +2123,10 @@ const typeSwitch = (scope, type, bc, returns = valtypeBinary) => {
2186
2123
  return bc[known] ?? bc.default;
2187
2124
  }
2188
2125
 
2189
- if (Prefs.typeswitchUseBrtable)
2126
+ if (Prefs.typeswitchBrtable)
2190
2127
  return brTable(type, bc, returns);
2191
2128
 
2192
- const tmp = localTmp(scope, '#typeswitch_tmp', Valtype.i32);
2129
+ const tmp = localTmp(scope, '#typeswitch_tmp' + (Prefs.typeswitchUniqueTmp ? randId() : ''), Valtype.i32);
2193
2130
  const out = [
2194
2131
  ...type,
2195
2132
  [ Opcodes.local_set, tmp ],
@@ -2241,11 +2178,11 @@ const allocVar = (scope, name, global = false, type = true) => {
2241
2178
  return target[name].idx;
2242
2179
  }
2243
2180
 
2244
- let idx = global ? globalInd++ : scope.localInd++;
2181
+ let idx = global ? globals['#ind']++ : scope.localInd++;
2245
2182
  target[name] = { idx, type: valtypeBinary };
2246
2183
 
2247
2184
  if (type) {
2248
- let typeIdx = global ? globalInd++ : scope.localInd++;
2185
+ let typeIdx = global ? globals['#ind']++ : scope.localInd++;
2249
2186
  target[name + '#type'] = { idx: typeIdx, type: Valtype.i32, name };
2250
2187
  }
2251
2188
 
@@ -2338,24 +2275,10 @@ const generateVar = (scope, decl) => {
2338
2275
  }
2339
2276
 
2340
2277
  if (x.init) {
2341
- // if (isFuncType(x.init.type)) {
2342
- // // let a = function () { ... }
2343
- // x.init.id = { name };
2344
-
2345
- // const func = generateFunc(scope, x.init);
2346
-
2347
- // out.push(
2348
- // ...number(func.index - importedFuncs.length),
2349
- // [ global ? Opcodes.global_set : Opcodes.local_set, idx ],
2350
-
2351
- // ...setType(scope, name, TYPES.function)
2352
- // );
2353
-
2354
- // continue;
2355
- // }
2278
+ const alreadyArray = scope.arrays?.get(name) != null;
2356
2279
 
2357
2280
  const generated = generate(scope, x.init, global, name);
2358
- if (scope.arrays?.get(name) != null) {
2281
+ if (!alreadyArray && scope.arrays?.get(name) != null) {
2359
2282
  // hack to set local as pointer before
2360
2283
  out.push(...number(scope.arrays.get(name)), [ global ? Opcodes.global_set : Opcodes.local_set, idx ]);
2361
2284
  if (generated.at(-1) == Opcodes.i32_from_u) generated.pop();
@@ -2407,19 +2330,12 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
2407
2330
 
2408
2331
  // hack: .length setter
2409
2332
  if (decl.left.type === 'MemberExpression' && decl.left.property.name === 'length') {
2410
- const name = decl.left.object.name;
2411
- const pointer = scope.arrays?.get(name);
2412
-
2413
- const aotPointer = Prefs.aotPointerOpt && pointer != null;
2414
-
2415
2333
  const newValueTmp = localTmp(scope, '__length_setter_tmp');
2416
2334
  const pointerTmp = op === '=' ? null : localTmp(scope, '__member_setter_ptr_tmp', Valtype.i32);
2417
2335
 
2418
2336
  return [
2419
- ...(aotPointer ? number(0, Valtype.i32) : [
2420
- ...generate(scope, decl.left.object),
2421
- Opcodes.i32_to_u
2422
- ]),
2337
+ ...generate(scope, decl.left.object),
2338
+ Opcodes.i32_to_u,
2423
2339
  ...(!pointerTmp ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
2424
2340
 
2425
2341
  ...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
@@ -2430,7 +2346,7 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
2430
2346
  [ Opcodes.local_tee, newValueTmp ],
2431
2347
 
2432
2348
  Opcodes.i32_to_u,
2433
- [ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, ...unsignedLEB128(aotPointer ? pointer : 0) ],
2349
+ [ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, 0 ],
2434
2350
 
2435
2351
  [ Opcodes.local_get, newValueTmp ]
2436
2352
  ];
@@ -2438,21 +2354,14 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
2438
2354
 
2439
2355
  // arr[i]
2440
2356
  if (decl.left.type === 'MemberExpression' && decl.left.computed) {
2441
- const name = decl.left.object.name;
2442
- const pointer = scope.arrays?.get(name);
2443
-
2444
- const aotPointer = Prefs.aotPointerOpt && pointer != null;
2445
-
2446
2357
  const newValueTmp = localTmp(scope, '__member_setter_val_tmp');
2447
2358
  const pointerTmp = op === '=' ? -1 : localTmp(scope, '__member_setter_ptr_tmp', Valtype.i32);
2448
2359
 
2449
2360
  return [
2450
2361
  ...typeSwitch(scope, getNodeType(scope, decl.left.object), {
2451
2362
  [TYPES.array]: [
2452
- ...(aotPointer ? [] : [
2453
- ...generate(scope, decl.left.object),
2454
- Opcodes.i32_to_u
2455
- ]),
2363
+ ...generate(scope, decl.left.object),
2364
+ Opcodes.i32_to_u,
2456
2365
 
2457
2366
  // get index as valtype
2458
2367
  ...generate(scope, decl.left.property),
@@ -2461,39 +2370,22 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
2461
2370
  // turn into byte offset by * valtypeSize (4 for i32, 8 for i64/f64)
2462
2371
  ...number(ValtypeSize[valtype] + 1, Valtype.i32),
2463
2372
  [ Opcodes.i32_mul ],
2464
- ...(aotPointer ? [] : [ [ Opcodes.i32_add ] ]),
2373
+ [ Opcodes.i32_add ],
2465
2374
  ...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
2466
2375
 
2467
2376
  ...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
2468
2377
  [ Opcodes.local_get, pointerTmp ],
2469
- [ Opcodes.load, 0, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ]
2378
+ [ Opcodes.load, 0, ValtypeSize.i32 ]
2470
2379
  ], generate(scope, decl.right), [
2471
2380
  [ Opcodes.local_get, pointerTmp ],
2472
- [ Opcodes.i32_load8_u, 0, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32 + ValtypeSize[valtype]) ]
2381
+ [ Opcodes.i32_load8_u, 0, ValtypeSize.i32 + ValtypeSize[valtype] ]
2473
2382
  ], getNodeType(scope, decl.right), false, name, true)),
2474
2383
  [ Opcodes.local_tee, newValueTmp ],
2475
2384
 
2476
- [ Opcodes.store, 0, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ]
2385
+ [ Opcodes.store, 0, ValtypeSize.i32 ]
2477
2386
  ],
2478
2387
 
2479
2388
  default: internalThrow(scope, 'TypeError', `Cannot assign member with non-array`)
2480
-
2481
- // [TYPES.string]: [
2482
- // // turn into byte offset by * sizeof i16
2483
- // ...number(ValtypeSize.i16, Valtype.i32),
2484
- // [ Opcodes.i32_mul ],
2485
- // ...(aotPointer ? [] : [ [ Opcodes.i32_add ] ]),
2486
- // ...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
2487
-
2488
- // ...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
2489
- // [ Opcodes.local_get, pointerTmp ],
2490
- // [ Opcodes.load, Math.log2(ValtypeSize[valtype]) - 1, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ]
2491
- // ], generate(scope, decl.right), number(TYPES.string, Valtype.i32), getNodeType(scope, decl.right))),
2492
- // [ Opcodes.local_tee, newValueTmp ],
2493
-
2494
- // Opcodes.i32_to_u,
2495
- // [ StoreOps.i16, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ]
2496
- // ]
2497
2389
  }, Blocktype.void),
2498
2390
 
2499
2391
  [ Opcodes.local_get, newValueTmp ]
@@ -2571,7 +2463,7 @@ const generateUnary = (scope, decl) => {
2571
2463
  // * -1
2572
2464
 
2573
2465
  if (decl.prefix && decl.argument.type === 'Literal' && typeof decl.argument.value === 'number') {
2574
- // if -<N>, just return that
2466
+ // if -n, just return that as a const
2575
2467
  return number(-1 * decl.argument.value);
2576
2468
  }
2577
2469
 
@@ -2583,14 +2475,14 @@ const generateUnary = (scope, decl) => {
2583
2475
  case '!':
2584
2476
  const arg = decl.argument;
2585
2477
  if (arg.type === 'UnaryExpression' && arg.operator === '!') {
2586
- // !!x -> is x truthy
2478
+ // opt: !!x -> is x truthy
2587
2479
  return truthy(scope, generate(scope, arg.argument), getNodeType(scope, arg.argument), false, false);
2588
2480
  }
2481
+
2589
2482
  // !=
2590
- return falsy(scope, generate(scope, decl.argument), getNodeType(scope, decl.argument), false, false);
2483
+ return falsy(scope, generate(scope, arg), getNodeType(scope, arg), false, false);
2591
2484
 
2592
2485
  case '~':
2593
- // todo: does not handle Infinity properly (should convert to 0) (but opt const converting saves us sometimes)
2594
2486
  return [
2595
2487
  ...generate(scope, decl.argument),
2596
2488
  Opcodes.i32_to,
@@ -2877,12 +2769,12 @@ const generateForOf = (scope, decl) => {
2877
2769
 
2878
2770
  // // todo: we should only do this for strings but we don't know at compile-time :(
2879
2771
  // hack: this is naughty and will break things!
2880
- let newOut = number(0, Valtype.f64), newPointer = -1;
2772
+ let newOut = number(0, Valtype.i32), newPointer = number(0, Valtype.i32);
2881
2773
  if (pages.hasAnyString) {
2882
2774
  // todo: we use i16 even for bytestrings which should not make a bad thing happen, just be confusing for debugging?
2883
2775
  0, [ newOut, newPointer ] = makeArray(scope, {
2884
- rawElements: new Array(1)
2885
- }, isGlobal, leftName, true, 'i16');
2776
+ rawElements: new Array(0)
2777
+ }, isGlobal, leftName, true, 'i16', true);
2886
2778
  }
2887
2779
 
2888
2780
  // set type for local
@@ -2929,23 +2821,28 @@ const generateForOf = (scope, decl) => {
2929
2821
  [TYPES.string]: [
2930
2822
  ...setType(scope, leftName, TYPES.string),
2931
2823
 
2932
- [ Opcodes.loop, Blocktype.void ],
2933
-
2934
2824
  // setup new/out array
2935
2825
  ...newOut,
2936
- [ Opcodes.drop ],
2937
2826
 
2938
- ...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,
2939
2835
 
2940
2836
  // load current string ind {arg}
2941
2837
  [ Opcodes.local_get, pointer ],
2942
- [ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128(ValtypeSize.i32) ],
2838
+ [ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],
2943
2839
 
2944
2840
  // store to new string ind 0
2945
- [ Opcodes.i32_store16, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128(newPointer + ValtypeSize.i32) ],
2841
+ [ Opcodes.i32_store16, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],
2946
2842
 
2947
2843
  // return new string (page)
2948
- ...number(newPointer),
2844
+ ...newPointer,
2845
+ Opcodes.i32_from_u,
2949
2846
 
2950
2847
  [ isGlobal ? Opcodes.global_set : Opcodes.local_set, local.idx ],
2951
2848
 
@@ -2977,25 +2874,30 @@ const generateForOf = (scope, decl) => {
2977
2874
  [TYPES.bytestring]: [
2978
2875
  ...setType(scope, leftName, TYPES.bytestring),
2979
2876
 
2980
- [ Opcodes.loop, Blocktype.void ],
2981
-
2982
2877
  // setup new/out array
2983
2878
  ...newOut,
2984
- [ Opcodes.drop ],
2985
2879
 
2986
- ...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,
2987
2888
 
2988
2889
  // load current string ind {arg}
2989
2890
  [ Opcodes.local_get, pointer ],
2990
2891
  [ Opcodes.local_get, counter ],
2991
2892
  [ Opcodes.i32_add ],
2992
- [ Opcodes.i32_load8_u, 0, ...unsignedLEB128(ValtypeSize.i32) ],
2893
+ [ Opcodes.i32_load8_u, 0, ValtypeSize.i32 ],
2993
2894
 
2994
2895
  // store to new string ind 0
2995
- [ Opcodes.i32_store8, 0, ...unsignedLEB128(newPointer + ValtypeSize.i32) ],
2896
+ [ Opcodes.i32_store8, 0, ValtypeSize.i32 ],
2996
2897
 
2997
2898
  // return new string (page)
2998
- ...number(newPointer),
2899
+ ...newPointer,
2900
+ Opcodes.i32_from_u,
2999
2901
 
3000
2902
  [ isGlobal ? Opcodes.global_set : Opcodes.local_set, local.idx ],
3001
2903
 
@@ -3210,18 +3112,6 @@ const allocPage = (scope, reason, type) => {
3210
3112
  scope.pages ??= new Map();
3211
3113
  scope.pages.set(reason, { ind, type });
3212
3114
 
3213
- if (Prefs.allocLog) log('alloc', `allocated new page of memory (${ind}) | ${reason} (type: ${type})`);
3214
-
3215
- return ind;
3216
- };
3217
-
3218
- // todo: add scope.pages
3219
- const freePage = reason => {
3220
- const { ind } = pages.get(reason);
3221
- pages.delete(reason);
3222
-
3223
- if (Prefs.allocLog) log('alloc', `freed page of memory (${ind}) | ${reason}`);
3224
-
3225
3115
  return ind;
3226
3116
  };
3227
3117
 
@@ -3259,39 +3149,58 @@ const compileBytes = (val, itemType) => {
3259
3149
  }
3260
3150
  };
3261
3151
 
3262
- const getAllocType = itemType => {
3263
- switch (itemType) {
3264
- case 'i8': return 'bytestring';
3265
- case 'i16': return 'string';
3152
+ const makeData = (scope, elements, offset = null, itemType, initEmpty) => {
3153
+ const length = elements.length;
3266
3154
 
3267
- default: return 'array';
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');
3159
+
3160
+ if (!initEmpty) for (let i = 0; i < length; i++) {
3161
+ if (elements[i] == null) continue;
3162
+
3163
+ bytes.push(...compileBytes(elements[i], itemType));
3268
3164
  }
3269
- };
3270
3165
 
3271
- const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty = false, itemType = valtype, typed = false) => {
3272
- const out = [];
3166
+ const obj = { bytes };
3167
+ if (offset != null) obj.offset = offset;
3168
+
3169
+ const idx = data.push(obj) - 1;
3273
3170
 
3274
- scope.arrays ??= new Map();
3171
+ scope.data ??= [];
3172
+ scope.data.push(idx);
3275
3173
 
3276
- let firstAssign = false;
3277
- if (!scope.arrays.has(name) || name === '$undeclared') {
3278
- firstAssign = true;
3174
+ return { idx, size: bytes.length };
3175
+ };
3176
+
3177
+ const printStaticStr = str => {
3178
+ const out = [];
3279
3179
 
3280
- // todo: can we just have 1 undeclared array? probably not? but this is not really memory efficient
3281
- const uniqueName = name === '$undeclared' ? name + Math.random().toString().slice(2) : name;
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
+ }
3282
3188
 
3283
- let page;
3284
- if (Prefs.scopedPageNames) page = allocPage(scope, `${getAllocType(itemType)}: ${scope.name}/${uniqueName}`, itemType);
3285
- else page = allocPage(scope, `${getAllocType(itemType)}: ${uniqueName}`, itemType);
3189
+ return out;
3190
+ };
3286
3191
 
3287
- // hack: use 1 for page 0 pointer for fast truthiness
3288
- const ptr = page === 0 ? 1 : (page * pageSize);
3289
- scope.arrays.set(name, ptr);
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;
3290
3199
  }
3291
3200
 
3292
- const pointer = scope.arrays.get(name);
3201
+ const out = [];
3293
3202
 
3294
- const local = global ? globals[name] : scope.locals[name];
3203
+ const uniqueName = name === '$undeclared' ? name + randId() : name;
3295
3204
 
3296
3205
  const useRawElements = !!decl.rawElements;
3297
3206
  const elements = useRawElements ? decl.rawElements : decl.elements;
@@ -3299,46 +3208,81 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
3299
3208
  const valtype = itemTypeToValtype[itemType];
3300
3209
  const length = elements.length;
3301
3210
 
3302
- if (firstAssign && useRawElements && !Prefs.noData) {
3303
- // if length is 0 memory/data will just be 0000... anyway
3304
- if (length !== 0) {
3305
- let bytes = compileBytes(length, 'i32');
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}: `),
3306
3224
 
3307
- if (!initEmpty) for (let i = 0; i < length; i++) {
3308
- if (elements[i] == null) continue;
3225
+ [ Opcodes.local_get, tmp ],
3226
+ Opcodes.i32_from_u,
3227
+ [ Opcodes.call, 0 ],
3309
3228
 
3310
- 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
+ );
3311
3245
  }
3312
3246
 
3313
- const ind = data.push({
3314
- offset: pointer,
3315
- bytes
3316
- }) - 1;
3247
+ // return pointer in out
3248
+ out.push(
3249
+ ...pointer,
3250
+ ...(!intOut ? [ Opcodes.i32_from_u ] : [])
3251
+ );
3317
3252
 
3318
- scope.data ??= [];
3319
- scope.data.push(ind);
3253
+ return [ out, pointer ];
3320
3254
  }
3255
+ } else {
3256
+ const rawPtr = read_signedLEB128(pointer[0].slice(1));
3321
3257
 
3322
- // local value as pointer
3323
- out.push(...number(pointer));
3258
+ scope.arrays ??= new Map();
3259
+ const firstAssign = !scope.arrays.has(uniqueName);
3260
+ if (firstAssign) scope.arrays.set(uniqueName, rawPtr);
3324
3261
 
3325
- return [ out, pointer ];
3326
- }
3262
+ if (Prefs.data && firstAssign && useRawElements) {
3263
+ makeData(scope, elements, rawPtr, itemType, initEmpty);
3327
3264
 
3328
- const pointerTmp = local != null ? localTmp(scope, '#makearray_pointer_tmp', Valtype.i32) : null;
3329
- if (pointerTmp != null) {
3330
- out.push(
3331
- [ global ? Opcodes.global_get : Opcodes.local_get, local.idx ],
3332
- Opcodes.i32_to_u,
3333
- [ Opcodes.local_set, pointerTmp ]
3334
- );
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
+ }
3335
3280
  }
3336
3281
 
3337
- const pointerWasm = pointerTmp != null ? [ [ Opcodes.local_get, pointerTmp ] ] : number(pointer, Valtype.i32);
3338
3282
 
3339
3283
  // store length
3340
3284
  out.push(
3341
- ...pointerWasm,
3285
+ ...pointer,
3342
3286
  ...number(length, Valtype.i32),
3343
3287
  [ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, 0 ]
3344
3288
  );
@@ -3350,11 +3294,11 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
3350
3294
 
3351
3295
  const offset = ValtypeSize.i32 + i * sizePerEl;
3352
3296
  out.push(
3353
- ...pointerWasm,
3297
+ ...pointer,
3354
3298
  ...(useRawElements ? number(elements[i], Valtype[valtype]) : generate(scope, elements[i])),
3355
3299
  [ storeOp, 0, ...unsignedLEB128(offset) ],
3356
3300
  ...(!typed ? [] : [ // typed presumes !useRawElements
3357
- ...pointerWasm,
3301
+ ...pointer,
3358
3302
  ...getNodeType(scope, elements[i]),
3359
3303
  [ Opcodes.i32_store8, 0, ...unsignedLEB128(offset + ValtypeSize[itemType]) ]
3360
3304
  ])
@@ -3362,12 +3306,13 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
3362
3306
  }
3363
3307
 
3364
3308
  // local value as pointer
3365
- out.push(...pointerWasm, Opcodes.i32_from_u);
3309
+ out.push(...pointer);
3310
+ if (!intOut) out.push(Opcodes.i32_from_u);
3366
3311
 
3367
3312
  return [ out, pointer ];
3368
3313
  };
3369
3314
 
3370
- const storeArray = (scope, array, index, element, aotPointer = null) => {
3315
+ const storeArray = (scope, array, index, element) => {
3371
3316
  if (!Array.isArray(element)) element = generate(scope, element);
3372
3317
  if (typeof index === 'number') index = number(index);
3373
3318
 
@@ -3379,26 +3324,25 @@ const storeArray = (scope, array, index, element, aotPointer = null) => {
3379
3324
  Opcodes.i32_to_u,
3380
3325
  ...number(ValtypeSize[valtype] + 1, Valtype.i32),
3381
3326
  [ Opcodes.i32_mul ],
3382
- ...(aotPointer ? [] : [
3383
- ...array,
3384
- Opcodes.i32_to_u,
3385
- [ Opcodes.i32_add ],
3386
- ]),
3327
+
3328
+ ...array,
3329
+ Opcodes.i32_to_u,
3330
+ [ Opcodes.i32_add ],
3387
3331
  [ Opcodes.local_set, offset ],
3388
3332
 
3389
3333
  // store value
3390
3334
  [ Opcodes.local_get, offset ],
3391
3335
  ...generate(scope, element),
3392
- [ Opcodes.store, 0, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ],
3336
+ [ Opcodes.store, 0, ValtypeSize.i32 ],
3393
3337
 
3394
3338
  // store type
3395
3339
  [ Opcodes.local_get, offset ],
3396
3340
  ...getNodeType(scope, element),
3397
- [ Opcodes.i32_store8, 0, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32 + ValtypeSize[valtype]) ]
3341
+ [ Opcodes.i32_store8, 0, ValtypeSize.i32 + ValtypeSize[valtype] ]
3398
3342
  ];
3399
3343
  };
3400
3344
 
3401
- const loadArray = (scope, array, index, aotPointer = null) => {
3345
+ const loadArray = (scope, array, index) => {
3402
3346
  if (typeof index === 'number') index = number(index);
3403
3347
 
3404
3348
  const offset = localTmp(scope, '#loadArray_offset', Valtype.i32);
@@ -3409,20 +3353,19 @@ const loadArray = (scope, array, index, aotPointer = null) => {
3409
3353
  Opcodes.i32_to_u,
3410
3354
  ...number(ValtypeSize[valtype] + 1, Valtype.i32),
3411
3355
  [ Opcodes.i32_mul ],
3412
- ...(aotPointer ? [] : [
3413
- ...array,
3414
- Opcodes.i32_to_u,
3415
- [ Opcodes.i32_add ],
3416
- ]),
3356
+
3357
+ ...array,
3358
+ Opcodes.i32_to_u,
3359
+ [ Opcodes.i32_add ],
3417
3360
  [ Opcodes.local_set, offset ],
3418
3361
 
3419
3362
  // load value
3420
3363
  [ Opcodes.local_get, offset ],
3421
- [ Opcodes.load, 0, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ],
3364
+ [ Opcodes.load, 0, ValtypeSize.i32 ],
3422
3365
 
3423
3366
  // load type
3424
3367
  [ Opcodes.local_get, offset ],
3425
- [ Opcodes.i32_load8_u, 0, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32 + ValtypeSize[valtype]) ]
3368
+ [ Opcodes.i32_load8_u, 0, ValtypeSize.i32 + ValtypeSize[valtype] ]
3426
3369
  ];
3427
3370
  };
3428
3371
 
@@ -3454,7 +3397,7 @@ const makeString = (scope, str, global = false, name = '$undeclared', forceBytes
3454
3397
  };
3455
3398
 
3456
3399
  const generateArray = (scope, decl, global = false, name = '$undeclared', initEmpty = false) => {
3457
- return makeArray(scope, decl, global, name, initEmpty, valtype, true)[0];
3400
+ return makeArray(scope, decl, global, name, initEmpty, valtype, false, true)[0];
3458
3401
  };
3459
3402
 
3460
3403
  const generateObject = (scope, decl, global = false, name = '$undeclared') => {
@@ -3473,9 +3416,6 @@ const withType = (scope, wasm, type) => [
3473
3416
 
3474
3417
  const generateMember = (scope, decl, _global, _name) => {
3475
3418
  const name = decl.object.name;
3476
- const pointer = scope.arrays?.get(name);
3477
-
3478
- const aotPointer = Prefs.aotPointerOpt && pointer;
3479
3419
 
3480
3420
  // hack: .name
3481
3421
  if (decl.property.name === 'name') {
@@ -3510,18 +3450,16 @@ const generateMember = (scope, decl, _global, _name) => {
3510
3450
  }
3511
3451
 
3512
3452
  if (builtinFuncs[name]) return withType(scope, number(builtinFuncs[name].typedParams ? (builtinFuncs[name].params.length / 2) : builtinFuncs[name].params.length), TYPES.number);
3513
- if (importedFuncs[name]) return withType(scope, number(importedFuncs[name].params), TYPES.number);
3453
+ if (importedFuncs[name]) return withType(scope, number(importedFuncs[name].params.length ?? importedFuncs[name].params), TYPES.number);
3514
3454
  if (internalConstrs[name]) return withType(scope, number(internalConstrs[name].length ?? 0), TYPES.number);
3515
3455
 
3516
3456
  if (Prefs.fastLength) {
3517
3457
  // presume valid length object
3518
3458
  return [
3519
- ...(aotPointer ? number(0, Valtype.i32) : [
3520
- ...generate(scope, decl.object),
3521
- Opcodes.i32_to_u
3522
- ]),
3459
+ ...generate(scope, decl.object),
3460
+ Opcodes.i32_to_u,
3523
3461
 
3524
- [ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, ...unsignedLEB128(aotPointer ? pointer : 0) ],
3462
+ [ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
3525
3463
  Opcodes.i32_from_u
3526
3464
  ];
3527
3465
  }
@@ -3530,12 +3468,10 @@ const generateMember = (scope, decl, _global, _name) => {
3530
3468
  const known = knownType(scope, type);
3531
3469
  if (known != null) {
3532
3470
  if ([ TYPES.string, TYPES.bytestring, TYPES.array ].includes(known)) return [
3533
- ...(aotPointer ? number(0, Valtype.i32) : [
3534
- ...generate(scope, decl.object),
3535
- Opcodes.i32_to_u
3536
- ]),
3471
+ ...generate(scope, decl.object),
3472
+ Opcodes.i32_to_u,
3537
3473
 
3538
- [ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, ...unsignedLEB128(aotPointer ? pointer : 0) ],
3474
+ [ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
3539
3475
  Opcodes.i32_from_u
3540
3476
  ];
3541
3477
 
@@ -3545,12 +3481,10 @@ const generateMember = (scope, decl, _global, _name) => {
3545
3481
  return [
3546
3482
  ...typeIsOneOf(getNodeType(scope, decl.object), [ TYPES.string, TYPES.bytestring, TYPES.array ]),
3547
3483
  [ Opcodes.if, valtypeBinary ],
3548
- ...(aotPointer ? number(0, Valtype.i32) : [
3549
- ...generate(scope, decl.object),
3550
- Opcodes.i32_to_u
3551
- ]),
3484
+ ...generate(scope, decl.object),
3485
+ Opcodes.i32_to_u,
3552
3486
 
3553
- [ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, ...unsignedLEB128(aotPointer ? pointer : 0) ],
3487
+ [ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
3554
3488
  Opcodes.i32_from_u,
3555
3489
 
3556
3490
  ...setLastType(scope, TYPES.number),
@@ -3593,25 +3527,29 @@ const generateMember = (scope, decl, _global, _name) => {
3593
3527
 
3594
3528
  // // todo: we should only do this for strings but we don't know at compile-time :(
3595
3529
  // hack: this is naughty and will break things!
3596
- let newOut = number(0, valtypeBinary), newPointer = -1;
3530
+ let newOut = number(0, Valtype.i32), newPointer = number(0, Valtype.i32);
3597
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?
3598
3533
  0, [ newOut, newPointer ] = makeArray(scope, {
3599
- rawElements: new Array(1)
3600
- }, _global, _name, true, 'i16');
3534
+ rawElements: new Array(0)
3535
+ }, _global, _name, true, 'i16', true);
3601
3536
  }
3602
3537
 
3603
3538
  return typeSwitch(scope, getNodeType(scope, decl.object), {
3604
3539
  [TYPES.array]: [
3605
- ...loadArray(scope, object, property, aotPointer),
3540
+ ...loadArray(scope, object, property),
3606
3541
  ...setLastType(scope)
3607
3542
  ],
3608
-
3609
3543
  [TYPES.string]: [
3610
3544
  // setup new/out array
3611
3545
  ...newOut,
3612
- [ Opcodes.drop ],
3613
3546
 
3614
- ...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,
3615
3553
 
3616
3554
  ...property,
3617
3555
  Opcodes.i32_to_u,
@@ -3619,46 +3557,48 @@ const generateMember = (scope, decl, _global, _name) => {
3619
3557
  ...number(ValtypeSize.i16, Valtype.i32),
3620
3558
  [ Opcodes.i32_mul ],
3621
3559
 
3622
- ...(aotPointer ? [] : [
3623
- ...object,
3624
- Opcodes.i32_to_u,
3625
- [ Opcodes.i32_add ]
3626
- ]),
3560
+ ...object,
3561
+ Opcodes.i32_to_u,
3562
+ [ Opcodes.i32_add ],
3627
3563
 
3628
3564
  // load current string ind {arg}
3629
- [ 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 ],
3630
3566
 
3631
3567
  // store to new string ind 0
3632
- [ Opcodes.i32_store16, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128(newPointer + ValtypeSize.i32) ],
3568
+ [ Opcodes.i32_store16, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],
3633
3569
 
3634
3570
  // return new string (page)
3635
- ...number(newPointer),
3571
+ ...newPointer,
3572
+ Opcodes.i32_from_u,
3636
3573
  ...setLastType(scope, TYPES.string)
3637
3574
  ],
3638
3575
  [TYPES.bytestring]: [
3639
3576
  // setup new/out array
3640
3577
  ...newOut,
3641
- [ Opcodes.drop ],
3642
3578
 
3643
- ...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,
3644
3585
 
3645
3586
  ...property,
3646
3587
  Opcodes.i32_to_u,
3647
3588
 
3648
- ...(aotPointer ? [] : [
3649
- ...object,
3650
- Opcodes.i32_to_u,
3651
- [ Opcodes.i32_add ]
3652
- ]),
3589
+ ...object,
3590
+ Opcodes.i32_to_u,
3591
+ [ Opcodes.i32_add ],
3653
3592
 
3654
3593
  // load current string ind {arg}
3655
- [ Opcodes.i32_load8_u, 0, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ],
3594
+ [ Opcodes.i32_load8_u, 0, ValtypeSize.i32 ],
3656
3595
 
3657
3596
  // store to new string ind 0
3658
- [ Opcodes.i32_store8, 0, ...unsignedLEB128(newPointer + ValtypeSize.i32) ],
3597
+ [ Opcodes.i32_store8, 0, ValtypeSize.i32 ],
3659
3598
 
3660
3599
  // return new string (page)
3661
- ...number(newPointer),
3600
+ ...newPointer,
3601
+ Opcodes.i32_from_u,
3662
3602
  ...setLastType(scope, TYPES.bytestring)
3663
3603
  ],
3664
3604
 
@@ -3666,7 +3606,7 @@ const generateMember = (scope, decl, _global, _name) => {
3666
3606
  });
3667
3607
  };
3668
3608
 
3669
- const randId = () => Math.random().toString(16).slice(0, -4);
3609
+ const randId = () => Math.random().toString(16).slice(1, -2).padEnd(12, '0');
3670
3610
 
3671
3611
  const objectHack = node => {
3672
3612
  if (!node) return node;
@@ -3718,7 +3658,7 @@ const generateFunc = (scope, decl) => {
3718
3658
  if (decl.async) return todo(scope, 'async functions are not supported');
3719
3659
  if (decl.generator) return todo(scope, 'generator functions are not supported');
3720
3660
 
3721
- const name = decl.id ? decl.id.name : `anonymous_${randId()}`;
3661
+ const name = decl.id ? decl.id.name : `anonymous${randId()}`;
3722
3662
  const params = decl.params ?? [];
3723
3663
 
3724
3664
  // TODO: share scope/locals between !!!
@@ -3803,9 +3743,9 @@ const internalConstrs = {
3803
3743
 
3804
3744
  // new Array(n)
3805
3745
 
3806
- const [ , pointer ] = makeArray(scope, {
3746
+ const [ out, pointer ] = makeArray(scope, {
3807
3747
  rawElements: new Array(0)
3808
- }, global, name, true);
3748
+ }, global, name, true, undefined, true);
3809
3749
 
3810
3750
  const arg = decl.arguments[0] ?? DEFAULT_VALUE;
3811
3751
 
@@ -3814,12 +3754,13 @@ const internalConstrs = {
3814
3754
  if (literalValue < 0 || !Number.isFinite(literalValue) || literalValue > 4294967295) return internalThrow(scope, 'RangeThrow', 'Invalid array length', true);
3815
3755
 
3816
3756
  return [
3817
- ...number(0, Valtype.i32),
3757
+ ...out,
3818
3758
  ...generate(scope, arg, global, name),
3819
3759
  Opcodes.i32_to_u,
3820
- [ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, ...unsignedLEB128(pointer) ],
3760
+ [ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, 0 ],
3821
3761
 
3822
- ...number(pointer)
3762
+ ...pointer,
3763
+ Opcodes.i32_from_u
3823
3764
  ];
3824
3765
  },
3825
3766
  type: TYPES.array,
@@ -3968,8 +3909,9 @@ const internalConstrs = {
3968
3909
  };
3969
3910
 
3970
3911
  export default program => {
3971
- globals = {};
3972
- globalInd = 0;
3912
+ globals = {
3913
+ ['#ind']: 0
3914
+ };
3973
3915
  tags = [];
3974
3916
  exceptions = [];
3975
3917
  funcs = [];
@@ -3979,19 +3921,8 @@ export default program => {
3979
3921
  data = [];
3980
3922
  currentFuncIndex = importedFuncs.length;
3981
3923
 
3982
- globalThis.valtype = 'f64';
3983
-
3984
- const valtypeOpt = process.argv.find(x => x.startsWith('--valtype='));
3985
- if (valtypeOpt) valtype = valtypeOpt.split('=')[1];
3986
-
3987
- globalThis.valtypeBinary = Valtype[valtype];
3988
-
3989
3924
  const valtypeInd = ['i32', 'i64', 'f64'].indexOf(valtype);
3990
3925
 
3991
- globalThis.pageSize = PageSize;
3992
- const pageSizeOpt = process.argv.find(x => x.startsWith('--page-size='));
3993
- if (pageSizeOpt) pageSize = parseInt(pageSizeOpt.split('=')[1]) * 1024;
3994
-
3995
3926
  // set generic opcodes for current valtype
3996
3927
  Opcodes.const = [ Opcodes.i32_const, Opcodes.i64_const, Opcodes.f64_const ][valtypeInd];
3997
3928
  Opcodes.eq = [ Opcodes.i32_eq, Opcodes.i64_eq, Opcodes.f64_eq ][valtypeInd];
@@ -4013,6 +3944,7 @@ export default program => {
4013
3944
  builtinFuncs = new BuiltinFuncs();
4014
3945
  builtinVars = new BuiltinVars();
4015
3946
  prototypeFuncs = new PrototypeFuncs();
3947
+ allocator = makeAllocator(Prefs.allocator ?? 'static');
4016
3948
 
4017
3949
  program.id = { name: 'main' };
4018
3950
 
@@ -4055,6 +3987,8 @@ export default program => {
4055
3987
  else main.returns = [];
4056
3988
  }
4057
3989
 
3990
+ delete globals['#ind'];
3991
+
4058
3992
  // if blank main func and other exports, remove it
4059
3993
  if (main.wasm.length === 0 && funcs.reduce((acc, x) => acc + (x.export ? 1 : 0), 0) > 1) funcs.splice(main.index - importedFuncs.length, 1);
4060
3994