Commit graph

126 commits

Author SHA1 Message Date
Andreas Kling
e59bf87374 Userland: Replace VERIFY(is<T>) with verify_cast<T>
Instead of doing a VERIFY(is<T>(x)) and *then* casting it to T, we can
just do the cast right away with verify_cast<T>. :^)
2021-06-24 21:13:09 +02:00
Andreas Kling
c2ad599783 LibJS: Rename CallFrame => ExecutionContext
This struct represents what the ECMAScript specification calls an
"execution context" so let's use the same terminology. :^)
2021-06-24 19:28:00 +02:00
Andreas Kling
8a3c9d9851 LibJS: Remove direct argument loading since it was buggy
The parser doesn't always track lexical scopes correctly, so let's not
rely on that for direct argument loading.

This reverts the LoadArguments bytecode instruction as well. We can
bring these things back when the parser can reliably tell us that
a given Identifier is indeed a function argument.
2021-06-22 22:20:17 +02:00
Andreas Kling
1f8b6ac3c3 LibJS: Begin implementing GlobalEnvironmentRecord
These represent the outermost scope in the environment record
hierarchy. The spec says they should be a "composite" of two things:

- An ObjectEnvironmentRecord wrapping the global object
- A DeclarativeEnvironmentRecord for other declarations

It's not yet clear to me how this should work, so this patch only
implements the first part, an object record wrapping the global object.
2021-06-22 18:44:53 +02:00
Andreas Kling
1d20380859 LibJS: Split the per-call-frame environment into lexical and variable
To better follow the spec, we need to distinguish between the current
execution context's lexical environment and variable environment.

This patch moves us to having two record pointers, although both of
them point at the same environment records for now.
2021-06-22 18:44:53 +02:00
Andreas Kling
08510a0c80 LibJS: Rename VM::current_scope() => current_environment_record()
And rename some related functions that wrapped this as well.
2021-06-21 23:49:50 +02:00
Andreas Kling
6c6dbcfc36 LibJS: Rename Environment Records so they match the spec :^)
This patch makes the following name changes:

- ScopeObject => EnvironmentRecord
- LexicalEnvironment => DeclarativeEnvironmentRecord
- WithScope => ObjectEnvironmentRecord
2021-06-21 23:49:50 +02:00
Matthew Olsson
df65ff8a1e LibJS: Add bytecode support for regexp literals 2021-06-21 00:28:07 +02:00
Gunnar Beutner
fbaf763e2a LibJS: Let if yield undefined for branches that don't yield a value
According to 13.6.7 the return value for if expressions should be
undefined when the branch statements don't yield a value.
2021-06-20 15:01:11 +02:00
Matthew Olsson
25baefdd1e LibJS: Support object rest elements in the bytecode interpreter 2021-06-19 09:38:26 +02:00
Matthew Olsson
57b9a228ab LibJS: Support array rest elements in the bytecode interpreter 2021-06-19 09:38:26 +02:00
Matthew Olsson
7983324639 LibJS: Implement array destructuring for the bytecode interpreter 2021-06-19 09:38:26 +02:00
Matthew Olsson
1f8e643ef0 LibJS: Support object destructuring in the bytecode interpreter 2021-06-19 09:38:26 +02:00
Matthew Olsson
f39ab2e60a LibJS: Add JumpUndefined bytecode 2021-06-19 09:38:26 +02:00
Matthew Olsson
3ee627909a LibJS: Ensure GetBy{Id,Value} never load <empty> into the accumulator 2021-06-19 09:38:26 +02:00
Matthew Olsson
ce04c2259f LibJS: Restructure and fully implement BindingPatterns 2021-06-19 09:38:26 +02:00
Linus Groh
317b88a8c3 LibJS: Replace Object's create_empty() with create() taking a prototype
This now matches the spec's OrdinaryObjectCreate() across the board:
instead of implicitly setting the created object's prototype to
%Object.prototype% and then in many cases setting it to a nullptr right
away, it now has an 'Object* prototype' parameter with _no default
value_. This makes the code easier to compare with the spec, very clear
in terms of what prototype is being used as well as avoiding unnecessary
shape transitions.

Also fixes a couple of cases were we weren't setting the correct
prototype.

There's no reason to assume that the object would not be empty (as in
having own properties), so let's follow our existing pattern of
Type::create(...) and simply call it 'create'.
2021-06-16 22:49:04 +01:00
Ali Mohammad Pur
1414c7b049 LibJS: Add a basic pass manager and add some basic passes
This commit adds a bunch of passes, the most interesting of which is a
pass that merges blocks together, and a pass that places blocks that
flow into each other next to each other, and a very simply pass that
removes duplicate basic blocks.
Note that this does not remove the jump at the end of each block in that
pass to avoid scope creep in the passes.
2021-06-15 22:06:33 +04:30
Ali Mohammad Pur
e81fd7106b LibJS: Rename the overridden Instruction methods to foo_impl
These are pretty hairy if someone forgets to override one, as the
catchall function in Instruction will keep calling itself over and over
again, leading to really hard-to-debug situations.
2021-06-15 22:06:33 +04:30
Ali Mohammad Pur
4c7c7c38e2 LibJS: Make EnterUnwindContext a terminator op
Otherwise a basic block could have multiple outgoing edges without
having much reason to do so.
2021-06-15 22:06:33 +04:30
Ali Mohammad Pur
e73b142a97 LibJS: Make basic block size customizable
And keep the default 4 KiB for the code generator.
2021-06-15 22:06:33 +04:30
Ali Mohammad Pur
3194177dce LibJS: Correctly parse yield-from expressions
This commit implements parsing for `yield *expr`, and the multiple
ways something can or can't be parsed like that.
Also makes yield-from a TODO in the bytecode generator.
Behold, the glory of javascript syntax:
```js
// 'yield' = expression in generators.
function* foo() {
    yield
    *bar; // <- Syntax error here, expression can't start with *
}

// 'yield' = identifier anywhere else.
function foo() {
    yield
    *bar; // Perfectly fine, this is just `yield * bar`
}
```
2021-06-14 13:06:08 +01:00
Andreas Kling
91fbeeab72 LibJS: Add LoadArgument bytecode instruction for fast argument access
This is generated for Identifier nodes that represent a function
argument variable. It loads a given argument index from the current
call frame into the accumulator.
2021-06-14 11:26:12 +02:00
Idan Horowitz
6913f06b6f LibJS: Store and maintain an "execution generation" counter
This counter is increased each time a synchronous execution sequence
completes, and will allow us to emulate the abstract operations
AddToKeptObjects & ClearKeptObjects efficiently.
2021-06-12 18:39:23 +01:00
Andreas Kling
06fdc26656 LibJS: Fix all clang-tidy warnings in Bytecode/Op.h
- Add missing explicit to constructors
- Use move() where appropriate
2021-06-12 11:22:46 +02:00
Gunnar Beutner
6a78b44c22 LibJS: Add missing length() method for NewArray 2021-06-12 11:14:55 +02:00
Gal Horowitz
b47d117bd2 LibJS: Add bytecode generation for simple ObjectExpressions
Bytecode is now generated for object literals which only contain simple
key-value pairs (i.e. no spread, getters or setters)
2021-06-11 22:44:17 +02:00
Ali Mohammad Pur
8b3f8879c1 LibJS: Use an enum class instead of 'bool is_generator'
This avoid confusion in the order of the multiple boolean parameters
that exist.
2021-06-11 19:42:58 +04:30
Marcin Gasperowicz
a64089092f LibJS: Implement bytecode generation for switch 2021-06-11 13:12:26 +02:00
Andreas Kling
af48a066c6 LibJS: Add bytecode generation for FunctionExpression :^) 2021-06-11 10:46:46 +02:00
Andreas Kling
9ee5029bc5 LibJS: Basic bytecode support for computed member expressions
Expressions like foo[1 + 2] now work, and you can assign to them
as well! :^)
2021-06-11 00:36:18 +02:00
Ali Mohammad Pur
3234697eca LibJS: Implement generator functions (only in bytecode mode) 2021-06-11 00:30:09 +02:00
Ali Mohammad Pur
c53a86a3fe LibJS: Resolve the `this' value in call expression bytecode 2021-06-11 00:30:09 +02:00
Ali Mohammad Pur
4cfdfb6a88 LibJS: Automatically split linear bytecode into multiple blocks
...instead of crashing :^)
2021-06-11 00:30:09 +02:00
Andreas Kling
93a07ba962 LibJS: Remove GlobalObject& argument from VM::construct()
We can just get the global object from the constructor function.
2021-06-10 23:17:29 +02:00
Andreas Kling
f5feb1d2cd LibJS: Very basic support for "new" construction in bytecode VM
This patch adds a CallType to the Bytecode::Op::Call instruction,
which can be either Call or Construct. We then generate Construct
calls for the NewExpression AST node.

When executed, these get fed into VM::construct().
2021-06-10 23:01:49 +02:00
Andreas Kling
c3c68399b5 LibJS: Generate bytecode for entering nested lexical environments
This adds a new PushLexicalEnvironment instruction that creates a new
LexicalEnvironment and pushes it on the VM's scope stack.

There is no corresponding PopLexicalEnvironment instruction yet,
so this will behave incorrectly with let/const scopes for example.
2021-06-10 22:20:23 +02:00
Andreas Kling
d560ee118d LibJS: Allocate 4 KiB for Bytecode::BasicBlock
There's no reason not to, since we're using mmap() for these anyway
and that gives us memory in 4 KiB increments. :^)
2021-06-10 21:59:49 +02:00
Andreas Kling
22c803d8e5 LibJS: Always keep the global object in bytecode VM register $1 2021-06-10 21:59:49 +02:00
Andreas Kling
b3e6a6c1cd LibJS: Perform function instantiation in bytecode
This replaces Bytecode::Op::EnterScope with a new NewFunction op that
instantiates a ScriptFunction from a given FunctionNode (AST).

This is then used to instantiate the local functions directly from
bytecode when entering a ScopeNode. :^)
2021-06-10 21:59:49 +02:00
Andreas Kling
941be2dcc2 LibJS: Add empty bytecode generation for VariableDeclaration
These will be partly handled by the relevant ScopeNode due to
hoisting, same basic idea as function declarations.

VariableDeclaration needs to do some work, but let's stub it out
first and start empty.
2021-06-10 21:59:49 +02:00
Gunnar Beutner
67cc31a74f LibJS: Implement bytecode generation for try..catch..finally
EnterUnwindContext pushes an unwind context (exception handler and/or
finalizer) onto a stack.

LeaveUnwindContext pops the unwind context from that stack.

Upon return to the interpreter loop we check whether the VM has an
exception pending. If no unwind context is available we return from the
loop. If an exception handler is available we clear the VM's exception,
put the exception value into the accumulator register, clear the unwind
context's handler and jump to the handler. If no handler is available
but a finalizer is available we save the exception value + metadata (for
 later use by ContinuePendingUnwind), clear the VM's exception, pop the
unwind context and jump to the finalizer.

ContinuePendingUnwind checks whether a saved exception is available. If
no saved exception is available it jumps to the resume label. Otherwise
it stores the exception into the VM.

The Jump after LeaveUnwindContext could be integrated into the
LeaveUnwindContext instruction. I've kept them separate for now to make
the bytecode more readable.

> try { 1; throw "x" } catch (e) { 2 } finally { 3 }; 4
1:
[   0] EnterScope
[  10] EnterUnwindContext handler:@4 finalizer:@3
[  38] EnterScope
[  48] LoadImmediate 1
[  60] NewString 1 ("x")
[  70] Throw
<for non-terminated blocks: insert LeaveUnwindContext + Jump @3 here>
2:
[   0] LoadImmediate 4
3:
[   0] EnterScope
[  10] LoadImmediate 3
[  28] ContinuePendingUnwind resume:@2
4:
[   0] SetVariable 0 (e)
[  10] EnterScope
[  20] LoadImmediate 2
[  38] LeaveUnwindContext
[  3c] Jump @3

String Table:
0: e
1: x
2021-06-10 21:59:46 +02:00
Gunnar Beutner
319a60043b LibJS: Let the bytecode interpreter set the VM's last value 2021-06-10 21:47:25 +02:00
xyanrch
a0412e0d5e LibJS: Implement bytecode generation for BreakStatement 2021-06-10 21:48:20 +04:30
Luke
5da94b30eb LibJS: Add logical assignment bytecode generation 2021-06-10 00:28:34 +02:00
Gunnar Beutner
9dc9ddbf82 LibJS: Fix evaluation order for tagged template literals
This ensures that the tag function is evaluated first.
2021-06-09 22:26:27 +02:00
Gunnar Beutner
2d48fe894f LibJS: Generate bytecode for tagged template literals 2021-06-09 21:54:31 +02:00
Gunnar Beutner
25ab31219c LibJS: Fix the return value for TemplateLiteral
This ensures that the bytecode generated for TemplateLiterals returns
the correct value.
2021-06-09 21:50:39 +02:00
Gunnar Beutner
6af7e74a25 LibJS: Don't generate code after we've encountered a terminating op 2021-06-09 20:04:11 +02:00
Gunnar Beutner
d198e41f74 LibJS: Stop bytecode execution after we've encountered an exception 2021-06-09 20:04:11 +02:00