porffor 0.25.1 → 0.25.2
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 +2 -3
- package/compiler/builtins.js +1 -1
- package/compiler/builtins_objects.js +104 -41
- package/compiler/builtins_precompiled.js +148 -148
- package/compiler/codegen.js +14 -6
- package/compiler/precompile.js +3 -2
- package/compiler/wrap.js +4 -1
- package/package.json +1 -1
- package/runner/index.js +5 -3
- package/todo.txt +0 -2
package/CONTRIBUTING.md
CHANGED
@@ -200,13 +200,12 @@ Store the character code into the `out` pointer variable, and increment it.
|
|
200
200
|
|
201
201
|
- For declaring variables, you must use explicit type annotations currently (eg `let a: number = 1`, not `let a = 1`).
|
202
202
|
- You might spot `Porffor.fastOr`/`Porffor.fastAnd`, these are non-short circuiting versions of `||`/`&&`, taking any number of conditions as arguments. You shouldn't don't need to use or worry about these.
|
203
|
-
-
|
204
|
-
- Attempt to avoid string/array-heavy code and use more variables instead if possible, easier on memory and CPU/perf.
|
203
|
+
- Attempt to avoid object/string/array-heavy code and use more variables instead if possible, easier on memory and CPU/perf.
|
205
204
|
- Do not set a return type for prototype methods, it can cause errors/unexpected results.
|
206
205
|
- You cannot use other functions in the file not exported, or variables not inside the current function.
|
207
206
|
- `if (...)` uses a fast truthy implementation which is not spec-compliant as most conditions should be strictly checked. To use spec-compliant behavior, use `if (Boolean(...))`.
|
208
207
|
- For object (string/array/etc) literals, you must use a variable eg `const out: bytestring = 'foobar'; console.log(out);` instead of `console.log('foobar')` due to precompile's allocator constraints.
|
209
|
-
-
|
208
|
+
- You should generally use non-strict equality ops (`==`/`!=`).
|
210
209
|
|
211
210
|
<br>
|
212
211
|
|
package/compiler/builtins.js
CHANGED
@@ -190,7 +190,7 @@ export const BuiltinFuncs = function() {
|
|
190
190
|
...number(TYPES.number, Valtype.i32),
|
191
191
|
[ Opcodes.local_get, 1 ],
|
192
192
|
...number(TYPES.number, Valtype.i32),
|
193
|
-
[ Opcodes.call, builtin('__Math_pow') ],
|
193
|
+
[ Opcodes.call, ...builtin('__Math_pow') ],
|
194
194
|
[ Opcodes.drop ],
|
195
195
|
]
|
196
196
|
};
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import { Opcodes, PageSize, Valtype } from './wasmSpec.js';
|
1
|
+
import { Blocktype, Opcodes, PageSize, Valtype } from './wasmSpec.js';
|
2
2
|
import { TYPES } from './types.js';
|
3
3
|
import { number } from './embedding.js';
|
4
4
|
|
@@ -6,64 +6,92 @@ export default function({ builtinFuncs }, Prefs) {
|
|
6
6
|
const done = new Set();
|
7
7
|
const object = (name, props) => {
|
8
8
|
done.add(name);
|
9
|
+
const prefix = name === 'globalThis' ? '' : `__${name}_`;
|
10
|
+
|
11
|
+
builtinFuncs['#get_' + name] = {
|
12
|
+
params: [],
|
13
|
+
locals: [],
|
14
|
+
globals: [ Valtype.i32 ],
|
15
|
+
globalNames: [ '#getptr_' + name ],
|
16
|
+
returns: [ Valtype.i32 ],
|
17
|
+
returnType: TYPES.object,
|
18
|
+
wasm: (scope, { allocPage, makeString, generate, getNodeType, builtin }) => {
|
19
|
+
if (globalThis.precompile) return [ [ 'get object', name ] ];
|
20
|
+
|
21
|
+
// todo/perf: precompute bytes here instead of calling real funcs if we really care about perf later
|
22
|
+
|
23
|
+
const page = allocPage(scope, `builtin object: ${name}`);
|
24
|
+
const ptr = page === 0 ? 4 : page * PageSize;
|
25
|
+
|
26
|
+
const out = [
|
27
|
+
// check if already made/cached
|
28
|
+
[ Opcodes.global_get, 0 ],
|
29
|
+
[ Opcodes.if, Blocktype.void ],
|
30
|
+
[ Opcodes.global_get, 0 ],
|
31
|
+
[ Opcodes.return ],
|
32
|
+
[ Opcodes.end ],
|
33
|
+
|
34
|
+
// set cache & ptr for use
|
35
|
+
...number(ptr, Valtype.i32),
|
36
|
+
[ Opcodes.global_set, 0 ],
|
37
|
+
];
|
9
38
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
// todo: precompute bytes here instead of calling real funcs if we really care about perf later
|
39
|
+
for (const x in props) {
|
40
|
+
let value = {
|
41
|
+
type: 'Identifier',
|
42
|
+
name: prefix + x
|
43
|
+
};
|
17
44
|
|
18
|
-
|
19
|
-
const ptr = page === 0 ? 4 : page * PageSize;
|
20
|
-
cached = ptr;
|
45
|
+
let flags = 0b0000;
|
21
46
|
|
22
|
-
|
47
|
+
const d = props[x];
|
48
|
+
if (d.configurable) flags |= 0b0010;
|
49
|
+
if (d.enumerable) flags |= 0b0100;
|
50
|
+
if (d.writable) flags |= 0b1000;
|
23
51
|
|
24
|
-
|
25
|
-
|
26
|
-
type: 'Identifier',
|
27
|
-
name: '__' + name + '_' + x
|
28
|
-
};
|
52
|
+
// hack: do not generate objects inside of objects as it causes issues atm
|
53
|
+
if (this[prefix + x]?.type === TYPES.object) value = { type: 'ObjectExpression', properties: [] };
|
29
54
|
|
30
|
-
|
55
|
+
out.push(
|
56
|
+
[ Opcodes.global_get, 0 ],
|
57
|
+
...number(TYPES.object, Valtype.i32),
|
31
58
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
if (d.writable) flags |= 0b1000;
|
36
|
-
|
37
|
-
out.push(
|
38
|
-
...number(ptr, Valtype.i32),
|
39
|
-
...number(TYPES.object, Valtype.i32),
|
59
|
+
...makeString(scope, x, false, `#builtin_object_${name}_${x}`),
|
60
|
+
Opcodes.i32_to_u,
|
61
|
+
...number(TYPES.bytestring, Valtype.i32),
|
40
62
|
|
41
|
-
|
42
|
-
|
43
|
-
...number(TYPES.bytestring, Valtype.i32),
|
63
|
+
...generate(scope, value),
|
64
|
+
...getNodeType(scope, value),
|
44
65
|
|
45
|
-
|
46
|
-
|
66
|
+
...number(flags, Valtype.i32),
|
67
|
+
...number(TYPES.number, Valtype.i32),
|
47
68
|
|
48
|
-
|
49
|
-
|
69
|
+
[ Opcodes.call, ...builtin('__Porffor_object_define') ],
|
70
|
+
[ Opcodes.drop ],
|
71
|
+
[ Opcodes.drop ]
|
72
|
+
);
|
73
|
+
}
|
50
74
|
|
51
|
-
|
52
|
-
|
53
|
-
[ Opcodes.
|
75
|
+
out.push(
|
76
|
+
// return ptr
|
77
|
+
[ Opcodes.global_get, 0 ]
|
54
78
|
);
|
79
|
+
return out;
|
55
80
|
}
|
56
|
-
|
57
|
-
out.push(...number(ptr));
|
58
|
-
return out;
|
59
81
|
};
|
82
|
+
|
83
|
+
|
84
|
+
this[name] = (scope, { builtin }) => [
|
85
|
+
[ Opcodes.call, ...builtin('#get_' + name) ],
|
86
|
+
Opcodes.i32_from_u
|
87
|
+
];
|
60
88
|
this[name].type = TYPES.object;
|
61
89
|
|
62
90
|
for (const x in props) {
|
63
91
|
const d = props[x];
|
64
92
|
|
65
93
|
if (d.value) {
|
66
|
-
const k =
|
94
|
+
const k = prefix + x;
|
67
95
|
|
68
96
|
if (typeof d.value === 'number') {
|
69
97
|
this[k] = number(d.value);
|
@@ -189,7 +217,42 @@ export default function({ builtinFuncs }, Prefs) {
|
|
189
217
|
});
|
190
218
|
}
|
191
219
|
|
192
|
-
|
220
|
+
const enumerableGlobals = [ 'atob', 'btoa', 'performance', 'crypto', 'navigator' ];
|
221
|
+
object('globalThis', {
|
222
|
+
// 19.1 Value Properties of the Global Object
|
223
|
+
// https://tc39.es/ecma262/#sec-value-properties-of-the-global-object
|
224
|
+
// 19.1.1 globalThis
|
225
|
+
globalThis: {
|
226
|
+
writable: true,
|
227
|
+
enumerable: false,
|
228
|
+
configurable: true
|
229
|
+
},
|
230
|
+
|
231
|
+
// 19.1.2 Infinity
|
232
|
+
// 19.1.3 NaN
|
233
|
+
// 19.1.4 undefined
|
234
|
+
...props({
|
235
|
+
writable: false,
|
236
|
+
enumerable: false,
|
237
|
+
configurable: false
|
238
|
+
}, [ 'Infinity', 'NaN', 'undefined' ]),
|
239
|
+
|
240
|
+
// 19.2 Function Properties of the Global Object
|
241
|
+
// https://tc39.es/ecma262/#sec-function-properties-of-the-global-object
|
242
|
+
// 19.3 Constructor Properties of the Global Object
|
243
|
+
// https://tc39.es/ecma262/#sec-constructor-properties-of-the-global-object
|
244
|
+
...props({
|
245
|
+
writable: true,
|
246
|
+
enumerable: false,
|
247
|
+
configurable: true
|
248
|
+
}, builtinFuncKeys.filter(x => !x.startsWith('__') && !enumerableGlobals.includes(x) && !x.startsWith('f64') && !x.startsWith('i32'))),
|
249
|
+
|
250
|
+
...props({
|
251
|
+
writable: true,
|
252
|
+
enumerable: true,
|
253
|
+
configurable: true
|
254
|
+
}, enumerableGlobals)
|
255
|
+
});
|
193
256
|
|
194
257
|
if (Prefs.logMissingObjects) for (const x of Object.keys(builtinFuncs).concat(Object.keys(this))) {
|
195
258
|
if (!x.startsWith('__')) continue;
|