Commit graph

259 commits

Author SHA1 Message Date
Luke Wilde
4db2efaecb LibJS/Bytecode: Implement yield* 2022-12-10 00:21:10 +00:00
Luke Wilde
758a4cb1a6 LibJS/Bytecode: Implement var/lexical binding destructuring in for/of 2022-12-10 00:21:10 +00:00
Andreas Kling
b894acd6b2 LibJS: Make one compact allocation for CallExpression and its Arguments
Instead of CallExpression storing its arguments in a Vector<Argument>,
we now custom-allocate the memory slot for CallExpression (and its
subclass NewExpression) so that it fits both CallExpression and its list
of Arguments in one allocation.

This reduces memory usage on twitter.com/awesomekling by 8.8 MiB :^)
2022-12-08 23:36:17 +00:00
Hendiadyoin1
fcc3348bc8 LibJS: Intercept returns through finally blocks in Bytecode
This is still not perfect, as we now actually crash in the
`try-finally-continue` tests, while we now succeed all
`try-catch-finally-*` tests.

Note that we do not yet go through the finally block when exiting the
unwind context through a break or continue.
2022-12-06 16:09:24 +03:30
Hendiadyoin1
133faa0acc LibJS: Remove FinishUnwind instruction
This is essentially a LeaveUnwind+Jump, so lets just do that, that will
make it easier to optimize it, or see unwind state transitions
2022-12-06 16:09:24 +03:30
Hendiadyoin1
fc332be2e5 LibJS: Leave unwind contexts on enter of finally blocks in Bytecode
Before we were doing so while exiting the catch-block, but not when
exiting the try-block.
This now centralizes the responsibility to exit the unwind context to
the finalizer, ignoring return/break/continue.
This makes it easier to handle the return case in a future commit.
2022-12-06 16:09:24 +03:30
Linus Groh
6e19ab2bbc AK+Everywhere: Rename String to DeprecatedString
We have a new, improved string type coming up in AK (OOM aware, no null
state), and while it's going to use UTF-8, the name UTF8String is a
mouthful - so let's free up the String name by renaming the existing
class.
Making the old one have an annoying name will hopefully also help with
quick adoption :^)
2022-12-06 08:54:33 +01:00
Luke Wilde
5bc3371226 LibJS: Perform received abrupt generator completions in the generator
Previously, throw and return completions would not be executed inside
the generator. This is incorrect, as throw and return need to perform
unwinds which can potentially execute more code inside the generator,
such as finally blocks.

This is done by also passing the completion type alongside the passed
in value. The continuation block will immediately extract and type and
value and perform the appropriate operation for the given type.

For normal completions, this is continuing as normal.
For throw completions, it will perform `throw <value>`.
For return completions, it will perform `return <value>`, which is a
`Yield return` in this case due to being inside a generator.

This also refactors GeneratorObject to properly send across the
completion type and value to the generator inside of trying to operate
on the completions itself.

This is a prerequisite for yield*, as it performs special iterator
operations when receiving a throw/return completion and does not
complete the generator like the regular yield would.

There's still more work to be done to make GeneratorObject::execute
be closer to the spec. It's mostly a restructuring of the existing
GeneratorObject::next_impl.
2022-11-26 12:55:59 +01:00
Luke Wilde
b914680f0c LibJS/Bytecode: Make yield by itself yield undefined 2022-11-26 12:55:59 +01:00
Andreas Kling
178f0b9971 LibJS: Support non-base-10 BigInt literals in bytecode VM
Fixes 39 tests in test262 and a handful in test-js. :^)
2022-10-19 19:58:15 +02:00
Andreas Kling
29935fe943 LibJS: Support for (x in obj) iteration in bytecode VM
We were mistakenly treating these as `for (x of obj)`. By reorganizing
the code a little bit, we actually support both kinds of iteration with
less duplication. :^)

Fixes 17 tests in test262.
2022-10-19 19:03:57 +02:00
Hendiadyoin1
490c097bc4 LibJS: Forward a string aproximation of the CallExpression to Call Ops
This gives us better debug output when analysing calls to `undefined`
and also fixes multiple test-js cases expecting an
`(evaluated from $Expression)` in the error message.

This also refactors out the generation of that string, to avoid code
duplication with the AST interpreter.
2022-10-17 01:36:41 +02:00
Hendiadyoin1
89408d5f64 LibJS: Handle argument spreading in the bytecode vm 2022-10-01 00:04:02 +01:00
Hendiadyoin1
ae52ae8f9f LibJS: Add support for SpreadExpressions in array literals for bytecode
For this it adds another opcode `Append $lhs` which appends the
accumulator to the Array in $lhs, optionally spreading it.
2022-10-01 00:04:02 +01:00
Hendiadyoin1
4235b2020f LibJS: Switch to array-calls in the bytecode vm
This will make it easier to implement spreading arguments.
2022-10-01 00:04:02 +01:00
Hendiadyoin1
ab763a56f6 LibJS: Allow SpreadExpressions to generate bytecode 2022-10-01 00:04:02 +01:00
Hendiadyoin1
21ae882cfd LibJS: Implement SuperCall for the Bytecode-VM 2022-08-31 15:22:36 +01:00
Luke Wilde
fe2efbb2fc LibJS/Bytecode: Implement initializers for array binding patterns 2022-07-18 09:00:21 +01:00
Luke Wilde
0151dc562a LibJS/Bytecode: Implement destructuring assignment 2022-07-18 09:00:21 +01:00
Luke Wilde
f99f5d740e LibJS/Bytecode: Evaluate LHS of assignment before RHS
We had the same issue with the AST interpreter, see issue #3689.
2022-07-18 09:00:21 +01:00
Luke Wilde
896c477107 LibJS/Bytecode: Don't begin breakable scope before variable scope in for
This is no longer required, since the variable scope is ended after
switching to the end block, which means that LeaveLexicalEnvironment
will always be generated instead of depending on the unwind mechanism
to handle it for us.
2022-07-18 09:00:21 +01:00
Luke Wilde
3a48c7fdaf LibJS/Bytecode: Check for lexical bindings only in current scope
BlockDeclarationInstantiation takes as input the new lexical
environment that was created and checks if there is a binding for the
current name only in this new scope.

This allows shadowing lexical variables and prevents us crashing due to
an already initialized lexical variable in this case:
```js
let x = 1;
{
    let x = 1;
}
```
2022-07-18 09:00:21 +01:00
Luke Wilde
c55a4c7f30 LibJS/Bytecode: Create global variables before setting them
This allows them to be accessed before assignment, and also prevents
throwing in strict mode as we are trying to set a non-existent
variable.
2022-07-18 09:00:21 +01:00
Luke Wilde
c153d1779e LibJS/Bytecode: End the for variable scope at the start of its end block
If the for loop's body is not block terminated, we will generate a Jump
to the end block which will block terminate the body. Then, we ended
the lexical variable scope if needed. However, since the body is now
block terminated, the "LeaveLexicalEnvironment" instruction that is
generated by end_variable_scope is now dropped on the floor.

This fixes this by moving it to the beginning of the end block.
2022-06-30 15:59:55 +01:00
Luke Wilde
bc08d39754 LibJS/Bytecode: Make for, do/while and while always switch to end block
Previously we only did this if the body block was not terminated.
If it was, all future codegen would happen in this block terminated
body block until another switch occurred, dropping all generated
instructions in this time on the floor.
2022-06-30 18:35:18 +04:30
Luke Wilde
125a71d36d LibJS/Bytecode: Define named functions as a variable inside their scope
This allows you to recurse into a named function that is stored in a
variable. For example, this would previously print "wrong" instead of
"right":
```js
function g() { console.log("wrong") }
f = function g(i) { if (i !== 1) g(1); else console.log("right"); }
f()
```
2022-06-13 07:13:03 +04:30
Luke Wilde
77f88d00e0 LibJS/Bytecode: Make return; return undefined
Previously it would return whatever was in the accumulator.
2022-06-13 07:13:03 +04:30
Luke Wilde
482a827346 LibJS/Bytecode: Make typeof return "undefined" on unresolvable IDs
Previously it would throw instead of returning "undefined" for
`typeof Identifier` if Identifier does not exist.
2022-06-13 07:13:03 +04:30
Luke Wilde
c0fadfb9b7 LibJS/Bytecode: Implement break/continue labels
This is done by keeping track of all the labels that apply to a given
break/continue scope alongside their bytecode target. When a
break/continue with a label is generated, we scan from the most inner
scope to the most outer scope looking for the label, performing any
necessary unwinds on the way. Once the label is found, it is then
jumped to.
2022-06-13 07:13:03 +04:30
Linus Groh
9f3f3b0864 LibJS: Remove implicit wrapping/unwrapping of completion records
This is an editorial change in the ECMA-262 spec, with similar changes
in some proposals.

See:
- https://github.com/tc39/ecma262/commit/7575f74
- https://github.com/tc39/proposal-array-grouping/commit/df899eb
- https://github.com/tc39/proposal-shadowrealm/commit/9eb5a12
- https://github.com/tc39/proposal-shadowrealm/commit/c81f527
2022-05-03 01:09:29 +02:00
Ali Mohammad Pur
4b5a9bab34 LibJS: Actually generate a lexical env for SwitchStatement in BC
We had code for this in ScopeNode, but that function was never called
for a SwitchStatement.
This fixes a bunch of scoping tests for switch.
2022-04-05 11:46:48 +02:00
Ali Mohammad Pur
0e1943937c LibJS: Use InitializeOrSet to initialize function declarations in BC
A function may be redefined, in which case the existing binding is
expected to be reused.
2022-04-05 11:46:48 +02:00
Idan Horowitz
086969277e Everywhere: Run clang-format 2022-04-01 21:24:45 +01:00
Ali Mohammad Pur
7ea095feb0 LibJS: Don't assume that for-in/of target is a variable on LHS::Assign
e.g. `for ([foo.bar] in ...)` is actually a binding pattern.
2022-03-31 18:11:08 +02:00
Ali Mohammad Pur
56c0fdc1c4 LibJS: Implement codegen for MemberExpression binding patterns 2022-03-31 18:11:08 +02:00
Ali Mohammad Pur
007ffcd763 LibJS: Implement bytecode generation for all ObjectExpression properties 2022-03-31 18:11:08 +02:00
Luke Wilde
7cc53b7ef1 LibJS/Bytecode: Implement the delete unary expression
`delete` has to operate directly on Reference Records, so this
introduces a new set of operations called DeleteByValue, DeleteVariable
and DeleteById. They operate similarly to their Get counterparts,
except they end in creating a (temporary) Reference and calling delete_
on it.
2022-03-28 14:05:33 +02:00
Luke Wilde
88901182b8 LibJS: Generate update Jump in for/in/of only if block is not terminated
The body of for/in/of can contain an unconditional block terminator
(e.g. return, throw), so we have to check for that before generating
the Jump to the loop update block.
2022-03-28 14:05:33 +02:00
Luke Wilde
eac5534ce4 LibJS/Bytecode: Add support for new.target 2022-03-19 22:01:52 +01:00
Ali Mohammad Pur
8f7021faf7 LibJS: Implement bytecode generation for For-In/Of statements
This also implements the rather interesting behaviour that #12772 relies
on, so this fixes that bug in BC mode (the AST interp remains affected).
2022-03-19 12:51:29 +01:00
Luke Wilde
db1236b336 LibJS/Bytecode: Fix typo in object binding an entry with no alias
In object binding, we would attempt to get NonnullRefPtr<Identifier>
from alias on the alias.has<Empty>() code path. In this case, we need
to get it from name instead.
2022-03-15 11:57:51 +03:30
Luke Wilde
515f3e0b85 LibJS/Bytecode: End for's variable scope after update block generation
The update block can generate bytecode that refers to the lexical
environment, so we have to end the scope after it has been generated.
Previously the Jump to the update block would terminate the block,
causing us to leave the lexical environment just before jumping to the
update block.
2022-03-15 11:57:51 +03:30
Luke Wilde
1fc6bbcdc3 LibJS: Stop generating switch case statements on block termination
After we terminate a block (e.g. break, continue), we cannot generate
anymore bytecode for the block. This caused us to crash with this
example code:
```
a = 0;
switch (a) {
    case 0:
        break;
        console.log("hello world");
}
```
Anything after a block terminating instruction is considered
unreachable code, so we can safely skip any statements after it.
2022-03-15 11:57:51 +03:30
Ali Mohammad Pur
a37bee919a LibJS: Use ranges instead of specifying all registers for NewArray
Listing all the registers will lead to the inability to allocate enough
space in one basic block (as there can be an arbitrary number of
registers used), instead switch to specifying the range of registers
used and save a lot of space in the process.
2022-03-14 21:15:27 +03:30
Luke Wilde
750b69540e LibJS/Bytecode: Setup declarative environment for lexical for statements 2022-03-14 21:15:27 +03:30
Luke Wilde
97af7654dd LibJS/Bytecode: Setup declarative environment for catch with variable 2022-03-14 21:15:27 +03:30
Luke Wilde
04774f923f LibJS/Bytecode: Setup lexical environment boundary for with statements
This allows us to properly unwind the object environment for `with` on
a block terminating instruction, e.g. an unconditional throw.
2022-03-14 21:15:27 +03:30
Luke Wilde
9f4cc6435d LibJS/Bytecode: Unwind to closest unwind boundary on Throw
This will leave any lexical/variable environments on the way to the
closest unwind context boundary.

This will not leave the closest unwind context, as we still need the
unwind context to perform the Throw instruction correctly.
2022-03-14 21:15:27 +03:30
Luke Wilde
0356239f3e LibJS/Bytecode: Unconditionally end break/continuable scopes
Previously we would only end these scopes if the block was not
terminated. If the block was generated, we would not end the scope
and would generate other bytecode with these scopes still open.

These functions do not generate any code, so they can be used even if
the current block is terminated. The enter and end scope functions are
only used to track where to unwind to when break/continue are used.
2022-03-14 21:15:27 +03:30
Ali Mohammad Pur
2000251333 LibJS: Implement bytecode generation for WithStatement 2022-03-13 17:50:21 +01:00