porffor 0.16.0-30af62694 → 0.16.0-4d434e797

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
+ }, assign ? false : global, assign ? undefined : 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
@@ -1014,12 +958,9 @@ const performOp = (scope, op, left, right, leftType, rightType, _global = false,
1014
958
  [ Opcodes.end ],
1015
959
  ]));
1016
960
 
1017
- // if not already in block, add a block
1018
- // if (endOut.length === 0) {
1019
- startOut.push(stringOnly([ Opcodes.block, Valtype.i32 ]));
1020
- // endOut.push(stringOnly([ Opcodes.end ]));
1021
- endOut.unshift(stringOnly([ Opcodes.end ]));
1022
- // }
961
+ // add a surrounding block
962
+ startOut.push(stringOnly([ Opcodes.block, Valtype.i32 ]));
963
+ endOut.unshift(stringOnly([ Opcodes.end ]));
1023
964
  }
1024
965
 
1025
966
  return finalize([
@@ -1054,7 +995,7 @@ const asmFuncToAsm = (func, scope) => {
1054
995
  });
1055
996
  };
1056
997
 
1057
- const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes = [], globalInits, returns, returnType, localNames = [], globalNames = [], data: _data = [], table = false }) => {
998
+ const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes = [], globalInits = [], returns, returnType, localNames = [], globalNames = [], data: _data = [], table = false }) => {
1058
999
  const existing = funcs.find(x => x.name === name);
1059
1000
  if (existing) return existing;
1060
1001
 
@@ -1068,7 +1009,7 @@ const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes
1068
1009
 
1069
1010
  for (const x of _data) {
1070
1011
  const copy = { ...x };
1071
- copy.offset += pages.size * pageSize;
1012
+ if (copy.offset != null) copy.offset += pages.size * pageSize;
1072
1013
  data.push(copy);
1073
1014
  }
1074
1015
 
@@ -1091,9 +1032,9 @@ const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes
1091
1032
 
1092
1033
  let baseGlobalIdx, i = 0;
1093
1034
  for (const type of globalTypes) {
1094
- if (baseGlobalIdx === undefined) baseGlobalIdx = globalInd;
1035
+ if (baseGlobalIdx === undefined) baseGlobalIdx = globals['#ind'];
1095
1036
 
1096
- globals[globalNames[i] ?? `${name}_global_${i}`] = { idx: globalInd++, type, init: globalInits[i] ?? 0 };
1037
+ globals[globalNames[i] ?? `${name}_global_${i}`] = { idx: globals['#ind']++, type, init: globalInits[i] ?? 0 };
1097
1038
  i++;
1098
1039
  }
1099
1040
 
@@ -1106,11 +1047,15 @@ const asmFunc = (name, { wasm, params, locals: localTypes, globals: globalTypes
1106
1047
  }
1107
1048
  }
1108
1049
 
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));
1050
+ if (table) {
1051
+ for (const inst of wasm) {
1052
+ if (inst[0] === Opcodes.i32_load16_u && inst.at(-1) === 'read_argc') {
1053
+ inst.splice(2, 99);
1054
+ inst.push(...unsignedLEB128(allocPage({}, 'func argc lut') * pageSize));
1055
+ }
1113
1056
  }
1057
+
1058
+ funcs.table = true;
1114
1059
  }
1115
1060
 
1116
1061
  func.wasm = wasm;
@@ -1318,7 +1263,15 @@ const getNodeType = (scope, node) => {
1318
1263
  }
1319
1264
 
1320
1265
  if (node.type === 'AssignmentExpression') {
1321
- return getNodeType(scope, node.right);
1266
+ const op = node.operator.slice(0, -1) || '=';
1267
+ if (op === '=') return getNodeType(scope, node.right);
1268
+
1269
+ return getNodeType(scope, {
1270
+ type: ['||', '&&', '??'].includes(op) ? 'LogicalExpression' : 'BinaryExpression',
1271
+ left: node.left,
1272
+ right: node.right,
1273
+ operator: op
1274
+ });
1322
1275
  }
1323
1276
 
1324
1277
  if (node.type === 'ArrayExpression') {
@@ -1337,23 +1290,6 @@ const getNodeType = (scope, node) => {
1337
1290
  if (knownLeft === TYPES.bytestring || knownRight === TYPES.bytestring) return TYPES.bytestring;
1338
1291
 
1339
1292
  return TYPES.number;
1340
-
1341
- // todo: string concat types
1342
- // if (node.operator !== '+') return TYPES.number;
1343
- // else return [
1344
- // // if left is string
1345
- // ...getNodeType(scope, node.left),
1346
- // ...number(TYPES.string, Valtype.i32),
1347
- // [ Opcodes.i32_eq ],
1348
-
1349
- // // if right is string
1350
- // ...getNodeType(scope, node.right),
1351
- // ...number(TYPES.string, Valtype.i32),
1352
- // [ Opcodes.i32_eq ],
1353
-
1354
- // // if either are true
1355
- // [ Opcodes.i32_or ],
1356
- // ];
1357
1293
  }
1358
1294
 
1359
1295
  if (node.type === 'UnaryExpression') {
@@ -1373,7 +1309,6 @@ const getNodeType = (scope, node) => {
1373
1309
  if (Prefs.fastLength) return TYPES.number;
1374
1310
  }
1375
1311
 
1376
-
1377
1312
  const objectKnownType = knownType(scope, getNodeType(scope, node.object));
1378
1313
  if (objectKnownType != null) {
1379
1314
  if (name === 'length') {
@@ -1384,7 +1319,6 @@ const getNodeType = (scope, node) => {
1384
1319
  if (node.computed) {
1385
1320
  if (objectKnownType === TYPES.string) return TYPES.string;
1386
1321
  if (objectKnownType === TYPES.bytestring) return TYPES.bytestring;
1387
- if (objectKnownType === TYPES.array) return TYPES.number;
1388
1322
  }
1389
1323
  }
1390
1324
 
@@ -1450,10 +1384,10 @@ const countLeftover = wasm => {
1450
1384
 
1451
1385
  if (depth === 0)
1452
1386
  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)) {}
1387
+ 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
1388
  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
1389
  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;
1390
+ else if (inst[0] === Opcodes.memory_copy[0] && (inst[1] === Opcodes.memory_copy[1] || inst[1] === Opcodes.memory_init[1])) count -= 3;
1457
1391
  else if (inst[0] === Opcodes.return) count = 0;
1458
1392
  else if (inst[0] === Opcodes.call) {
1459
1393
  let func = funcs.find(x => x.index === inst[1]);
@@ -1725,7 +1659,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
1725
1659
  }, generate(scope, decl.arguments[0] ?? DEFAULT_VALUE), getNodeType(scope, decl.arguments[0] ?? DEFAULT_VALUE), protoLocal, protoLocal2, (length, itemType) => {
1726
1660
  return makeArray(scope, {
1727
1661
  rawElements: new Array(length)
1728
- }, _global, _name, true, itemType);
1662
+ }, _global, _name, true, itemType, true);
1729
1663
  }, () => {
1730
1664
  optUnused = true;
1731
1665
  return unusedValue;
@@ -1998,13 +1932,18 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
1998
1932
  continue;
1999
1933
  }
2000
1934
 
2001
- if (valtypeBinary !== Valtype.i32 && (
1935
+ if (valtypeBinary !== Valtype.i32 &&
2002
1936
  (builtinFuncs[name] && builtinFuncs[name].params[i * (typedParams ? 2 : 1)] === Valtype.i32)
2003
- // (importedFuncs[name] && name.startsWith('profile'))
2004
- )) {
1937
+ ) {
2005
1938
  out.push(Opcodes.i32_to);
2006
1939
  }
2007
1940
 
1941
+ if (valtypeBinary === Valtype.i32 &&
1942
+ (builtinFuncs[name] && builtinFuncs[name].params[i * (typedParams ? 2 : 1)] === Valtype.f64)
1943
+ ) {
1944
+ out.push(Opcodes.f64_convert_i32_s);
1945
+ }
1946
+
2008
1947
  if (typedParams) out = out.concat(getNodeType(scope, arg));
2009
1948
  }
2010
1949
 
@@ -2026,6 +1965,10 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
2026
1965
  out.push(Opcodes.i32_from);
2027
1966
  }
2028
1967
 
1968
+ if (builtinFuncs[name] && builtinFuncs[name].returns?.[0] === Valtype.f64 && valtypeBinary === Valtype.i32) {
1969
+ out.push(Opcodes.i32_trunc_sat_f64_s);
1970
+ }
1971
+
2029
1972
  return out;
2030
1973
  };
2031
1974
 
@@ -2115,7 +2058,6 @@ const brTable = (input, bc, returns) => {
2115
2058
  }
2116
2059
 
2117
2060
  for (let i = 0; i < count; i++) {
2118
- // if (i === 0) out.push([ Opcodes.block, returns, 'br table start' ]);
2119
2061
  if (i === 0) out.push([ Opcodes.block, returns ]);
2120
2062
  else out.push([ Opcodes.block, Blocktype.void ]);
2121
2063
  }
@@ -2149,10 +2091,8 @@ const brTable = (input, bc, returns) => {
2149
2091
  [ Opcodes.br_table, ...encodeVector(table), 0 ]
2150
2092
  );
2151
2093
 
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
2094
+ // sort the wrong way and then reverse
2095
+ // so strings ('default') are at the start before any numbers
2156
2096
  const orderedBc = keys.sort((a, b) => b - a).reverse();
2157
2097
 
2158
2098
  br = count - 1;
@@ -2178,7 +2118,7 @@ const typeSwitch = (scope, type, bc, returns = valtypeBinary) => {
2178
2118
  return bc[known] ?? bc.default;
2179
2119
  }
2180
2120
 
2181
- if (Prefs.typeswitchUseBrtable)
2121
+ if (Prefs.typeswitchBrtable)
2182
2122
  return brTable(type, bc, returns);
2183
2123
 
2184
2124
  const tmp = localTmp(scope, '#typeswitch_tmp' + (Prefs.typeswitchUniqueTmp ? randId() : ''), Valtype.i32);
@@ -2233,11 +2173,11 @@ const allocVar = (scope, name, global = false, type = true) => {
2233
2173
  return target[name].idx;
2234
2174
  }
2235
2175
 
2236
- let idx = global ? globalInd++ : scope.localInd++;
2176
+ let idx = global ? globals['#ind']++ : scope.localInd++;
2237
2177
  target[name] = { idx, type: valtypeBinary };
2238
2178
 
2239
2179
  if (type) {
2240
- let typeIdx = global ? globalInd++ : scope.localInd++;
2180
+ let typeIdx = global ? globals['#ind']++ : scope.localInd++;
2241
2181
  target[name + '#type'] = { idx: typeIdx, type: Valtype.i32, name };
2242
2182
  }
2243
2183
 
@@ -2330,24 +2270,10 @@ const generateVar = (scope, decl) => {
2330
2270
  }
2331
2271
 
2332
2272
  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
- // }
2273
+ const alreadyArray = scope.arrays?.get(name) != null;
2348
2274
 
2349
2275
  const generated = generate(scope, x.init, global, name);
2350
- if (scope.arrays?.get(name) != null) {
2276
+ if (!alreadyArray && scope.arrays?.get(name) != null) {
2351
2277
  // hack to set local as pointer before
2352
2278
  out.push(...number(scope.arrays.get(name)), [ global ? Opcodes.global_set : Opcodes.local_set, idx ]);
2353
2279
  if (generated.at(-1) == Opcodes.i32_from_u) generated.pop();
@@ -2399,19 +2325,12 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
2399
2325
 
2400
2326
  // hack: .length setter
2401
2327
  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
2328
  const newValueTmp = localTmp(scope, '__length_setter_tmp');
2408
2329
  const pointerTmp = op === '=' ? null : localTmp(scope, '__member_setter_ptr_tmp', Valtype.i32);
2409
2330
 
2410
2331
  return [
2411
- ...(aotPointer ? number(0, Valtype.i32) : [
2412
- ...generate(scope, decl.left.object),
2413
- Opcodes.i32_to_u
2414
- ]),
2332
+ ...generate(scope, decl.left.object),
2333
+ Opcodes.i32_to_u,
2415
2334
  ...(!pointerTmp ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
2416
2335
 
2417
2336
  ...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
@@ -2422,7 +2341,7 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
2422
2341
  [ Opcodes.local_tee, newValueTmp ],
2423
2342
 
2424
2343
  Opcodes.i32_to_u,
2425
- [ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, ...unsignedLEB128(aotPointer ? pointer : 0) ],
2344
+ [ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, 0 ],
2426
2345
 
2427
2346
  [ Opcodes.local_get, newValueTmp ]
2428
2347
  ];
@@ -2430,21 +2349,14 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
2430
2349
 
2431
2350
  // arr[i]
2432
2351
  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
2352
  const newValueTmp = localTmp(scope, '__member_setter_val_tmp');
2439
2353
  const pointerTmp = op === '=' ? -1 : localTmp(scope, '__member_setter_ptr_tmp', Valtype.i32);
2440
2354
 
2441
2355
  return [
2442
2356
  ...typeSwitch(scope, getNodeType(scope, decl.left.object), {
2443
2357
  [TYPES.array]: [
2444
- ...(aotPointer ? [] : [
2445
- ...generate(scope, decl.left.object),
2446
- Opcodes.i32_to_u
2447
- ]),
2358
+ ...generate(scope, decl.left.object),
2359
+ Opcodes.i32_to_u,
2448
2360
 
2449
2361
  // get index as valtype
2450
2362
  ...generate(scope, decl.left.property),
@@ -2453,39 +2365,22 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
2453
2365
  // turn into byte offset by * valtypeSize (4 for i32, 8 for i64/f64)
2454
2366
  ...number(ValtypeSize[valtype] + 1, Valtype.i32),
2455
2367
  [ Opcodes.i32_mul ],
2456
- ...(aotPointer ? [] : [ [ Opcodes.i32_add ] ]),
2368
+ [ Opcodes.i32_add ],
2457
2369
  ...(op === '=' ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
2458
2370
 
2459
2371
  ...(op === '=' ? generate(scope, decl.right) : performOp(scope, op, [
2460
2372
  [ Opcodes.local_get, pointerTmp ],
2461
- [ Opcodes.load, 0, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ]
2373
+ [ Opcodes.load, 0, ValtypeSize.i32 ]
2462
2374
  ], generate(scope, decl.right), [
2463
2375
  [ Opcodes.local_get, pointerTmp ],
2464
- [ Opcodes.i32_load8_u, 0, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32 + ValtypeSize[valtype]) ]
2376
+ [ Opcodes.i32_load8_u, 0, ValtypeSize.i32 + ValtypeSize[valtype] ]
2465
2377
  ], getNodeType(scope, decl.right), false, name, true)),
2466
2378
  [ Opcodes.local_tee, newValueTmp ],
2467
2379
 
2468
- [ Opcodes.store, 0, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ]
2380
+ [ Opcodes.store, 0, ValtypeSize.i32 ]
2469
2381
  ],
2470
2382
 
2471
2383
  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
2384
  }, Blocktype.void),
2490
2385
 
2491
2386
  [ Opcodes.local_get, newValueTmp ]
@@ -2547,9 +2442,7 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
2547
2442
  [ isGlobal ? Opcodes.global_set : Opcodes.local_set, local.idx ],
2548
2443
  [ isGlobal ? Opcodes.global_get : Opcodes.local_get, local.idx ],
2549
2444
 
2550
- // todo: string concat types
2551
-
2552
- ...setType(scope, name, TYPES.number)
2445
+ ...setType(scope, name, getNodeType(scope, decl))
2553
2446
  ];
2554
2447
  };
2555
2448
 
@@ -2869,12 +2762,12 @@ const generateForOf = (scope, decl) => {
2869
2762
 
2870
2763
  // // todo: we should only do this for strings but we don't know at compile-time :(
2871
2764
  // hack: this is naughty and will break things!
2872
- let newOut = number(0, Valtype.f64), newPointer = -1;
2765
+ let newOut = number(0, Valtype.i32), newPointer = number(0, Valtype.i32);
2873
2766
  if (pages.hasAnyString) {
2874
2767
  // todo: we use i16 even for bytestrings which should not make a bad thing happen, just be confusing for debugging?
2875
2768
  0, [ newOut, newPointer ] = makeArray(scope, {
2876
- rawElements: new Array(1)
2877
- }, isGlobal, leftName, true, 'i16');
2769
+ rawElements: new Array(0)
2770
+ }, isGlobal, leftName, true, 'i16', true);
2878
2771
  }
2879
2772
 
2880
2773
  // set type for local
@@ -2921,23 +2814,28 @@ const generateForOf = (scope, decl) => {
2921
2814
  [TYPES.string]: [
2922
2815
  ...setType(scope, leftName, TYPES.string),
2923
2816
 
2924
- [ Opcodes.loop, Blocktype.void ],
2925
-
2926
2817
  // setup new/out array
2927
2818
  ...newOut,
2928
- [ Opcodes.drop ],
2929
2819
 
2930
- ...number(0, Valtype.i32), // base 0 for store after
2820
+ // set length to 1
2821
+ ...number(1, Valtype.i32),
2822
+ [ Opcodes.i32_store, 0, 0 ],
2823
+
2824
+ [ Opcodes.loop, Blocktype.void ],
2825
+
2826
+ // use as pointer for store later
2827
+ ...newPointer,
2931
2828
 
2932
2829
  // load current string ind {arg}
2933
2830
  [ Opcodes.local_get, pointer ],
2934
- [ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128(ValtypeSize.i32) ],
2831
+ [ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],
2935
2832
 
2936
2833
  // store to new string ind 0
2937
- [ Opcodes.i32_store16, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128(newPointer + ValtypeSize.i32) ],
2834
+ [ Opcodes.i32_store16, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],
2938
2835
 
2939
2836
  // return new string (page)
2940
- ...number(newPointer),
2837
+ ...newPointer,
2838
+ Opcodes.i32_from_u,
2941
2839
 
2942
2840
  [ isGlobal ? Opcodes.global_set : Opcodes.local_set, local.idx ],
2943
2841
 
@@ -2969,25 +2867,30 @@ const generateForOf = (scope, decl) => {
2969
2867
  [TYPES.bytestring]: [
2970
2868
  ...setType(scope, leftName, TYPES.bytestring),
2971
2869
 
2972
- [ Opcodes.loop, Blocktype.void ],
2973
-
2974
2870
  // setup new/out array
2975
2871
  ...newOut,
2976
- [ Opcodes.drop ],
2977
2872
 
2978
- ...number(0, Valtype.i32), // base 0 for store after
2873
+ // set length to 1
2874
+ ...number(1, Valtype.i32),
2875
+ [ Opcodes.i32_store, 0, 0 ],
2876
+
2877
+ [ Opcodes.loop, Blocktype.void ],
2878
+
2879
+ // use as pointer for store later
2880
+ ...newPointer,
2979
2881
 
2980
2882
  // load current string ind {arg}
2981
2883
  [ Opcodes.local_get, pointer ],
2982
2884
  [ Opcodes.local_get, counter ],
2983
2885
  [ Opcodes.i32_add ],
2984
- [ Opcodes.i32_load8_u, 0, ...unsignedLEB128(ValtypeSize.i32) ],
2886
+ [ Opcodes.i32_load8_u, 0, ValtypeSize.i32 ],
2985
2887
 
2986
2888
  // store to new string ind 0
2987
- [ Opcodes.i32_store8, 0, ...unsignedLEB128(newPointer + ValtypeSize.i32) ],
2889
+ [ Opcodes.i32_store8, 0, ValtypeSize.i32 ],
2988
2890
 
2989
2891
  // return new string (page)
2990
- ...number(newPointer),
2892
+ ...newPointer,
2893
+ Opcodes.i32_from_u,
2991
2894
 
2992
2895
  [ isGlobal ? Opcodes.global_set : Opcodes.local_set, local.idx ],
2993
2896
 
@@ -3202,18 +3105,6 @@ const allocPage = (scope, reason, type) => {
3202
3105
  scope.pages ??= new Map();
3203
3106
  scope.pages.set(reason, { ind, type });
3204
3107
 
3205
- if (Prefs.allocLog) log('alloc', `allocated new page of memory (${ind}) | ${reason} (type: ${type})`);
3206
-
3207
- return ind;
3208
- };
3209
-
3210
- // todo: add scope.pages
3211
- const freePage = reason => {
3212
- const { ind } = pages.get(reason);
3213
- pages.delete(reason);
3214
-
3215
- if (Prefs.allocLog) log('alloc', `freed page of memory (${ind}) | ${reason}`);
3216
-
3217
3108
  return ind;
3218
3109
  };
3219
3110
 
@@ -3251,39 +3142,58 @@ const compileBytes = (val, itemType) => {
3251
3142
  }
3252
3143
  };
3253
3144
 
3254
- const getAllocType = itemType => {
3255
- switch (itemType) {
3256
- case 'i8': return 'bytestring';
3257
- case 'i16': return 'string';
3145
+ const makeData = (scope, elements, offset = null, itemType, initEmpty) => {
3146
+ const length = elements.length;
3147
+
3148
+ // if length is 0 memory/data will just be 0000... anyway
3149
+ if (length === 0) return false;
3258
3150
 
3259
- default: return 'array';
3151
+ let bytes = compileBytes(length, 'i32');
3152
+
3153
+ if (!initEmpty) for (let i = 0; i < length; i++) {
3154
+ if (elements[i] == null) continue;
3155
+
3156
+ bytes.push(...compileBytes(elements[i], itemType));
3260
3157
  }
3261
- };
3262
3158
 
3263
- const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty = false, itemType = valtype, typed = false) => {
3264
- const out = [];
3159
+ const obj = { bytes };
3160
+ if (offset != null) obj.offset = offset;
3265
3161
 
3266
- scope.arrays ??= new Map();
3162
+ const idx = data.push(obj) - 1;
3267
3163
 
3268
- let firstAssign = false;
3269
- if (!scope.arrays.has(name) || name === '$undeclared') {
3270
- firstAssign = true;
3164
+ scope.data ??= [];
3165
+ scope.data.push(idx);
3271
3166
 
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;
3167
+ return { idx, size: bytes.length };
3168
+ };
3274
3169
 
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);
3170
+ const printStaticStr = str => {
3171
+ const out = [];
3278
3172
 
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);
3173
+ for (let i = 0; i < str.length; i++) {
3174
+ out.push(
3175
+ // ...number(str.charCodeAt(i)),
3176
+ ...number(str.charCodeAt(i), Valtype.i32),
3177
+ Opcodes.i32_from_u,
3178
+ [ Opcodes.call, importedFuncs.printChar ]
3179
+ );
3180
+ }
3181
+
3182
+ return out;
3183
+ };
3184
+
3185
+ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty = false, itemType = valtype, intOut = false, typed = false) => {
3186
+ if (itemType !== 'i16' && itemType !== 'i8') {
3187
+ pages.hasArray = true;
3188
+ } else {
3189
+ pages.hasAnyString = true;
3190
+ if (itemType === 'i8') pages.hasByteString = true;
3191
+ else pages.hasString = true;
3282
3192
  }
3283
3193
 
3284
- const pointer = scope.arrays.get(name);
3194
+ const out = [];
3285
3195
 
3286
- const local = global ? globals[name] : scope.locals[name];
3196
+ const uniqueName = name === '$undeclared' ? name + randId() : name;
3287
3197
 
3288
3198
  const useRawElements = !!decl.rawElements;
3289
3199
  const elements = useRawElements ? decl.rawElements : decl.elements;
@@ -3291,46 +3201,81 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
3291
3201
  const valtype = itemTypeToValtype[itemType];
3292
3202
  const length = elements.length;
3293
3203
 
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');
3204
+ const allocated = allocator.alloc({ scope, pages, globals, asmFunc, funcIndex }, uniqueName, { itemType });
3205
+
3206
+ let pointer = allocated;
3207
+ if (allocator.constructor.name !== 'StaticAllocator') {
3208
+ // const tmp = localTmp(scope, '#makearray_pointer' + uniqueName, Valtype.i32);
3209
+ const tmp = localTmp(scope, '#makearray_pointer' + name, Valtype.i32);
3210
+ out.push(
3211
+ ...allocated,
3212
+ [ Opcodes.local_set, tmp ]
3213
+ );
3214
+
3215
+ if (Prefs.runtimeAllocLog) out.push(
3216
+ ...printStaticStr(`${name}: `),
3217
+
3218
+ [ Opcodes.local_get, tmp ],
3219
+ Opcodes.i32_from_u,
3220
+ [ Opcodes.call, 0 ],
3221
+
3222
+ ...number(10),
3223
+ [ Opcodes.call, 1 ]
3224
+ );
3298
3225
 
3299
- if (!initEmpty) for (let i = 0; i < length; i++) {
3300
- if (elements[i] == null) continue;
3226
+ pointer = [ [ Opcodes.local_get, tmp ] ];
3301
3227
 
3302
- bytes.push(...compileBytes(elements[i], itemType));
3228
+ if (Prefs.data && useRawElements) {
3229
+ const data = makeData(scope, elements, null, itemType, initEmpty);
3230
+ if (data) {
3231
+ // init data
3232
+ out.push(
3233
+ ...pointer,
3234
+ ...number(0, Valtype.i32),
3235
+ ...number(data.size, Valtype.i32),
3236
+ [ ...Opcodes.memory_init, ...unsignedLEB128(data.idx), 0 ]
3237
+ );
3303
3238
  }
3304
3239
 
3305
- const ind = data.push({
3306
- offset: pointer,
3307
- bytes
3308
- }) - 1;
3240
+ // return pointer in out
3241
+ out.push(
3242
+ ...pointer,
3243
+ ...(!intOut ? [ Opcodes.i32_from_u ] : [])
3244
+ );
3309
3245
 
3310
- scope.data ??= [];
3311
- scope.data.push(ind);
3246
+ return [ out, pointer ];
3312
3247
  }
3248
+ } else {
3249
+ const rawPtr = read_signedLEB128(pointer[0].slice(1));
3313
3250
 
3314
- // local value as pointer
3315
- out.push(...number(pointer));
3251
+ scope.arrays ??= new Map();
3252
+ const firstAssign = !scope.arrays.has(uniqueName);
3253
+ if (firstAssign) scope.arrays.set(uniqueName, rawPtr);
3316
3254
 
3317
- return [ out, pointer ];
3318
- }
3255
+ if (Prefs.data && firstAssign && useRawElements) {
3256
+ makeData(scope, elements, rawPtr, itemType, initEmpty);
3319
3257
 
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
- );
3258
+ // local value as pointer
3259
+ return [ number(rawPtr, intOut ? Valtype.i32 : valtypeBinary), pointer ];
3260
+ }
3261
+
3262
+ const local = global ? globals[name] : scope.locals[name];
3263
+ const pointerTmp = local != null ? localTmp(scope, '#makearray_pointer_tmp', Valtype.i32) : null;
3264
+ if (pointerTmp != null) {
3265
+ out.push(
3266
+ [ global ? Opcodes.global_get : Opcodes.local_get, local.idx ],
3267
+ Opcodes.i32_to_u,
3268
+ [ Opcodes.local_set, pointerTmp ]
3269
+ );
3270
+
3271
+ pointer = [ [ Opcodes.local_get, pointerTmp ] ];
3272
+ }
3327
3273
  }
3328
3274
 
3329
- const pointerWasm = pointerTmp != null ? [ [ Opcodes.local_get, pointerTmp ] ] : number(pointer, Valtype.i32);
3330
3275
 
3331
3276
  // store length
3332
3277
  out.push(
3333
- ...pointerWasm,
3278
+ ...pointer,
3334
3279
  ...number(length, Valtype.i32),
3335
3280
  [ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, 0 ]
3336
3281
  );
@@ -3342,11 +3287,11 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
3342
3287
 
3343
3288
  const offset = ValtypeSize.i32 + i * sizePerEl;
3344
3289
  out.push(
3345
- ...pointerWasm,
3290
+ ...pointer,
3346
3291
  ...(useRawElements ? number(elements[i], Valtype[valtype]) : generate(scope, elements[i])),
3347
3292
  [ storeOp, 0, ...unsignedLEB128(offset) ],
3348
3293
  ...(!typed ? [] : [ // typed presumes !useRawElements
3349
- ...pointerWasm,
3294
+ ...pointer,
3350
3295
  ...getNodeType(scope, elements[i]),
3351
3296
  [ Opcodes.i32_store8, 0, ...unsignedLEB128(offset + ValtypeSize[itemType]) ]
3352
3297
  ])
@@ -3354,12 +3299,13 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
3354
3299
  }
3355
3300
 
3356
3301
  // local value as pointer
3357
- out.push(...pointerWasm, Opcodes.i32_from_u);
3302
+ out.push(...pointer);
3303
+ if (!intOut) out.push(Opcodes.i32_from_u);
3358
3304
 
3359
3305
  return [ out, pointer ];
3360
3306
  };
3361
3307
 
3362
- const storeArray = (scope, array, index, element, aotPointer = null) => {
3308
+ const storeArray = (scope, array, index, element) => {
3363
3309
  if (!Array.isArray(element)) element = generate(scope, element);
3364
3310
  if (typeof index === 'number') index = number(index);
3365
3311
 
@@ -3371,26 +3317,25 @@ const storeArray = (scope, array, index, element, aotPointer = null) => {
3371
3317
  Opcodes.i32_to_u,
3372
3318
  ...number(ValtypeSize[valtype] + 1, Valtype.i32),
3373
3319
  [ Opcodes.i32_mul ],
3374
- ...(aotPointer ? [] : [
3375
- ...array,
3376
- Opcodes.i32_to_u,
3377
- [ Opcodes.i32_add ],
3378
- ]),
3320
+
3321
+ ...array,
3322
+ Opcodes.i32_to_u,
3323
+ [ Opcodes.i32_add ],
3379
3324
  [ Opcodes.local_set, offset ],
3380
3325
 
3381
3326
  // store value
3382
3327
  [ Opcodes.local_get, offset ],
3383
3328
  ...generate(scope, element),
3384
- [ Opcodes.store, 0, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ],
3329
+ [ Opcodes.store, 0, ValtypeSize.i32 ],
3385
3330
 
3386
3331
  // store type
3387
3332
  [ Opcodes.local_get, offset ],
3388
3333
  ...getNodeType(scope, element),
3389
- [ Opcodes.i32_store8, 0, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32 + ValtypeSize[valtype]) ]
3334
+ [ Opcodes.i32_store8, 0, ValtypeSize.i32 + ValtypeSize[valtype] ]
3390
3335
  ];
3391
3336
  };
3392
3337
 
3393
- const loadArray = (scope, array, index, aotPointer = null) => {
3338
+ const loadArray = (scope, array, index) => {
3394
3339
  if (typeof index === 'number') index = number(index);
3395
3340
 
3396
3341
  const offset = localTmp(scope, '#loadArray_offset', Valtype.i32);
@@ -3401,20 +3346,19 @@ const loadArray = (scope, array, index, aotPointer = null) => {
3401
3346
  Opcodes.i32_to_u,
3402
3347
  ...number(ValtypeSize[valtype] + 1, Valtype.i32),
3403
3348
  [ Opcodes.i32_mul ],
3404
- ...(aotPointer ? [] : [
3405
- ...array,
3406
- Opcodes.i32_to_u,
3407
- [ Opcodes.i32_add ],
3408
- ]),
3349
+
3350
+ ...array,
3351
+ Opcodes.i32_to_u,
3352
+ [ Opcodes.i32_add ],
3409
3353
  [ Opcodes.local_set, offset ],
3410
3354
 
3411
3355
  // load value
3412
3356
  [ Opcodes.local_get, offset ],
3413
- [ Opcodes.load, 0, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ],
3357
+ [ Opcodes.load, 0, ValtypeSize.i32 ],
3414
3358
 
3415
3359
  // load type
3416
3360
  [ Opcodes.local_get, offset ],
3417
- [ Opcodes.i32_load8_u, 0, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32 + ValtypeSize[valtype]) ]
3361
+ [ Opcodes.i32_load8_u, 0, ValtypeSize.i32 + ValtypeSize[valtype] ]
3418
3362
  ];
3419
3363
  };
3420
3364
 
@@ -3446,7 +3390,7 @@ const makeString = (scope, str, global = false, name = '$undeclared', forceBytes
3446
3390
  };
3447
3391
 
3448
3392
  const generateArray = (scope, decl, global = false, name = '$undeclared', initEmpty = false) => {
3449
- return makeArray(scope, decl, global, name, initEmpty, valtype, true)[0];
3393
+ return makeArray(scope, decl, global, name, initEmpty, valtype, false, true)[0];
3450
3394
  };
3451
3395
 
3452
3396
  const generateObject = (scope, decl, global = false, name = '$undeclared') => {
@@ -3465,9 +3409,6 @@ const withType = (scope, wasm, type) => [
3465
3409
 
3466
3410
  const generateMember = (scope, decl, _global, _name) => {
3467
3411
  const name = decl.object.name;
3468
- const pointer = scope.arrays?.get(name);
3469
-
3470
- const aotPointer = Prefs.aotPointerOpt && pointer;
3471
3412
 
3472
3413
  // hack: .name
3473
3414
  if (decl.property.name === 'name') {
@@ -3508,12 +3449,10 @@ const generateMember = (scope, decl, _global, _name) => {
3508
3449
  if (Prefs.fastLength) {
3509
3450
  // presume valid length object
3510
3451
  return [
3511
- ...(aotPointer ? number(0, Valtype.i32) : [
3512
- ...generate(scope, decl.object),
3513
- Opcodes.i32_to_u
3514
- ]),
3452
+ ...generate(scope, decl.object),
3453
+ Opcodes.i32_to_u,
3515
3454
 
3516
- [ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, ...unsignedLEB128(aotPointer ? pointer : 0) ],
3455
+ [ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
3517
3456
  Opcodes.i32_from_u
3518
3457
  ];
3519
3458
  }
@@ -3522,12 +3461,10 @@ const generateMember = (scope, decl, _global, _name) => {
3522
3461
  const known = knownType(scope, type);
3523
3462
  if (known != null) {
3524
3463
  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
- ]),
3464
+ ...generate(scope, decl.object),
3465
+ Opcodes.i32_to_u,
3529
3466
 
3530
- [ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, ...unsignedLEB128(aotPointer ? pointer : 0) ],
3467
+ [ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
3531
3468
  Opcodes.i32_from_u
3532
3469
  ];
3533
3470
 
@@ -3537,12 +3474,10 @@ const generateMember = (scope, decl, _global, _name) => {
3537
3474
  return [
3538
3475
  ...typeIsOneOf(getNodeType(scope, decl.object), [ TYPES.string, TYPES.bytestring, TYPES.array ]),
3539
3476
  [ Opcodes.if, valtypeBinary ],
3540
- ...(aotPointer ? number(0, Valtype.i32) : [
3541
- ...generate(scope, decl.object),
3542
- Opcodes.i32_to_u
3543
- ]),
3477
+ ...generate(scope, decl.object),
3478
+ Opcodes.i32_to_u,
3544
3479
 
3545
- [ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, ...unsignedLEB128(aotPointer ? pointer : 0) ],
3480
+ [ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
3546
3481
  Opcodes.i32_from_u,
3547
3482
 
3548
3483
  ...setLastType(scope, TYPES.number),
@@ -3585,25 +3520,29 @@ const generateMember = (scope, decl, _global, _name) => {
3585
3520
 
3586
3521
  // // todo: we should only do this for strings but we don't know at compile-time :(
3587
3522
  // hack: this is naughty and will break things!
3588
- let newOut = number(0, valtypeBinary), newPointer = -1;
3589
- if (pages.hasAnyString) {
3523
+ let newOut = number(0, Valtype.i32), newPointer = number(0, Valtype.i32);
3524
+ if (pages.hasAnyString && knownType(scope, getNodeType(scope, decl.object)) !== TYPES.array) {
3525
+ // todo: we use i16 even for bytestrings which should not make a bad thing happen, just be confusing for debugging?
3590
3526
  0, [ newOut, newPointer ] = makeArray(scope, {
3591
- rawElements: new Array(1)
3592
- }, _global, _name, true, 'i16');
3527
+ rawElements: new Array(0)
3528
+ }, _global, _name, true, 'i16', true);
3593
3529
  }
3594
3530
 
3595
3531
  return typeSwitch(scope, getNodeType(scope, decl.object), {
3596
3532
  [TYPES.array]: [
3597
- ...loadArray(scope, object, property, aotPointer),
3533
+ ...loadArray(scope, object, property),
3598
3534
  ...setLastType(scope)
3599
3535
  ],
3600
-
3601
3536
  [TYPES.string]: [
3602
3537
  // setup new/out array
3603
3538
  ...newOut,
3604
- [ Opcodes.drop ],
3605
3539
 
3606
- ...number(0, Valtype.i32), // base 0 for store later
3540
+ // set length to 1
3541
+ ...number(1, Valtype.i32),
3542
+ [ Opcodes.i32_store, 0, 0 ],
3543
+
3544
+ // use as pointer for store later
3545
+ ...newPointer,
3607
3546
 
3608
3547
  ...property,
3609
3548
  Opcodes.i32_to_u,
@@ -3611,46 +3550,48 @@ const generateMember = (scope, decl, _global, _name) => {
3611
3550
  ...number(ValtypeSize.i16, Valtype.i32),
3612
3551
  [ Opcodes.i32_mul ],
3613
3552
 
3614
- ...(aotPointer ? [] : [
3615
- ...object,
3616
- Opcodes.i32_to_u,
3617
- [ Opcodes.i32_add ]
3618
- ]),
3553
+ ...object,
3554
+ Opcodes.i32_to_u,
3555
+ [ Opcodes.i32_add ],
3619
3556
 
3620
3557
  // load current string ind {arg}
3621
- [ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ],
3558
+ [ Opcodes.i32_load16_u, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],
3622
3559
 
3623
3560
  // store to new string ind 0
3624
- [ Opcodes.i32_store16, Math.log2(ValtypeSize.i16) - 1, ...unsignedLEB128(newPointer + ValtypeSize.i32) ],
3561
+ [ Opcodes.i32_store16, Math.log2(ValtypeSize.i16) - 1, ValtypeSize.i32 ],
3625
3562
 
3626
3563
  // return new string (page)
3627
- ...number(newPointer),
3564
+ ...newPointer,
3565
+ Opcodes.i32_from_u,
3628
3566
  ...setLastType(scope, TYPES.string)
3629
3567
  ],
3630
3568
  [TYPES.bytestring]: [
3631
3569
  // setup new/out array
3632
3570
  ...newOut,
3633
- [ Opcodes.drop ],
3634
3571
 
3635
- ...number(0, Valtype.i32), // base 0 for store later
3572
+ // set length to 1
3573
+ ...number(1, Valtype.i32),
3574
+ [ Opcodes.i32_store, 0, 0 ],
3575
+
3576
+ // use as pointer for store later
3577
+ ...newPointer,
3636
3578
 
3637
3579
  ...property,
3638
3580
  Opcodes.i32_to_u,
3639
3581
 
3640
- ...(aotPointer ? [] : [
3641
- ...object,
3642
- Opcodes.i32_to_u,
3643
- [ Opcodes.i32_add ]
3644
- ]),
3582
+ ...object,
3583
+ Opcodes.i32_to_u,
3584
+ [ Opcodes.i32_add ],
3645
3585
 
3646
3586
  // load current string ind {arg}
3647
- [ Opcodes.i32_load8_u, 0, ...unsignedLEB128((aotPointer ? pointer : 0) + ValtypeSize.i32) ],
3587
+ [ Opcodes.i32_load8_u, 0, ValtypeSize.i32 ],
3648
3588
 
3649
3589
  // store to new string ind 0
3650
- [ Opcodes.i32_store8, 0, ...unsignedLEB128(newPointer + ValtypeSize.i32) ],
3590
+ [ Opcodes.i32_store8, 0, ValtypeSize.i32 ],
3651
3591
 
3652
3592
  // return new string (page)
3653
- ...number(newPointer),
3593
+ ...newPointer,
3594
+ Opcodes.i32_from_u,
3654
3595
  ...setLastType(scope, TYPES.bytestring)
3655
3596
  ],
3656
3597
 
@@ -3795,9 +3736,9 @@ const internalConstrs = {
3795
3736
 
3796
3737
  // new Array(n)
3797
3738
 
3798
- const [ , pointer ] = makeArray(scope, {
3739
+ const [ out, pointer ] = makeArray(scope, {
3799
3740
  rawElements: new Array(0)
3800
- }, global, name, true);
3741
+ }, global, name, true, undefined, true);
3801
3742
 
3802
3743
  const arg = decl.arguments[0] ?? DEFAULT_VALUE;
3803
3744
 
@@ -3806,12 +3747,13 @@ const internalConstrs = {
3806
3747
  if (literalValue < 0 || !Number.isFinite(literalValue) || literalValue > 4294967295) return internalThrow(scope, 'RangeThrow', 'Invalid array length', true);
3807
3748
 
3808
3749
  return [
3809
- ...number(0, Valtype.i32),
3750
+ ...out,
3810
3751
  ...generate(scope, arg, global, name),
3811
3752
  Opcodes.i32_to_u,
3812
- [ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, ...unsignedLEB128(pointer) ],
3753
+ [ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, 0 ],
3813
3754
 
3814
- ...number(pointer)
3755
+ ...pointer,
3756
+ Opcodes.i32_from_u
3815
3757
  ];
3816
3758
  },
3817
3759
  type: TYPES.array,
@@ -3960,8 +3902,9 @@ const internalConstrs = {
3960
3902
  };
3961
3903
 
3962
3904
  export default program => {
3963
- globals = {};
3964
- globalInd = 0;
3905
+ globals = {
3906
+ ['#ind']: 0
3907
+ };
3965
3908
  tags = [];
3966
3909
  exceptions = [];
3967
3910
  funcs = [];
@@ -3994,6 +3937,7 @@ export default program => {
3994
3937
  builtinFuncs = new BuiltinFuncs();
3995
3938
  builtinVars = new BuiltinVars();
3996
3939
  prototypeFuncs = new PrototypeFuncs();
3940
+ allocator = makeAllocator(Prefs.allocator ?? 'static');
3997
3941
 
3998
3942
  program.id = { name: 'main' };
3999
3943
 
@@ -4036,6 +3980,8 @@ export default program => {
4036
3980
  else main.returns = [];
4037
3981
  }
4038
3982
 
3983
+ delete globals['#ind'];
3984
+
4039
3985
  // if blank main func and other exports, remove it
4040
3986
  if (main.wasm.length === 0 && funcs.reduce((acc, x) => acc + (x.export ? 1 : 0), 0) > 1) funcs.splice(main.index - importedFuncs.length, 1);
4041
3987