porffor 0.0.0-ba812f2 → 0.0.0-beff13f
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/README.md +5 -5
- package/c.exe +0 -0
- package/compiler/2c.js +112 -19
- package/compiler/builtins.js +6 -0
- package/compiler/codeGen.js +295 -81
- package/compiler/embedding.js +9 -5
- package/compiler/index.js +5 -5
- package/compiler/opt.js +14 -18
- package/compiler/parse.js +2 -2
- package/compiler/prototype.js +90 -28
- package/compiler/sections.js +17 -4
- package/compiler/wrap.js +9 -2
- package/g.exe +0 -0
- package/out.exe +0 -0
- package/package.json +1 -1
- package/r.js +39 -1
- package/rhemyn/README.md +1 -1
- package/rhemyn/compile.js +1 -1
- package/rhemyn/parse.js +12 -10
- package/runner/index.js +5 -3
- package/runner/info.js +37 -2
- package/tmp.c +46 -25
package/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# porffor
|
2
2
|
a basic experimental wip *aot* optimizing js -> wasm/c engine/compiler/runtime in js. not serious/intended for (real) use. (this is a straight forward, honest readme)<br>
|
3
|
-
age: ~
|
3
|
+
age: ~2 months
|
4
4
|
|
5
5
|
## design
|
6
6
|
porffor is a very unique js engine, due a very different approach. it is seriously limited, but what it can do, it does pretty well. key differences:
|
@@ -83,6 +83,8 @@ these include some early (stage 1/0) and/or dead (last commit years ago) proposa
|
|
83
83
|
- truthy/falsy (eg `!'' == true`)
|
84
84
|
- string comparison (eg `'a' == 'a'`, `'a' != 'b'`)
|
85
85
|
- nullish coalescing operator (`??`)
|
86
|
+
- `for...of` (arrays and strings)
|
87
|
+
- array member setting (`arr[0] = 2`, `arr[0] += 2`, etc)
|
86
88
|
|
87
89
|
### built-ins
|
88
90
|
|
@@ -110,11 +112,9 @@ these include some early (stage 1/0) and/or dead (last commit years ago) proposa
|
|
110
112
|
no particular order and no guarentees, just what could happen soon™
|
111
113
|
|
112
114
|
- arrays
|
113
|
-
- member setting (`arr[0] = 2`)
|
114
115
|
- more of `Array` prototype
|
115
116
|
- arrays/strings inside arrays
|
116
117
|
- destructuring
|
117
|
-
- for .. of
|
118
118
|
- strings
|
119
119
|
- member setting
|
120
120
|
- objects
|
@@ -132,10 +132,9 @@ no particular order and no guarentees, just what could happen soon™
|
|
132
132
|
- rewrite local indexes per func for smallest local header and remove unused idxs
|
133
133
|
- smarter inline selection (snapshots?)
|
134
134
|
- remove const ifs (`if (true)`, etc)
|
135
|
-
- use data segments for initing arrays
|
136
135
|
|
137
136
|
## porfformance
|
138
|
-
*for the things it supports*, porffor is blazingly
|
137
|
+
*for the things it supports most of the time*, porffor is blazingly fast compared to most interpreters, and common engines running without JIT. for those with JIT, it is not that much slower like a traditional interpreter would be; mostly the same or a bit faster/slower depending on what.
|
139
138
|
|
140
139
|

|
141
140
|
|
@@ -158,6 +157,7 @@ mostly for reducing size. do not really care about compiler perf/time as long as
|
|
158
157
|
- remove unneeded single just used vars
|
159
158
|
- remove unneeded blocks (no `br`s inside)
|
160
159
|
- remove unused imports
|
160
|
+
- use data segments for initing arrays/strings
|
161
161
|
|
162
162
|
### wasm module
|
163
163
|
- type cache/index (no repeated types)
|
package/c.exe
CHANGED
Binary file
|
package/compiler/2c.js
CHANGED
@@ -2,8 +2,6 @@ import { read_ieee754_binary64, read_signedLEB128 } from './encoding.js';
|
|
2
2
|
import { Blocktype, Opcodes, Valtype } from './wasmSpec.js';
|
3
3
|
import { operatorOpcode } from './expression.js';
|
4
4
|
|
5
|
-
import fs from 'fs';
|
6
|
-
|
7
5
|
const CValtype = {
|
8
6
|
i8: 'char',
|
9
7
|
i16: 'unsigned short', // presume all i16 stuff is unsigned
|
@@ -36,18 +34,24 @@ const todo = msg => {
|
|
36
34
|
throw new TodoError(`todo: ${msg}`);
|
37
35
|
};
|
38
36
|
|
37
|
+
const removeBrackets = str => str.startsWith('(') && str.endsWith(')') ? str.slice(1, -1) : str;
|
38
|
+
|
39
39
|
export default ({ funcs, globals, tags, exceptions, pages }) => {
|
40
|
-
const invOperatorOpcode =
|
40
|
+
const invOperatorOpcode = Object.values(operatorOpcode).reduce((acc, x) => {
|
41
|
+
for (const k in x) {
|
42
|
+
acc[x[k]] = k;
|
43
|
+
}
|
44
|
+
return acc;
|
45
|
+
}, {});
|
41
46
|
const invGlobals = inv(globals, x => x.idx);
|
42
47
|
|
43
|
-
const includes = new Map();
|
48
|
+
const includes = new Map(), unixIncludes = new Map(), winIncludes = new Map();
|
44
49
|
let out = '';
|
45
50
|
|
46
51
|
for (const x in globals) {
|
47
52
|
const g = globals[x];
|
48
53
|
|
49
|
-
out += `${CValtype[g.type]} ${x}`;
|
50
|
-
if (x.init) out += ` ${x.init}`;
|
54
|
+
out += `${CValtype[g.type]} ${x} = ${g.init ?? 0}`;
|
51
55
|
out += ';\n';
|
52
56
|
}
|
53
57
|
|
@@ -58,7 +62,43 @@ export default ({ funcs, globals, tags, exceptions, pages }) => {
|
|
58
62
|
|
59
63
|
if (out) out += '\n';
|
60
64
|
|
65
|
+
let depth = 1;
|
66
|
+
const line = (str, semi = true) => out += `${' '.repeat(depth * 2)}${str}${semi ? ';' : ''}\n`;
|
67
|
+
const lines = lines => {
|
68
|
+
for (const x of lines) {
|
69
|
+
out += `${' '.repeat(depth * 2)}${x}\n`;
|
70
|
+
}
|
71
|
+
};
|
72
|
+
|
73
|
+
const platformSpecific = (win, unix, add = true) => {
|
74
|
+
let tmp = '';
|
75
|
+
|
76
|
+
if (win) {
|
77
|
+
if (add) out += '#ifdef _WIN32\n';
|
78
|
+
else tmp += '#ifdef _WIN32\n';
|
79
|
+
|
80
|
+
if (add) lines(win.split('\n'));
|
81
|
+
else tmp += win + (win.endsWith('\n') ? '' : '\n');
|
82
|
+
}
|
83
|
+
|
84
|
+
if (unix) {
|
85
|
+
if (add) out += (win ? '#else' : '#ifndef _WIN32') + '\n';
|
86
|
+
else tmp += (win ? '#else' : '#ifndef _WIN32') + '\n';
|
87
|
+
|
88
|
+
if (add) lines(unix.split('\n'));
|
89
|
+
else tmp += unix + (unix.endsWith('\n') ? '' : '\n');
|
90
|
+
}
|
91
|
+
|
92
|
+
if (win || unix)
|
93
|
+
if (add) out += '#endif\n';
|
94
|
+
else tmp += '#endif\n';
|
95
|
+
|
96
|
+
return tmp;
|
97
|
+
};
|
98
|
+
|
61
99
|
for (const f of funcs) {
|
100
|
+
depth = 1;
|
101
|
+
|
62
102
|
const invLocals = inv(f.locals, x => x.idx);
|
63
103
|
if (f.returns.length > 1) todo('funcs returning >1 value unsupported');
|
64
104
|
|
@@ -66,16 +106,13 @@ export default ({ funcs, globals, tags, exceptions, pages }) => {
|
|
66
106
|
|
67
107
|
const returns = f.returns.length === 1;
|
68
108
|
|
69
|
-
const shouldInline =
|
109
|
+
const shouldInline = f.internal;
|
70
110
|
out += `${f.name === 'main' ? 'int' : CValtype[f.returns[0]]} ${shouldInline ? 'inline ' : ''}${sanitize(f.name)}(${f.params.map((x, i) => `${CValtype[x]} ${invLocals[i]}`).join(', ')}) {\n`;
|
71
111
|
|
72
|
-
let depth = 1;
|
73
|
-
const line = (str, semi = true) => out += `${' '.repeat(depth * 2)}${str}${semi ? ';' : ''}\n`;
|
74
|
-
|
75
112
|
const localKeys = Object.keys(f.locals).sort((a, b) => f.locals[a].idx - f.locals[b].idx).slice(f.params.length).sort((a, b) => f.locals[a].idx - f.locals[b].idx);
|
76
113
|
for (const x of localKeys) {
|
77
114
|
const l = f.locals[x];
|
78
|
-
line(`${CValtype[l.type]} ${x}`);
|
115
|
+
line(`${CValtype[l.type]} ${x} = 0`);
|
79
116
|
}
|
80
117
|
|
81
118
|
if (localKeys.length !== 0) out += '\n';
|
@@ -96,7 +133,8 @@ export default ({ funcs, globals, tags, exceptions, pages }) => {
|
|
96
133
|
if (['==', '!=', '>', '>=', '<', '<='].includes(op)) lastCond = true;
|
97
134
|
else lastCond = false;
|
98
135
|
|
99
|
-
vals.push(`${a} ${op} ${b}`);
|
136
|
+
// vals.push(`${a} ${op} ${b}`);
|
137
|
+
vals.push(`(${removeBrackets(a)} ${op} ${b})`);
|
100
138
|
continue;
|
101
139
|
}
|
102
140
|
|
@@ -120,6 +158,7 @@ export default ({ funcs, globals, tags, exceptions, pages }) => {
|
|
120
158
|
|
121
159
|
switch (i[0]) {
|
122
160
|
case Opcodes.i32_const:
|
161
|
+
case Opcodes.i64_const:
|
123
162
|
vals.push(read_signedLEB128(i.slice(1)).toString());
|
124
163
|
break;
|
125
164
|
|
@@ -132,24 +171,42 @@ export default ({ funcs, globals, tags, exceptions, pages }) => {
|
|
132
171
|
break;
|
133
172
|
|
134
173
|
case Opcodes.local_set:
|
135
|
-
line(`${invLocals[i[1]]} = ${vals.pop()}`);
|
174
|
+
line(`${invLocals[i[1]]} = ${removeBrackets(vals.pop())}`);
|
136
175
|
break;
|
137
176
|
|
138
177
|
case Opcodes.local_tee:
|
139
|
-
|
178
|
+
line(`${invLocals[i[1]]} = ${removeBrackets(vals.pop())}`);
|
179
|
+
vals.push(`${invLocals[i[1]]}`);
|
180
|
+
// vals.push(`${invLocals[i[1]]} = ${vals.pop()}`);
|
181
|
+
break;
|
182
|
+
|
183
|
+
case Opcodes.global_get:
|
184
|
+
vals.push(`${invGlobals[i[1]]}`);
|
185
|
+
break;
|
186
|
+
|
187
|
+
case Opcodes.global_set:
|
188
|
+
line(`${invGlobals[i[1]]} = ${removeBrackets(vals.pop())}`);
|
140
189
|
break;
|
141
190
|
|
142
191
|
case Opcodes.f64_trunc:
|
143
192
|
// vals.push(`trunc(${vals.pop()})`);
|
144
|
-
vals.push(`(int)(${vals.pop()})`); // this is ~10x faster with clang
|
193
|
+
vals.push(`(int)(${removeBrackets(vals.pop())})`); // this is ~10x faster with clang??
|
194
|
+
break;
|
195
|
+
|
196
|
+
case Opcodes.f64_convert_i32_u:
|
197
|
+
case Opcodes.f64_convert_i32_s:
|
198
|
+
case Opcodes.f64_convert_i64_u:
|
199
|
+
case Opcodes.f64_convert_i64_s:
|
200
|
+
// int to double
|
201
|
+
vals.push(`(double)${vals.pop()}`);
|
145
202
|
break;
|
146
203
|
|
147
204
|
case Opcodes.return:
|
148
|
-
line(`return${returns ? ` ${vals.pop()}` : ''}`);
|
205
|
+
line(`return${returns ? ` ${removeBrackets(vals.pop())}` : ''}`);
|
149
206
|
break;
|
150
207
|
|
151
208
|
case Opcodes.if:
|
152
|
-
let cond = vals.pop();
|
209
|
+
let cond = removeBrackets(vals.pop());
|
153
210
|
if (!lastCond) {
|
154
211
|
if (cond.startsWith('(long)')) cond = `${cond.slice(6)} == 1e+0`;
|
155
212
|
else cond += ' == 1';
|
@@ -214,12 +271,44 @@ export default ({ funcs, globals, tags, exceptions, pages }) => {
|
|
214
271
|
line(`printf("%f\\n", ${vals.pop()})`);
|
215
272
|
includes.set('stdio.h', true);
|
216
273
|
break;
|
274
|
+
|
275
|
+
case 'time':
|
276
|
+
line(`double _time_out`);
|
277
|
+
/* platformSpecific(
|
278
|
+
`FILETIME _time_filetime;
|
279
|
+
GetSystemTimeAsFileTime(&_time_filetime);
|
280
|
+
|
281
|
+
ULARGE_INTEGER _time_ularge;
|
282
|
+
_time_ularge.LowPart = _time_filetime.dwLowDateTime;
|
283
|
+
_time_ularge.HighPart = _time_filetime.dwHighDateTime;
|
284
|
+
_time_out = (_time_ularge.QuadPart - 116444736000000000i64) / 10000.;`,
|
285
|
+
`struct timespec _time;
|
286
|
+
clock_gettime(CLOCK_MONOTONIC, &_time);
|
287
|
+
_time_out = _time.tv_nsec / 1000000.;`); */
|
288
|
+
platformSpecific(
|
289
|
+
`LARGE_INTEGER _time_freq, _time_t;
|
290
|
+
QueryPerformanceFrequency(&_time_freq);
|
291
|
+
QueryPerformanceCounter(&_time_t);
|
292
|
+
_time_out = ((double)_time_t.QuadPart / _time_freq.QuadPart) * 1000.;`,
|
293
|
+
`struct timespec _time;
|
294
|
+
clock_gettime(CLOCK_MONOTONIC, &_time);
|
295
|
+
_time_out = _time.tv_nsec / 1000000.;`);
|
296
|
+
vals.push(`_time_out`);
|
297
|
+
|
298
|
+
unixIncludes.set('time.h', true);
|
299
|
+
winIncludes.set('windows.h', true);
|
300
|
+
break;
|
301
|
+
|
302
|
+
default:
|
303
|
+
log('2c', `unimplemented import: ${importFunc.name}`);
|
304
|
+
break;
|
217
305
|
}
|
306
|
+
|
218
307
|
break;
|
219
308
|
}
|
220
309
|
|
221
310
|
let args = [];
|
222
|
-
for (let j = 0; j < func.params.length; j++) args.unshift(vals.pop());
|
311
|
+
for (let j = 0; j < func.params.length; j++) args.unshift(removeBrackets(vals.pop()));
|
223
312
|
|
224
313
|
if (func.returns.length === 1) vals.push(`${sanitize(func.name)}(${args.join(', ')})`)
|
225
314
|
else line(`${sanitize(func.name)}(${args.join(', ')})`);
|
@@ -251,7 +340,11 @@ export default ({ funcs, globals, tags, exceptions, pages }) => {
|
|
251
340
|
out += '}\n\n';
|
252
341
|
}
|
253
342
|
|
254
|
-
|
343
|
+
depth = 0;
|
344
|
+
|
345
|
+
const makeIncludes = includes => [...includes.keys()].map(x => `#include <${x}>\n`).join('');
|
346
|
+
|
347
|
+
out = platformSpecific(makeIncludes(winIncludes), makeIncludes(unixIncludes), false) + '\n' + makeIncludes(includes) + '\n' + out;
|
255
348
|
|
256
349
|
return out;
|
257
350
|
};
|