porffor 0.25.1 → 0.25.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.
@@ -845,6 +845,11 @@ const nullish = (scope, wasm, type, intIn = false, intOut = false) => {
845
845
  ...(!useTmp ? [] : [ [ Opcodes.local_set, tmp ] ]),
846
846
 
847
847
  ...typeSwitch(scope, type, {
848
+ [TYPES.empty]: [
849
+ // empty
850
+ ...(!useTmp ? [ [ Opcodes.drop ] ] : []),
851
+ ...number(1, intOut ? Valtype.i32 : valtypeBinary)
852
+ ],
848
853
  [TYPES.undefined]: [
849
854
  // undefined
850
855
  ...(!useTmp ? [ [ Opcodes.drop ] ] : []),
@@ -1189,7 +1194,7 @@ const generateBinaryExp = (scope, decl, _global, _name) => {
1189
1194
  const asmFuncToAsm = (scope, func) => {
1190
1195
  return func(scope, {
1191
1196
  TYPES, TYPE_NAMES, typeSwitch, makeArray, makeString, allocPage, internalThrow,
1192
- getNodeType, generateIdent,
1197
+ getNodeType, generate, generateIdent,
1193
1198
  builtin: n => {
1194
1199
  let idx = funcIndex[n] ?? importedFuncs[n];
1195
1200
  if (idx == null && builtinFuncs[n]) {
@@ -3962,7 +3967,7 @@ const generateForIn = (scope, decl) => {
3962
3967
  depth.push('if');
3963
3968
  depth.push('forin');
3964
3969
  depth.push('block');
3965
- depth.push('block');
3970
+ depth.push('if');
3966
3971
 
3967
3972
  // setup local for left
3968
3973
  generate(scope, decl.left);
@@ -3984,6 +3989,7 @@ const generateForIn = (scope, decl) => {
3984
3989
  [TYPES.object]: [
3985
3990
  [ Opcodes.loop, Blocktype.void ],
3986
3991
 
3992
+ // read key
3987
3993
  [ Opcodes.local_get, pointer ],
3988
3994
  [ Opcodes.i32_load, 0, 5 ],
3989
3995
  [ Opcodes.local_tee, localTmp(scope, '#forin_tmp', Valtype.i32) ],
@@ -4009,11 +4015,18 @@ const generateForIn = (scope, decl) => {
4009
4015
  [ isGlobal ? Opcodes.global_set : Opcodes.local_set, local.idx ],
4010
4016
 
4011
4017
  [ Opcodes.block, Blocktype.void ],
4012
- [ Opcodes.block, Blocktype.void ],
4018
+
4019
+ // todo/perf: do not read key for non-enumerables
4020
+ // only run body if entry is enumerable
4021
+ [ Opcodes.local_get, pointer ],
4022
+ [ Opcodes.i32_load8_u, 0, 17 ],
4023
+ [ Opcodes.i32_const, 0b0100 ],
4024
+ [ Opcodes.i32_and ],
4025
+ [ Opcodes.if, Blocktype.void ],
4013
4026
  ...generate(scope, decl.body),
4014
4027
  [ Opcodes.end ],
4015
4028
 
4016
- // increment iter pointer by 14
4029
+ // increment pointer by 14
4017
4030
  [ Opcodes.local_get, pointer ],
4018
4031
  ...number(14, Valtype.i32),
4019
4032
  [ Opcodes.i32_add ],
@@ -4122,7 +4135,7 @@ const generateBreak = (scope, decl) => {
4122
4135
  while: 2, // loop > if (wanted branch) (we are here)
4123
4136
  dowhile: 2, // loop > block (wanted branch) > block (we are here)
4124
4137
  forof: 2, // loop > block (wanted branch) > block (we are here)
4125
- forin: 2, // loop > block (wanted branch) > block (we are here)
4138
+ forin: 2, // loop > block (wanted branch) > if (we are here)
4126
4139
  if: 1, // break inside if, branch 0 to skip the rest of the if
4127
4140
  switch: 1
4128
4141
  })[type];
@@ -4145,7 +4158,7 @@ const generateContinue = (scope, decl) => {
4145
4158
  while: 1, // loop (wanted branch) > if (we are here)
4146
4159
  dowhile: 3, // loop > block > block (wanted branch) (we are here)
4147
4160
  forof: 3, // loop > block > block (wanted branch) (we are here)
4148
- forin: 3 // loop > block > block (wanted branch) (we are here)
4161
+ forin: 3 // loop > block > if (wanted branch) (we are here)
4149
4162
  })[type];
4150
4163
 
4151
4164
  return [
@@ -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`);
@@ -204,9 +204,10 @@ ${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(/\["throw","(.*?)","(.*?)"\]/g, (_, constructor, message) => `...internalThrow(scope, '${constructor}', \`${message}\`)`);
207
+ .replace(/\["throw","(.*?)","(.*?)"\]/g, (_, constructor, message) => `...internalThrow(scope, '${constructor}', \`${message}\`)`)
208
+ .replace(/\["get object","(.*?)"\]/g, (_, objName) => `...generateIdent(scope, { name: '${objName}' })`);
208
209
 
209
- return `(scope, {${`${str.includes('allocPage(') ? 'allocPage,' : ''}${str.includes('glbl(') ? 'glbl,' : ''}${str.includes('loc(') ? 'loc,' : ''}${str.includes('builtin(') ? 'builtin,' : ''}${str.includes('internalThrow(') ? 'internalThrow,' : ''}`.slice(0, -1)}}) => ` + str;
210
+ return `(scope, {${`${str.includes('allocPage(') ? 'allocPage,' : ''}${str.includes('glbl(') ? 'glbl,' : ''}${str.includes('loc(') ? 'loc,' : ''}${str.includes('builtin(') ? 'builtin,' : ''}${str.includes('internalThrow(') ? 'internalThrow,' : ''}${str.includes('generateIdent(') ? 'generateIdent,' : ''}`.slice(0, -1)}}) => ` + str;
210
211
  };
211
212
 
212
213
  const locals = Object.entries(x.locals).sort((a,b) => a[1].idx - b[1].idx)
package/compiler/wrap.js CHANGED
@@ -69,7 +69,10 @@ const porfToJSValue = ({ memory, funcs, pages }, value, type) => {
69
69
 
70
70
  const vValue = read(Float64Array, memory, value + offset + 4, 1)[0];
71
71
  const vType = tail >>> 8;
72
- const v = porfToJSValue({ memory, funcs, pages }, vValue, vType);
72
+
73
+ // do not recursive call forever for direct circular
74
+ const v = vValue === value && vType === type ? out :
75
+ porfToJSValue({ memory, funcs, pages }, vValue, vType);
73
76
 
74
77
  const flags = tail & 0xff;
75
78
 
@@ -277,10 +280,6 @@ export default (source, flags = [ 'module' ], customImports = {}, print = str =>
277
280
  const printDecomp = (middleIndex, func, funcs, globals, exceptions) => {
278
281
  console.log(`\x1B[35m\x1B[1mporffor backtrace\u001b[0m`);
279
282
 
280
- const strParams = func.params.map(v => invValtype[v]);
281
- const strReturns = func.returns.map(v => invValtype[v]);
282
- console.log(`\x1B[1m${func.name}\x1B[0m \x1B[90m(${strParams.join(', ')}) -> (${strReturns.join(', ')})\x1B[0m`);
283
-
284
283
  const surrounding = Prefs.backtraceSurrounding ?? 5;
285
284
  let min = middleIndex - surrounding;
286
285
  let max = middleIndex + surrounding + 1;
@@ -289,7 +288,7 @@ export default (source, flags = [ 'module' ], customImports = {}, print = str =>
289
288
  max = func.wasm.length;
290
289
  }
291
290
 
292
- const decomp = decompile(func.wasm.slice(min, max), '', 0, func.locals, func.params, func.returns, funcs, globals, exceptions).slice(0, -1).split('\n');
291
+ 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');
293
292
 
294
293
  const noAnsi = s => s.replace(/\u001b\[[0-9]+m/g, '');
295
294
  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.1+b0893a7c3",
4
+ "version": "0.25.3+8f4d9af84",
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.1+b0893a7c3';
3
+ globalThis.version = '0.25.3+8f4d9af84';
4
4
 
5
5
  // deno compat
6
6
  if (typeof process === 'undefined' && typeof Deno !== 'undefined') {
@@ -26,18 +26,20 @@ if (process.argv.includes('--help')) {
26
26
  console.log(`\x1B[1m\x1B[35mPorffor\x1B[0m is a JavaScript engine/runtime/compiler. \x1B[90m(${globalThis.version})\x1B[0m`);
27
27
 
28
28
  // basic usage
29
- console.log(`Usage: \x1B[1mporf [command] path/to/script.js [...prefs] [...args]\x1B[0m`);
29
+ console.log(`Usage: \x1B[1mporf [command] [...prefs] path/to/script.js [...args]\x1B[0m`);
30
30
 
31
31
  // commands
32
32
  console.log(`\n\x1B[1mCommands:\x1B[0m`);
33
33
  for (const [ cmd, [ color, desc ] ] of Object.entries({
34
34
  run: [ 34, 'Run a JS file' ],
35
35
  wasm: [ 34, 'Compile a JS file to a Wasm binary\n' ],
36
+
36
37
  c: [ 31, 'Compile a JS file to C source code' ],
37
38
  native: [ 31, 'Compile a JS file to a native binary\n' ],
39
+
38
40
  profile: [ 33, 'Profile a JS file' ],
39
41
  debug: [ 33, 'Debug a JS file' ],
40
- 'debug-wasm': [ 33, 'Debug the compiled Wasm of a JS file' ]
42
+ 'debug-wasm': [ 33, 'Debug the compiled Wasm of a JS file' ],
41
43
  })) {
42
44
  console.log(` \x1B[1m\x1B[${color}m${cmd}\x1B[0m${' '.repeat(20 - cmd.length - (desc.startsWith('🧪') ? 3 : 0))}${desc}`);
43
45
  }
@@ -106,7 +108,33 @@ if (['precompile', 'run', 'wasm', 'native', 'c', 'profile', 'debug', 'debug-wasm
106
108
 
107
109
  globalThis.file = file;
108
110
 
109
- 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) {
110
138
  if (process.argv.includes('-v') || process.argv.includes('--version')) {
111
139
  // just print version
112
140
  console.log(globalThis.version);
@@ -118,7 +146,7 @@ if (!file) {
118
146
  await done();
119
147
  }
120
148
 
121
- const source = fs.readFileSync(file, 'utf8');
149
+ source ||= fs.readFileSync(file, 'utf8');
122
150
 
123
151
  const compile = (await import('../compiler/wrap.js')).default;
124
152
 
@@ -135,19 +163,20 @@ const print = str => {
135
163
  };
136
164
 
137
165
  let runStart;
166
+ let ret;
138
167
  try {
139
168
  if (process.argv.includes('-b')) {
140
169
  const { wasm, exports } = compile(source, process.argv.includes('--module') ? [ 'module' ] : [], {}, print);
141
170
 
142
171
  runStart = performance.now();
143
- if (!process.argv.includes('--no-run')) exports.main();
172
+ if (!process.argv.includes('--no-run')) ret = exports.main();
144
173
 
145
174
  console.log(`\n\nwasm size: ${wasm.byteLength} bytes`);
146
175
  } else {
147
176
  const { exports } = compile(source, process.argv.includes('--module') ? [ 'module' ] : [], {}, print);
148
177
 
149
178
  runStart = performance.now();
150
- if (!process.argv.includes('--no-run')) exports.main();
179
+ if (!process.argv.includes('--no-run')) ret = exports.main();
151
180
  }
152
181
  // if (cache) process.stdout.write(cache);
153
182
  } catch (e) {
@@ -157,4 +186,12 @@ try {
157
186
  console.error(out);
158
187
  }
159
188
 
160
- 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
+ }
package/todo.txt DELETED
@@ -1,2 +0,0 @@
1
- - retain previous attrs if they are undefined (configurable, other attrs?, set/get) in defineProperty
2
- - make missing objects