Commit graph

79 commits

Author SHA1 Message Date
Daniel Bertalan
cff8f56ce7 LibJS/Bytecode: Do not unwind eagerly after throwing Await
If an exception was thrown while evaluating the argument of an `await`
expression, we should jump to the continuation block instead of eagerly
rejecting the caller async function.

This restores the behavior prior to the addition of the separate `Await`
instruction in d66eb4e3.
2023-07-15 11:27:43 +02:00
Daniel Bertalan
e3f65f215d LibJS/Bytecode: Do not rethrow caught exception from finally
If the exception from the `try` block has already been caught by
`catch`, we need to clear the saved exception before entering `finally`
so that ContinuePendingUnwind will not re-throw it.

9 new passes on test262 :^)
2023-07-14 17:05:29 +02:00
Andreas Kling
de8e4b1853 LibJS/Bytecode: Cache object own property accesses
The instructions GetById and GetByIdWithThis now remember the last-seen
Shape, and if we see the same object again, we reuse the property offset
from last time without doing a new lookup.

This allows us to use Object::get_direct(), bypassing the entire lookup
machinery and saving lots of time.

~23% speed-up on Kraken/ai-astar.js :^)
2023-07-09 12:54:06 +02:00
Andreas Kling
dc884aa0d3 LibJS/Bytecode: Remove unnecessary variable environment stack
The var environments will unwind as needed with the ExecutionContext
and there's no need to include it in the unwind info.

We still need to do this for lexical environments though, since they
can have short local lifetimes inside a function.
2023-07-02 18:30:02 +02:00
Andreas Kling
fb979dcf34 LibJS/Bytecode: Make Bytecode::Interpreter participate in GC marking
Since the relationship between VM and Bytecode::Interpreter is now
clear, we can have VM ask the Interpreter for roots in the GC marking
pass. This avoids having to register and unregister handles and
MarkedVectors over and over.

Since GeneratorObject can also own a RegisterWindow, we share the code
in a RegisterWindow::visit_edges() helper.

~4% speed-up on Kraken/stanford-crypto-ccm.js :^)
2023-07-02 14:50:02 +02:00
Andreas Kling
1efe4b58aa LibJS/Bytecode: Store current interpreter register window as a Span
This avoids a bunch of indirections on every single register access.

~17% speed-up on Kraken/stanford-crypto-aes.js :^)
2023-07-01 20:29:12 +01:00
Daniel Bertalan
cc9ec6693b LibJS: Remove the concept of bytecode optimization levels
While this would be useful in the future for implementing a multi-tiered
optimization strategy, currently a binary on/off is enough for us. This
removes the confusingly on-by-default `OptimizationLevel::None` option
which made the optimization pipeline a no-op even if
`Bytecode::Interpreter::set_optimizations_enabled` had been called.

Fixes #15982
2023-06-27 14:35:23 +03:30
Daniel Bertalan
e012565898 test262-runner+js: Respect the bytecode optimizations enabled flag 2023-06-27 14:35:23 +03:30
Andreas Kling
6537ed8fff LibJS/Bytecode: Simplify Bytecode::Interpreter lifetime model
The JS::VM now owns the one Bytecode::Interpreter. We no longer have
multiple bytecode interpreters, and there is no concept of a "current"
bytecode interpreter.

If you ask for VM::bytecode_interpreter_if_exists(), it will return null
if we're not running the program in "bytecode enabled" mode.

If you ask for VM::bytecode_interpreter(), it will return a bytecode
interpreter in all modes. This is used for situations where even the AST
interpreter switches to bytecode mode (generators, etc.)
2023-06-22 21:16:17 +02:00
Andreas Kling
9c568282dc Ladybird+LibJS: Add CLI option to run browser with LibJS bytecode VM
This required quite a bit of plumbing, but now you can run

    ladybird --use-bytecode
2023-06-17 14:16:45 +02:00
Andreas Kling
d063f35afd LibJS/Bytecode: Leave GlobalDeclarationInstantiation in C++
Don't try to implement this AO in bytecode. Instead, the bytecode
Interpreter class now has a run() API with the same inputs as the AST
interpreter. It sets up the necessary environments etc, including
invoking the GlobalDeclarationInstantiation AO.
2023-06-16 08:40:45 +02:00
Andreas Kling
ce634957c1 LibJS/Bytecode: Restore old environments when an exception is caught
Unwind contexts now remember the lexical and variable environments in
effect when they were created. If an exception is caught, we revert
to those environments in the running execution context.
2023-05-14 06:18:28 +02:00
Matthew Olsson
7c0c1c8f49 LibJS+LibWeb: Wrap raw JS::Cell*/& fields in GCPtr/NonnullGCPtr 2023-03-15 08:48:49 +01:00
Andreas Kling
359d6e7b0b Everywhere: Stop using NonnullOwnPtrVector
Same as NonnullRefPtrVector: weird semantics, questionable benefits.
2023-03-06 23:46:35 +01:00
Hendiadyoin1
de514f29ad LibJS: Align codegen AwaitExpressions to YieldExpressions
We use generators in bytecode to approximate async functions, but the
code generated by AwaitExpressions did not have the value processing
paths that Yield requires, eg the `generator.throw()` path, which is
used by AsyncFunctionDriverWrapper to signal Promise rejections.
2023-02-26 19:40:09 +01:00
Hendiadyoin1
1f6a0ef6e0 LibJS: Don't enter finally blocks upon yield in bytecode mode 2023-02-26 19:40:09 +01:00
Hendiadyoin1
d65488b80c LibJS: Generate unwind chains for continue in Bytecode
This works similar to `break`
The `try-finally-continue` still do not pass with this, likely because
of binding issues.
2023-02-26 19:40:09 +01:00
Hendiadyoin1
f5376cb282 LibJS: Generate unwind chains for break in Bytecode
This uses a newly added instruction `ScheduleJump`
This instruction tells the finally proceeding it, that instead of
jumping to it's next block it should jump to the designated block.
2023-02-26 19:40:09 +01:00
Linus Groh
09d40bfbb2 Everywhere: Use _{short_,}string to create Strings from literals 2023-02-25 20:51:49 +01:00
Timothy Flynn
24e9cea524 LibJS: Convert remaining usages of Value::TDSWOSE to Value::TSWOSE
Note the couple of cases using MUST are just debugging statements.
2023-02-16 14:32:22 +01:00
Timothy Flynn
b245300ba1 LibJS+Everywhere: Deprecate Value::to_string_without_side_effects 2023-02-16 14:32:22 +01:00
Timothy Flynn
f3db548a3d AK+Everywhere: Rename FlyString to DeprecatedFlyString
DeprecatedFlyString relies heavily on DeprecatedString's StringImpl, so
let's rename it to A) match the name of DeprecatedString, B) write a new
FlyString class that is tied to String.
2023-01-09 23:00:24 +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
c2108489a5 LibJS: Don't try to manage unwind contexts in the execution loop in BC
We are already doing this in a good manner via the generated code,
doing so in the execution loop as well will cause us to pop contexts
multiple times, which is not very good.
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
Hendiadyoin1
eb50969781 LibJS: Add an EliminateLoads pass to Bytecode
This pass tries to eliminate repeated lookups of variables by name, by
remembering where these where last loaded to.

For now the lookup cache needs to be fully cleared with each call or
property access, because we do not have a way to check if these have any
side effects on the currently visible scopes.

Note that property accesses can cause getters/setters to be called, so
these are treated as calls in all cases.
2022-12-03 15:25:05 +00:00
Hendiadyoin1
b86f1c2fe7 LibJS: Restore cached current_block on return in Bytecode
Otherwise debug prints will show the wrong block until we preform a jump
2022-12-03 17:07:30 +03:30
Luke Wilde
277132f70d LibJS/Bytecode: Store unwind contexts inside RegisterWindow
Unwind contexts need to be preserved as we exit and re-enter a
generator.

For example, this would previously crash when returning from the try
statement after yielding as we lost the unwind context when yielding,
but still have a LeaveUnwindContext instruction from running
`perform_needed_unwinds` when generating the return statement.
```js
function* a() {
    try {
        return (yield 1);
    } catch {}
}

iter = a();
iter.next();
iter.next();
```
2022-11-26 12:55:59 +01:00
Hendiadyoin1
a1f1d9e4a7 LibJS: Expose some information about the bytecode interpreters state
This is quite helpful, when reporting internal errors.
2022-11-01 11:21:18 +01:00
Andreas Kling
d9b543da68 LibJS: Disable bytecode optimizations by default
The optimization passes are not stable, which makes test262 flaky.
Address this by introducing a new OptimizationLevel::None and making it
the default.

This removes all the flakiness from test262 in my testing.

We can enable optimizations by default again once they have been made
stable. :^)
2022-10-19 14:37:57 +02:00
Linus Groh
987927a596 LibJS: Remove Bytecode::Register::global_object()
This is unused.
2022-08-23 13:58:30 +01:00
Linus Groh
275dea9d98 LibJS: Remove {Bytecode::,}Interpreter::global_object()
The basic idea is that a global object cannot just come out of nowhere,
it must be associated to a realm - so get it from there, if needed.

This is to enforce the changes from all the previous commits by not
handing out global objects unless you actually have an initialized
realm (either stored somewhere, or the VM's current realm).
2022-08-23 13:58:30 +01:00
Luke Wilde
8568d18d7d LibJS/Bytecode: Determine strict mode on an executable basis
An executable is generated for the top-level script and for each
function. Strict mode can only be changed with the first statement of
the top-level script and each function, which corresponds directly to
Executable.
2022-07-18 09:00:21 +01:00
Ali Mohammad Pur
d5791c85b4 LibJS: Avoid copying the frame into the interpreter in BC generators 2022-04-18 23:59:30 +04:30
Linus Groh
9422ae9bb2 LibJS: Add infallible variant of VM::push_execution_context()
It makes no sense to require passing a global object and doing a stack
space check in some cases where running out of stack is highly unlikely,
we can't recover from errors, and currently ignore the result anyway.

This is most commonly in constructors and when setting things up, rather
than regular function calls.
2022-03-18 01:12:12 +01:00
Luke Wilde
ada8880f58 LibJS: Leave unwind context if it has no finalizer when using handler
For example, a try/catch block with no finally. The try block and catch
block do not need to unwind to a finally block, so the unwind context
is no longer needed when we jump to the catch block.

If we threw an exception in a catch block of a try/catch, there will be
no handler or finalizer and the unit would continue on as if nothing
happened.

This would subsequently crash with the  `m_saved_exception.is_null()`
assertion failure when we next call a non-native function.
2022-03-14 21:15:27 +03:30
Ali Mohammad Pur
1bbfaf8627 LibJS: More properly implement scoping rules in bytecode codegen
Now we emit CreateVariable and SetVariable with the appropriate
initialization/environment modes, much closer to the spec.
This makes a whole lot of things like let/const variables, function
and variable hoisting and some other things work :^)
2022-02-13 14:41:33 +00:00
Ali Mohammad Pur
d7c207beb9 LibJS: Implement the NewClass opcode 2022-02-13 14:41:33 +00:00
davidot
9264f9d24e LibJS+Everywhere: Remove VM::exception() and most related functions
This commit removes all exception related code:
Remove VM::exception(), VM::throw_exception() etc. Any leftover
throw_exception calls are moved to throw_completion.
The one method left is clear_exception() which is now a no-op. Most of
these calls are just to clear whatever exception might have been thrown
when handling a Completion. So to have a cleaner commit this will be
removed in a next commit.

It also removes the actual Exception and TemporaryClearException classes
since these are no longer used.

In any spot where the exception was actually used an attempt was made to
preserve that behavior. However since it is no longer tracked by the VM
we cannot access exceptions which were thrown in previous calls.
There are two such cases which might have different behavior:
- In Web::DOM::Document::interpreter() the on_call_stack_emptied hook
  used to print any uncaught exception but this is now no longer
  possible as the VM does not store uncaught exceptions.
- In js the code used to be interruptable by throwing an exception on
  the VM. This is no longer possible but was already somewhat fragile
  before as you could happen to throw an exception just before a VERIFY.
2022-02-08 09:12:42 +00:00
davidot
dcc284705b LibJS: Always pop the execution context if we pushed one for bytecode 2022-02-08 09:12:42 +00:00
davidot
8108fc7f9c LibJS: Convert Instruction::execute in bytecode to ThrowCompletionOr
This allows us to use TRY in these functions :^).
2022-02-08 09:12:42 +00:00
davidot
6fa600fce3 LibJS: Fix the execution context for the bytecode interpreter
Because we now push an execution context when creating the "normal"
interpreter without valid environments we have to check for that case
as well when running the bytecode interpreter.
2022-01-24 19:55:50 +00:00
Linus Groh
963b0f76cf LibJS: Remove now unused VM::{set_,}last_value()
This was effectively replaced by correct use of completions, including
UpdateEmpty semantics.
2022-01-08 23:43:03 +01:00
Linus Groh
57de5056b6 LibJS: Convert push_execution_context() to ThrowCompletionOr 2021-11-14 16:14:38 +00:00
Ali Mohammad Pur
070d2eaa51 LibJS+LibTest+js: Convert BC::Interpreter::run to ThrowCompletionOr<>
Note that this is just a shallow API change.
2021-11-12 13:01:59 +00:00
Ali Mohammad Pur
c604e95993 LibJS: Run the queued promise reaction jobs on bytecode interpreter exit
This is the same as what the AST interpreter does.
2021-11-12 13:01:59 +00:00
Ali Mohammad Pur
e4a7f1a696 LibJS: Make Bytecode::Interpreter return the popped frame
And use it to _correctly_ implement state saving for generators.
Prior to this, we were capturing the caller frame, which is completely
irrelevant to the generator frame.
2021-11-12 13:01:59 +00:00
Andreas Kling
3618ca2420 LibJS: Propagate exceptions across bytecode executable boundaries
To support situations like this:

    function foo() { throw 1; }

    try {
        foo();
    } catch (e) {
    }

Each unwind context now keeps track of its origin executable.

When an exception is thrown, we return from run() immediately if the
nearest unwind context isn't in the current executable.

This causes a natural unwind to the point where we find the
catch/finally block(s) to jump into.
2021-10-25 12:57:21 +02:00
Andreas Kling
049b755123 LibJS: Make bytecode interpreter leave unwind context immediately
We were missing some "break" statements, causing us to actually finish
executing everything within "try" blocks before actually jumping to the
"catch" and/or "finally" blocks.
2021-10-25 12:57:21 +02:00
Andreas Kling
c95dde971b LibJS: Move global "should dump bytecode" flag into LibJS
This will allow us to trigger bytecode executable dumps when generating
bytecode inside LibJS as well, not just in clients like js and test-js.
2021-10-24 17:18:06 +02:00