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/CONTRIBUTING.md
CHANGED
@@ -23,7 +23,6 @@ The repo comes with easy alias scripts for Unix and Windows, which you can use l
|
|
23
23
|
|
24
24
|
You can also swap out `node` in the alias to use another runtime like Deno (`deno run -A ...`) or Bun (`bun ...`), or just use it yourself (eg `node runner/index.js ...`, `bun runner/index.js ...`). Node, Deno, Bun should work.
|
25
25
|
|
26
|
-
|
27
26
|
### Precompile
|
28
27
|
|
29
28
|
**If you update any file inside `compiler/builtins` you will need to do this for it to update inside Porffor otherwise your changes will have no effect.** Run `./porf precompile` to precompile. It may error during this, if so, you might have an error in your code or there could be a compiler error with Porffor (feel free to ask for help as soon as you encounter any errors with it).
|
@@ -98,7 +97,7 @@ Loads the character code at the pointer `pointer` **for a String**.[^1]
|
|
98
97
|
Porffor.wasm.i32.store(pointer, length, 0, 0)
|
99
98
|
```
|
100
99
|
|
101
|
-
Stores the length `length` at pointer `pointer`, setting the length of an object. This is mostly unneeded today as you can just do `obj.length = length`.
|
100
|
+
Stores the length `length` at pointer `pointer`, setting the length of an object. This is mostly unneeded today as you can just do `obj.length = length`. [^1]
|
102
101
|
|
103
102
|
<br>
|
104
103
|
|
@@ -200,13 +199,147 @@ Store the character code into the `out` pointer variable, and increment it.
|
|
200
199
|
|
201
200
|
- For declaring variables, you must use explicit type annotations currently (eg `let a: number = 1`, not `let a = 1`).
|
202
201
|
- 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.
|
202
|
+
- Attempt to avoid object/string/array-heavy code and use more variables instead if possible, easier on memory and CPU/perf.
|
205
203
|
- Do not set a return type for prototype methods, it can cause errors/unexpected results.
|
206
204
|
- You cannot use other functions in the file not exported, or variables not inside the current function.
|
207
205
|
- `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
206
|
- 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
|
-
-
|
207
|
+
- You should generally use non-strict equality ops (`==`/`!=`).
|
208
|
+
|
209
|
+
<br>
|
210
|
+
|
211
|
+
### Porffor.wasm
|
212
|
+
This is a macro that is essentially equivalent to C's `asm` macro. It allows you to write inline Wasm bytecode in a similar format to [WAT](https://developer.mozilla.org/en-US/docs/WebAssembly/Understanding_the_text_format).
|
213
|
+
|
214
|
+
Let's look at an example to better illustrate how the format works.
|
215
|
+
|
216
|
+
```ts
|
217
|
+
export const add_i32 = (a: any, b: any) => {
|
218
|
+
Porffor.wasm`
|
219
|
+
local aCasted i32
|
220
|
+
local bCasted i32
|
221
|
+
returns i32 i32
|
222
|
+
|
223
|
+
;; if both types are number
|
224
|
+
local.get ${a+1}
|
225
|
+
i32.const 1
|
226
|
+
i32.eq
|
227
|
+
local.get ${b+1}
|
228
|
+
i32.const 1
|
229
|
+
i32.eq
|
230
|
+
i32.and
|
231
|
+
if
|
232
|
+
local.get ${a}
|
233
|
+
i32.from
|
234
|
+
local.set aCasted
|
235
|
+
|
236
|
+
local.get ${b}
|
237
|
+
i32.from
|
238
|
+
local.set bCasted
|
239
|
+
|
240
|
+
local.get aCasted
|
241
|
+
local.get bCasted
|
242
|
+
i32.add
|
243
|
+
i32.const 1
|
244
|
+
return
|
245
|
+
end
|
246
|
+
|
247
|
+
;; return (0, 0) otherwise
|
248
|
+
i32.const 0
|
249
|
+
i32.const 0
|
250
|
+
return`;
|
251
|
+
}
|
252
|
+
```
|
253
|
+
|
254
|
+
---
|
255
|
+
|
256
|
+
```
|
257
|
+
local aCasted i32
|
258
|
+
local bCasted i32
|
259
|
+
```
|
260
|
+
|
261
|
+
Here we define two locals, which you can think of as typed variables. Here both of them have the type of `i32`, which was explained above. This type can also be `f64` or `i64`, which are doubles and 64-bit integers respectively.
|
262
|
+
|
263
|
+
---
|
264
|
+
|
265
|
+
```
|
266
|
+
returns i32 i32
|
267
|
+
```
|
268
|
+
|
269
|
+
This sets the return type of the function, what the stack must look like before a `return` instruction. Normally Porffor functions have the return type `(f64, i32)`, which represents the valtype (usually f64) and an i32 type.
|
270
|
+
|
271
|
+
> [!WARNING]
|
272
|
+
> This is something you have to be incredibly careful with, as Porffor expects most functions to return `(valtype, i32)`. Be incredibly careful when using this.
|
273
|
+
|
274
|
+
---
|
275
|
+
|
276
|
+
```
|
277
|
+
;; if both types are number
|
278
|
+
```
|
279
|
+
|
280
|
+
This is a comment. `;;` is Wasm's `//`.
|
281
|
+
|
282
|
+
---
|
283
|
+
|
284
|
+
```
|
285
|
+
local.get ${a+1}
|
286
|
+
i32.const 1
|
287
|
+
i32.eq
|
288
|
+
local.get ${b+1}
|
289
|
+
i32.const 1
|
290
|
+
i32.eq
|
291
|
+
i32.and
|
292
|
+
```
|
293
|
+
|
294
|
+
This part is a little more complicated, first you have to understand how Wasm represents function parameters and local variables in general. When looking at the decompiled output of something like `let a = 1;`, you'll likely see something like this:
|
295
|
+
```
|
296
|
+
f64.const 1
|
297
|
+
i32.const 1
|
298
|
+
local.set 1 ;; a#type (i32)
|
299
|
+
local.set 0 ;; a
|
300
|
+
```
|
301
|
+
Here the `i32.const 1` is equivalent to `TYPES.number`, which aligns with what we told Porffor to do, but what's up with the `local.set`s to a number? Well, internally locals are represented with indexes, and in this example `a` was assigned 0, and `a#type` was assigned 1.
|
302
|
+
|
303
|
+
That's where `local.get ${a+1}` comes from, it's Porffor's way of saying "get the local variable at index of `a` plus one". In most cases, this is the variable's type. The rest of the snippet is just checking if both of the parameters' types are equal to `TYPES.number`.
|
304
|
+
|
305
|
+
---
|
306
|
+
|
307
|
+
```
|
308
|
+
if
|
309
|
+
local.get ${a}
|
310
|
+
i32.from
|
311
|
+
local.set aCasted
|
312
|
+
|
313
|
+
local.get ${b}
|
314
|
+
i32.from
|
315
|
+
local.set bCasted
|
316
|
+
```
|
317
|
+
|
318
|
+
Here we start an if block, equivalent to JS's `if (...) {}`, and as the locals' names imply, cast them to `i32`s. There is one strange thing about this section though, if you look at Wasm's list of instructions you won't find a `i32.from`. This is because Porffor has custom instructions for converting to and from the valtype. In this case, converting the valtype into an `i32`. There are a few more of these instructions, but in general these instructions come in the format of `type.from` (create `type` from valtype) and `type.to` (create valtype from `type`). You can find a full list at the bottom of `codegen.js`.
|
319
|
+
|
320
|
+
---
|
321
|
+
|
322
|
+
```
|
323
|
+
local.get aCasted
|
324
|
+
local.get bCasted
|
325
|
+
i32.add
|
326
|
+
i32.const 1
|
327
|
+
return
|
328
|
+
end
|
329
|
+
```
|
330
|
+
|
331
|
+
Here, we get our two casted locals and add them together, returning the result and a `i32` with the value of 1. We then end the if block with the `end` instruction.
|
332
|
+
|
333
|
+
---
|
334
|
+
|
335
|
+
```
|
336
|
+
;; return (0, 0) otherwise
|
337
|
+
i32.const 0
|
338
|
+
i32.const 0
|
339
|
+
return
|
340
|
+
```
|
341
|
+
|
342
|
+
Finally, we return `(0, 0)` if either type is not a number. This example was very contrived, but should give you a good sense of how to use `Porffor.wasm`.
|
210
343
|
|
211
344
|
<br>
|
212
345
|
|
@@ -259,4 +392,9 @@ It will also log new passes/fails. Be careful as sometimes the overall passes ca
|
|
259
392
|
|
260
393
|
<br>
|
261
394
|
|
262
|
-
|
395
|
+
### Resources
|
396
|
+
|
397
|
+
- [MDN](https://developer.mozilla.org/en-US/), not only a great resource for learning JS, but also for implementing it, as it has high level descriptions of functionality, as well as links to the relevant portions of the spec that govern the feature.
|
398
|
+
- [WebAssembly Opcodes](https://pengowray.github.io/wasm-ops/), this website not only describes what each wasm instruction does but the necessary stack needed, and contains some other useful resources as well.
|
399
|
+
|
400
|
+
[^1]: The last two args are necessary for the Wasm instruction, but you don't need to worry about them (the first is alignment, the second is byte offset).
|
package/README.md
CHANGED
@@ -68,8 +68,8 @@ Expect nothing to work! Only very limited JS is currently supported. See files i
|
|
68
68
|
- `-O3` to enable advanceder opt (precompute const math). unstable!
|
69
69
|
|
70
70
|
## Limitations
|
71
|
-
- No full object support yet
|
72
71
|
- Little built-ins/prototype
|
72
|
+
- No object prototypes yet
|
73
73
|
- No async/promise/await
|
74
74
|
- No variables between scopes (except args and globals)
|
75
75
|
- No `eval()` etc (since it is AOT)
|
@@ -103,7 +103,7 @@ These include some early (stage 1/0) and/or dead (last commit years ago) proposa
|
|
103
103
|
- Declaring functions
|
104
104
|
- Calling functions
|
105
105
|
- `return`
|
106
|
-
- `let`/`const`/`var`
|
106
|
+
- Basic declarations (`let`/`const`/`var`)
|
107
107
|
- Some basic integer operators (`+-/*%`)
|
108
108
|
- Some basic integer bitwise operators (`&|`)
|
109
109
|
- Equality operators (`==`, `!=`, etc)
|
@@ -111,18 +111,18 @@ These include some early (stage 1/0) and/or dead (last commit years ago) proposa
|
|
111
111
|
- Some unary operators (`!`, `+`, `-`)
|
112
112
|
- Logical operators (`&&`, `||`)
|
113
113
|
- Declaring multiple variables in one (`let a, b = 0`)
|
114
|
+
- Array destructuring (`let [a, ...b] = foo`)
|
114
115
|
- Global variables (`var`/none in top scope)
|
115
|
-
-
|
116
|
-
- Bool literals as ints (not real type)
|
116
|
+
- Booleans
|
117
117
|
- `if` and `if ... else`
|
118
118
|
- Anonymous functions
|
119
119
|
- Setting functions using vars (`const foo = function() { ... }`)
|
120
120
|
- Arrow functions
|
121
|
-
- `undefined`/`null`
|
121
|
+
- `undefined`/`null`
|
122
122
|
- Update expressions (`a++`, `++b`, `c--`, etc)
|
123
123
|
- `for` loops (`for (let i = 0; i < N; i++)`, etc)
|
124
|
-
-
|
125
|
-
- `console.log`
|
124
|
+
- Basic objects (no prototypes)
|
125
|
+
- `console.log`
|
126
126
|
- `while` loops
|
127
127
|
- `break` and `continue`
|
128
128
|
- Named export funcs
|
@@ -131,7 +131,7 @@ These include some early (stage 1/0) and/or dead (last commit years ago) proposa
|
|
131
131
|
- Conditional/ternary operator (`cond ? a : b`)
|
132
132
|
- Recursive functions
|
133
133
|
- Bare returns (`return`)
|
134
|
-
- `throw` (literals only)
|
134
|
+
- `throw` (literals only, hack for `new Error`)
|
135
135
|
- Basic `try { ... } catch { ... }` (no error given)
|
136
136
|
- Calling functions with non-matching arguments (eg `f(a, b); f(0); f(1, 2, 3);`)
|
137
137
|
- `typeof`
|
@@ -145,11 +145,15 @@ These include some early (stage 1/0) and/or dead (last commit years ago) proposa
|
|
145
145
|
- String comparison (eg `'a' == 'a'`, `'a' != 'b'`)
|
146
146
|
- Nullish coalescing operator (`??`)
|
147
147
|
- `for...of` (arrays and strings)
|
148
|
+
- `for...in`
|
148
149
|
- Array member setting (`arr[0] = 2`, `arr[0] += 2`, etc)
|
149
150
|
- Array constructor (`Array(5)`, `new Array(1, 2, 3)`)
|
150
151
|
- Labelled statements (`foo: while (...)`)
|
151
152
|
- `do...while` loops
|
152
153
|
- Optional parameters (`(foo = 'bar') => { ... }`)
|
154
|
+
- Rest parameters (`(...foo) => { ... }`)
|
155
|
+
- `this`
|
156
|
+
- Constructors (`new Foo`)
|
153
157
|
|
154
158
|
### Built-ins
|
155
159
|
|
@@ -223,16 +227,27 @@ Porffor can run Test262 via some hacks/transforms which remove unsupported featu
|
|
223
227
|
|
224
228
|
## Codebase
|
225
229
|
- `compiler`: contains the compiler itself
|
226
|
-
- `
|
230
|
+
- `2c.js`: porffor's custom wasm-to-c engine
|
231
|
+
- `allocators.js`: static and dynamic allocators to power various language features
|
232
|
+
- `assemble.js`: assembles wasm ops and metadata into a wasm module/file
|
233
|
+
- `builtins.js`: all manually written built-ins of the engine (spec, custom. vars, funcs)
|
234
|
+
- `builtins_object.js`: all the various built-in objects (think `String`, `globalThis`, etc.)
|
235
|
+
- `builtins_precompiled.js`: dynamically generated builtins from the `builtins/` folder
|
227
236
|
- `codegen.js`: code (wasm) generation, ast -> wasm. The bulk of the effort
|
237
|
+
- `cyclone.js`: wasm partial constant evaluator (it is fast and dangerous hence "cyclone")
|
228
238
|
- `decompile.js`: basic wasm decompiler for debug info
|
229
239
|
- `embedding.js`: utils for embedding consts
|
230
240
|
- `encoding.js`: utils for encoding things as bytes as wasm expects
|
231
241
|
- `expression.js`: mapping most operators to an opcode (advanced are as built-ins eg `f64_%`)
|
242
|
+
- `havoc.js`: wasm rewrite library (it wreaks havoc upon wasm bytecode hence "havoc")
|
232
243
|
- `index.js`: doing all the compiler steps, takes code in, wasm out
|
233
244
|
- `opt.js`: self-made wasm bytecode optimizer
|
234
245
|
- `parse.js`: parser simply wrapping acorn
|
235
|
-
- `
|
246
|
+
- `pgo.js`: a profile guided optimizer
|
247
|
+
- `precompile.js`: the tool to generate `builtins_precompied.js`
|
248
|
+
- `prefs.js`: a utility to read command line arguments
|
249
|
+
- `prototype.js`: some builtin prototype functions
|
250
|
+
- `types.js`: definitions for each of the builtin types
|
236
251
|
- `wasmSpec.js`: "enums"/info from wasm spec
|
237
252
|
- `wrap.js`: wrapper for compiler which instantiates and produces nice exports
|
238
253
|
|
@@ -249,16 +264,16 @@ Porffor can run Test262 via some hacks/transforms which remove unsupported featu
|
|
249
264
|
- `test262`: test262 runner and utils
|
250
265
|
|
251
266
|
## Usecases
|
252
|
-
|
267
|
+
Currently, Porffor is seriously limited in features and functionality, however it has some key benefits:
|
253
268
|
- Safety. As Porffor is written in JS, a memory-safe language\*, and compiles JS to Wasm, a fully sandboxed environment\*, it is quite safe. (\* These rely on the underlying implementations being secure. You could also run Wasm, or even Porffor itself, with an interpreter instead of a JIT for bonus security points too.)
|
254
269
|
- Compiling JS to native binaries. This is still very early!
|
270
|
+
- Inline Wasm for when you want to beat the compiler in performance, or just want fine grained functionality.
|
271
|
+
- Potential for SIMD operations and other lower level concepts.
|
255
272
|
- More in future probably?
|
256
273
|
|
257
274
|
## Todo
|
258
275
|
No particular order and no guarentees, just what could happen soon™
|
259
276
|
|
260
|
-
- Objects
|
261
|
-
- Basic object expressions (eg `{}`, `{ a: 0 }`)
|
262
277
|
- Asur
|
263
278
|
- Support memory
|
264
279
|
- Support exceptions
|
@@ -272,8 +287,6 @@ No particular order and no guarentees, just what could happen soon™
|
|
272
287
|
- Runtime
|
273
288
|
- WASI target
|
274
289
|
- Run precompiled Wasm file if given
|
275
|
-
- Docs
|
276
|
-
- Update codebase readme section
|
277
290
|
- Cool proposals
|
278
291
|
- [Optional Chaining Assignment](https://github.com/tc39/proposal-optional-chaining-assignment)
|
279
292
|
- [Modulus and Additional Integer Math](https://github.com/tc39/proposal-integer-and-modulus-math)
|
@@ -303,7 +316,6 @@ Porffor intentionally does not use Wasm proposals which are not commonly impleme
|
|
303
316
|
- Exception handling (optional, only for errors)
|
304
317
|
- Tail calls (opt-in, off by default)
|
305
318
|
|
306
|
-
|
307
319
|
## FAQ
|
308
320
|
|
309
321
|
### 1. Why the name?
|
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;
|