porffor 0.47.6 → 0.47.8

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.
@@ -8,8 +8,8 @@ import { TYPES, TYPE_FLAGS, TYPE_NAMES, typeHasFlag } from './types.js';
8
8
  import * as Rhemyn from '../rhemyn/compile.js';
9
9
  import parse from './parse.js';
10
10
  import { log } from './log.js';
11
- import {} from './prefs.js';
12
- import makeAllocator from './allocators.js';
11
+ import './prefs.js';
12
+ import { allocPage as _allocPage, allocBytes, allocStr, nameToReason } from './allocator.js';
13
13
 
14
14
  let globals = {};
15
15
  let tags = [];
@@ -18,7 +18,6 @@ let exceptions = [];
18
18
  let funcIndex = {};
19
19
  let currentFuncIndex = importedFuncs.length;
20
20
  let builtinFuncs = {}, builtinVars = {}, prototypeFuncs = {};
21
- let allocator;
22
21
 
23
22
  class TodoError extends Error {
24
23
  constructor(message) {
@@ -191,6 +190,7 @@ const forceDuoValtype = (scope, wasm, forceValtype) => [
191
190
  ];
192
191
 
193
192
  const generate = (scope, decl, global = false, name = undefined, valueUnused = false) => {
193
+ if (valueUnused && !Prefs.optUnused) valueUnused = false;
194
194
  if (astCache.has(decl)) return astCache.get(decl);
195
195
 
196
196
  switch (decl.type) {
@@ -240,7 +240,7 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
240
240
  return cacheAst(decl, generateVar(scope, decl));
241
241
 
242
242
  case 'AssignmentExpression':
243
- return cacheAst(decl, generateAssign(scope, decl));
243
+ return cacheAst(decl, generateAssign(scope, decl, global, name, valueUnused));
244
244
 
245
245
  case 'UnaryExpression':
246
246
  return cacheAst(decl, generateUnary(scope, decl));
@@ -297,7 +297,7 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
297
297
  return cacheAst(decl, [[ Opcodes.call, importedFuncs.debugger ]]);
298
298
 
299
299
  case 'ArrayExpression':
300
- return cacheAst(decl, generateArray(scope, decl, global, name));
300
+ return cacheAst(decl, generateArray(scope, decl, global, name, globalThis.precompile));
301
301
 
302
302
  case 'ObjectExpression':
303
303
  return cacheAst(decl, generateObject(scope, decl, global, name));
@@ -348,10 +348,12 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
348
348
  return cacheAst(decl, []);
349
349
  }
350
350
 
351
- return cacheAst(decl, todo(scope, `no generation for ${decl.type}!`));
351
+ return cacheAst(decl, todo(scope, `no generation for ${decl.type}!`, !decl.type.endsWith('Statement') && !decl.type.endsWith('Declaration')));
352
352
  }
353
353
  };
354
354
 
355
+ const optional = (op, clause = op.at(-1)) => clause || clause === 0 ? (Array.isArray(op[0]) ? op : [ op ]) : [];
356
+
355
357
  const lookupName = (scope, name) => {
356
358
  if (Object.hasOwn(scope.locals, name)) return [ scope.locals[name], false ];
357
359
  if (Object.hasOwn(globals, name)) return [ globals[name], true ];
@@ -363,7 +365,7 @@ const internalThrow = (scope, constructor, message, expectsValue = Prefs.alwaysV
363
365
  ...generate(scope, {
364
366
  type: 'ThrowStatement',
365
367
  argument: {
366
- type: 'NewExpression',
368
+ type: 'CallExpression',
367
369
  callee: {
368
370
  type: 'Identifier',
369
371
  name: constructor
@@ -415,7 +417,7 @@ const generateIdent = (scope, decl) => {
415
417
 
416
418
  return generateArray(scope, {
417
419
  elements: names.map(x => ({ type: 'Identifier', name: x }))
418
- }, false, '#arguments');
420
+ }, false, '#arguments', true);
419
421
  }
420
422
 
421
423
  // no local var with name
@@ -1124,7 +1126,7 @@ const generateBinaryExp = (scope, decl, _global, _name) => {
1124
1126
 
1125
1127
  const asmFuncToAsm = (scope, func) => {
1126
1128
  return func(scope, {
1127
- Valtype, Opcodes, TYPES, TYPE_NAMES, typeSwitch, makeArray, makeString, allocPage, internalThrow,
1129
+ Valtype, Opcodes, TYPES, TYPE_NAMES, typeSwitch, makeString, allocPage, internalThrow,
1128
1130
  getNodeType, generate, generateIdent,
1129
1131
  builtin: (n, offset = false) => {
1130
1132
  let idx = funcIndex[n] ?? importedFuncs[n];
@@ -1197,6 +1199,10 @@ const asmFuncToAsm = (scope, func) => {
1197
1199
  return [];
1198
1200
  }, 0 ] ];
1199
1201
  }
1202
+ },
1203
+ i32ify: wasm => {
1204
+ wasm.push(Opcodes.i32_to_u);
1205
+ return wasm;
1200
1206
  }
1201
1207
  });
1202
1208
  };
@@ -1219,6 +1225,7 @@ const asmFunc = (name, { wasm, params = [], typedParams = false, locals: localTy
1219
1225
  }
1220
1226
 
1221
1227
  for (const x in _data) {
1228
+ if (data.find(y => y.page === x)) return;
1222
1229
  data.push({ page: x, bytes: _data[x] });
1223
1230
  }
1224
1231
 
@@ -1628,7 +1635,7 @@ const generateLiteral = (scope, decl, global, name) => {
1628
1635
  return number(decl.value ? 1 : 0);
1629
1636
 
1630
1637
  case 'string':
1631
- return makeString(scope, decl.value, global, name);
1638
+ return makeString(scope, decl.value);
1632
1639
 
1633
1640
  default:
1634
1641
  return todo(scope, `cannot generate literal of type ${typeof decl.value}`, true);
@@ -1653,14 +1660,17 @@ const countLeftover = wasm => {
1653
1660
  if (inst[0] === Opcodes.end) depth--;
1654
1661
 
1655
1662
  if (depth === 0)
1656
- if ([Opcodes.throw, Opcodes.drop, Opcodes.local_set, Opcodes.global_set].includes(inst[0])) count--;
1663
+ if ([Opcodes.drop, Opcodes.local_set, Opcodes.global_set].includes(inst[0])) count--;
1657
1664
  else if ([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.f32_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)) {}
1658
1665
  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++;
1659
1666
  else if ([Opcodes.i32_store, Opcodes.i64_store, Opcodes.f64_store, Opcodes.f32_store, Opcodes.i32_store16, Opcodes.i32_store8, Opcodes.select].includes(inst[0])) count -= 2;
1660
1667
  else if (inst[0] === Opcodes.memory_copy[0] && (inst[1] === Opcodes.memory_copy[1] || inst[1] === Opcodes.memory_init[1])) count -= 3;
1661
1668
  else if (inst[0] === Opcodes.return) count = 0;
1662
1669
  else if (inst[0] === Opcodes.catch) count += 2;
1663
- else if (inst[0] === Opcodes.call) {
1670
+ else if (inst[0] === Opcodes.throw) {
1671
+ count--;
1672
+ if ((Prefs.exceptionMode ?? 'stack') === 'stack' || (globalThis.precompile && inst[1] === 1)) count--;
1673
+ } else if (inst[0] === Opcodes.call) {
1664
1674
  if (inst[1] < importedFuncs.length) {
1665
1675
  const func = importedFuncs[inst[1]];
1666
1676
  count = count - func.params + func.returns;
@@ -1674,7 +1684,7 @@ const countLeftover = wasm => {
1674
1684
  count += 2; // fixed return (value, type)
1675
1685
  } else count--;
1676
1686
 
1677
- // console.log(count, depth, decompile([ inst ]).slice(0, -1));
1687
+ // console.log(count, depth, decompile([ inst ], undefined, undefined, undefined, undefined, undefined, funcs).slice(0, -1));
1678
1688
  }
1679
1689
 
1680
1690
  return count;
@@ -1694,7 +1704,7 @@ const generateExp = (scope, decl) => {
1694
1704
  }
1695
1705
  }
1696
1706
 
1697
- const out = generate(scope, expression, undefined, undefined, Prefs.optUnused);
1707
+ const out = generate(scope, expression, undefined, undefined, !scope.inEval);
1698
1708
  disposeLeftover(out);
1699
1709
 
1700
1710
  return out;
@@ -1716,33 +1726,7 @@ const generateChain = (scope, decl) => {
1716
1726
  return generate(scope, decl.expression);
1717
1727
  };
1718
1728
 
1719
- const CTArrayUtil = {
1720
- getLengthI32: pointer => [
1721
- ...number(0, Valtype.i32),
1722
- [ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, ...unsignedLEB128(pointer) ]
1723
- ],
1724
-
1725
- getLength: pointer => [
1726
- ...number(0, Valtype.i32),
1727
- [ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, ...unsignedLEB128(pointer) ],
1728
- Opcodes.i32_from_u
1729
- ],
1730
-
1731
- setLengthI32: (pointer, value) => [
1732
- ...number(0, Valtype.i32),
1733
- ...value,
1734
- [ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, ...unsignedLEB128(pointer) ]
1735
- ],
1736
-
1737
- setLength: (pointer, value) => [
1738
- ...number(0, Valtype.i32),
1739
- ...value,
1740
- Opcodes.i32_to_u,
1741
- [ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, ...unsignedLEB128(pointer) ]
1742
- ]
1743
- };
1744
-
1745
- const RTArrayUtil = {
1729
+ const ArrayUtil = {
1746
1730
  getLengthI32: pointer => [
1747
1731
  ...pointer,
1748
1732
  [ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ]
@@ -1969,10 +1953,12 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
1969
1953
  throw e;
1970
1954
  }
1971
1955
 
1956
+ scope.inEval = true;
1972
1957
  const out = generate(scope, {
1973
1958
  type: 'BlockStatement',
1974
1959
  body: parsed.body
1975
1960
  });
1961
+ scope.inEval = false;
1976
1962
 
1977
1963
  const lastInst = out[out.length - 1];
1978
1964
  if (lastInst && lastInst[0] === Opcodes.drop) {
@@ -1985,12 +1971,6 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
1985
1971
  out.push(...setLastType(scope, TYPES.undefined));
1986
1972
  }
1987
1973
 
1988
- // if (lastInst && lastInst[0] === Opcodes.drop) {
1989
- // out.splice(out.length - 1, 1);
1990
- // } else if (countLeftover(out) === 0) {
1991
- // out.push(...number(UNDEFINED));
1992
- // }
1993
-
1994
1974
  return out;
1995
1975
  }
1996
1976
 
@@ -2200,7 +2180,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
2200
2180
  const protoFunc = protoCands[x];
2201
2181
  if (protoFunc.noArgRetLength && decl.arguments.length === 0) {
2202
2182
  protoBC[x] = [
2203
- ...RTArrayUtil.getLength(getPointer),
2183
+ ...ArrayUtil.getLength(getPointer),
2204
2184
  ...setLastType(scope, TYPES.number)
2205
2185
  ];
2206
2186
  continue;
@@ -2214,19 +2194,18 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
2214
2194
  const protoOut = protoFunc(getPointer, {
2215
2195
  getCachedI32: () => [ [ Opcodes.local_get, lengthLocal ] ],
2216
2196
  setCachedI32: () => [ [ Opcodes.local_set, lengthLocal ] ],
2217
- get: () => RTArrayUtil.getLength(getPointer),
2218
- getI32: () => RTArrayUtil.getLengthI32(getPointer),
2219
- set: value => RTArrayUtil.setLength(getPointer, value),
2220
- setI32: value => RTArrayUtil.setLengthI32(getPointer, value)
2197
+ get: () => ArrayUtil.getLength(getPointer),
2198
+ getI32: () => ArrayUtil.getLengthI32(getPointer),
2199
+ set: value => ArrayUtil.setLength(getPointer, value),
2200
+ setI32: value => ArrayUtil.setLengthI32(getPointer, value)
2221
2201
  },
2222
2202
  generate(scope, decl.arguments[0] ?? DEFAULT_VALUE()),
2223
2203
  getNodeType(scope, decl.arguments[0] ?? DEFAULT_VALUE()),
2224
2204
  protoLocal, protoLocal2,
2225
- (length, itemType) => {
2226
- return makeArray(scope, {
2227
- rawElements: new Array(length)
2228
- }, _global, _name, true, itemType, true);
2229
- },
2205
+ bytes => [
2206
+ ...number(bytes, Valtype.i32),
2207
+ [ Opcodes.call, includeBuiltin(scope, '__Porffor_allocateBytes').index ]
2208
+ ],
2230
2209
  () => {
2231
2210
  optUnused = true;
2232
2211
  return unusedValue;
@@ -2252,7 +2231,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
2252
2231
  ] : []),
2253
2232
 
2254
2233
  ...(useLengthCache ? [
2255
- ...RTArrayUtil.getLengthI32(getPointer),
2234
+ ...ArrayUtil.getLengthI32(getPointer),
2256
2235
  [ Opcodes.local_set, lengthLocal ],
2257
2236
  ] : []),
2258
2237
 
@@ -3335,7 +3314,6 @@ const isIdentAssignable = (scope, name, op = '=') => {
3335
3314
  return false;
3336
3315
  };
3337
3316
 
3338
- // todo: optimize this func for valueUnused
3339
3317
  const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
3340
3318
  const { type, name } = decl.left;
3341
3319
  const [ local, isGlobal ] = lookupName(scope, name);
@@ -3361,8 +3339,8 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
3361
3339
 
3362
3340
  // hack: .length setter
3363
3341
  if (type === 'MemberExpression' && decl.left.property.name === 'length' && !decl._internalAssign) {
3364
- const newValueTmp = localTmp(scope, '__length_setter_tmp');
3365
- const pointerTmp = localTmp(scope, '__member_setter_ptr_tmp', Valtype.i32);
3342
+ const newValueTmp = !valueUnused && localTmp(scope, '__length_setter_tmp');
3343
+ let pointerTmp = op !== '=' && localTmp(scope, '__member_setter_ptr_tmp', Valtype.i32);
3366
3344
 
3367
3345
  const out = [
3368
3346
  ...generate(scope, decl.left.object),
@@ -3375,23 +3353,32 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
3375
3353
  [ Opcodes.i32_load, Math.log2(ValtypeSize.i32) - 1, 0 ],
3376
3354
  Opcodes.i32_from_u
3377
3355
  ], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right))),
3378
- [ Opcodes.local_tee, newValueTmp ],
3356
+ ...optional([ Opcodes.local_tee, newValueTmp ]),
3379
3357
 
3380
3358
  Opcodes.i32_to_u,
3381
3359
  [ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, 0 ],
3382
3360
 
3383
- [ Opcodes.local_get, newValueTmp ]
3361
+ ...optional([ Opcodes.local_get, newValueTmp ])
3384
3362
  ];
3385
3363
 
3386
3364
  const type = getNodeType(scope, decl.left.object);
3387
3365
  const known = knownType(scope, type);
3388
3366
  if (known != null && typeHasFlag(known, TYPE_FLAGS.length)) return [
3389
3367
  ...out,
3390
- ...(!pointerTmp ? [] : [ [ Opcodes.local_tee, pointerTmp ] ]),
3368
+ ...optional([ Opcodes.local_tee, pointerTmp ]),
3391
3369
 
3392
- ...lengthTypeWasm
3370
+ ...lengthTypeWasm,
3371
+ ...optional(number(UNDEFINED), valueUnused)
3393
3372
  ];
3394
3373
 
3374
+ pointerTmp ||= localTmp(scope, '__member_setter_ptr_tmp', Valtype.i32);
3375
+
3376
+ const slow = generate(scope, {
3377
+ ...decl,
3378
+ _internalAssign: true
3379
+ });
3380
+ if (valueUnused) disposeLeftover(slow);
3381
+
3395
3382
  return [
3396
3383
  ...out,
3397
3384
  [ Opcodes.local_set, pointerTmp ],
@@ -3399,33 +3386,31 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
3399
3386
  ...type,
3400
3387
  ...number(TYPE_FLAGS.length, Valtype.i32),
3401
3388
  [ Opcodes.i32_and ],
3402
- [ Opcodes.if, valtypeBinary ],
3389
+ [ Opcodes.if, valueUnused ? Blocktype.void : valtypeBinary ],
3403
3390
  [ Opcodes.local_get, pointerTmp ],
3404
3391
  ...lengthTypeWasm,
3405
3392
  [ Opcodes.else ],
3406
- ...generate(scope, {
3407
- ...decl,
3408
- _internalAssign: true
3409
- }),
3410
- [ Opcodes.end ]
3393
+ ...slow,
3394
+ [ Opcodes.end ],
3395
+ ...optional(number(UNDEFINED), valueUnused)
3411
3396
  ];
3412
3397
  }
3413
3398
 
3414
3399
  // arr[i]
3415
3400
  if (type === 'MemberExpression') {
3416
- const newValueTmp = localTmp(scope, '#member_setter_val_tmp');
3401
+ const newValueTmp = !valueUnused && localTmp(scope, '#member_setter_val_tmp');
3417
3402
  const pointerTmp = localTmp(scope, '#member_setter_ptr_tmp', Valtype.i32);
3418
3403
 
3419
3404
  const object = decl.left.object;
3420
3405
  const property = getProperty(decl.left);
3421
3406
 
3422
3407
  // todo/perf: use i32 object (and prop?) locals
3423
- const objectWasm = [ [ Opcodes.local_get, localTmp(scope, '#member_obj') ] ];
3408
+ const objectWasm = [ [ Opcodes.local_get, localTmp(scope, '#member_obj_assign') ] ];
3424
3409
  const propertyWasm = [ [ Opcodes.local_get, localTmp(scope, '#member_prop_assign') ] ];
3425
3410
 
3426
3411
  return [
3427
3412
  ...generate(scope, object),
3428
- [ Opcodes.local_set, localTmp(scope, '#member_obj') ],
3413
+ [ Opcodes.local_set, objectWasm[0][1] ],
3429
3414
 
3430
3415
  ...generate(scope, property, false, '#member_prop_assign'),
3431
3416
  [ Opcodes.local_set, localTmp(scope, '#member_prop_assign') ],
@@ -3454,14 +3439,14 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
3454
3439
  [ Opcodes.local_get, pointerTmp ],
3455
3440
  [ Opcodes.i32_load8_u, 0, ValtypeSize.i32 + ValtypeSize[valtype] ]
3456
3441
  ], getNodeType(scope, decl.right), false, name, true)),
3457
- [ Opcodes.local_tee, newValueTmp ],
3442
+ ...optional([ Opcodes.local_tee, newValueTmp ]),
3458
3443
  [ Opcodes.store, 0, ValtypeSize.i32 ],
3459
3444
 
3460
3445
  [ Opcodes.local_get, pointerTmp ],
3461
3446
  ...getNodeType(scope, decl),
3462
3447
  [ Opcodes.i32_store8, 0, ValtypeSize.i32 + ValtypeSize[valtype] ],
3463
3448
 
3464
- [ Opcodes.local_get, newValueTmp ]
3449
+ ...optional([ Opcodes.local_get, newValueTmp ])
3465
3450
  ],
3466
3451
 
3467
3452
  ...wrapBC({
@@ -3474,7 +3459,7 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
3474
3459
  [ Opcodes.i32_load8_u, 0, 4 ],
3475
3460
  Opcodes.i32_from_u
3476
3461
  ], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
3477
- [ Opcodes.local_tee, newValueTmp ],
3462
+ ...optional([ Opcodes.local_tee, newValueTmp ]),
3478
3463
 
3479
3464
  Opcodes.i32_to_u,
3480
3465
  [ Opcodes.i32_store8, 0, 4 ]
@@ -3488,7 +3473,7 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
3488
3473
  [ Opcodes.i32_load8_u, 0, 4 ],
3489
3474
  Opcodes.i32_from_u
3490
3475
  ], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
3491
- [ Opcodes.local_tee, newValueTmp ],
3476
+ ...optional([ Opcodes.local_tee, newValueTmp ]),
3492
3477
 
3493
3478
  ...number(0),
3494
3479
  [ Opcodes.f64_max ],
@@ -3506,7 +3491,7 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
3506
3491
  [ Opcodes.i32_load8_s, 0, 4 ],
3507
3492
  Opcodes.i32_from
3508
3493
  ], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
3509
- [ Opcodes.local_tee, newValueTmp ],
3494
+ ...optional([ Opcodes.local_tee, newValueTmp ]),
3510
3495
 
3511
3496
  Opcodes.i32_to,
3512
3497
  [ Opcodes.i32_store8, 0, 4 ]
@@ -3522,7 +3507,7 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
3522
3507
  [ Opcodes.i32_load16_u, 0, 4 ],
3523
3508
  Opcodes.i32_from_u
3524
3509
  ], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
3525
- [ Opcodes.local_tee, newValueTmp ],
3510
+ ...optional([ Opcodes.local_tee, newValueTmp ]),
3526
3511
 
3527
3512
  Opcodes.i32_to_u,
3528
3513
  [ Opcodes.i32_store16, 0, 4 ]
@@ -3538,7 +3523,7 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
3538
3523
  [ Opcodes.i32_load16_s, 0, 4 ],
3539
3524
  Opcodes.i32_from
3540
3525
  ], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
3541
- [ Opcodes.local_tee, newValueTmp ],
3526
+ ...optional([ Opcodes.local_tee, newValueTmp ]),
3542
3527
 
3543
3528
  Opcodes.i32_to,
3544
3529
  [ Opcodes.i32_store16, 0, 4 ]
@@ -3554,7 +3539,7 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
3554
3539
  [ Opcodes.i32_load, 0, 4 ],
3555
3540
  Opcodes.i32_from_u
3556
3541
  ], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
3557
- [ Opcodes.local_tee, newValueTmp ],
3542
+ ...optional([ Opcodes.local_tee, newValueTmp ]),
3558
3543
 
3559
3544
  Opcodes.i32_to_u,
3560
3545
  [ Opcodes.i32_store, 0, 4 ]
@@ -3570,7 +3555,7 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
3570
3555
  [ Opcodes.i32_load, 0, 4 ],
3571
3556
  Opcodes.i32_from
3572
3557
  ], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
3573
- [ Opcodes.local_tee, newValueTmp ],
3558
+ ...optional([ Opcodes.local_tee, newValueTmp ]),
3574
3559
 
3575
3560
  Opcodes.i32_to,
3576
3561
  [ Opcodes.i32_store, 0, 4 ]
@@ -3586,7 +3571,7 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
3586
3571
  [ Opcodes.f32_load, 0, 4 ],
3587
3572
  [ Opcodes.f64_promote_f32 ]
3588
3573
  ], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
3589
- [ Opcodes.local_tee, newValueTmp ],
3574
+ ...optional([ Opcodes.local_tee, newValueTmp ]),
3590
3575
 
3591
3576
  [ Opcodes.f32_demote_f64 ],
3592
3577
  [ Opcodes.f32_store, 0, 4 ]
@@ -3601,7 +3586,7 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
3601
3586
  [ Opcodes.local_get, pointerTmp ],
3602
3587
  [ Opcodes.f64_load, 0, 4 ]
3603
3588
  ], generate(scope, decl.right), number(TYPES.number, Valtype.i32), getNodeType(scope, decl.right), false, name, true)),
3604
- [ Opcodes.local_tee, newValueTmp ],
3589
+ ...optional([ Opcodes.local_tee, newValueTmp ]),
3605
3590
 
3606
3591
  [ Opcodes.f64_store, 0, 4 ]
3607
3592
  ],
@@ -3616,12 +3601,12 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
3616
3601
  ],
3617
3602
  postlude: [
3618
3603
  // setLastType(scope, TYPES.number)
3619
- [ Opcodes.local_get, newValueTmp ]
3604
+ ...optional([ Opcodes.local_get, newValueTmp ])
3620
3605
  ]
3621
3606
  }),
3622
3607
  } : {}),
3623
3608
 
3624
- [TYPES.undefined]: internalThrow(scope, 'TypeError', 'Cannot set property of undefined', true),
3609
+ [TYPES.undefined]: internalThrow(scope, 'TypeError', 'Cannot set property of undefined', !valueUnused),
3625
3610
 
3626
3611
  // default: internalThrow(scope, 'TypeError', `Cannot assign member with this type`)
3627
3612
  default: () => [
@@ -3652,9 +3637,11 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
3652
3637
 
3653
3638
  [ Opcodes.call, includeBuiltin(scope, scope.strict ? '__Porffor_object_setStrict' : '__Porffor_object_set').index ],
3654
3639
  [ Opcodes.drop ],
3640
+ ...(valueUnused ? [ [ Opcodes.drop ] ] : [])
3655
3641
  // ...setLastType(scope, getNodeType(scope, decl)),
3656
3642
  ]
3657
- }, valtypeBinary)
3643
+ }, valueUnused ? Blocktype.void : valtypeBinary),
3644
+ ...optional(number(UNDEFINED), valueUnused)
3658
3645
  ];
3659
3646
  }
3660
3647
 
@@ -3682,7 +3669,8 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
3682
3669
  // set global and return (eg a = 2)
3683
3670
  return [
3684
3671
  ...generateVarDstr(scope, 'var', name, decl.right, undefined, true),
3685
- ...generate(scope, decl.left)
3672
+ ...optional(generate(scope, decl.left), !valueUnused),
3673
+ ...optional(number(UNDEFINED), valueUnused)
3686
3674
  ];
3687
3675
  }
3688
3676
 
@@ -3690,7 +3678,10 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
3690
3678
  if (local.metadata?.kind === 'const') return internalThrow(scope, 'TypeError', `Cannot assign to constant variable ${name}`, true);
3691
3679
 
3692
3680
  if (op === '=') {
3693
- return setLocalWithType(scope, name, isGlobal, decl.right, true);
3681
+ const out = setLocalWithType(scope, name, isGlobal, decl.right, !valueUnused);
3682
+
3683
+ if (valueUnused) out.push(...number(UNDEFINED));
3684
+ return out;
3694
3685
  }
3695
3686
 
3696
3687
  if (op === '||' || op === '&&' || op === '??') {
@@ -3713,12 +3704,15 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
3713
3704
  ];
3714
3705
  }
3715
3706
 
3716
- return setLocalWithType(
3707
+ const out = setLocalWithType(
3717
3708
  scope, name, isGlobal,
3718
3709
  performOp(scope, op, [ [ isGlobal ? Opcodes.global_get : Opcodes.local_get, local.idx ] ], generate(scope, decl.right), getType(scope, name), getNodeType(scope, decl.right), isGlobal, name, true),
3719
- true,
3710
+ !valueUnused,
3720
3711
  getNodeType(scope, decl)
3721
3712
  );
3713
+
3714
+ if (valueUnused) out.push(...number(UNDEFINED));
3715
+ return out;
3722
3716
  };
3723
3717
 
3724
3718
  const ifIdentifierErrors = (scope, decl) => {
@@ -3859,15 +3853,15 @@ const generateUnary = (scope, decl) => {
3859
3853
  disposeLeftover(out);
3860
3854
 
3861
3855
  out.push(...typeSwitch(scope, overrideType ?? getNodeType(scope, decl.argument), [
3862
- [ TYPES.number, () => makeString(scope, 'number', false, '#typeof_result') ],
3863
- [ TYPES.boolean, () => makeString(scope, 'boolean', false, '#typeof_result') ],
3864
- [ [ TYPES.string, TYPES.bytestring ], () => makeString(scope, 'string', false, '#typeof_result') ],
3865
- [ [ TYPES.undefined, TYPES.empty ], () => makeString(scope, 'undefined', false, '#typeof_result') ],
3866
- [ TYPES.function, () => makeString(scope, 'function', false, '#typeof_result') ],
3867
- [ TYPES.symbol, () => makeString(scope, 'symbol', false, '#typeof_result') ],
3856
+ [ TYPES.number, () => makeString(scope, 'number') ],
3857
+ [ TYPES.boolean, () => makeString(scope, 'boolean') ],
3858
+ [ [ TYPES.string, TYPES.bytestring ], () => makeString(scope, 'string') ],
3859
+ [ [ TYPES.undefined, TYPES.empty ], () => makeString(scope, 'undefined') ],
3860
+ [ TYPES.function, () => makeString(scope, 'function') ],
3861
+ [ TYPES.symbol, () => makeString(scope, 'symbol') ],
3868
3862
 
3869
3863
  // object and internal types
3870
- [ 'default', () => makeString(scope, 'object', false, '#typeof_result') ],
3864
+ [ 'default', () => makeString(scope, 'object') ],
3871
3865
  ]));
3872
3866
 
3873
3867
  return out;
@@ -3903,6 +3897,7 @@ const generateUpdate = (scope, decl, _global, _name, valueUnused = false) => {
3903
3897
  out.push([ isGlobal ? Opcodes.global_set : Opcodes.local_set, idx ]);
3904
3898
  if (decl.prefix && !valueUnused) out.push([ isGlobal ? Opcodes.global_get : Opcodes.local_get, idx ]);
3905
3899
 
3900
+ if (valueUnused) out.push(...number(UNDEFINED));
3906
3901
  return out;
3907
3902
  }
3908
3903
 
@@ -3920,7 +3915,7 @@ const generateUpdate = (scope, decl, _global, _name, valueUnused = false) => {
3920
3915
  prefix: true,
3921
3916
  argument: decl.argument
3922
3917
  }),
3923
- [ decl.prefix ? Opcodes.local_set : Opcodes.local_tee, tmp ],
3918
+ [ decl.prefix || valueUnused ? Opcodes.local_set : Opcodes.local_tee, tmp ],
3924
3919
 
3925
3920
  // x = tmp + 1
3926
3921
  ...generate(scope, {
@@ -3933,8 +3928,9 @@ const generateUpdate = (scope, decl, _global, _name, valueUnused = false) => {
3933
3928
  left: { type: 'Identifier', name: '#updatetmp' },
3934
3929
  right: { type: 'Literal', value: 1 }
3935
3930
  }
3936
- }),
3937
- ...(decl.prefix ? [] : [ [ Opcodes.drop ] ])
3931
+ }, _global, _name, valueUnused),
3932
+ ...(decl.prefix || valueUnused ? [] : [ [ Opcodes.drop ] ]),
3933
+ ...optional(number(UNDEFINED), valueUnused)
3938
3934
  ];
3939
3935
  };
3940
3936
 
@@ -4195,7 +4191,8 @@ const generateForOf = (scope, decl) => {
4195
4191
  ...setType(scope, tmpName, TYPES.string),
4196
4192
 
4197
4193
  // allocate out string
4198
- [ Opcodes.call, includeBuiltin(scope, '__Porffor_allocate').index ],
4194
+ ...number(8, Valtype.i32),
4195
+ [ Opcodes.call, includeBuiltin(scope, '__Porffor_allocateBytes').index ],
4199
4196
  [ Opcodes.local_tee, localTmp(scope, '#forof_allocd', Valtype.i32) ],
4200
4197
 
4201
4198
  // set length to 1
@@ -4250,7 +4247,8 @@ const generateForOf = (scope, decl) => {
4250
4247
  ...setType(scope, tmpName, TYPES.bytestring),
4251
4248
 
4252
4249
  // allocate out string
4253
- [ Opcodes.call, includeBuiltin(scope, '__Porffor_allocate').index ],
4250
+ ...number(8, Valtype.i32),
4251
+ [ Opcodes.call, includeBuiltin(scope, '__Porffor_allocateBytes').index ],
4254
4252
  [ Opcodes.local_tee, localTmp(scope, '#forof_allocd', Valtype.i32) ],
4255
4253
 
4256
4254
  // set length to 1
@@ -4897,18 +4895,7 @@ const generateMeta = (scope, decl) => {
4897
4895
  };
4898
4896
 
4899
4897
  let pages = new Map();
4900
- const allocPage = (scope, reason, type) => {
4901
- const ptr = i => i === 0 ? 16 : (i * pageSize);
4902
- if (pages.has(reason)) return ptr(pages.get(reason).ind);
4903
-
4904
- const ind = pages.size;
4905
- pages.set(reason, { ind, type });
4906
-
4907
- scope.pages ??= new Map();
4908
- scope.pages.set(reason, { ind, type });
4909
-
4910
- return ptr(ind);
4911
- };
4898
+ const allocPage = (scope, name) => _allocPage({ scope, pages }, name);
4912
4899
 
4913
4900
  const itemTypeToValtype = {
4914
4901
  i32: 'i32',
@@ -4942,18 +4929,23 @@ const compileBytes = (val, itemType) => {
4942
4929
  }
4943
4930
  };
4944
4931
 
4945
- const makeData = (scope, elements, page = null, itemType, initEmpty) => {
4932
+ const makeData = (scope, elements, page = null, itemType = 'i8') => {
4933
+ // if data for page already exists, abort
4934
+ if (page && data.find(x => x.page === page)) return;
4935
+
4946
4936
  const length = elements.length;
4947
4937
 
4948
4938
  // if length is 0 memory/data will just be 0000... anyway
4949
4939
  if (length === 0) return false;
4950
4940
 
4951
4941
  let bytes = compileBytes(length, 'i32');
4952
-
4953
- if (!initEmpty) for (let i = 0; i < length; i++) {
4954
- if (elements[i] == null) continue;
4955
-
4956
- bytes.push(...compileBytes(elements[i], itemType));
4942
+ if (itemType === 'i8') {
4943
+ bytes = bytes.concat(elements);
4944
+ } else {
4945
+ for (let i = 0; i < length; i++) {
4946
+ if (elements[i] == null) continue;
4947
+ bytes.push(...compileBytes(elements[i], itemType));
4948
+ }
4957
4949
  }
4958
4950
 
4959
4951
  const obj = { bytes, page };
@@ -4981,169 +4973,6 @@ const printStaticStr = str => {
4981
4973
  return out;
4982
4974
  };
4983
4975
 
4984
- const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty = false, itemType = valtype, intOut = false, typed = false) => {
4985
- const out = [];
4986
-
4987
- const uniqueName = name === '$undeclared' ? name + uniqId() : name;
4988
-
4989
- const useRawElements = !!decl.rawElements;
4990
- const elements = useRawElements ? decl.rawElements : decl.elements;
4991
-
4992
- const valtype = itemTypeToValtype[itemType];
4993
- const length = elements.length;
4994
-
4995
- const allocated = allocator.alloc({ scope, pages, globals, asmFunc, funcIndex }, uniqueName, { itemType });
4996
-
4997
- let pointer = allocated;
4998
- if (allocator.constructor.name !== 'StaticAllocator') {
4999
- // const tmp = localTmp(scope, '#makearray_pointer' + uniqueName, Valtype.i32);
5000
- const tmp = localTmp(scope, '#makearray_pointer' + name, Valtype.i32);
5001
- out.push(
5002
- ...allocated,
5003
- [ Opcodes.local_set, tmp ]
5004
- );
5005
-
5006
- if (Prefs.runtimeAllocLog) out.push(
5007
- ...printStaticStr(`${name}: `),
5008
-
5009
- [ Opcodes.local_get, tmp ],
5010
- Opcodes.i32_from_u,
5011
- [ Opcodes.call, 0 ],
5012
-
5013
- ...number(10),
5014
- [ Opcodes.call, 1 ]
5015
- );
5016
-
5017
- pointer = [ [ Opcodes.local_get, tmp ] ];
5018
-
5019
- if (Prefs.data && useRawElements) {
5020
- const data = makeData(scope, elements, null, itemType, initEmpty);
5021
- if (data) {
5022
- // init data
5023
- out.push(
5024
- ...pointer,
5025
- ...number(0, Valtype.i32),
5026
- ...number(data.size, Valtype.i32),
5027
- [ ...Opcodes.memory_init, ...unsignedLEB128(data.idx), 0 ]
5028
- );
5029
- }
5030
-
5031
- // return pointer in out
5032
- out.push(
5033
- ...pointer,
5034
- ...(!intOut ? [ Opcodes.i32_from_u ] : [])
5035
- );
5036
-
5037
- return [ out, pointer ];
5038
- }
5039
- } else {
5040
- const rawPtr = allocator.lastPtr;
5041
-
5042
- scope.arrays ??= new Map();
5043
- const firstAssign = !scope.arrays.has(uniqueName);
5044
- if (firstAssign) scope.arrays.set(uniqueName, rawPtr);
5045
-
5046
- const local = global ? globals[name] : scope.locals?.[name];
5047
- if (
5048
- Prefs.data && useRawElements &&
5049
- name !== '#member_prop' && name !== '#member_prop_assign' &&
5050
- (!globalThis.precompile || !global)
5051
- ) {
5052
- if (Prefs.activeData && firstAssign) {
5053
- makeData(scope, elements, allocator.lastName, itemType, initEmpty);
5054
-
5055
- // local value as pointer
5056
- return [ number(rawPtr, intOut ? Valtype.i32 : valtypeBinary), pointer ];
5057
- }
5058
-
5059
- if (Prefs.passiveData) {
5060
- const data = makeData(scope, elements, null, itemType, initEmpty);
5061
- if (data) {
5062
- // init data
5063
- out.push(
5064
- ...pointer,
5065
- ...number(0, Valtype.i32),
5066
- ...number(data.size, Valtype.i32),
5067
- [ ...Opcodes.memory_init, ...unsignedLEB128(data.idx), 0 ]
5068
- );
5069
- }
5070
-
5071
- // return pointer in out
5072
- out.push(...number(rawPtr, intOut ? Valtype.i32 : valtypeBinary));
5073
-
5074
- return [ out, pointer ];
5075
- }
5076
- }
5077
-
5078
- if (local != null) {
5079
- // hack: handle allocation for #member_prop's here instead of in several places /shrug
5080
- let shouldGet = true;
5081
- if (name === '#member_prop') {
5082
- out.push(...number(rawPtr));
5083
- shouldGet = false;
5084
- }
5085
-
5086
- if (name === '#member_prop_assign') {
5087
- out.push(
5088
- [ Opcodes.call, includeBuiltin(scope, '__Porffor_allocate').index ],
5089
- Opcodes.i32_from_u
5090
- );
5091
- shouldGet = false;
5092
- }
5093
-
5094
- const pointerTmp = localTmp(scope, '#makearray_pointer_tmp', Valtype.i32);
5095
- out.push(
5096
- ...(shouldGet ? [
5097
- [ global ? Opcodes.global_get : Opcodes.local_get, local.idx ],
5098
- Opcodes.i32_to_u
5099
- ] : [
5100
- // hack: make precompile realise we are allocating
5101
- ...(globalThis.precompile ? [
5102
- [ global ? Opcodes.global_set : Opcodes.local_set, local.idx ],
5103
- [ global ? Opcodes.global_get : Opcodes.local_get, local.idx ],
5104
- ] : []),
5105
- Opcodes.i32_to_u
5106
- ]),
5107
- [ Opcodes.local_set, pointerTmp ]
5108
- );
5109
-
5110
- pointer = [ [ Opcodes.local_get, pointerTmp ] ];
5111
- }
5112
- }
5113
-
5114
-
5115
- // store length
5116
- out.push(
5117
- ...pointer,
5118
- ...number(length, Valtype.i32),
5119
- [ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, 0 ]
5120
- );
5121
-
5122
- const storeOp = StoreOps[itemType];
5123
- const sizePerEl = ValtypeSize[itemType] + (typed ? 1 : 0);
5124
- if (!initEmpty) for (let i = 0; i < length; i++) {
5125
- if (elements[i] == null) continue;
5126
-
5127
- const offset = ValtypeSize.i32 + i * sizePerEl;
5128
- out.push(
5129
- ...pointer,
5130
- ...(useRawElements ? number(elements[i], Valtype[valtype]) : generate(scope, elements[i])),
5131
- [ storeOp, 0, ...unsignedLEB128(offset) ],
5132
- ...(!typed ? [] : [ // typed presumes !useRawElements
5133
- ...pointer,
5134
- ...getNodeType(scope, elements[i]),
5135
- [ Opcodes.i32_store8, 0, ...unsignedLEB128(offset + ValtypeSize[itemType]) ]
5136
- ])
5137
- );
5138
- }
5139
-
5140
- // local value as pointer
5141
- out.push(...pointer);
5142
- if (!intOut) out.push(Opcodes.i32_from_u);
5143
-
5144
- return [ out, pointer ];
5145
- };
5146
-
5147
4976
  const storeArray = (scope, array, index, element) => {
5148
4977
  if (!Array.isArray(element)) element = generate(scope, element);
5149
4978
  if (typeof index === 'number') index = number(index);
@@ -5209,25 +5038,83 @@ const byteStringable = str => {
5209
5038
  return true;
5210
5039
  };
5211
5040
 
5212
- const makeString = (scope, str, global = false, name = '$undeclared', forceBytestring = undefined) => {
5213
- const rawElements = new Array(str.length);
5214
- let byteStringable = true;
5041
+ const makeString = (scope, str, forceBytestring = undefined) => {
5042
+ if (str.length === 0) return number(0);
5043
+
5044
+ const elements = new Array(str.length);
5045
+ let bytestring = forceBytestring !== false;
5215
5046
  for (let i = 0; i < str.length; i++) {
5216
5047
  const c = str.charCodeAt(i);
5217
- rawElements[i] = c;
5048
+ elements[i] = c;
5218
5049
 
5219
- if (byteStringable && c > 0xFF) byteStringable = false;
5050
+ if (bytestring && c > 0xFF) bytestring = false;
5220
5051
  }
5221
5052
 
5222
- if (byteStringable && forceBytestring === false) byteStringable = false;
5053
+ if (globalThis.precompile) return [
5054
+ [ Opcodes.const, 'str', str, forceBytestring ]
5055
+ ];
5223
5056
 
5224
- return makeArray(scope, {
5225
- rawElements
5226
- }, global, name, false, byteStringable ? 'i8' : 'i16')[0];
5057
+ const ptr = allocStr({ scope, pages }, str, bytestring);
5058
+ makeData(scope, elements, str, bytestring ? 'i8' : 'i16');
5059
+
5060
+ return number(ptr);
5227
5061
  };
5228
5062
 
5229
- const generateArray = (scope, decl, global = false, name = '$undeclared', initEmpty = false) => {
5230
- return makeArray(scope, decl, global, name, initEmpty, valtype, false, true)[0];
5063
+ const generateArray = (scope, decl, global = false, name = '$undeclared', staticAlloc = false) => {
5064
+ const elements = decl.elements;
5065
+ const length = elements.length;
5066
+
5067
+ const out = [];
5068
+ let pointer;
5069
+
5070
+ if (staticAlloc) {
5071
+ const uniqueName = name === '$undeclared' ? name + uniqId() : name;
5072
+
5073
+ const ptr = allocPage(scope, uniqueName);
5074
+ pointer = number(ptr, Valtype.i32)[0];
5075
+
5076
+ scope.arrays ??= new Map();
5077
+ scope.arrays.set(uniqueName, ptr);
5078
+ } else {
5079
+ const tmp = localTmp(scope, '#create_array' + uniqId(), Valtype.i32);
5080
+ out.push(
5081
+ [ Opcodes.call, includeBuiltin(scope, '__Porffor_allocate').index ],
5082
+ [ Opcodes.local_set, tmp ]
5083
+ );
5084
+
5085
+ pointer = [ Opcodes.local_get, tmp ];
5086
+ }
5087
+
5088
+ // store length
5089
+ if (length !== 0) out.push(
5090
+ pointer,
5091
+ ...number(length, Valtype.i32),
5092
+ [ Opcodes.i32_store, Math.log2(ValtypeSize.i32) - 1, 0 ]
5093
+ );
5094
+
5095
+ // todo: rewrite below to support RestElement (holdover from makeArray)
5096
+ for (let i = 0; i < length; i++) {
5097
+ if (elements[i] == null) continue;
5098
+
5099
+ const offset = ValtypeSize.i32 + i * (ValtypeSize[valtype] + 1);
5100
+ out.push(
5101
+ pointer,
5102
+ ...generate(scope, elements[i]),
5103
+ [ Opcodes.store, 0, ...unsignedLEB128(offset) ],
5104
+
5105
+ pointer,
5106
+ ...getNodeType(scope, elements[i]),
5107
+ [ Opcodes.i32_store8, 0, ...unsignedLEB128(offset + ValtypeSize[valtype]) ]
5108
+ );
5109
+ }
5110
+
5111
+ // return array pointer
5112
+ out.push(
5113
+ pointer,
5114
+ Opcodes.i32_from_u
5115
+ );
5116
+
5117
+ return out;
5231
5118
  };
5232
5119
 
5233
5120
  // opt: do not call ToPropertyKey for non-computed properties as unneeded
@@ -5380,7 +5267,7 @@ const generateMember = (scope, decl, _global, _name, _objectWasm = undefined) =>
5380
5267
  if (name.startsWith('__')) name = name.split('_').pop();
5381
5268
  if (name.startsWith('#')) name = '';
5382
5269
 
5383
- return withType(scope, makeString(scope, name, _global, _name, true), TYPES.bytestring);
5270
+ return withType(scope, makeString(scope, name, true), TYPES.bytestring);
5384
5271
  }
5385
5272
 
5386
5273
  const object = decl.object;
@@ -5560,7 +5447,8 @@ const generateMember = (scope, decl, _global, _name, _objectWasm = undefined) =>
5560
5447
 
5561
5448
  [TYPES.string]: () => [
5562
5449
  // allocate out string
5563
- [ Opcodes.call, includeBuiltin(scope, '__Porffor_allocate').index ],
5450
+ ...number(8, Valtype.i32),
5451
+ [ Opcodes.call, includeBuiltin(scope, '__Porffor_allocateBytes').index ],
5564
5452
  [ Opcodes.local_tee, localTmp(scope, '#member_allocd', Valtype.i32) ],
5565
5453
 
5566
5454
  // set length to 1
@@ -5594,7 +5482,8 @@ const generateMember = (scope, decl, _global, _name, _objectWasm = undefined) =>
5594
5482
 
5595
5483
  [TYPES.bytestring]: () => [
5596
5484
  // allocate out string
5597
- [ Opcodes.call, includeBuiltin(scope, '__Porffor_allocate').index ],
5485
+ ...number(8, Valtype.i32),
5486
+ [ Opcodes.call, includeBuiltin(scope, '__Porffor_allocateBytes').index ],
5598
5487
  [ Opcodes.local_tee, localTmp(scope, '#member_allocd', Valtype.i32) ],
5599
5488
 
5600
5489
  // set length to 1
@@ -5982,8 +5871,8 @@ const generateTaggedTemplate = (scope, decl, global = false, name = undefined) =
5982
5871
  return out;
5983
5872
  },
5984
5873
 
5985
- __Porffor_bs: str => makeString(scope, str, global, name, true),
5986
- __Porffor_s: str => makeString(scope, str, global, name, false)
5874
+ __Porffor_bs: str => makeString(scope, str, true),
5875
+ __Porffor_s: str => makeString(scope, str, false)
5987
5876
  };
5988
5877
 
5989
5878
  const { quasis, expressions } = decl.quasi;
@@ -6171,7 +6060,7 @@ const generateFunc = (scope, decl, forceNoExpr = false) => {
6171
6060
  }
6172
6061
 
6173
6062
  if ([
6174
- TYPES.date, TYPES.number, TYPES.promise, TYPES.symbol,
6063
+ TYPES.date, TYPES.number, TYPES.promise, TYPES.symbol, TYPES.function,
6175
6064
  TYPES.set, TYPES.map,
6176
6065
  TYPES.weakref, TYPES.weakset, TYPES.weakmap,
6177
6066
  TYPES.arraybuffer, TYPES.sharedarraybuffer, TYPES.dataview
@@ -6288,13 +6177,12 @@ const generateFunc = (scope, decl, forceNoExpr = false) => {
6288
6177
  if (name === 'main') {
6289
6178
  func.gotLastType = true;
6290
6179
  func.export = true;
6291
- func.returns = [ valtypeBinary, Valtype.i32 ];
6292
6180
 
6293
6181
  let finalStatement = decl.body.body[decl.body.body.length - 1];
6294
6182
  if (finalStatement?.type === 'EmptyStatement') finalStatement = decl.body.body[decl.body.body.length - 2];
6295
6183
 
6296
6184
  const lastInst = wasm[wasm.length - 1] ?? [ Opcodes.end ];
6297
- if (lastInst[0] === Opcodes.drop) {
6185
+ if (lastInst[0] === Opcodes.drop || lastInst[0] === Opcodes.f64_const) {
6298
6186
  if (finalStatement.type.endsWith('Declaration')) {
6299
6187
  // final statement is decl, force undefined
6300
6188
  disposeLeftover(wasm);
@@ -6332,7 +6220,7 @@ const generateFunc = (scope, decl, forceNoExpr = false) => {
6332
6220
  }
6333
6221
  } else {
6334
6222
  // add end return if not found
6335
- if (wasm[wasm.length - 1]?.[0] !== Opcodes.return && countLeftover(wasm) === 0) {
6223
+ if (wasm[wasm.length - 1]?.[0] !== Opcodes.return && countLeftover(wasm) < func.returns.length) {
6336
6224
  wasm.push(...generateReturn(func, {}));
6337
6225
  }
6338
6226
  }
@@ -6572,7 +6460,6 @@ export default program => {
6572
6460
  builtinFuncs = new BuiltinFuncs();
6573
6461
  builtinVars = new BuiltinVars({ builtinFuncs });
6574
6462
  prototypeFuncs = new PrototypeFuncs();
6575
- allocator = makeAllocator(Prefs.allocator ?? 'static');
6576
6463
 
6577
6464
  const getObjectName = x => x.startsWith('__') && x.slice(2, x.indexOf('_', 2));
6578
6465
  objectHackers = ['assert', 'compareArray', 'Test262Error', ...new Set(Object.keys(builtinFuncs).map(getObjectName).concat(Object.keys(builtinVars).map(getObjectName)).filter(x => x))];