porffor 0.25.2 → 0.25.4

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.
@@ -333,7 +333,10 @@ const generateIdent = (scope, decl) => {
333
333
  if (Object.hasOwn(globals, name)) return [ [ Opcodes.global_get, globals[name].idx ] ];
334
334
 
335
335
  if (Object.hasOwn(importedFuncs, name)) return number(importedFuncs[name] - importedFuncs.length);
336
- if (Object.hasOwn(funcIndex, name)) return number(funcIndex[name] - importedFuncs.length);
336
+ if (Object.hasOwn(funcIndex, name)) {
337
+ if (globalThis.precompile) return [ [ Opcodes.const, 'funcref', name ] ];
338
+ return number(funcIndex[name] - importedFuncs.length);
339
+ }
337
340
  }
338
341
 
339
342
  if (local?.idx === undefined && rawName.startsWith('__')) {
@@ -845,6 +848,11 @@ const nullish = (scope, wasm, type, intIn = false, intOut = false) => {
845
848
  ...(!useTmp ? [] : [ [ Opcodes.local_set, tmp ] ]),
846
849
 
847
850
  ...typeSwitch(scope, type, {
851
+ [TYPES.empty]: [
852
+ // empty
853
+ ...(!useTmp ? [ [ Opcodes.drop ] ] : []),
854
+ ...number(1, intOut ? Valtype.i32 : valtypeBinary)
855
+ ],
848
856
  [TYPES.undefined]: [
849
857
  // undefined
850
858
  ...(!useTmp ? [ [ Opcodes.drop ] ] : []),
@@ -1190,7 +1198,7 @@ const asmFuncToAsm = (scope, func) => {
1190
1198
  return func(scope, {
1191
1199
  TYPES, TYPE_NAMES, typeSwitch, makeArray, makeString, allocPage, internalThrow,
1192
1200
  getNodeType, generate, generateIdent,
1193
- builtin: n => {
1201
+ builtin: (n, float = false, offset = false) => {
1194
1202
  let idx = funcIndex[n] ?? importedFuncs[n];
1195
1203
  if (idx == null && builtinFuncs[n]) {
1196
1204
  includeBuiltin(null, n);
@@ -1198,7 +1206,9 @@ const asmFuncToAsm = (scope, func) => {
1198
1206
  }
1199
1207
 
1200
1208
  if (idx == null) throw new Error(`builtin('${n}') failed to find a func (inside ${scope.name})`);
1201
- return unsignedLEB128(idx);
1209
+ if (offset) idx -= importedFuncs.length;
1210
+
1211
+ return float ? ieee754_binary64(idx) : unsignedLEB128(idx);
1202
1212
  },
1203
1213
  glbl: (opcode, name, type) => {
1204
1214
  const globalName = '#porf#' + name; // avoid potential name clashing with user js
@@ -2352,6 +2362,23 @@ const generateCall = (scope, decl, _global, _name, unusedValue = false) => {
2352
2362
  ...internalThrow(scope, 'TypeError', `${unhackName(name)} is not a constructor`),
2353
2363
  [ Opcodes.end ],
2354
2364
 
2365
+ // [ Opcodes.local_get, funcLocal ],
2366
+ // Opcodes.i32_from_u,
2367
+ // [ Opcodes.call, 0 ],
2368
+
2369
+ // ...number(32),
2370
+ // [ Opcodes.call, 1 ],
2371
+
2372
+ // [ Opcodes.local_get, funcLocal ],
2373
+ // ...number(128, Valtype.i32),
2374
+ // [ Opcodes.i32_mul ],
2375
+ // [ Opcodes.i32_load16_u, 0, ...unsignedLEB128(allocPage(scope, 'func lut') * pageSize), 'read func lut' ],
2376
+ // Opcodes.i32_from_u,
2377
+ // [ Opcodes.call, 0 ],
2378
+
2379
+ // ...number(10),
2380
+ // [ Opcodes.call, 1 ],
2381
+
2355
2382
  ...brTable([
2356
2383
  // get argc of func we are calling
2357
2384
  [ Opcodes.local_get, funcLocal ],
@@ -5228,11 +5255,53 @@ const generateFunc = (scope, decl) => {
5228
5255
 
5229
5256
  const wasm = func.wasm = prelude.concat(generate(func, body));
5230
5257
 
5231
- if (name === 'main') func.gotLastType = true;
5258
+ if (name === 'main') {
5259
+ func.gotLastType = true;
5260
+
5261
+ func.export = true;
5262
+ func.returns = [ valtypeBinary, Valtype.i32 ];
5263
+
5264
+ const lastInst = func.wasm[func.wasm.length - 1] ?? [ Opcodes.end ];
5265
+ if (lastInst[0] === Opcodes.drop) {
5266
+ func.wasm.splice(func.wasm.length - 1, 1);
5267
+
5268
+ const finalStatement = decl.body.body[decl.body.body.length - 1];
5269
+ func.wasm.push(...getNodeType(func, finalStatement));
5270
+ }
5271
+
5272
+ if (lastInst[0] === Opcodes.end || lastInst[0] === Opcodes.local_set || lastInst[0] === Opcodes.global_set) {
5273
+ if (lastInst[0] === Opcodes.local_set && lastInst[1] === func.locals['#last_type'].idx) {
5274
+ func.wasm.splice(main.wasm.length - 1, 1);
5275
+ } else {
5276
+ func.returns = [];
5277
+ }
5278
+ }
5279
+
5280
+ if (lastInst[0] === Opcodes.call) {
5281
+ const callee = funcs.find(x => x.index === lastInst[1]);
5282
+ if (callee) func.returns = callee.returns.slice();
5283
+ else func.returns = [];
5284
+ }
5232
5285
 
5233
- // add end return if not found
5234
- if (name !== 'main' && wasm[wasm.length - 1]?.[0] !== Opcodes.return && countLeftover(wasm) === 0) {
5235
- wasm.push(...generateReturn(func, {}));
5286
+ // inject promise job runner func at the end of main if used
5287
+ if (Object.hasOwn(funcIndex, 'Promise')) {
5288
+ wasm.push(
5289
+ ...generateCall(func, {
5290
+ callee: {
5291
+ type: 'Identifier',
5292
+ name: '__Porffor_promise_runJobs'
5293
+ },
5294
+ arguments: []
5295
+ }).slice(0, -1), // remove set last type
5296
+ [ Opcodes.drop ],
5297
+ [ Opcodes.drop ]
5298
+ );
5299
+ }
5300
+ } else {
5301
+ // add end return if not found
5302
+ if (wasm[wasm.length - 1]?.[0] !== Opcodes.return && countLeftover(wasm) === 0) {
5303
+ wasm.push(...generateReturn(func, {}));
5304
+ }
5236
5305
  }
5237
5306
 
5238
5307
  if (func.constr) {
@@ -5483,31 +5552,6 @@ export default program => {
5483
5552
 
5484
5553
  const main = generateFunc(scope, program);
5485
5554
 
5486
- main.export = true;
5487
- main.returns = [ valtypeBinary, Valtype.i32 ];
5488
-
5489
- const lastInst = main.wasm[main.wasm.length - 1] ?? [ Opcodes.end ];
5490
- if (lastInst[0] === Opcodes.drop) {
5491
- main.wasm.splice(main.wasm.length - 1, 1);
5492
-
5493
- const finalStatement = program.body.body[program.body.body.length - 1];
5494
- main.wasm.push(...getNodeType(main, finalStatement));
5495
- }
5496
-
5497
- if (lastInst[0] === Opcodes.end || lastInst[0] === Opcodes.local_set || lastInst[0] === Opcodes.global_set) {
5498
- if (lastInst[0] === Opcodes.local_set && lastInst[1] === main.locals['#last_type'].idx) {
5499
- main.wasm.splice(main.wasm.length - 1, 1);
5500
- } else {
5501
- main.returns = [];
5502
- }
5503
- }
5504
-
5505
- if (lastInst[0] === Opcodes.call) {
5506
- const func = funcs.find(x => x.index === lastInst[1]);
5507
- if (func) main.returns = func.returns.slice();
5508
- else main.returns = [];
5509
- }
5510
-
5511
5555
  delete globals['#ind'];
5512
5556
 
5513
5557
  // if blank main func and other exports, remove it
@@ -11,17 +11,26 @@ export default (wasm, name = '', ind = 0, locals = {}, params = [], returns = []
11
11
  const invLocals = inv(locals, x => x.idx);
12
12
  const invGlobals = inv(globals, x => x.idx);
13
13
 
14
- const makeSignature = (params, returns) => `(${params.map(x => invValtype[x]).join(', ')}) -> (${returns.map(x => invValtype[x]).join(', ')})`;
14
+ const makeSignature = (params, returns, locals) => {
15
+ if (locals) {
16
+ const localNames = inv(locals, x => x.idx);
17
+ return `(${params.map((x, i) => `${localNames[i]}(${i}): ${invValtype[x]}`).join(', ')}) -> (${returns.map(x => invValtype[x]).join(', ')})`;
18
+ }
19
+
20
+ return `(${params.map((x, i) => invValtype[x]).join(', ')}) -> (${returns.map(x => invValtype[x]).join(', ')})`;
21
+ }
15
22
 
16
- let out = '', depth = name ? 1 : 0;
17
- if (name) out += `${makeSignature(params, returns)} ;; $${name} (${ind})\n`;
23
+ let out = '', depth = 0;
24
+ if (name) out += `${name}(${ind}) ${makeSignature(params, returns, locals)}\n`;
18
25
 
19
26
  const justLocals = Object.values(locals).sort((a, b) => a.idx - b.idx).slice(params.length);
20
- if (name && justLocals.length > 0) out += ` local ${justLocals.map(x => invValtype[x.type]).join(' ')}\n`;
27
+ for (const x of justLocals) {
28
+ out += `;; local ${invLocals[x.idx]}(${x.idx}): ${invValtype[x.type]}\n`
29
+ }
21
30
 
22
31
  let i = -1, lastInst;
23
32
  let byte = 0;
24
- for (let inst of wasm.concat(name ? [ [ Opcodes.end ] ] : [])) {
33
+ for (let inst of wasm) {
25
34
  i++;
26
35
  if (inst[0] === null) continue;
27
36
 
@@ -102,6 +111,7 @@ export default (wasm, name = '', ind = 0, locals = {}, params = [], returns = []
102
111
  const name = invLocals[inst[1]];
103
112
  const type = invValtype[locals[name]?.type];
104
113
  if (name) out += ` ;; $${name}${type !== valtype ? ` (${type})` : ''}`;
114
+ else out += ` ;; unknown local`
105
115
  }
106
116
 
107
117
  if (inst[0] === Opcodes.global_get || inst[0] === Opcodes.global_set) {
@@ -130,4 +140,4 @@ export const highlightAsm = asm => asm
130
140
  .replace(/(block|loop|if|end|else|try|catch_all|catch|delegate)/g, _ => `\x1B[95m${_}\x1B[0m`)
131
141
  .replace(/unreachable/g, _ => `\x1B[91m${_}\x1B[0m`)
132
142
  .replace(/ \-?[0-9\.]+/g, _ => ` \x1B[33m${_.slice(1)}\x1B[0m`)
133
- .replace(/ ;;.*$/gm, _ => `\x1B[90m${_.replaceAll(/\x1B\[[0-9]+m/g, '')}\x1B[0m`);
143
+ .replace(/;;.*$/gm, _ => `\x1B[90m${_.replaceAll(/\x1B\[[0-9]+m/g, '')}\x1B[0m`);
package/compiler/opt.js CHANGED
@@ -347,7 +347,7 @@ export default (funcs, globals, pages, tags, exceptions) => {
347
347
  continue;
348
348
  }
349
349
 
350
- if (lastInst[0] === Opcodes.i32_const && (inst[0] === Opcodes.i32_from[0] || inst[0] === Opcodes.i32_from_u[0])) {
350
+ if (lastInst[0] === Opcodes.i32_const && (inst[0] === Opcodes.i32_from[0] || inst[0] === Opcodes.i32_from_u[0]) && (typeof lastInst[1] !== 'string')) {
351
351
  // change i32 const and immediate convert to const (opposite way of previous)
352
352
  // i32.const 0
353
353
  // f64.convert_i32_s || f64.convert_i32_u
@@ -191,7 +191,7 @@ const precompile = async () => {
191
191
  }
192
192
 
193
193
  const total = performance.now() - t;
194
- console.log(`\r${' '.repeat(100)}\r\u001b[90m${`[${total.toFixed(2)}ms]`.padEnd(12, ' ')}\u001b[0m\u001b[92mcompiled ${fileCount} files (${funcs.length} funcs)\u001b[0m \u001b[90m(${['parse', 'codegen', 'opt'].map(x => `${x}: ${((timing[x] / total) * 100).toFixed(2)}%`).join(', ')})\u001b[0m`);
194
+ console.log(`\r${' '.repeat(100)}\r\u001b[90m${`[${total.toFixed(2)}ms]`.padEnd(12, ' ')}\u001b[0m\u001b[92mcompiled ${fileCount} files (${funcs.length} funcs)\u001b[0m \u001b[90m(${['parse', 'codegen', 'opt'].map(x => `${x}: ${((timing[x] / total) * 100).toFixed(0)}%`).join(', ')})\u001b[0m`);
195
195
 
196
196
  return `// autogenerated by compiler/precompile.js
197
197
  import { number } from './embedding.js';
@@ -204,6 +204,7 @@ ${funcs.map(x => {
204
204
  .replace(/\["global",(.*?),"(.*?)",(.*?)\]/g, (_, opcode, name, valtype) => `...glbl(${opcode}, '${name}', ${valtype})`)
205
205
  .replace(/\"local","(.*?)",(.*?)\]/g, (_, name, valtype) => `loc('${name}', ${valtype})]`)
206
206
  .replace(/\[16,"(.*?)"]/g, (_, name) => `[16, ...builtin('${name}')]`)
207
+ .replace(/\[68,"funcref","(.*?)"]/g, (_, name, offset) => `[68,...builtin('${name}', true, true)]`)
207
208
  .replace(/\["throw","(.*?)","(.*?)"\]/g, (_, constructor, message) => `...internalThrow(scope, '${constructor}', \`${message}\`)`)
208
209
  .replace(/\["get object","(.*?)"\]/g, (_, objName) => `...generateIdent(scope, { name: '${objName}' })`);
209
210
 
package/compiler/types.js CHANGED
@@ -72,6 +72,8 @@ registerInternalType('WeakRef');
72
72
  registerInternalType('WeakSet');
73
73
  registerInternalType('WeakMap');
74
74
 
75
+ registerInternalType('Promise');
76
+
75
77
  if (Prefs.largestTypes) {
76
78
  const typeKeys = Object.keys(TYPES);
77
79
  const typeVals = Object.values(TYPES);
package/compiler/wrap.js CHANGED
@@ -35,7 +35,7 @@ export const writeByteStr = (memory, ptr, str) => {
35
35
  }
36
36
  };
37
37
 
38
- const porfToJSValue = ({ memory, funcs, pages }, value, type) => {
38
+ const porfToJSValue = ({ memory, funcs, pages }, value, type, override = undefined) => {
39
39
  switch (type) {
40
40
  case TYPES.empty:
41
41
  case TYPES.undefined:
@@ -138,7 +138,8 @@ ${flags & 0b0001 ? ` get func idx: ${get}
138
138
  }
139
139
 
140
140
  case TYPES.array: {
141
- const length = read(Uint32Array, memory, value, 1)[0];
141
+ let length = read(Uint32Array, memory, value, 1)[0];
142
+ if (override) length = override;
142
143
 
143
144
  const out = [];
144
145
  for (let i = 0; i < length; i++) {
@@ -258,6 +259,30 @@ ${flags & 0b0001 ? ` get func idx: ${get}
258
259
  return out;
259
260
  }
260
261
 
262
+ case TYPES.promise: {
263
+ const [ result, _state, fulfillReactions, rejectReactions ] = porfToJSValue({ memory, funcs, pages }, value, TYPES.array, 4);
264
+
265
+ const state = ({
266
+ 0: 'pending',
267
+ 1: 'fulfilled',
268
+ 2: 'rejected'
269
+ })[_state];
270
+ const stateColor = ({
271
+ 0: '\x1B[93m',
272
+ 1: '\x1B[32m',
273
+ 2: '\x1B[31m'
274
+ })[_state];
275
+
276
+ const out = { state, result };
277
+ Object.defineProperty(out, Symbol.for('nodejs.util.inspect.custom'), {
278
+ value(depth, opts, inspect) {
279
+ return `${opts.colors ? '\x1B[36m' : ''}Promise${opts.colors ? '\x1B[0m' : ''} (state: ${opts.colors ? stateColor : ''}<${state}>${opts.colors ? '\x1B[0m' : ''}, result: ${inspect(result, opts)})`;
280
+ }
281
+ });
282
+
283
+ return out;
284
+ }
285
+
261
286
  default: return value;
262
287
  }
263
288
  };
@@ -280,10 +305,6 @@ export default (source, flags = [ 'module' ], customImports = {}, print = str =>
280
305
  const printDecomp = (middleIndex, func, funcs, globals, exceptions) => {
281
306
  console.log(`\x1B[35m\x1B[1mporffor backtrace\u001b[0m`);
282
307
 
283
- const strParams = func.params.map(v => invValtype[v]);
284
- const strReturns = func.returns.map(v => invValtype[v]);
285
- console.log(`\x1B[1m${func.name}\x1B[0m \x1B[90m(${strParams.join(', ')}) -> (${strReturns.join(', ')})\x1B[0m`);
286
-
287
308
  const surrounding = Prefs.backtraceSurrounding ?? 5;
288
309
  let min = middleIndex - surrounding;
289
310
  let max = middleIndex + surrounding + 1;
@@ -292,7 +313,7 @@ export default (source, flags = [ 'module' ], customImports = {}, print = str =>
292
313
  max = func.wasm.length;
293
314
  }
294
315
 
295
- const decomp = decompile(func.wasm.slice(min, max), '', 0, func.locals, func.params, func.returns, funcs, globals, exceptions).slice(0, -1).split('\n');
316
+ const decomp = decompile(func.wasm.slice(min, max), func.name, 0, func.locals, func.params, func.returns, funcs, globals, exceptions).slice(0, -1).split('\n');
296
317
 
297
318
  const noAnsi = s => s.replace(/\u001b\[[0-9]+m/g, '');
298
319
  let longest = 0;
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.25.2+bd0735a02",
4
+ "version": "0.25.4+3aca9688e",
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.25.2+bd0735a02';
3
+ globalThis.version = '0.25.4+3aca9688e';
4
4
 
5
5
  // deno compat
6
6
  if (typeof process === 'undefined' && typeof Deno !== 'undefined') {
@@ -108,7 +108,33 @@ if (['precompile', 'run', 'wasm', 'native', 'c', 'profile', 'debug', 'debug-wasm
108
108
 
109
109
  globalThis.file = file;
110
110
 
111
- if (!file) {
111
+ let source = '', printOutput = false;
112
+ if (process.argv.length >= 4) {
113
+ let evalIndex = process.argv.indexOf('-e');
114
+ if (evalIndex === -1) evalIndex = process.argv.indexOf('--eval');
115
+ if (evalIndex !== -1) {
116
+ source = process.argv[evalIndex + 1];
117
+ if (source) {
118
+ if (source.startsWith('"') || source.startsWith("'")) source = source.slice(1, -1);
119
+ process.argv.splice(evalIndex, 2); // remove flag and value
120
+ }
121
+ }
122
+
123
+ let printIndex = process.argv.indexOf('-p');
124
+ if (printIndex === -1) printIndex = process.argv.indexOf('--print');
125
+ if (printIndex !== -1) {
126
+ process.argv.push('--no-opt-unused');
127
+ source = process.argv[printIndex + 1];
128
+ if (source) {
129
+ if (source.startsWith('"') || source.startsWith("'")) source = source.slice(1, -1);
130
+ process.argv.splice(printIndex, 2); // remove flag and value
131
+ }
132
+
133
+ printOutput = true;
134
+ }
135
+ }
136
+
137
+ if (!file && !source) {
112
138
  if (process.argv.includes('-v') || process.argv.includes('--version')) {
113
139
  // just print version
114
140
  console.log(globalThis.version);
@@ -120,7 +146,7 @@ if (!file) {
120
146
  await done();
121
147
  }
122
148
 
123
- const source = fs.readFileSync(file, 'utf8');
149
+ source ||= fs.readFileSync(file, 'utf8');
124
150
 
125
151
  const compile = (await import('../compiler/wrap.js')).default;
126
152
 
@@ -137,19 +163,20 @@ const print = str => {
137
163
  };
138
164
 
139
165
  let runStart;
166
+ let ret;
140
167
  try {
141
168
  if (process.argv.includes('-b')) {
142
169
  const { wasm, exports } = compile(source, process.argv.includes('--module') ? [ 'module' ] : [], {}, print);
143
170
 
144
171
  runStart = performance.now();
145
- if (!process.argv.includes('--no-run')) exports.main();
172
+ if (!process.argv.includes('--no-run')) ret = exports.main();
146
173
 
147
174
  console.log(`\n\nwasm size: ${wasm.byteLength} bytes`);
148
175
  } else {
149
176
  const { exports } = compile(source, process.argv.includes('--module') ? [ 'module' ] : [], {}, print);
150
177
 
151
178
  runStart = performance.now();
152
- if (!process.argv.includes('--no-run')) exports.main();
179
+ if (!process.argv.includes('--no-run')) ret = exports.main();
153
180
  }
154
181
  // if (cache) process.stdout.write(cache);
155
182
  } catch (e) {
@@ -159,4 +186,12 @@ try {
159
186
  console.error(out);
160
187
  }
161
188
 
162
- if (process.argv.includes('-t')) console.log(`${process.argv.includes('-b') ? '' : '\n\n'}total time: ${(performance.now() - start).toFixed(2)}ms\nexecution time: ${(performance.now() - runStart).toFixed(2)}ms`);
189
+ if (process.argv.includes('-t')) console.log(`${process.argv.includes('-b') ? '' : '\n\n'}total time: ${(performance.now() - start).toFixed(2)}ms\nexecution time: ${(performance.now() - runStart).toFixed(2)}ms`);
190
+
191
+ if (printOutput) {
192
+ if (process.argv.includes('-d') && ret?.type != null) {
193
+ ret = ret.js;
194
+ }
195
+
196
+ console.log(ret);
197
+ }