Commit graph

84 commits

Author SHA1 Message Date
Idan Horowitz
005d75656e LibCrypto: Replace from_base{2,8,10,16}() & to_base10 with from_base(N)
This allows us to support parsing and serializing BigIntegers to and
from any base N (such that 2 <= N <= 36).
2021-06-29 16:55:54 +01:00
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
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
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
ce04c2259f LibJS: Restructure and fully implement BindingPatterns 2021-06-19 09:38:26 +02:00
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
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
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
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
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
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
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
b78f1c1261 LibJS: Generate bytecode for throw statements 2021-06-09 20:04:11 +02:00
Gunnar Beutner
6a0d1fa259 LibJS: Store strings in a string table
Instead of using Strings in the bytecode ops this adds a global string
table to the Executable struct which individual operations can refer
to using indices. This brings bytecode ops one step closer to being
pointer free.
2021-06-09 17:42:52 +02:00
Andreas Kling
59eedd6de0 LibJS: Implement bytecode generation for UpdateExpression :^)
Added Increment and Decrement bytecode ops to support this. Postfix
updates use a temporary register to preserve the original value.

Note that this patch only implements Identifier updates. Member
expression updates are a TODO.
2021-06-09 11:40:38 +02:00
Andreas Kling
99ffcc28c2 LibJS: Print the name of AST nodes that are missing generate_bytecode()
This way you know which one it is right away. :^)
2021-06-09 09:32:09 +02:00
Luke
597e0d95fe LibJS: Only set element in array literal to an empty value if it's null
This avoids an unnecessary empty load that immediately gets overridden.

For example, `[1,,]` would appear as:
[   0] EnterScope
[  10] LoadImmediate value:<empty>
[  28] LoadImmediate value:1
[  40] Store dst:$1
[  48] LoadImmediate value:<empty>
[  60] Store dst:$2
[  68] NewArray, elements:[$1,$2]

But now appears as:
[   0] EnterScope
[  10] LoadImmediate value:1
[  28] Store dst:$1
[  30] LoadImmediate value:<empty>
[  48] Store dst:$2
[  50] NewArray, elements:[$1,$2]
2021-06-09 09:14:40 +02:00
Ali Mohammad Pur
01e8f0889a LibJS: Generate bytecode in basic blocks instead of one big block
This limits the size of each block (currently set to 1K), and gets us
closer to a canonical, more easily analysable bytecode format.
As a result of this, "Labels" are now simply entries to basic blocks.
Since there is no more 'conditional' jump (as all jumps are always
taken), JumpIf{True,False} are unified to JumpConditional, and
JumpIfNullish is renamed to JumpNullish.
Also fixes #7914 as a result of reimplementing the loop logic.
2021-06-09 09:07:29 +02:00
Matthew Olsson
f286cf1792 LibJS: Fix not executing the expression of a return statement 2021-06-09 01:33:38 +02:00
Gunnar Beutner
a1e5711a27 LibJS: Generate bytecode for array expressions 2021-06-09 01:27:18 +02:00
Andreas Kling
b8a5ea1f8d Revert "LibJS: Add bytecode instruction handles"
This reverts commit a01bd35c67.

This broke simple programs like:

function sum(a, b) { return a + b; }
console.log(sum(1, 2));
2021-06-09 00:50:42 +02:00
Matthew Olsson
a01bd35c67 LibJS: Add bytecode instruction handles
This change removes the mmap inside of Block in favor of a growing
vector of bytes. This is favorable for two reasons:
  - We don't take more space than we need
  - There is no limit to the growth of the vector (previously, if
    the Block overstepped its 64kb boundary, it would just crash)

However, if that vector happens to resize, any pointer pointing into
that vector would become invalid. To avoid this, this commit adds an
InstructionHandle<Op> class which just stores a block and an offset
into that block.
2021-06-09 00:37:17 +02:00
Gunnar Beutner
5ff85abe8c LibJS: Make sure loop results are initialized
This ensures that "while", do...while, "for" expressions have a
properly initialized result value even if the user terminated
the loop body via break or the loop body wasn't executed at all.
2021-06-08 21:49:52 +01:00
Matthew Olsson
9bed2e4f4a LibJS: Introduce an accumulator register to Bytecode::Interpreter
This commit introduces the concept of an accumulator register to
LibJS's bytecode interpreter. The accumulator register is always
register 0, and most simple instructions use it for reading and
writing.

Not only does this slim down the AST, but it also simplifies a lot of
the code. For example, the generate_bytecode methods no longer need
to return an Optional<Register>, as any opcode which has a "return"
value will always put it into the accumulator.

This also renames the old Op::Load to Op::LoadImmediate, and uses
Op::Load to load from a register into the accumulator. There is
also an Op::Store to put the value in the accumulator into another
register.
2021-06-08 21:00:12 +02:00
Gunnar Beutner
75a12bc2b7 LibJS: Generate bytecode for template literals 2021-06-08 19:47:32 +02:00
Linus Groh
68ce69db88 LibJS: Add for loop bytecode generation 2021-06-08 11:59:32 +02:00
Gunnar Beutner
50ece3dd1b LibJS: Implement bytecode generation for BigInts 2021-06-08 10:57:28 +01:00
Gunnar Beutner
0975e08285 LibJS: Make if yield undefined for the else branch if it is missing 2021-06-08 11:38:48 +02:00
Gunnar Beutner
d9989fd259 LibJS: Remove redundant jump for IfStatements 2021-06-08 11:38:48 +02:00
Gunnar Beutner
ef83872f62 LibJS: Make JumpIf{True,False,Nullish} inherit from Jump
This saves a few lines in LogicalExpression::generate_bytecode.
2021-06-08 11:38:48 +02:00
Luke
1dc31842cb LibJS: Add sequence expression bytecode generation 2021-06-08 11:20:10 +02:00