porffor 0.18.2 → 0.18.3

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
@@ -175,16 +175,15 @@ These include some early (stage 1/0) and/or dead (last commit years ago) proposa
175
175
  ### Custom
176
176
 
177
177
  - Supports i32, i64, and f64 for valtypes
178
- - Start of a SIMD api (docs needed)
179
178
  - Intrinsic functions (see below)
180
179
  - Inlining wasm via ``asm`...``\` "macro"
181
180
 
182
181
  ## Versioning
183
- Porffor uses a unique versioning system, here's an example: `0.14.0-15cb49f07`. Let's break it down:
182
+ Porffor uses a unique versioning system, here's an example: `0.18.2+2aa3f0589`. Let's break it down:
184
183
  1. `0` - major, always `0` as Porffor is not ready yet
185
- 2. `14` - minor, total Test262 pass percentage (floored to nearest int)
186
- 3. `0` - micro, always `0` as unused
187
- 4. `15cb49f07` - commit hash
184
+ 2. `18` - minor, total Test262 pass percentage (floored to nearest int)
185
+ 3. `2` - micro, build number for that minor (incremented each publish/git push)
186
+ 4. `2aa3f0589` - commit hash
188
187
 
189
188
  ## Performance
190
189
  *For the features it supports most of the time*, Porffor is *blazingly fast* compared to most interpreters and common engines running without JIT. For those with JIT, it is usually slower by default, but can catch up with compiler arguments and typed input, even more so when compiling to native binaries.
package/bf ADDED
Binary file
package/compiler/2c.js CHANGED
@@ -171,9 +171,6 @@ const removeBrackets = str => {
171
171
  };
172
172
 
173
173
  export default ({ funcs, globals, tags, data, exceptions, pages }) => {
174
- // fix declaring order for c
175
- funcs.reverse();
176
-
177
174
  const invOperatorOpcode = Object.values(operatorOpcode).reduce((acc, x) => {
178
175
  for (const k in x) {
179
176
  acc[x[k]] = k;
@@ -201,7 +198,7 @@ export default ({ funcs, globals, tags, data, exceptions, pages }) => {
201
198
 
202
199
  includes.set('stdint.h', true);
203
200
 
204
- let out = ``;
201
+ globalThis.out = ``;
205
202
 
206
203
  for (const x in globals) {
207
204
  const g = globals[x];
@@ -231,15 +228,12 @@ export default ({ funcs, globals, tags, data, exceptions, pages }) => {
231
228
 
232
229
  if (out) out += '\n';
233
230
 
234
- let depth = 1;
235
- let brDepth = 0;
236
- const line = (str, semi = true) => out += `${' '.repeat((depth + brDepth) * 2)}${str}${semi ? ';' : ''}\n`;
231
+ const line = (str, semi = true) => out += `${str}${semi ? ';' : ''}\n`;
237
232
  const lines = lines => {
238
233
  for (const x of lines) {
239
- out += `${' '.repeat((depth + brDepth) * 2)}${x}\n`;
234
+ out += x + '\n';
240
235
  }
241
236
  };
242
-
243
237
  const platformSpecific = (win, unix, add = true) => {
244
238
  let tmp = '';
245
239
 
@@ -268,11 +262,46 @@ export default ({ funcs, globals, tags, data, exceptions, pages }) => {
268
262
 
269
263
  let brId = 0;
270
264
 
271
- for (const f of funcs) {
272
- depth = 1;
273
- brDepth = 0;
265
+ const cified = new Set();
266
+ const cify = f => {
267
+ let out = '';
268
+
269
+ let depth = 1;
270
+ let brDepth = 0;
271
+ const line = (str, semi = true) => out += `${' '.repeat((depth + brDepth) * 2)}${str}${semi ? ';' : ''}\n`;
272
+ const lines = lines => {
273
+ for (const x of lines) {
274
+ out += `${' '.repeat((depth + brDepth) * 2)}${x}\n`;
275
+ }
276
+ };
277
+ const platformSpecific = (win, unix, add = true) => {
278
+ let tmp = '';
279
+
280
+ if (win) {
281
+ if (add) out += '#ifdef _WIN32\n';
282
+ else tmp += '#ifdef _WIN32\n';
283
+
284
+ if (add) lines(win.split('\n'));
285
+ else tmp += win + (win.endsWith('\n') ? '' : '\n');
286
+ }
287
+
288
+ if (unix) {
289
+ if (add) out += (win ? '#else' : '#ifndef _WIN32') + '\n';
290
+ else tmp += (win ? '#else' : '#ifndef _WIN32') + '\n';
291
+
292
+ if (add) lines(unix.split('\n'));
293
+ else tmp += unix + (unix.endsWith('\n') ? '' : '\n');
294
+ }
295
+
296
+ if (win || unix)
297
+ if (add) out += '#endif\n';
298
+ else tmp += '#endif\n';
299
+
300
+ return tmp;
301
+ };
274
302
 
275
303
  let retTmpId = 0;
304
+ let tmpId = 0;
276
305
 
277
306
  const invLocals = inv(f.locals, x => x.idx);
278
307
 
@@ -598,6 +627,11 @@ _time_out = _time.tv_nsec / 1000000. + _time.tv_sec * 1000.;`);
598
627
  break;
599
628
  }
600
629
 
630
+ if (!cified.has(func.name) && func.name !== f.name) {
631
+ cify(func);
632
+ cified.add(func.name);
633
+ }
634
+
601
635
  let args = [];
602
636
  for (let j = 0; j < func.params.length; j++) args.unshift(removeBrackets(vals.pop()));
603
637
 
@@ -663,6 +697,53 @@ _time_out = _time.tv_nsec / 1000000. + _time.tv_sec * 1000.;`);
663
697
  break;
664
698
  }
665
699
 
700
+ case Opcodes.f64_abs: {
701
+ break;
702
+ }
703
+ case Opcodes.f64_neg: {
704
+ break;
705
+ }
706
+
707
+ case Opcodes.f64_ceil: {
708
+ break;
709
+ }
710
+ case Opcodes.f64_floor: {
711
+ break;
712
+ }
713
+ case Opcodes.f64_trunc: {
714
+ break;
715
+ }
716
+ case Opcodes.f64_nearest: {
717
+ break;
718
+ }
719
+
720
+ case Opcodes.f64_sqrt: {
721
+ break;
722
+ }
723
+ case Opcodes.f64_min: {
724
+ const b = vals.pop();
725
+ const a = vals.pop();
726
+
727
+ const id = tmpId++;
728
+ line(`const f64 _tmp${id}a = ${a}`);
729
+ line(`const f64 _tmp${id}b = ${b}`);
730
+ vals.push(`(_tmp${id}a > _tmp${id}b ? _tmp${id}b : _tmp${id}a)`);
731
+ break;
732
+ }
733
+ case Opcodes.f64_max: {
734
+ const b = vals.pop();
735
+ const a = vals.pop();
736
+
737
+ const id = tmpId++;
738
+ line(`const f64 _tmp${id}a = ${a}`);
739
+ line(`const f64 _tmp${id}b = ${b}`);
740
+ vals.push(`(_tmp${id}a > _tmp${id}b ? _tmp${id}a : _tmp${id}b)`);
741
+ break;
742
+ }
743
+ case Opcodes.f64_copysign: {
744
+ break;
745
+ }
746
+
666
747
  default:
667
748
  if (CMemFuncs[i[0]]) {
668
749
  const name = invOpcodes[i[0]];
@@ -698,9 +779,11 @@ _time_out = _time.tv_nsec / 1000000. + _time.tv_sec * 1000.;`);
698
779
  }
699
780
 
700
781
  out += '}\n\n';
701
- }
702
782
 
703
- depth = 0;
783
+ globalThis.out = globalThis.out + out;
784
+ };
785
+
786
+ cify(funcs.find(x => x.name === 'main'));
704
787
 
705
788
  const makeIncludes = includes => [...includes.keys()].map(x => `#include <${x}>\n`).join('');
706
789
  out = platformSpecific(makeIncludes(winIncludes), makeIncludes(unixIncludes), false) + '\n' + makeIncludes(includes) + '\n' + alwaysPreface + [...prepend.values()].join('\n') + '\n\n' + out;
@@ -2092,7 +2092,7 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
2092
2092
  if (func && func.hasRestArgument) {
2093
2093
  if (args.length < paramCount) {
2094
2094
  args = args.concat(new Array(paramCount - 1 - args.length).fill(DEFAULT_VALUE));
2095
- }
2095
+ }
2096
2096
  const restArgs = args.slice(paramCount - 1);
2097
2097
  args = args.slice(0, paramCount - 1);
2098
2098
  args.push({
@@ -4402,7 +4402,7 @@ const generateFunc = (scope, decl) => {
4402
4402
  defaultValues[name] = x.right;
4403
4403
  break;
4404
4404
  }
4405
-
4405
+
4406
4406
  case 'RestElement': {
4407
4407
  name = x.argument.name;
4408
4408
  func.hasRestArgument = true;
@@ -66,6 +66,42 @@ export default wasm => {
66
66
  };
67
67
 
68
68
  switch (opcode) {
69
+ case Opcodes.if: {
70
+ if (stack.length < 1) { empty(); break; }
71
+ const cond = bool(pop());
72
+
73
+ // find else split and end
74
+ let j = i + 1;
75
+ let depth = 0, elseStart = 0;
76
+ for (; j < wasm.length; j++) {
77
+ const op = wasm[j][0];
78
+ if (op === Opcodes.if || op === Opcodes.block || op === Opcodes.loop || op === Opcodes.try) depth++;
79
+ if (op === Opcodes.else && depth === 0) elseStart = j;
80
+ if (op === Opcodes.end) {
81
+ depth--;
82
+ if (depth < 0) break;
83
+ }
84
+ if (op === Opcodes.br || op === Opcodes.br_if) wasm[j][1] -= 1;
85
+ }
86
+
87
+ if (cond) {
88
+ // remove else if it exists, or just remove end
89
+ if (elseStart) wasm.splice(elseStart, j - elseStart + 1);
90
+ else wasm.splice(j, 1);
91
+ } else {
92
+ // remove truthy conseq and keep else if it exists, or just remove entire thing
93
+ if (elseStart) {
94
+ wasm.splice(j, 1); // remove end
95
+ wasm.splice(i + 1, elseStart - i + 1); // remove truthy conseq
96
+ } else wasm.splice(i + 1, j - i + 0); // no else, remove entire if
97
+ }
98
+
99
+ // remove this if op
100
+ wasm.splice(i, 1);
101
+
102
+ break;
103
+ }
104
+
69
105
  case Opcodes.i32_const: {
70
106
  const n = read_signedLEB128(op.slice(1));
71
107
  push(n);
@@ -70,7 +70,7 @@ export default (wasm, name = '', ind = 0, locals = {}, params = [], returns = []
70
70
  } else if (inst[0] === Opcodes.i32_load || inst[0] === Opcodes.i64_load || inst[0] === Opcodes.f64_load || inst[0] === Opcodes.i32_store || inst[0] === Opcodes.i64_store || inst[0] === Opcodes.f64_store || inst[0] === Opcodes.i32_store16 || inst[0] === Opcodes.i32_load16_u) {
71
71
  out += ` ${inst[1]} ${read_unsignedLEB128(inst.slice(2))}`;
72
72
  } else for (const operand of inst.slice(1)) {
73
- if (inst[0] === Opcodes.if || inst[0] === Opcodes.loop || inst[0] === Opcodes.block) {
73
+ if (inst[0] === Opcodes.if || inst[0] === Opcodes.loop || inst[0] === Opcodes.block || inst[0] === Opcodes.try) {
74
74
  if (operand === Blocktype.void) continue;
75
75
  out += ` ${invValtype[operand]}`;
76
76
  } else {
@@ -80,7 +80,7 @@ export default (wasm, name = '', ind = 0, locals = {}, params = [], returns = []
80
80
 
81
81
  if (comments.length > 0) out += ` ;; ${comments.join(' ')}`;
82
82
 
83
- if (inst[0] === Opcodes.if || inst[0] === Opcodes.loop || inst[0] === Opcodes.block || inst[0] === Opcodes.else) {
83
+ if (inst[0] === Opcodes.if || inst[0] === Opcodes.loop || inst[0] === Opcodes.block || inst[0] === Opcodes.else || inst[0] === Opcodes.try || inst[0] === Opcodes.catch_all) {
84
84
  out += ` ;; label @${depth}`;
85
85
  }
86
86
 
package/compiler/index.js CHANGED
@@ -89,6 +89,7 @@ export default (code, flags) => {
89
89
 
90
90
  console.log(`${x.name}: ${preOps} -> ${x.wasm.length} ops`);
91
91
  }
92
+ opt(funcs, globals, pages, tags, exceptions);
92
93
 
93
94
  console.log(`cyclone total time: ${(performance.now() - t).toFixed(2)}ms`);
94
95
 
package/compiler/opt.js CHANGED
@@ -114,8 +114,6 @@ export default (funcs, globals, pages, tags, exceptions) => {
114
114
  while (runs > 0) {
115
115
  runs--;
116
116
 
117
- let depth = [];
118
-
119
117
  let getCount = {}, setCount = {};
120
118
  for (const x in f.locals) {
121
119
  getCount[f.locals[x].idx] = 0;
@@ -128,9 +126,6 @@ export default (funcs, globals, pages, tags, exceptions) => {
128
126
  inst = [ ...inst ];
129
127
  wasm[i] = inst;
130
128
 
131
- if (inst[0] === Opcodes.if || inst[0] === Opcodes.loop || inst[0] === Opcodes.block) depth.push(inst[0]);
132
- if (inst[0] === Opcodes.end) depth.pop();
133
-
134
129
  if (inst[0] === Opcodes.local_get) getCount[inst[1]]++;
135
130
  if (inst[0] === Opcodes.local_set || inst[0] === Opcodes.local_tee) setCount[inst[1]]++;
136
131
 
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.18.2+2aa3f0589",
4
+ "version": "0.18.3+945765df9",
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.18.2+2aa3f0589';
3
+ globalThis.version = '0.18.3+945765df9';
4
4
 
5
5
  // deno compat
6
6
  if (typeof process === 'undefined' && typeof Deno !== 'undefined') {