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.
- package/CONTRIBUTING.md +144 -6
- package/README.md +28 -16
- package/compiler/builtins.js +1 -1
- package/compiler/builtins_objects.js +104 -41
- package/compiler/builtins_precompiled.js +165 -165
- package/compiler/codegen.js +19 -6
- package/compiler/decompile.js +16 -6
- package/compiler/precompile.js +3 -2
- package/compiler/wrap.js +5 -6
- package/package.json +1 -1
- package/runner/index.js +45 -8
- package/todo.txt +0 -2
package/compiler/codegen.js
CHANGED
@@ -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('
|
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
|
-
|
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
|
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) >
|
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 >
|
4161
|
+
forin: 3 // loop > block > if (wanted branch) (we are here)
|
4149
4162
|
})[type];
|
4150
4163
|
|
4151
4164
|
return [
|
package/compiler/decompile.js
CHANGED
@@ -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
|
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 =
|
17
|
-
if (name) out += `${makeSignature(params, returns)}
|
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
|
-
|
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
|
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(
|
143
|
+
.replace(/;;.*$/gm, _ => `\x1B[90m${_.replaceAll(/\x1B\[[0-9]+m/g, '')}\x1B[0m`);
|
package/compiler/precompile.js
CHANGED
@@ -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
|
-
|
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),
|
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
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.
|
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 [...
|
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
|
-
|
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
|
-
|
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