porffor 0.14.0-f67c123a1 → 0.16.0-a2e115b05
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 +15 -9
- package/README.md +9 -13
- package/asur/index.js +1 -1
- package/compiler/2c.js +104 -51
- package/compiler/assemble.js +26 -1
- package/compiler/builtins/annexb_string.ts +1 -0
- package/compiler/builtins/array.ts +84 -4
- package/compiler/builtins/base64.ts +1 -0
- package/compiler/builtins/boolean.ts +3 -1
- package/compiler/builtins/console.ts +6 -0
- package/compiler/builtins/crypto.ts +1 -0
- package/compiler/builtins/date.ts +2 -0
- package/compiler/builtins/error.js +22 -0
- package/compiler/builtins/escape.ts +1 -2
- package/compiler/builtins/function.ts +2 -0
- package/compiler/builtins/int.ts +2 -0
- package/compiler/builtins/math.ts +410 -0
- package/compiler/builtins/number.ts +2 -0
- package/compiler/builtins/object.ts +2 -0
- package/compiler/builtins/porffor.d.ts +11 -0
- package/compiler/builtins/set.ts +20 -7
- package/compiler/builtins/string.ts +1 -0
- package/compiler/builtins/symbol.ts +62 -0
- package/compiler/builtins.js +48 -10
- package/compiler/codegen.js +569 -258
- package/compiler/decompile.js +5 -1
- package/compiler/generated_builtins.js +555 -60
- package/compiler/index.js +5 -9
- package/compiler/opt.js +2 -2
- package/compiler/parse.js +2 -2
- package/compiler/precompile.js +5 -4
- package/compiler/prefs.js +6 -2
- package/compiler/prototype.js +180 -157
- package/compiler/wrap.js +82 -40
- package/package.json +1 -1
- package/runner/index.js +5 -4
- package/runner/repl.js +18 -2
package/compiler/wrap.js
CHANGED
@@ -8,7 +8,7 @@ import Prefs from './prefs.js';
|
|
8
8
|
|
9
9
|
const bold = x => `\u001b[1m${x}\u001b[0m`;
|
10
10
|
|
11
|
-
const porfToJSValue = (memory, funcs, value, type) => {
|
11
|
+
const porfToJSValue = ({ memory, funcs, pages }, value, type) => {
|
12
12
|
switch (type) {
|
13
13
|
case TYPES.boolean: return Boolean(value);
|
14
14
|
case TYPES.undefined: return undefined;
|
@@ -41,9 +41,22 @@ const porfToJSValue = (memory, funcs, value, type) => {
|
|
41
41
|
case TYPES.array: {
|
42
42
|
const length = (new Int32Array(memory.buffer, value, 1))[0];
|
43
43
|
|
44
|
-
|
45
|
-
|
46
|
-
|
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;
|
47
60
|
}
|
48
61
|
|
49
62
|
case TYPES.date: {
|
@@ -66,12 +79,24 @@ const porfToJSValue = (memory, funcs, value, type) => {
|
|
66
79
|
// console.log(' memory:', Array.from(new Uint8Array(memory.buffer, offset, 9)).map(x => x.toString(16).padStart(2, '0')).join(' '));
|
67
80
|
// console.log(' read:', { value: v, type: t }, '\n');
|
68
81
|
|
69
|
-
out.add(porfToJSValue(memory, funcs, v, t));
|
82
|
+
out.add(porfToJSValue({ memory, funcs, pages }, v, t));
|
70
83
|
}
|
71
84
|
|
72
85
|
return out;
|
73
86
|
}
|
74
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
|
+
|
75
100
|
default: return value;
|
76
101
|
}
|
77
102
|
};
|
@@ -91,40 +116,12 @@ export default async (source, flags = [ 'module' ], customImports = {}, print =
|
|
91
116
|
times.push(performance.now() - t1);
|
92
117
|
if (Prefs.profileCompiler) console.log(bold(`compiled in ${times[0].toFixed(2)}ms`));
|
93
118
|
|
94
|
-
const
|
95
|
-
|
96
|
-
let instance;
|
97
|
-
try {
|
98
|
-
let wasmEngine = WebAssembly;
|
99
|
-
if (Prefs.asur) {
|
100
|
-
log.warning('wrap', 'using our !experimental! asur wasm engine instead of host to run');
|
101
|
-
wasmEngine = await import('../asur/index.js');
|
102
|
-
}
|
103
|
-
|
104
|
-
0, { instance } = await wasmEngine.instantiate(wasm, {
|
105
|
-
'': {
|
106
|
-
p: valtype === 'i64' ? i => print(Number(i).toString()) : i => print(i.toString()),
|
107
|
-
c: valtype === 'i64' ? i => print(String.fromCharCode(Number(i))) : i => print(String.fromCharCode(i)),
|
108
|
-
t: () => performance.now(),
|
109
|
-
u: () => performance.timeOrigin,
|
110
|
-
y: () => {},
|
111
|
-
z: () => {},
|
112
|
-
...customImports
|
113
|
-
}
|
114
|
-
});
|
115
|
-
} catch (e) {
|
116
|
-
// only backtrace for runner, not test262/etc
|
117
|
-
if (!process.argv[1].includes('/runner')) throw e;
|
118
|
-
|
119
|
-
const funcInd = parseInt(e.message.match(/function #([0-9]+) /)?.[1]);
|
120
|
-
const blobOffset = parseInt(e.message.split('@')?.[1]);
|
121
|
-
|
122
|
-
if (!funcInd) throw e;
|
119
|
+
const backtrace = (funcInd, blobOffset) => {
|
120
|
+
if (funcInd == null || blobOffset == null) return false;
|
123
121
|
|
124
122
|
// convert blob offset -> function wasm offset.
|
125
123
|
// this is not good code and is somewhat duplicated
|
126
124
|
// I just want it to work for debugging, I don't care about perf/yes
|
127
|
-
|
128
125
|
const func = funcs.find(x => x.index === funcInd);
|
129
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);
|
130
127
|
|
@@ -142,7 +139,7 @@ export default async (source, flags = [ 'module' ], customImports = {}, print =
|
|
142
139
|
|
143
140
|
if (typeCount !== 0) localDecl.push(encodeLocal(typeCount, lastType));
|
144
141
|
|
145
|
-
const toFind = encodeVector(localDecl).concat(func.wasm.flat().filter(x => x != null && x <= 0xff).slice(0,
|
142
|
+
const toFind = encodeVector(localDecl).concat(func.wasm.flat().filter(x => x != null && x <= 0xff).slice(0, 60));
|
146
143
|
|
147
144
|
let i = 0;
|
148
145
|
for (; i < wasm.length; i++) {
|
@@ -157,7 +154,7 @@ export default async (source, flags = [ 'module' ], customImports = {}, print =
|
|
157
154
|
if (!mismatch) break;
|
158
155
|
}
|
159
156
|
|
160
|
-
if (i === wasm.length)
|
157
|
+
if (i === wasm.length) return false;
|
161
158
|
|
162
159
|
const offset = (blobOffset - i) + encodeVector(localDecl).length;
|
163
160
|
|
@@ -168,7 +165,7 @@ export default async (source, flags = [ 'module' ], customImports = {}, print =
|
|
168
165
|
if (cumLen === offset) break;
|
169
166
|
}
|
170
167
|
|
171
|
-
if (cumLen !== offset)
|
168
|
+
if (cumLen !== offset) return false;
|
172
169
|
|
173
170
|
i -= 1;
|
174
171
|
|
@@ -193,6 +190,38 @@ export default async (source, flags = [ 'module' ], customImports = {}, print =
|
|
193
190
|
console.log(decomp.join('\n'));
|
194
191
|
console.log('\x1B[90m...\x1B[0m\n');
|
195
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);
|
196
225
|
throw e;
|
197
226
|
}
|
198
227
|
|
@@ -200,6 +229,7 @@ export default async (source, flags = [ 'module' ], customImports = {}, print =
|
|
200
229
|
if (Prefs.profileCompiler) console.log(`instantiated in ${times[1].toFixed(2)}ms`);
|
201
230
|
|
202
231
|
const exports = {};
|
232
|
+
const rawValues = process.argv.includes('-i');
|
203
233
|
|
204
234
|
const exceptTag = instance.exports['0'], memory = instance.exports['$'];
|
205
235
|
for (const x in instance.exports) {
|
@@ -218,10 +248,11 @@ export default async (source, flags = [ 'module' ], customImports = {}, print =
|
|
218
248
|
exports[func.name] = function() {
|
219
249
|
try {
|
220
250
|
const ret = exp.apply(this, arguments);
|
221
|
-
|
222
251
|
if (ret == null) return undefined;
|
223
252
|
|
224
|
-
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]);
|
225
256
|
} catch (e) {
|
226
257
|
if (e.is && e.is(exceptTag)) {
|
227
258
|
const exceptId = e.getArg(exceptTag, 0);
|
@@ -236,6 +267,17 @@ export default async (source, flags = [ 'module' ], customImports = {}, print =
|
|
236
267
|
throw new constructor(exception.message);
|
237
268
|
}
|
238
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
|
+
|
239
281
|
throw e;
|
240
282
|
}
|
241
283
|
};
|
package/package.json
CHANGED
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\
|
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(
|
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
|
-
|
90
|
-
|
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 });
|