porffor 0.34.6 → 0.34.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.
@@ -48,12 +48,18 @@ const cacheAst = (decl, wasm) => {
48
48
  return wasm;
49
49
  };
50
50
 
51
- const funcRef = (idx, name) => {
51
+ const funcRef = func => {
52
+ // generate func
53
+ func.generate?.();
54
+
52
55
  if (globalThis.precompile) return [
53
- [ Opcodes.const, 'funcref', name ]
56
+ [ Opcodes.const, 'funcref', func.name ]
54
57
  ];
55
58
 
56
- return number(idx - importedFuncs.length);
59
+ return [
60
+ [ Opcodes.const, func.index - importedFuncs.length ]
61
+ // [ Opcodes.const, func.index - importedFuncs.length, 'funcref' ]
62
+ ];
57
63
  };
58
64
 
59
65
  const generate = (scope, decl, global = false, name = undefined, valueUnused = false) => {
@@ -189,6 +195,9 @@ const generate = (scope, decl, global = false, name = undefined, valueUnused = f
189
195
 
190
196
  for (const x of newFuncs) {
191
197
  x.export = true;
198
+
199
+ // generate func
200
+ x.generate?.();
192
201
  }
193
202
  }
194
203
 
@@ -344,9 +353,7 @@ const generateIdent = (scope, decl) => {
344
353
  if (Object.hasOwn(globals, name)) return [ [ Opcodes.global_get, globals[name].idx ] ];
345
354
 
346
355
  if (Object.hasOwn(importedFuncs, name)) return number(importedFuncs[name] - importedFuncs.length);
347
- if (Object.hasOwn(funcIndex, name)) {
348
- return funcRef(funcIndex[name], name);
349
- }
356
+ if (Object.hasOwn(funcIndex, name)) return funcRef(funcByName(name));
350
357
  }
351
358
 
352
359
  if (local?.idx === undefined && rawName.startsWith('__')) {
@@ -1117,6 +1124,14 @@ const asmFuncToAsm = (scope, func) => {
1117
1124
 
1118
1125
  return idx;
1119
1126
  },
1127
+ funcRef: name => {
1128
+ if (funcIndex[name] == null && builtinFuncs[name]) {
1129
+ includeBuiltin(scope, name);
1130
+ }
1131
+
1132
+ const func = funcByName(name);
1133
+ return funcRef(func);
1134
+ },
1120
1135
  glbl: (opcode, name, type) => {
1121
1136
  const globalName = '#porf#' + name; // avoid potential name clashing with user js
1122
1137
  if (!globals[globalName]) {
@@ -1164,7 +1179,7 @@ const asmFunc = (name, { wasm, params = [], typedParams = false, locals: localTy
1164
1179
  wasm = [];
1165
1180
  }
1166
1181
 
1167
- const existing = funcs.find(x => x.name === name);
1182
+ const existing = funcByName(name);
1168
1183
  if (existing) return existing;
1169
1184
 
1170
1185
  const nameParam = i => localNames[i] ?? (i >= params.length ? ['a', 'b', 'c'][i - params.length] : ['x', 'y', 'z'][i]);
@@ -1223,7 +1238,7 @@ const asmFunc = (name, { wasm, params = [], typedParams = false, locals: localTy
1223
1238
  for (const inst of wasm) {
1224
1239
  if (inst.at(-1) === 'read func lut') {
1225
1240
  inst.splice(2, 99);
1226
- inst.push(...unsignedLEB128(allocPage({}, 'func lut') * pageSize));
1241
+ inst.push(...unsignedLEB128(allocPage({}, 'func lut')));
1227
1242
  }
1228
1243
  }
1229
1244
 
@@ -1391,7 +1406,7 @@ const getNodeType = (scope, node) => {
1391
1406
  return TYPES.number;
1392
1407
  }
1393
1408
 
1394
- const func = funcs.find(x => x.name === name);
1409
+ const func = funcByName(name);
1395
1410
  if (func) {
1396
1411
  if (func.returnType != null) return func.returnType;
1397
1412
  }
@@ -1616,11 +1631,11 @@ const countLeftover = wasm => {
1616
1631
  else if (inst[0] === Opcodes.memory_copy[0] && (inst[1] === Opcodes.memory_copy[1] || inst[1] === Opcodes.memory_init[1])) count -= 3;
1617
1632
  else if (inst[0] === Opcodes.return) count = 0;
1618
1633
  else if (inst[0] === Opcodes.call) {
1619
- let func = funcs.find(x => x.index === inst[1]);
1620
1634
  if (inst[1] < importedFuncs.length) {
1621
- func = importedFuncs[inst[1]];
1635
+ const func = importedFuncs[inst[1]];
1622
1636
  count = count - func.params + func.returns;
1623
1637
  } else {
1638
+ const func = funcByIndex(inst[1]);
1624
1639
  count = count - func.params.length + func.returns.length;
1625
1640
  }
1626
1641
  } else if (inst[0] === Opcodes.call_indirect) {
@@ -1855,7 +1870,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
1855
1870
 
1856
1871
  // opt: virtualize iifes
1857
1872
  if (isFuncType(decl.callee.type)) {
1858
- const [ func ] = generateFunc(scope, decl.callee);
1873
+ const [ func ] = generateFunc(scope, decl.callee, true);
1859
1874
  name = func.name;
1860
1875
  }
1861
1876
 
@@ -2439,19 +2454,19 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
2439
2454
  [ Opcodes.i32_mul ],
2440
2455
  ...number(4, Valtype.i32),
2441
2456
  [ Opcodes.i32_add ],
2442
- [ Opcodes.i32_load8_u, 0, ...unsignedLEB128(allocPage(scope, 'func lut') * pageSize), 'read func lut' ],
2457
+ [ Opcodes.i32_load8_u, 0, ...unsignedLEB128(allocPage(scope, 'func lut')), 'read func lut' ],
2443
2458
  [ Opcodes.local_set, flags ],
2444
2459
 
2445
2460
  // check if non-constructor was called with new, if so throw
2446
- [ Opcodes.local_get, flags ],
2447
- ...number(0b10, Valtype.i32),
2448
- [ Opcodes.i32_and ],
2449
- [ Opcodes.i32_eqz ],
2450
- [ Opcodes.i32_const, decl._new ? 1 : 0 ],
2451
- [ Opcodes.i32_and ],
2452
- [ Opcodes.if, Blocktype.void ],
2453
- ...internalThrow(scope, 'TypeError', `${unhackName(name)} is not a constructor`),
2454
- [ Opcodes.end ],
2461
+ ...(decl._new ? [
2462
+ [ Opcodes.local_get, flags ],
2463
+ ...number(0b10, Valtype.i32),
2464
+ [ Opcodes.i32_and ],
2465
+ [ Opcodes.i32_eqz ],
2466
+ [ Opcodes.if, Blocktype.void ],
2467
+ ...internalThrow(scope, 'TypeError', `${unhackName(name)} is not a constructor`),
2468
+ [ Opcodes.end ],
2469
+ ] : []),
2455
2470
 
2456
2471
  // [ Opcodes.local_get, funcLocal ],
2457
2472
  // Opcodes.i32_from_u,
@@ -2463,10 +2478,18 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
2463
2478
  // [ Opcodes.local_get, funcLocal ],
2464
2479
  // ...number(64, Valtype.i32),
2465
2480
  // [ Opcodes.i32_mul ],
2466
- // [ Opcodes.i32_load16_u, 0, ...unsignedLEB128(allocPage(scope, 'func lut') * pageSize), 'read func lut' ],
2481
+ // [ Opcodes.i32_load16_u, 0, ...unsignedLEB128(allocPage(scope, 'func lut')), 'read func lut' ],
2467
2482
  // Opcodes.i32_from_u,
2468
2483
  // [ Opcodes.call, 0 ],
2469
2484
 
2485
+ // [ Opcodes.local_get, funcLocal ],
2486
+ // [ Opcodes.call, includeBuiltin(scope, '__Porffor_funcLut_name').index ],
2487
+ // Opcodes.i32_from_u,
2488
+ // ...number(TYPES.bytestring, Valtype.i32),
2489
+ // [ Opcodes.call, includeBuiltin(scope, '__Porffor_printString').index ],
2490
+ // [ Opcodes.drop ],
2491
+ // [ Opcodes.drop ],
2492
+
2470
2493
  // ...number(10),
2471
2494
  // [ Opcodes.call, 1 ],
2472
2495
 
@@ -2475,7 +2498,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
2475
2498
  [ Opcodes.local_get, funcLocal ],
2476
2499
  ...number(64, Valtype.i32),
2477
2500
  [ Opcodes.i32_mul ],
2478
- [ Opcodes.i32_load16_u, 0, ...unsignedLEB128(allocPage(scope, 'func lut') * pageSize), 'read func lut' ]
2501
+ [ Opcodes.i32_load16_u, 0, ...unsignedLEB128(allocPage(scope, 'func lut')), 'read func lut' ]
2479
2502
  ], tableBc, valtypeBinary)
2480
2503
  ],
2481
2504
 
@@ -2491,7 +2514,11 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
2491
2514
  ];
2492
2515
  }
2493
2516
 
2494
- const func = funcs[idx - importedFuncs.length]; // idx === scope.index ? scope : funcs.find(x => x.index === idx);
2517
+ const func = funcByIndex(idx);
2518
+
2519
+ // generate func
2520
+ if (func) func.generate?.();
2521
+
2495
2522
  const userFunc = func && !func.internal;
2496
2523
  const typedParams = userFunc || func?.typedParams;
2497
2524
  const typedReturns = (userFunc && func.returnType == null) || builtinFuncs[name]?.typedReturns;
@@ -2987,7 +3014,7 @@ const generateVarDstr = (scope, kind, pattern, init, defaultValue, global) => {
2987
3014
  // hack for let a = function () { ... }
2988
3015
  if (!init.id) {
2989
3016
  init.id = { name };
2990
- generateFunc(scope, init);
3017
+ generateFunc(scope, init, true);
2991
3018
  return out;
2992
3019
  }
2993
3020
  }
@@ -4774,7 +4801,8 @@ const generateMeta = (scope, decl) => {
4774
4801
 
4775
4802
  let pages = new Map();
4776
4803
  const allocPage = (scope, reason, type) => {
4777
- if (pages.has(reason)) return pages.get(reason).ind;
4804
+ const ptr = i => i === 0 ? 16 : (i * pageSize);
4805
+ if (pages.has(reason)) return ptr(pages.get(reason).ind);
4778
4806
 
4779
4807
  if (reason.startsWith('array:')) pages.hasArray = true;
4780
4808
  if (reason.startsWith('string:')) pages.hasString = true;
@@ -4787,7 +4815,7 @@ const allocPage = (scope, reason, type) => {
4787
4815
  scope.pages ??= new Map();
4788
4816
  scope.pages.set(reason, { ind, type });
4789
4817
 
4790
- return ind;
4818
+ return ptr(ind);
4791
4819
  };
4792
4820
 
4793
4821
  const itemTypeToValtype = {
@@ -5257,7 +5285,7 @@ const generateMember = (scope, decl, _global, _name, _objectWasm = undefined) =>
5257
5285
  // todo: support optional
5258
5286
 
5259
5287
  if (!scope.noFastFuncMembers) {
5260
- const func = funcs.find(x => x.name === name);
5288
+ const func = funcByName(name);
5261
5289
  if (func) return withType(scope, number(countLength(func, name)), TYPES.number);
5262
5290
 
5263
5291
  if (Object.hasOwn(builtinFuncs, name)) return withType(scope, number(countLength(builtinFuncs[name], name)), TYPES.number);
@@ -5676,6 +5704,9 @@ const generateClass = (scope, decl) => {
5676
5704
  type: expr ? 'FunctionExpression' : 'FunctionDeclaration'
5677
5705
  });
5678
5706
 
5707
+ // always generate class constructor funcs
5708
+ func.generate();
5709
+
5679
5710
  if (decl.superClass) {
5680
5711
  out.push(
5681
5712
  ...generateCall(scope, {
@@ -5808,14 +5839,25 @@ const objectHack = node => {
5808
5839
  for (const x in node) {
5809
5840
  if (node[x] != null && typeof node[x] === 'object') {
5810
5841
  if (node[x].type) node[x] = objectHack(node[x]);
5811
- if (Array.isArray(node[x])) node[x] = node[x].map(y => objectHack(y));
5842
+ if (Array.isArray(node[x])) node[x] = node[x].map(objectHack);
5812
5843
  }
5813
5844
  }
5814
5845
 
5815
5846
  return node;
5816
5847
  };
5817
5848
 
5818
- const generateFunc = (scope, decl) => {
5849
+ const funcByIndex = idx => {
5850
+ if (idx == null ||
5851
+ idx < importedFuncs.length) return null;
5852
+
5853
+ const func = funcs[idx - importedFuncs.length];
5854
+ if (func && func.index === idx) return func;
5855
+
5856
+ return funcs.find(x => x.index === idx);
5857
+ };
5858
+ const funcByName = name => funcByIndex(funcIndex[name]);
5859
+
5860
+ const generateFunc = (scope, decl, outUnused = false) => {
5819
5861
  const name = decl.id ? decl.id.name : `#anonymous${uniqId()}`;
5820
5862
  if (decl.type.startsWith('Class')) {
5821
5863
  const out = generateClass(scope, {
@@ -5823,7 +5865,7 @@ const generateFunc = (scope, decl) => {
5823
5865
  id: { name }
5824
5866
  });
5825
5867
 
5826
- const func = funcs.find(x => x.name === name);
5868
+ const func = funcByName(name);
5827
5869
  return [ func, out ];
5828
5870
  }
5829
5871
 
@@ -5843,25 +5885,145 @@ const generateFunc = (scope, decl) => {
5843
5885
  // not async or generator
5844
5886
  !decl.async && !decl.generator,
5845
5887
  _onlyConstr: decl._onlyConstr,
5846
- strict: scope.strict
5888
+ strict: scope.strict,
5889
+
5890
+ generate() {
5891
+ if (func.wasm) return func.wasm;
5892
+
5893
+ // generating, stub _wasm
5894
+ func.wasm = [];
5895
+
5896
+ let body = objectHack(decl.body);
5897
+ if (decl.type === 'ArrowFunctionExpression' && decl.expression) {
5898
+ // hack: () => 0 -> () => return 0
5899
+ body = {
5900
+ type: 'ReturnStatement',
5901
+ argument: decl.body
5902
+ };
5903
+ }
5904
+
5905
+ for (const x in defaultValues) {
5906
+ prelude.push(
5907
+ ...getType(func, x),
5908
+ ...number(TYPES.undefined, Valtype.i32),
5909
+ [ Opcodes.i32_eq ],
5910
+ [ Opcodes.if, Blocktype.void ],
5911
+ ...generate(func, defaultValues[x], false, x),
5912
+ [ Opcodes.local_set, func.locals[x].idx ],
5913
+
5914
+ ...setType(func, x, getNodeType(func, defaultValues[x])),
5915
+ [ Opcodes.end ]
5916
+ );
5917
+ }
5918
+
5919
+ for (const x in destructuredArgs) {
5920
+ prelude.push(
5921
+ ...generateVarDstr(func, 'var', destructuredArgs[x], { type: 'Identifier', name: x }, undefined, false)
5922
+ );
5923
+ }
5924
+
5925
+ if (decl.async) {
5926
+ // make out promise local
5927
+ allocVar(func, '#async_out_promise', false, false);
5928
+ func.async = true;
5929
+ }
5930
+
5931
+ const wasm = prelude.concat(generate(func, body));
5932
+
5933
+ if (decl.async) {
5934
+ // make promise at the start
5935
+ wasm.unshift(
5936
+ [ Opcodes.call, includeBuiltin(func, '__Porffor_promise_create').index ],
5937
+ [ Opcodes.drop ],
5938
+ [ Opcodes.local_set, func.locals['#async_out_promise'].idx ]
5939
+ );
5940
+
5941
+ // todo: wrap in try and reject thrown value once supported
5942
+ }
5943
+
5944
+ if (!globalThis.precompile && func.constr) {
5945
+ wasm.unshift(
5946
+ // opt: do not check for pure constructors
5947
+ ...(func._onlyConstr ? [] : [
5948
+ // if being constructed
5949
+ [ Opcodes.local_get, func.locals['#newtarget'].idx ],
5950
+ Opcodes.i32_to_u,
5951
+ [ Opcodes.if, Blocktype.void ],
5952
+ ]),
5953
+ // set prototype of this ;)
5954
+ ...generate(func, setObjProp({ type: 'ThisExpression' }, '__proto__', getObjProp(func.name, 'prototype'))),
5955
+ ...(func._onlyConstr ? [] : [ [ Opcodes.end ] ])
5956
+ );
5957
+ }
5958
+
5959
+ if (name === 'main') {
5960
+ func.gotLastType = true;
5961
+ func.export = true;
5962
+ func.returns = [ valtypeBinary, Valtype.i32 ];
5963
+
5964
+ let finalStatement = decl.body.body[decl.body.body.length - 1];
5965
+ if (finalStatement?.type === 'EmptyStatement') finalStatement = decl.body.body[decl.body.body.length - 2];
5966
+
5967
+ const lastInst = wasm[wasm.length - 1] ?? [ Opcodes.end ];
5968
+ if (lastInst[0] === Opcodes.drop) {
5969
+ if (finalStatement.type.endsWith('Declaration')) {
5970
+ // final statement is decl, force undefined
5971
+ disposeLeftover(wasm);
5972
+ wasm.push(
5973
+ ...number(UNDEFINED),
5974
+ ...number(TYPES.undefined, Valtype.i32)
5975
+ );
5976
+ } else {
5977
+ wasm.splice(wasm.length - 1, 1);
5978
+ wasm.push(...getNodeType(func, finalStatement));
5979
+ }
5980
+ }
5981
+
5982
+ if (lastInst[0] === Opcodes.end || lastInst[0] === Opcodes.local_set || lastInst[0] === Opcodes.global_set) {
5983
+ if (lastInst[0] === Opcodes.local_set && lastInst[1] === func.locals['#last_type'].idx) {
5984
+ wasm.splice(wasm.length - 1, 1);
5985
+ } else {
5986
+ func.returns = [];
5987
+ }
5988
+ }
5989
+
5990
+ if (lastInst[0] === Opcodes.call) {
5991
+ const callee = funcByIndex(lastInst[1]);
5992
+ if (callee) func.returns = callee.returns.slice();
5993
+ else func.returns = [];
5994
+ }
5995
+
5996
+ // inject promise job runner func at the end of main if job queue is used
5997
+ if (Object.hasOwn(funcIndex, '__ecma262_HostEnqueuePromiseJob')) {
5998
+ wasm.push(
5999
+ [ Opcodes.call, includeBuiltin(scope, '__Porffor_promise_runJobs').index ],
6000
+ [ Opcodes.drop ],
6001
+ [ Opcodes.drop ]
6002
+ );
6003
+ }
6004
+ } else {
6005
+ // add end return if not found
6006
+ if (wasm[wasm.length - 1]?.[0] !== Opcodes.return && countLeftover(wasm) === 0) {
6007
+ wasm.push(...generateReturn(func, {}));
6008
+ }
6009
+ }
6010
+
6011
+ return func.wasm = wasm;
6012
+ }
5847
6013
  };
5848
6014
 
5849
6015
  funcIndex[name] = func.index;
5850
6016
  funcs.push(func);
5851
6017
 
5852
- const out = decl.type.endsWith('Expression') ? funcRef(func.index, func.name) : [];
5853
-
5854
6018
  let errorWasm = null;
5855
6019
  if (decl.generator) errorWasm = todo(scope, 'generator functions are not supported');
5856
6020
 
5857
6021
  if (errorWasm) {
6022
+ // func.params = [];
5858
6023
  func.wasm = errorWasm.concat([
5859
6024
  ...number(UNDEFINED),
5860
6025
  ...number(TYPES.undefined, Valtype.i32)
5861
6026
  ]);
5862
- func.params = [];
5863
- func.constr = false;
5864
- return [ func, out ];
5865
6027
  }
5866
6028
 
5867
6029
  if (typedInput && decl.returnType) {
@@ -5936,121 +6098,13 @@ const generateFunc = (scope, decl) => {
5936
6098
 
5937
6099
  func.params = Object.values(func.locals).map(x => x.type);
5938
6100
 
5939
- let body = objectHack(decl.body);
5940
- if (decl.type === 'ArrowFunctionExpression' && decl.expression) {
5941
- // hack: () => 0 -> () => return 0
5942
- body = {
5943
- type: 'ReturnStatement',
5944
- argument: decl.body
5945
- };
5946
- }
5947
-
5948
- for (const x in defaultValues) {
5949
- prelude.push(
5950
- ...getType(func, x),
5951
- ...number(TYPES.undefined, Valtype.i32),
5952
- [ Opcodes.i32_eq ],
5953
- [ Opcodes.if, Blocktype.void ],
5954
- ...generate(func, defaultValues[x], false, x),
5955
- [ Opcodes.local_set, func.locals[x].idx ],
5956
-
5957
- ...setType(func, x, getNodeType(func, defaultValues[x])),
5958
- [ Opcodes.end ]
5959
- );
5960
- }
5961
-
5962
- for (const x in destructuredArgs) {
5963
- prelude.push(
5964
- ...generateVarDstr(func, 'var', destructuredArgs[x], { type: 'Identifier', name: x }, undefined, false)
5965
- );
5966
- }
5967
-
5968
- if (decl.async) {
5969
- // make out promise local
5970
- allocVar(func, '#async_out_promise', false, false);
5971
- func.async = true;
5972
- }
5973
-
5974
- const wasm = func.wasm = prelude.concat(generate(func, body));
5975
-
5976
- if (decl.async) {
5977
- // make promise at the start
5978
- wasm.unshift(
5979
- [ Opcodes.call, includeBuiltin(func, '__Porffor_promise_create').index ],
5980
- [ Opcodes.drop ],
5981
- [ Opcodes.local_set, func.locals['#async_out_promise'].idx ]
5982
- );
5983
-
5984
- // todo: wrap in try and reject thrown value once supported
5985
- }
5986
-
5987
- if (!globalThis.precompile && func.constr) {
5988
- wasm.unshift(
5989
- // opt: do not check for pure constructors
5990
- ...(func._onlyConstr ? [] : [
5991
- // if being constructed
5992
- [ Opcodes.local_get, func.locals['#newtarget'].idx ],
5993
- Opcodes.i32_to_u,
5994
- [ Opcodes.if, Blocktype.void ],
5995
- ]),
5996
- // set prototype of this ;)
5997
- ...generate(func, setObjProp({ type: 'ThisExpression' }, '__proto__', getObjProp(func.name, 'prototype'))),
5998
- ...(func._onlyConstr ? [] : [ [ Opcodes.end ] ])
5999
- );
6000
- }
6001
-
6002
- if (name === 'main') {
6003
- func.gotLastType = true;
6004
- func.export = true;
6005
- func.returns = [ valtypeBinary, Valtype.i32 ];
6006
-
6007
- let finalStatement = decl.body.body[decl.body.body.length - 1];
6008
- if (finalStatement?.type === 'EmptyStatement') finalStatement = decl.body.body[decl.body.body.length - 2];
6009
-
6010
- const lastInst = func.wasm[func.wasm.length - 1] ?? [ Opcodes.end ];
6011
- if (lastInst[0] === Opcodes.drop) {
6012
- if (finalStatement.type.endsWith('Declaration')) {
6013
- // final statement is decl, force undefined
6014
- disposeLeftover(wasm);
6015
- func.wasm.push(
6016
- ...number(UNDEFINED),
6017
- ...number(TYPES.undefined, Valtype.i32)
6018
- );
6019
- } else {
6020
- func.wasm.splice(func.wasm.length - 1, 1);
6021
- func.wasm.push(...getNodeType(func, finalStatement));
6022
- }
6023
- }
6024
-
6025
- if (lastInst[0] === Opcodes.end || lastInst[0] === Opcodes.local_set || lastInst[0] === Opcodes.global_set) {
6026
- if (lastInst[0] === Opcodes.local_set && lastInst[1] === func.locals['#last_type'].idx) {
6027
- func.wasm.splice(func.wasm.length - 1, 1);
6028
- } else {
6029
- func.returns = [];
6030
- }
6031
- }
6032
-
6033
- if (lastInst[0] === Opcodes.call) {
6034
- const callee = funcs.find(x => x.index === lastInst[1]);
6035
- if (callee) func.returns = callee.returns.slice();
6036
- else func.returns = [];
6037
- }
6101
+ // force generate for main
6102
+ if (name === 'main') func.generate();
6038
6103
 
6039
- // inject promise job runner func at the end of main if job queue is used
6040
- if (Object.hasOwn(funcIndex, '__ecma262_HostEnqueuePromiseJob')) {
6041
- wasm.push(
6042
- [ Opcodes.call, includeBuiltin(scope, '__Porffor_promise_runJobs').index ],
6043
- [ Opcodes.drop ],
6044
- [ Opcodes.drop ]
6045
- );
6046
- }
6047
- } else {
6048
- // add end return if not found
6049
- if (wasm[wasm.length - 1]?.[0] !== Opcodes.return && countLeftover(wasm) === 0) {
6050
- wasm.push(...generateReturn(func, {}));
6051
- }
6052
- }
6104
+ // force generate all for precompile
6105
+ if (globalThis.precompile) func.generate();
6053
6106
 
6107
+ const out = decl.type.endsWith('Expression') && !outUnused ? funcRef(func) : [];
6054
6108
  return [ func, out ];
6055
6109
  };
6056
6110
 
@@ -6255,11 +6309,6 @@ export default program => {
6255
6309
 
6256
6310
  program.id = { name: 'main' };
6257
6311
 
6258
- const scope = {
6259
- locals: {},
6260
- localInd: 0
6261
- };
6262
-
6263
6312
  program.body = {
6264
6313
  type: 'BlockStatement',
6265
6314
  body: program.body
@@ -6267,12 +6316,63 @@ export default program => {
6267
6316
 
6268
6317
  if (Prefs.astLog) console.log(JSON.stringify(program.body.body, null, 2));
6269
6318
 
6270
- const [ main ] = generateFunc(scope, program);
6319
+ const [ main ] = generateFunc({}, program);
6271
6320
 
6272
6321
  delete globals['#ind'];
6273
6322
 
6274
6323
  // if blank main func and other exports, remove it
6275
6324
  if (main.wasm.length === 0 && funcs.reduce((acc, x) => acc + (x.export ? 1 : 0), 0) > 1) funcs.splice(main.index - importedFuncs.length, 1);
6276
6325
 
6326
+ // make ~empty funcs for never generated funcs
6327
+ // todo: these should just be deleted once able
6328
+ for (let i = 0; i < funcs.length; i++) {
6329
+ const f = funcs[i];
6330
+ if (f.internal || f.wasm) {
6331
+ continue;
6332
+ }
6333
+
6334
+ // make wasm just return 0s for expected returns
6335
+ f.wasm = f.returns.map(x => number(0, x)).flat();
6336
+
6337
+ // alternative: make func empty, may break some indirect calls
6338
+ // f.wasm = [];
6339
+ // f.returns = [];
6340
+ // f.params = [];
6341
+ // f.locals = {};
6342
+ }
6343
+
6344
+ // // remove never generated functions
6345
+ // let indexDelta = 0;
6346
+ // const funcRemap = new Map();
6347
+ // for (let i = 0; i < funcs.length; i++) {
6348
+ // const f = funcs[i];
6349
+ // if (f.internal || f.wasm) {
6350
+ // if (indexDelta) {
6351
+ // funcRemap.set(f.index, f.index - indexDelta);
6352
+ // f.index -= indexDelta;
6353
+ // }
6354
+ // continue;
6355
+ // }
6356
+
6357
+ // funcs.splice(i--, 1);
6358
+ // indexDelta++;
6359
+ // }
6360
+
6361
+ // // remap call ops
6362
+ // if (indexDelta) for (let i = 0; i < funcs.length; i++) {
6363
+ // const wasm = funcs[i].wasm;
6364
+ // for (let j = 0; j < wasm.length; j++) {
6365
+ // const op = wasm[j];
6366
+ // if (op[0] === Opcodes.call) {
6367
+ // let idx = op[1];
6368
+ // wasm[j] = [ Opcodes.call, funcRemap.get(idx) ?? idx ];
6369
+ // }
6370
+
6371
+ // if (op[0] === Opcodes.const && op[2] === 'funcref') {
6372
+ // wasm[j] = [ Opcodes.const, funcRemap.get(op[1] + importedFuncs.length) - importedFuncs.length ];
6373
+ // }
6374
+ // }
6375
+ // }
6376
+
6277
6377
  return { funcs, globals, tags, exceptions, pages, data };
6278
6378
  };
@@ -99,7 +99,7 @@ export default (wasm, name = '', ind = 0, locals = {}, params = [], returns = []
99
99
 
100
100
  if (inst[0] === Opcodes.call || inst[0] === Opcodes.return_call) {
101
101
  const idx = inst[1];
102
- const callFunc = funcs.find(x => x.index === idx);
102
+ const callFunc = funcs.find(x => (x.asmIndex ?? x.index) === idx);
103
103
  if (callFunc) out += ` ;; $${callFunc.name} ${makeSignature(callFunc.params, callFunc.returns)}`;
104
104
  if (globalThis.importFuncs && idx < importFuncs.length) {
105
105
  const importFunc = importFuncs[idx];
@@ -203,15 +203,15 @@ ${funcs.map(x => {
203
203
  if (Number.isNaN(v) || v === Infinity || v === -Infinity) return v.toString();
204
204
  return v;
205
205
  })
206
- .replace(/\["alloc","(.*?)","(.*?)",(.*?)\]/g, (_, reason, type, valtype) => `...number(allocPage(_,'${reason}','${type}')*pageSize,${valtype})`)
206
+ .replace(/\["alloc","(.*?)","(.*?)",(.*?)\]/g, (_, reason, type, valtype) => `...number(allocPage(_,'${reason}','${type}'),${valtype})`)
207
207
  .replace(/\["global",(.*?),"(.*?)",(.*?)\]/g, (_, opcode, name, valtype) => `...glbl(${opcode},'${name}',${valtype})`)
208
208
  .replace(/\"local","(.*?)",(.*?)\]/g, (_, name, valtype) => `loc('${name}',${valtype})]`)
209
209
  .replace(/\[16,"(.*?)"]/g, (_, name) => `[16,builtin('${name}')]`)
210
- .replace(/\[68,"funcref","(.*?)"]/g, (_, name, offset) => `[68,builtin('${name}',1)]`)
210
+ .replace(/\[68,"funcref","(.*?)"]/g, (_, name) => `...funcRef('${name}')`)
211
211
  .replace(/\["throw","(.*?)","(.*?)"\]/g, (_, constructor, message) => `...internalThrow(_,'${constructor}',\`${message}\`)`)
212
212
  .replace(/\["get object","(.*?)"\]/g, (_, objName) => `...generateIdent(_,{name:'${objName}'})`);
213
213
 
214
- return `(_,{${`${str.includes('allocPage(') ? 'allocPage,' : ''}${str.includes('glbl(') ? 'glbl,' : ''}${str.includes('loc(') ? 'loc,' : ''}${str.includes('builtin(') ? 'builtin,' : ''}${str.includes('internalThrow(') ? 'internalThrow,' : ''}${str.includes('generateIdent(') ? 'generateIdent,' : ''}`.slice(0, -1)}})=>`.replace('_,{}', '') + str;
214
+ return `(_,{${`${str.includes('allocPage(') ? 'allocPage,' : ''}${str.includes('glbl(') ? 'glbl,' : ''}${str.includes('loc(') ? 'loc,' : ''}${str.includes('builtin(') ? 'builtin,' : ''}${str.includes('funcRef(') ? 'funcRef,' : ''}${str.includes('internalThrow(') ? 'internalThrow,' : ''}${str.includes('generateIdent(') ? 'generateIdent,' : ''}`.slice(0, -1)}})=>`.replace('_,{}', '') + str;
215
215
  };
216
216
 
217
217
  const locals = Object.entries(x.locals).sort((a,b) => a[1].idx - b[1].idx)
package/compiler/wrap.js CHANGED
@@ -127,7 +127,8 @@ ${flags & 0b0001 ? ` get func idx: ${get}
127
127
  if (value < 0) {
128
128
  func = importedFuncs[value + importedFuncs.length];
129
129
  } else {
130
- func = funcs.find(x => ((x.originalIndex ?? x.index) - importedFuncs.length) === value);
130
+ value += importedFuncs.length;
131
+ func = funcs.find(x => x.index === value);
131
132
  }
132
133
 
133
134
  if (!func) return function () {};
@@ -502,7 +503,7 @@ export default (source, flags = [ 'module' ], customImports = {}, print = str =>
502
503
 
503
504
  if (exceptionMode === 'stackest') {
504
505
  const constructorIdx = e.getArg(exceptTag, 0);
505
- const constructorName = constructorIdx == -1 ? null : funcs.find(x => ((x.originalIndex ?? x.index) - importedFuncs.length) === constructorIdx)?.name;
506
+ const constructorName = constructorIdx == -1 ? null : funcs.find(x => (x.index - importedFuncs.length) === constructorIdx)?.name;
506
507
 
507
508
  const value = e.getArg(exceptTag, 1);
508
509
  const type = e.getArg(exceptTag, 2);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "porffor",
3
3
  "description": "a basic experimental wip aot optimizing js -> wasm engine/compiler/runtime in js",
4
- "version": "0.34.6+581b45353",
4
+ "version": "0.34.8+3c064d5f4",
5
5
  "author": "CanadaHonk",
6
6
  "license": "MIT",
7
7
  "scripts": {},
package/runner/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import fs from 'node:fs';
3
- globalThis.version = '0.34.6+581b45353';
3
+ globalThis.version = '0.34.8+3c064d5f4';
4
4
 
5
5
  // deno compat
6
6
  if (typeof process === 'undefined' && typeof Deno !== 'undefined') {