Commit graph

257 commits

Author SHA1 Message Date
Andreas Kling
021a141b53 LibJS: Make array-like Put access on ordinary objects much faster
This patch adds a fast path to the PutByValue bytecode op that bypasses
a ton of things *if* a set of assumptions hold:

- The property key must be a non-negative Int32
- The base object must not interfere with indexed property access
- The base object must have simple indexed property storage
- The property key must already be present as an own property
- The existing value must not have any accessors defined

If this holds (which it should in many common cases), we can skip all
kinds of checks and poke directly at the property storage, saving time.

16% speed-up on the entire Kraken benchmark :^)
(including: 88% speed-up on Kraken/imaging-desaturate.js)
(including: 55% speed-up on Kraken/audio-fft.js)
(including: 54% speed-up on Kraken/audio-beat-detection.js)
2023-10-05 16:57:45 +02:00
Andreas Kling
27a83f7e5e LibJS: Make array-like Get access on ordinary objects much faster
This patch adds a fast path to the GetByValue bytecode op that bypasses
a ton of things *if* a set of assumptions hold:

- The property key must be a non-negative Int32
- The base object must not interfere with indexed property access
- The property key must already be present as an own property
- The existing value must not have any accessors defined

If this holds (which it should in the common case), we can poke directly
at the indexed property storage and save a boatload of time.

10% speed-up on the entire Kraken benchmark :^)
(including: 31% speed-up on Kraken/audio-dft.js)
(including: 23% speed-up on Kraken/stanford-crypto-aes.js)
2023-10-05 16:57:45 +02:00
Andreas Kling
c14db6ab12 LibJS: Make Executable ref-counted and let instruction iterator co-own it
This ensures that the instruction stream pointed at by the instruction
iterator remains valid as long as the iterator exists.
2023-10-03 08:23:33 +02:00
Andreas Kling
feedbd6a01 LibJS: Put __builtin_unreachable() in unused bytecode opcode handlers
For the opcodes that are handled directly in the interpreter loop,
we want the compiler to know that there's nothing to inline here.
2023-09-28 06:09:16 +02:00
Andreas Kling
f3606adc58 LibJS: Inline bytecode ops for direct local/register access
These can do a lot less stuff if we put them directly in the interpreter
loop and allow them to access the locals/registers arrays directly.
2023-09-28 06:09:16 +02:00
Andreas Kling
ae1ac9871b LibJS: Move all bytecode instruction implementations to Interpreter.cpp
This allows aggressive inlining without LTO.
2023-09-28 06:09:16 +02:00
Andreas Kling
e5474c384d LibJS: Inline flow control ops in the bytecode interpreter loop
Instead of calling out to helper functions for flow control (and then
checking control flags on every iteration), we now simply inline those
ops in the interpreter loop directly.
2023-09-28 06:09:16 +02:00
Andreas Kling
39cfb64269 LibJS: Return early from Interpreter on unhandled exception
If we don't have a local unwind context to handle the exception, we can
just return right away. This allows us to remove one check from the
inner loop.
2023-09-28 06:09:16 +02:00
Andreas Kling
c9eff35b96 LibJS: Use goto instead of bool will_jump in interpreter loop
This is honestly less spaghetti-ish.
2023-09-28 06:09:16 +02:00
Andreas Kling
9fe38245b2 LibJS: Move bytecode interpreter's inner loop to its own function 2023-09-28 06:09:16 +02:00
Andreas Kling
951a85992b LibJS: Mark the exception path as [[unlikely]] in the interpreter loop 2023-09-28 06:09:16 +02:00
Andreas Kling
213b835b57 LibJS: Remove Bytecode::Interpreter::debug_position()
This was only used in one place, and that place is already covered
by a VERIFY anyway.
2023-09-28 06:09:16 +02:00
Andreas Kling
0c746366cc LibJS: Keep return value in a call frame register 2023-09-28 06:09:16 +02:00
Andreas Kling
c833885fb5 LibJS: Keep cached this value in a call frame register
Just moving more things to call frame registers..
2023-09-28 06:09:16 +02:00
Andreas Kling
3887b840a3 LibJS: Keep current exception in a call frame register
Instead of keeping it in a Bytecode::Interpreter member, move it into
a dedicated call frame register.
2023-09-28 06:09:16 +02:00
Andreas Kling
3ccac0cf6e LibJS: Remove unused realm parameter from run_and_return_frame() 2023-09-21 16:19:13 +02:00
Andreas Kling
d6e959686d LibJS: Remove automatic ExecutionContext creation in BC interpreter
This was a remnant from the AST/BC hybrid interpreter times. We've had
a VERIFY in here for weeks now that would catch anything depending on
this behavior, and nothing has hit it, so let's remove the unnecessary
code (but leave the VERIFY) :^)
2023-09-21 16:19:13 +02:00
Andreas Kling
c78506d79b LibJS: Only update EC instruction pointer when pushing to EC stack
Instead of trying to keep a live reference to the bytecode interpreter's
current instruction stream iterator, we now simply copy the current
iterator whenever pushing to the ExecutionContext stack.

This fixes a stack-use-after-return issue reported by ASAN.
2023-09-02 19:24:29 +02:00
Andreas Kling
1c06111cbd LibJS: Add file & line number to bytecode VM stack traces :^)
This works by adding source start/end offset to every bytecode
instruction. In the future we can make this more efficient by keeping
a map of bytecode ranges to source ranges in the Executable instead,
but let's just get traces working first.

Co-Authored-By: Andrew Kaster <akaster@serenityos.org>
2023-09-02 15:37:53 +02:00
Andreas Kling
97ebfd9f0f LibJS: Make Value::to_string_without_side_effects() infallible
Work towards #20449.
2023-08-09 17:09:16 +02:00
Andreas Kling
2eaa528a0e LibJS: Rip out the AST interpreter :^)
This has been superseded by the bytecode VM, which is both faster
and more capable.
2023-08-08 13:07:13 +02:00
Andreas Kling
e2c8d5859e LibJS: Remove ability to disable bytecode VM 2023-08-08 13:07:13 +02:00
Andreas Kling
d1d24569f8 LibJS/Bytecode: Remove unused AST interpreter hacks from bytecode VM 2023-08-08 13:07:13 +02:00
Andreas Kling
34344120f2 AK: Make "foo"_string infallible
Stop worrying about tiny OOMs.

Work towards #20405.
2023-08-07 16:03:27 +02:00
Aliaksandr Kalenik
2bdc69c42c LibJS: Add caching of this value in ResolveThisBinding instruction
Because "this" value cannot be changed during function execution it is
safe to compute it once and then use for future access.

This optimization makes ai-astar.js run 8% faster.
2023-07-29 04:23:49 +02:00
Andreas Kling
9f06e130a2 LibJS/Bytecode: Keep saved return value in call frame register
This fixes an issue where returning inside a `try` block and then
calling a function inside `finally` would clobber the saved return
value from the `try` block.

Note that we didn't need to change the base of register allocation,
since it was already 1 too high.

With this fixed, https://microsoft.com/edge loads in bytecode mode. :^)

Thanks to Luke for reducing the issue!
2023-07-21 19:15:33 +02:00
Timothy Flynn
77d7f715e3 LibJS+CI: Remove bytecode optimization passes for now
These passes have not been shown to actually optimize any JS, and tests
have become very flaky with optimizations enabled. Until some measurable
benefit is shown, remove the optimization passes to reduce overhead of
maintaining bytecode operations and to reduce CI churn. The framework
for optimizations will live on in git history, and can be restored once
proven useful.
2023-07-21 19:47:36 +03:30
Andreas Kling
6de22ec789 LibJS/Bytecode: Rename RegisterWindow to CallFrame
This is a better name for what it actually represents.
2023-07-21 14:14:00 +02:00
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