porffor 0.37.8 → 0.37.10

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.
package/README.md CHANGED
@@ -64,8 +64,7 @@ Expect nothing to work! Only very limited JS is currently supported. See files i
64
64
  - `--valtype=i32|i64|f64` (default: `f64`) to set valtype
65
65
  - `-O0` to disable opt
66
66
  - `-O1` (default) to enable basic opt (simplify insts, treeshake wasm imports)
67
- - `-O2` to enable advanced opt (inlining). unstable!
68
- - `-O3` to enable advanceder opt (precompute const math). unstable!
67
+ - `-O2` to enable advanced opt (partial evaluation). unstable!
69
68
 
70
69
  ## Current limitations
71
70
  - Limited async support
@@ -274,7 +273,7 @@ Currently, Porffor is seriously limited in features and functionality, however i
274
273
  - More in future probably?
275
274
 
276
275
  ## Todo
277
- No particular order and no guarentees, just what could happen soon™
276
+ No particular order and no guarantees, just what could happen soon™
278
277
 
279
278
  - Asur
280
279
  - Support memory
@@ -328,7 +327,7 @@ Porffor intentionally does not use Wasm proposals which are not commonly impleme
328
327
  ### 2. Why at all?
329
328
  Yes!
330
329
 
331
- ## 3. Isn't this the same as AssemblyScript/other Wasm langs?
330
+ ### 3. Isn't this the same as AssemblyScript/other Wasm langs?
332
331
  No. they are not alike at all internally and have very different goals/ideals:
333
332
  - Porffor is made as a generic JS engine, not for Wasm stuff specifically
334
333
  - Porffor primarily consumes JS
@@ -58,7 +58,7 @@ export default (funcs, globals, tags, pages, data, flags, noTreeshake = false) =
58
58
  const getType = (params, returns) => {
59
59
  const hash = `${params.join(',')}_${returns.join(',')}`;
60
60
  if (Prefs.optLog) log('assemble', `getType(${JSON.stringify(params)}, ${JSON.stringify(returns)}) -> ${hash} | cache: ${typeCache[hash]}`);
61
- if (optLevel >= 1 && typeCache[hash] !== undefined) return typeCache[hash];
61
+ if (typeCache[hash] !== undefined) return typeCache[hash];
62
62
 
63
63
  const type = [ FuncType, ...encodeVector(params), ...encodeVector(returns) ];
64
64
  const idx = types.length;
@@ -233,7 +233,6 @@ export default (funcs, globals, tags, pages, data, flags, noTreeshake = false) =
233
233
  time('global section');
234
234
 
235
235
  if (Prefs.alwaysMemory && pages.size === 0) pages.set('--always-memory', 0);
236
- if (optLevel === 0) pages.set('O0 precaution', 0);
237
236
 
238
237
  const usesMemory = pages.size > 0;
239
238
  const memorySection = !usesMemory ? [] : createSection(
package/compiler/index.js CHANGED
@@ -53,6 +53,8 @@ const progressClear = () => {
53
53
  };
54
54
 
55
55
  export default (code, flags) => {
56
+ const optLevel = parseInt(process.argv.find(x => x.startsWith('-O'))?.[2] ?? 1);
57
+
56
58
  let target = Prefs.target ?? 'wasm';
57
59
  if (Prefs.native) target = 'native';
58
60
 
@@ -67,8 +69,13 @@ export default (code, flags) => {
67
69
 
68
70
  // change some prefs by default for c/native
69
71
  if (target !== 'wasm') {
70
- Prefs.pgo = Prefs.pgo === false ? false : true;
71
- Prefs.passiveData = false;
72
+ Prefs.pgo = Prefs.pgo === false ? false : true; // enable pgo
73
+ Prefs.passiveData = false; // disable using passive Wasm data as unsupported by 2c for now
74
+ }
75
+
76
+ // change some prefs by default for -O2
77
+ if (optLevel >= 2) {
78
+ Prefs.cyclone = Prefs.cyclone === false ? false : true; // enable cyclone
72
79
  }
73
80
 
74
81
  if (Prefs.pgo) pgo.setup();
package/compiler/opt.js CHANGED
@@ -9,88 +9,7 @@ export default (funcs, globals, pages, tags, exceptions) => {
9
9
  if (optLevel === 0) return;
10
10
 
11
11
  const tailCall = Prefs.tailCall;
12
- if (tailCall) log.warning('opt', 'tail call proposal is not widely implemented! (you used -tail-call)');
13
-
14
- if (optLevel >= 2 && !Prefs.optNoInline) {
15
- // inline pass (very WIP)
16
- // get candidates for inlining
17
- // todo: pick smart in future (if func is used <N times? or?)
18
- const callsSelf = f => f.wasm.some(x => x[0] === Opcodes.call && x[1] === f.index);
19
- const suitableReturns = wasm => wasm.reduce((acc, x) => acc + (x[0] === Opcodes.return), 0) <= 1;
20
- const candidates = funcs.filter(x => x.name !== 'main' && Object.keys(x.locals).length === x.params.length && (x.returns.length === 0 || suitableReturns(x.wasm)) && !callsSelf(x) && !x.throws).reverse();
21
- if (Prefs.optLog) {
22
- log('opt', `found inline candidates: ${candidates.map(x => x.name).join(', ')} (${candidates.length}/${funcs.length - 1})`);
23
-
24
- let reasons = {};
25
- for (const f of funcs) {
26
- if (f.name === 'main') continue;
27
- reasons[f.name] = [];
28
-
29
- if (f.name === 'main') reasons[f.name].push('main');
30
- if (Object.keys(f.locals).length !== f.params.length) reasons[f.name].push('cannot inline funcs with locals yet');
31
- if (f.returns.length !== 0 && !suitableReturns(f.wasm)) reasons[f.name].push('cannot inline funcs with multiple returns yet');
32
- if (callsSelf(f)) reasons[f.name].push('cannot inline func calling itself');
33
- if (f.throws) reasons[f.name].push('will not inline funcs throwing yet');
34
- }
35
-
36
- if (Object.values(reasons).some(x => x.length > 0)) console.log(` reasons not:\n${Object.keys(reasons).filter(x => reasons[x].length > 0).map(x => ` ${x}: ${reasons[x].join(', ')}`).join('\n')}\n`)
37
- }
38
-
39
- for (const c of candidates) {
40
- const cWasm = c.wasm;
41
-
42
- for (const t of funcs) {
43
- const tWasm = t.wasm;
44
- if (t.name === c.name) continue; // skip self
45
-
46
- for (let i = 0; i < tWasm.length; i++) {
47
- const inst = tWasm[i];
48
- if (inst[0] === Opcodes.call && inst[1] === c.index) {
49
- if (Prefs.optLog) log('opt', `inlining call for ${c.name} (in ${t.name})`);
50
- tWasm.splice(i, 1); // remove this call
51
-
52
- // add params as locals and set in reverse order
53
- const paramIdx = {};
54
- let localIdx = Math.max(-1, ...Object.values(t.locals).map(x => x.idx)) + 1;
55
- for (let j = c.params.length - 1; j >= 0; j--) {
56
- const name = `__porf_inline_${c.name}_param_${j}`;
57
-
58
- if (t.locals[name] === undefined) {
59
- t.locals[name] = { idx: localIdx++, type: c.params[j] };
60
- }
61
-
62
- const idx = t.locals[name].idx;
63
- paramIdx[j] = idx;
64
-
65
- tWasm.splice(i, 0, [ Opcodes.local_set, idx ]);
66
- i++;
67
- }
68
-
69
- let iWasm = cWasm.slice().map(x => x.slice()); // deep clone arr (depth 2)
70
- // remove final return
71
- if (iWasm.length !== 0 && iWasm[iWasm.length - 1][0] === Opcodes.return) iWasm = iWasm.slice(0, -1);
72
-
73
- // adjust local operands to go to correct param index
74
- for (const inst of iWasm) {
75
- if ((inst[0] === Opcodes.local_get || inst[0] === Opcodes.local_set) && inst[1] < c.params.length) {
76
- if (Prefs.optLog) log('opt', `replacing local operand in inlined wasm (${inst[1]} -> ${paramIdx[inst[1]]})`);
77
- inst[1] = paramIdx[inst[1]];
78
- }
79
- }
80
-
81
- tWasm.splice(i, 0, ...iWasm);
82
- i += iWasm.length;
83
- }
84
- }
85
-
86
- if (t.index > c.index) t.index--; // adjust index if after removed func
87
- }
88
-
89
- funcs.splice(funcs.indexOf(c), 1); // remove func from funcs
90
- }
91
- }
92
-
93
- if (Prefs.optInlineOnly) return;
12
+ if (tailCall) log.warning('opt', 'tail call proposal is not widely implemented! (you used --tail-call)');
94
13
 
95
14
  // todo: this breaks exceptions after due to indexes not being adjusted
96
15
  // const tagUse = tags.reduce((acc, x) => { acc[x.idx] = 0; return acc; }, {});
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.37.8+d9c1c7b17",
4
+ "version": "0.37.10+b6f7de187",
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.37.8+d9c1c7b17';
3
+ globalThis.version = '0.37.10+b6f7de187';
4
4
 
5
5
  // deno compat
6
6
  if (typeof process === 'undefined' && typeof Deno !== 'undefined') {