porffor 0.58.19 → 0.59.1

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.
@@ -1505,6 +1505,7 @@ const asmFunc = (name, { wasm, params = [], typedParams = false, locals: localTy
1505
1505
  typeUsed(func, returnType);
1506
1506
  }
1507
1507
 
1508
+ func.jsLength = countLength(func);
1508
1509
  func.wasm = wasm;
1509
1510
  return func;
1510
1511
  };
@@ -1822,6 +1823,12 @@ const getNodeType = (scope, node) => {
1822
1823
  case '__Porffor_bs': return TYPES.bytestring;
1823
1824
  case '__Porffor_s': return TYPES.string;
1824
1825
  }
1826
+
1827
+ return getNodeType(scope, {
1828
+ type: 'CallExpression',
1829
+ callee: node.tag,
1830
+ arguments: []
1831
+ });
1825
1832
  }
1826
1833
 
1827
1834
  if (node.type === 'ThisExpression') {
@@ -5760,7 +5767,24 @@ const countLength = (func, name = undefined) => {
5760
5767
 
5761
5768
  let count = countParams(func, name);
5762
5769
  if (builtinFuncs[name] && name.includes('_prototype_')) count--;
5763
-
5770
+ if (func.hasRestArgument) count--;
5771
+
5772
+ if (func.internal) {
5773
+ // some js built-ins have an old non-standard length
5774
+ const override = ({
5775
+ Array: 1,
5776
+ String: 1,
5777
+ __Object_assign: 2,
5778
+ __String_fromCharCode: 1,
5779
+ __String_fromCodePoint: 1,
5780
+ __Array_prototype_concat: 1,
5781
+ __Array_prototype_push: 1,
5782
+ __Array_prototype_unshift: 1,
5783
+ __String_prototype_concat: 1,
5784
+ __ByteString_prototype_concat: 1
5785
+ })[name];
5786
+ if (override != null) return override;
5787
+ }
5764
5788
  return count;
5765
5789
  };
5766
5790
 
@@ -6581,20 +6605,41 @@ const generateTaggedTemplate = (scope, decl, global = false, name = undefined, v
6581
6605
  return cacheAst(decl, intrinsics[decl.tag.name](str));
6582
6606
  }
6583
6607
 
6584
- return generate(scope, {
6585
- type: 'CallExpression',
6586
- callee: decl.tag,
6587
- arguments: [
6588
- { // strings
6589
- type: 'ArrayExpression',
6590
- elements: quasis.map(x => ({
6591
- type: 'Literal',
6592
- value: x.value.cooked
6593
- }))
6594
- },
6595
- ...expressions
6596
- ]
6597
- });
6608
+ const tmp = localTmp(scope, '#tagged_template_strings');
6609
+ const tmpIdent = {
6610
+ type: 'Identifier',
6611
+ name: '#tagged_template_strings',
6612
+ _type: TYPES.array
6613
+ };
6614
+
6615
+ return [
6616
+ ...generate(scope, {
6617
+ type: 'ArrayExpression',
6618
+ elements: quasis.map(x => ({
6619
+ type: 'Literal',
6620
+ value: x.value.cooked
6621
+ }))
6622
+ }),
6623
+ [ Opcodes.local_set, tmp ],
6624
+
6625
+ ...generate(scope, setObjProp(tmpIdent, 'raw', {
6626
+ type: 'ArrayExpression',
6627
+ elements: quasis.map(x => ({
6628
+ type: 'Literal',
6629
+ value: x.value.raw
6630
+ }))
6631
+ })),
6632
+ [ Opcodes.drop ],
6633
+
6634
+ ...generate(scope, {
6635
+ type: 'CallExpression',
6636
+ callee: decl.tag,
6637
+ arguments: [
6638
+ tmpIdent,
6639
+ ...expressions
6640
+ ]
6641
+ })
6642
+ ];
6598
6643
  };
6599
6644
 
6600
6645
  globalThis._uniqId = 0;
package/compiler/pgo.js CHANGED
@@ -1,20 +1,26 @@
1
1
  import { Opcodes, Valtype } from './wasmSpec.js';
2
2
  import { number } from './encoding.js';
3
- import { createImport, importedFuncs } from './builtins.js';
3
+ import { createImport, importedFuncs, setImports } from './builtins.js';
4
4
  import assemble from './assemble.js';
5
5
  import wrap from './wrap.js';
6
6
  import * as Havoc from './havoc.js';
7
7
  import './prefs.js';
8
+ import fs from 'node:fs';
8
9
 
10
+ let activeFunc, localData;
9
11
  export const setup = () => {
10
12
  // enable these prefs by default for pgo
11
13
  for (const x of [
12
14
  'typeswitchUniqueTmp', // use unique tmps for typeswitches
13
- 'lengthNoTmp', // use duplicated inline code instead of tmp for .length
14
- 'cyclone', // enable cyclone pre-evaler
15
+ // 'cyclone', // enable cyclone pre-evaler
15
16
  ]) {
16
17
  Prefs[x] = Prefs[x] === false ? false : true;
17
18
  }
19
+
20
+ createImport('profileLocalSet', [ Valtype.i32, Valtype.i32, Valtype.f64 ], 0, (activeFunc, i, n) => {
21
+ if (activeFunc == null) throw 'fail';
22
+ localData[activeFunc][i].push(n);
23
+ });
18
24
  };
19
25
 
20
26
  export const run = obj => {
@@ -34,15 +40,7 @@ export const run = obj => {
34
40
 
35
41
  time(0, `injecting PGO logging...`);
36
42
 
37
- let activeFunc = null, abort = false;
38
- createImport('profile1', [ Valtype.i32 ], 0, n => {
39
- activeFunc = n;
40
- });
41
- createImport('profile2', [ Valtype.i32, Valtype.f64 ], 0, (i, n) => {
42
- if (activeFunc == null) throw 'fail';
43
- localData[activeFunc][i].push(n);
44
- });
45
-
43
+ let abort = false;
46
44
  let funcs = [];
47
45
  for (let i = 0; i < wasmFuncs.length; i++) {
48
46
  const { name, internal, params, locals, wasm } = wasmFuncs[i];
@@ -55,16 +53,13 @@ export const run = obj => {
55
53
  funcs.push({ name, id, locals, params, invLocals });
56
54
 
57
55
  wasm.unshift(
58
- // mark active func
59
- number(i, Valtype.i32),
60
- [ Opcodes.call, importedFuncs.profile1 ],
61
-
62
56
  // log args
63
57
  ...params.flatMap((_, i) => [
58
+ number(id, Valtype.i32),
64
59
  number(i, Valtype.i32),
65
60
  [ Opcodes.local_get, i ],
66
61
  ...(invLocals[i].type !== Valtype.f64 ? [ Opcodes.i32_from ] : []),
67
- [ Opcodes.call, importedFuncs.profile2 ]
62
+ [ Opcodes.call, importedFuncs.profileLocalSet ]
68
63
  ])
69
64
  );
70
65
 
@@ -72,49 +67,32 @@ export const run = obj => {
72
67
  const inst = wasm[j];
73
68
  if (inst[0] === Opcodes.local_set || inst[0] === Opcodes.local_tee) {
74
69
  wasm.splice(j + 1, 0,
70
+ number(id, Valtype.i32),
75
71
  number(inst[1], Valtype.i32),
76
72
  [ Opcodes.local_get, inst[1] ],
77
73
  ...(invLocals[inst[1]].type !== Valtype.f64 ? [ Opcodes.i32_from ] : []),
78
- [ Opcodes.call, importedFuncs.profile2 ]
74
+ [ Opcodes.call, importedFuncs.profileLocalSet ]
79
75
  );
80
76
  }
81
77
  }
82
78
  }
83
79
 
84
- let localData = funcs.map(x => new Array(Object.keys(x.locals).length).fill(0).map(() => []));
80
+ localData = funcs.map(x => new Array(Object.keys(x.locals).length).fill(0).map(() => []));
85
81
 
86
82
  time(0, `injected PGO logging`);
87
83
  time(1, `running with PGO logging...`);
88
84
 
89
-
90
85
  try {
91
86
  obj.wasm = assemble(obj.funcs, obj.globals, obj.tags, obj.pages, obj.data, true);
92
87
 
93
88
  Prefs._profileCompiler = Prefs.profileCompiler;
94
89
  Prefs.profileCompiler = false;
95
90
 
96
- const { exports } = wrap(obj, undefined, {
97
- readArgv: (ind, outPtr) => {
98
- // const pgoInd = process.argv.indexOf('--pgo');
99
- // let args = process.argv.slice(pgoInd);
100
- // args = args.slice(args.findIndex(x => !x.startsWith('-')) + 1);
101
-
102
- // const str = args[ind - 1];
103
- // if (pgoInd === -1 || !str) {
104
- // if (Prefs.pgoLog) console.log('\nPGO warning: script was expecting arguments, please specify args to use for PGO after --pgo arg');
105
- // return -1;
106
- // }
107
-
108
- // writeByteStr(exports.$, outPtr, str);
109
- // return str.length;
110
- return -1;
111
- },
112
- readFile: (pathPtr, outPtr) => {
113
- return -1;
114
- }
115
- }, () => {});
116
-
91
+ const priorImports = { ...importedFuncs };
92
+ const { exports } = wrap(obj, undefined, () => {});
117
93
  exports.main();
94
+
95
+ setImports(priorImports);
118
96
  } catch (e) {
119
97
  throw e;
120
98
  }
@@ -242,8 +220,8 @@ export const run = obj => {
242
220
  consts.push(number(c, valtype));
243
221
  }
244
222
 
245
- log += ` ${x.name}: replaced ${targets.length} locals with consts\n`;
246
- if (targets.length > 0) Havoc.localsToConsts(wasmFunc, targets, consts, { localKeys: x.localKeys });
223
+ // log += ` ${x.name}: replaced ${targets.length} locals with consts\n`;
224
+ // if (targets.length > 0) Havoc.localsToConsts(wasmFunc, targets, consts, { localKeys: x.localKeys });
247
225
  }
248
226
 
249
227
  time(3, 'optimized using PGO data\n' + log);
package/compiler/wrap.js CHANGED
@@ -481,10 +481,9 @@ export { createImport };
481
481
  *
482
482
  * @param {string} source - JavaScript source code to compile
483
483
  * @param {boolean} module - If the source is a module or not (default: false)
484
- * @param {object} customImports - Custom imports
485
484
  * @param {(str: string) => void} print - Function to use for printing (used by console.log etc)
486
485
  */
487
- export default (source, module = undefined, customImports = {}, print = str => process.stdout.write(str)) => {
486
+ export default (source, module = undefined, print = str => process.stdout.write(str)) => {
488
487
  createImport('print', 1, 0, i => print(i.toString()));
489
488
  createImport('printChar', 1, 0, i => print(String.fromCharCode(i)));
490
489
  createImport('time', 0, 1, () => performance.now());
@@ -512,12 +511,6 @@ export default (source, module = undefined, customImports = {}, print = str => p
512
511
  }
513
512
  });
514
513
 
515
- for (const x in customImports) {
516
- const custom = customImports[x];
517
- // todo: make a simpler api for just js functions at some point using function.length etc
518
- createImport(x, custom.params, custom.returns, custom.js, custom.c);
519
- }
520
-
521
514
  const times = [];
522
515
 
523
516
  const t1 = performance.now();
@@ -575,6 +568,8 @@ export default (source, module = undefined, customImports = {}, print = str => p
575
568
  instance = new WebAssembly.Instance(module, {
576
569
  '': Object.keys(importedFuncs).reduce((acc, y) => {
577
570
  const x = importedFuncs[y];
571
+ if (!x.import) return acc;
572
+
578
573
  acc[x.import] = x.js ?? (() => {});
579
574
  return acc;
580
575
  }, {})
package/fuzz/index.js CHANGED
@@ -246,7 +246,7 @@ if (cluster.isPrimary) {
246
246
  let stage = 0;
247
247
 
248
248
  try {
249
- const out = compile(code, false, {});
249
+ const out = compile(code, false);
250
250
 
251
251
  try {
252
252
  out.exports.main();
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "porffor",
3
3
  "description": "An ahead-of-time JavaScript compiler",
4
- "version": "0.58.19",
4
+ "version": "0.59.1",
5
5
  "author": "Oliver Medhurst <honk@goose.icu>",
6
6
  "license": "MIT",
7
7
  "scripts": {},
package/runtime/debug.js CHANGED
@@ -109,7 +109,7 @@ createImport('profile2', 1, 0, n => {
109
109
  });
110
110
 
111
111
  try {
112
- const { exports } = compile(source, undefined, {}, s => output += s);
112
+ const { exports } = compile(source, undefined, s => output += s);
113
113
  exports.main();
114
114
  } catch (e) {
115
115
  console.error(e);
package/runtime/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import fs from 'node:fs';
3
- globalThis.version = '0.58.19';
3
+ globalThis.version = '0.59.1';
4
4
 
5
5
  // deno compat
6
6
  if (typeof process === 'undefined' && typeof Deno !== 'undefined') {
@@ -94,7 +94,7 @@ globalThis.compileCallback = ({ funcs }) => {
94
94
  };
95
95
 
96
96
  console.log('Compiling...');
97
- const { exports } = compile(source, undefined, {}, () => {});
97
+ const { exports } = compile(source, undefined, () => {});
98
98
 
99
99
  // --- Execution with Progress Spinner ---
100
100
 
package/runtime/repl.js CHANGED
@@ -95,7 +95,7 @@ const run = (source, _context, _filename, callback, run = true) => {
95
95
 
96
96
  let shouldPrint = !prev;
97
97
  try {
98
- const { exports, pages } = compile(toRun, undefined, {}, str => {
98
+ const { exports, pages } = compile(toRun, undefined, str => {
99
99
  if (shouldPrint) process.stdout.write(str);
100
100
  if (str === '-4919') shouldPrint = true;
101
101
  });
package/wow.js DELETED
@@ -1 +0,0 @@
1
- (false ? 42 : 42) + (false ? null : 'G9vBsCA4GzkqlZN')