porffor 0.14.0-7bef6473d → 0.14.0-7f4307d22

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/compiler/wrap.js CHANGED
@@ -1,22 +1,27 @@
1
+ import { encodeVector, encodeLocal } from './encoding.js';
2
+ import { importedFuncs } from './builtins.js';
1
3
  import compile from './index.js';
2
4
  import decompile from './decompile.js';
3
- import { encodeVector, encodeLocal } from './encoding.js';
4
5
  import { TYPES } from './types.js';
5
6
  import { log } from './log.js';
6
7
  import Prefs from './prefs.js';
7
8
 
8
9
  const bold = x => `\u001b[1m${x}\u001b[0m`;
9
10
 
10
- const porfToJSValue = (memory, funcs, value, type) => {
11
+ const porfToJSValue = ({ memory, funcs, pages }, value, type) => {
11
12
  switch (type) {
12
13
  case TYPES.boolean: return Boolean(value);
13
14
  case TYPES.undefined: return undefined;
14
15
  case TYPES.object: return value === 0 ? null : {};
15
16
 
16
17
  case TYPES.function: {
17
- // wasm func index, including all imports
18
- const func = funcs.find(x => (x.originalIndex ?? x.index) === value);
19
- // if (!func) return value;
18
+ let func;
19
+ if (value < 0) {
20
+ func = importedFuncs[value + importedFuncs.length];
21
+ } else {
22
+ func = funcs.find(x => ((x.originalIndex ?? x.index) - importedFuncs.length) === value);
23
+ }
24
+
20
25
  if (!func) return function () {};
21
26
 
22
27
  // make fake empty func for repl/etc
@@ -36,9 +41,22 @@ const porfToJSValue = (memory, funcs, value, type) => {
36
41
  case TYPES.array: {
37
42
  const length = (new Int32Array(memory.buffer, value, 1))[0];
38
43
 
39
- // have to slice because of memory alignment (?)
40
- const buf = memory.buffer.slice(value + 4, value + 4 + 8 * length);
41
- return Array.from(new Float64Array(buf, 0, length));
44
+ const out = [];
45
+ for (let i = 0; i < length; i++) {
46
+ const offset = value + 4 + (i * 9);
47
+
48
+ // have to slice because of memory alignment (?)
49
+ const v = (new Float64Array(memory.buffer.slice(offset, offset + 8), 0, 1))[0];
50
+ const t = (new Uint8Array(memory.buffer, offset + 8, 1))[0];
51
+
52
+ // console.log(`reading value at index ${i}...`)
53
+ // console.log(' memory:', Array.from(new Uint8Array(memory.buffer, offset, 9)).map(x => x.toString(16).padStart(2, '0')).join(' '));
54
+ // console.log(' read:', { value: v, type: t }, '\n');
55
+
56
+ out.push(porfToJSValue({ memory, funcs, pages }, v, t));
57
+ }
58
+
59
+ return out;
42
60
  }
43
61
 
44
62
  case TYPES.date: {
@@ -61,12 +79,24 @@ const porfToJSValue = (memory, funcs, value, type) => {
61
79
  // console.log(' memory:', Array.from(new Uint8Array(memory.buffer, offset, 9)).map(x => x.toString(16).padStart(2, '0')).join(' '));
62
80
  // console.log(' read:', { value: v, type: t }, '\n');
63
81
 
64
- out.add(porfToJSValue(memory, funcs, v, t));
82
+ out.add(porfToJSValue({ memory, funcs, pages }, v, t));
65
83
  }
66
84
 
67
85
  return out;
68
86
  }
69
87
 
88
+ case TYPES.symbol: {
89
+ const descStore = pages.get('bytestring: __Porffor_symbol_descStore/ptr').ind * pageSize;
90
+ const offset = descStore + 4 + ((value - 1) * 9);
91
+
92
+ const v = (new Float64Array(memory.buffer.slice(offset, offset + 8), 0, 1))[0];
93
+ const t = (new Uint8Array(memory.buffer, offset + 8, 1))[0];
94
+
95
+ const desc = porfToJSValue({ memory, funcs, pages }, v, t);
96
+
97
+ return Symbol(desc);
98
+ }
99
+
70
100
  default: return value;
71
101
  }
72
102
  };
@@ -86,40 +116,12 @@ export default async (source, flags = [ 'module' ], customImports = {}, print =
86
116
  times.push(performance.now() - t1);
87
117
  if (Prefs.profileCompiler) console.log(bold(`compiled in ${times[0].toFixed(2)}ms`));
88
118
 
89
- const t2 = performance.now();
90
-
91
- let instance;
92
- try {
93
- let wasmEngine = WebAssembly;
94
- if (Prefs.asur) {
95
- log.warning('wrap', 'using our !experimental! asur wasm engine instead of host to run');
96
- wasmEngine = await import('../asur/index.js');
97
- }
98
-
99
- 0, { instance } = await wasmEngine.instantiate(wasm, {
100
- '': {
101
- p: valtype === 'i64' ? i => print(Number(i).toString()) : i => print(i.toString()),
102
- c: valtype === 'i64' ? i => print(String.fromCharCode(Number(i))) : i => print(String.fromCharCode(i)),
103
- t: () => performance.now(),
104
- u: () => performance.timeOrigin,
105
- y: () => {},
106
- z: () => {},
107
- ...customImports
108
- }
109
- });
110
- } catch (e) {
111
- // only backtrace for runner, not test262/etc
112
- if (!process.argv[1].includes('/runner')) throw e;
113
-
114
- const funcInd = parseInt(e.message.match(/function #([0-9]+) /)?.[1]);
115
- const blobOffset = parseInt(e.message.split('@')?.[1]);
116
-
117
- if (!funcInd) throw e;
119
+ const backtrace = (funcInd, blobOffset) => {
120
+ if (funcInd == null || blobOffset == null) return false;
118
121
 
119
122
  // convert blob offset -> function wasm offset.
120
123
  // this is not good code and is somewhat duplicated
121
124
  // I just want it to work for debugging, I don't care about perf/yes
122
-
123
125
  const func = funcs.find(x => x.index === funcInd);
124
126
  const locals = Object.values(func.locals).sort((a, b) => a.idx - b.idx).slice(func.params.length).sort((a, b) => a.idx - b.idx);
125
127
 
@@ -137,7 +139,7 @@ export default async (source, flags = [ 'module' ], customImports = {}, print =
137
139
 
138
140
  if (typeCount !== 0) localDecl.push(encodeLocal(typeCount, lastType));
139
141
 
140
- const toFind = encodeVector(localDecl).concat(func.wasm.flat().filter(x => x != null && x <= 0xff).slice(0, 40));
142
+ const toFind = encodeVector(localDecl).concat(func.wasm.flat().filter(x => x != null && x <= 0xff).slice(0, 60));
141
143
 
142
144
  let i = 0;
143
145
  for (; i < wasm.length; i++) {
@@ -152,7 +154,7 @@ export default async (source, flags = [ 'module' ], customImports = {}, print =
152
154
  if (!mismatch) break;
153
155
  }
154
156
 
155
- if (i === wasm.length) throw e;
157
+ if (i === wasm.length) return false;
156
158
 
157
159
  const offset = (blobOffset - i) + encodeVector(localDecl).length;
158
160
 
@@ -163,7 +165,7 @@ export default async (source, flags = [ 'module' ], customImports = {}, print =
163
165
  if (cumLen === offset) break;
164
166
  }
165
167
 
166
- if (cumLen !== offset) throw e;
168
+ if (cumLen !== offset) return false;
167
169
 
168
170
  i -= 1;
169
171
 
@@ -188,6 +190,38 @@ export default async (source, flags = [ 'module' ], customImports = {}, print =
188
190
  console.log(decomp.join('\n'));
189
191
  console.log('\x1B[90m...\x1B[0m\n');
190
192
 
193
+ return true;
194
+ };
195
+
196
+ const t2 = performance.now();
197
+
198
+ let instance;
199
+ try {
200
+ let wasmEngine = WebAssembly;
201
+ if (Prefs.asur) {
202
+ log.warning('wrap', 'using our !experimental! asur wasm engine instead of host to run');
203
+ wasmEngine = await import('../asur/index.js');
204
+ }
205
+
206
+ 0, { instance } = await wasmEngine.instantiate(wasm, {
207
+ '': {
208
+ p: valtype === 'i64' ? i => print(Number(i).toString()) : i => print(i.toString()),
209
+ c: valtype === 'i64' ? i => print(String.fromCharCode(Number(i))) : i => print(String.fromCharCode(i)),
210
+ t: () => performance.now(),
211
+ u: () => performance.timeOrigin,
212
+ y: () => {},
213
+ z: () => {},
214
+ ...customImports
215
+ }
216
+ });
217
+ } catch (e) {
218
+ // only backtrace for runner, not test262/etc
219
+ if (!process.argv[1].includes('/runner')) throw e;
220
+
221
+ const funcInd = parseInt(e.message.match(/function #([0-9]+) /)?.[1]);
222
+ const blobOffset = parseInt(e.message.split('@')?.[1]);
223
+
224
+ backtrace(funcInd, blobOffset);
191
225
  throw e;
192
226
  }
193
227
 
@@ -195,6 +229,7 @@ export default async (source, flags = [ 'module' ], customImports = {}, print =
195
229
  if (Prefs.profileCompiler) console.log(`instantiated in ${times[1].toFixed(2)}ms`);
196
230
 
197
231
  const exports = {};
232
+ const rawValues = process.argv.includes('-i');
198
233
 
199
234
  const exceptTag = instance.exports['0'], memory = instance.exports['$'];
200
235
  for (const x in instance.exports) {
@@ -213,10 +248,11 @@ export default async (source, flags = [ 'module' ], customImports = {}, print =
213
248
  exports[func.name] = function() {
214
249
  try {
215
250
  const ret = exp.apply(this, arguments);
216
-
217
251
  if (ret == null) return undefined;
218
252
 
219
- return porfToJSValue(memory, funcs, ret[0], ret[1])
253
+ if (rawValues) return { value: ret[0], type: ret[1], js: porfToJSValue({ memory, funcs, pages }, ret[0], ret[1]) };
254
+
255
+ return porfToJSValue({ memory, funcs, pages }, ret[0], ret[1]);
220
256
  } catch (e) {
221
257
  if (e.is && e.is(exceptTag)) {
222
258
  const exceptId = e.getArg(exceptTag, 0);
@@ -231,6 +267,17 @@ export default async (source, flags = [ 'module' ], customImports = {}, print =
231
267
  throw new constructor(exception.message);
232
268
  }
233
269
 
270
+ if (e instanceof WebAssembly.RuntimeError) {
271
+ // only backtrace for runner, not test262/etc
272
+ if (!process.argv[1].includes('/runner')) throw e;
273
+
274
+ const match = e.stack.match(/wasm-function\[([0-9]+)\]:([0-9a-z]+)/) ?? [];
275
+ const funcInd = parseInt(match[1]);
276
+ const blobOffset = parseInt(match[2]);
277
+
278
+ backtrace(funcInd, blobOffset);
279
+ }
280
+
234
281
  throw e;
235
282
  }
236
283
  };
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.14.0-7bef6473d",
4
+ "version": "0.14.0-7f4307d22",
5
5
  "author": "CanadaHonk",
6
6
  "license": "MIT",
7
7
  "scripts": {
package/runner/index.js CHANGED
@@ -25,7 +25,7 @@ if (process.argv.includes('--help')) {
25
25
  console.log(`Usage: \x1B[1mporf [command] path/to/script.js [...prefs] [...args]\x1B[0m`);
26
26
 
27
27
  // commands
28
- console.log(`\n\u001b[4mCommands\x1B[0m`);
28
+ console.log(`\n\x1B[1mCommands:\x1B[0m`);
29
29
  for (const [ cmd, [ color, desc ] ] of Object.entries({
30
30
  run: [ 34, 'Run a JS file' ],
31
31
  wasm: [ 34, 'Compile a JS file to a Wasm binary\n' ],
@@ -60,8 +60,10 @@ if (process.argv.includes('--help')) {
60
60
 
61
61
  let file = process.argv.slice(2).find(x => x[0] !== '-');
62
62
  if (['run', 'wasm', 'native', 'c', 'profile', 'debug', 'debug-wasm'].includes(file)) {
63
+ // remove this arg
64
+ process.argv.splice(process.argv.indexOf(file), 1);
65
+
63
66
  if (file === 'profile') {
64
- process.argv.splice(process.argv.indexOf(file), 1);
65
67
  await import('./profiler.js');
66
68
  await new Promise(() => {}); // do nothing for the rest of this file
67
69
  }
@@ -75,12 +77,11 @@ if (['run', 'wasm', 'native', 'c', 'profile', 'debug', 'debug-wasm'].includes(fi
75
77
  }
76
78
 
77
79
  if (file === 'debug') {
78
- process.argv.splice(process.argv.indexOf(file), 1);
79
80
  await import('./debug.js');
80
81
  await new Promise(() => {}); // do nothing for the rest of this file
81
82
  }
82
83
 
83
- file = process.argv.slice(process.argv.indexOf(file) + 1).find(x => x[0] !== '-');
84
+ file = process.argv.slice(2).find(x => x[0] !== '-');
84
85
 
85
86
  const nonOptOutFile = process.argv.slice(process.argv.indexOf(file) + 1).find(x => x[0] !== '-');
86
87
  if (nonOptOutFile) {
package/runner/repl.js CHANGED
@@ -1,6 +1,11 @@
1
+ import { TYPE_NAMES } from '../compiler/types.js';
1
2
  import compile from '../compiler/wrap.js';
2
3
  import version from './version.js';
3
4
 
5
+ import util from 'node:util';
6
+
7
+ process.argv.push('--no-opt-unused');
8
+
4
9
  let repl;
5
10
  try {
6
11
  // try importing node:repl
@@ -86,10 +91,21 @@ const run = async (source, _context, _filename, callback, run = true) => {
86
91
  lastPages = [...pages.keys()];
87
92
  }
88
93
 
89
- const ret = run ? exports.main() : undefined;
90
- callback(null, ret);
94
+ let ret = run ? exports.main() : undefined;
95
+ let value, type;
96
+ if (ret?.type != null) {
97
+ value = ret.value;
98
+ type = ret.type;
99
+ ret = ret.js;
100
+ }
101
+
102
+ console.log(util.inspect(ret, false, 2, true), (value != null ? `\x1B[34m\x1B[3m(value: ${value}, type: ${TYPE_NAMES[type]})\x1B[0m` : ''));
103
+
104
+ // callback(null, ret);
91
105
 
92
106
  prev = prev + ';\n' + source.trim();
107
+
108
+ callback();
93
109
  };
94
110
 
95
111
  const replServer = repl.start({ prompt: '> ', eval: run });