Commit graph

109 commits

Author SHA1 Message Date
Timothy Flynn
93712b24bf Everywhere: Hoist the Libraries folder to the top-level 2024-11-10 12:50:45 +01:00
Andreas Kling
dd419b5a8d AK: Make String::number() infallible
This API will always succeed in creating a String representing the
provided number in base-10.
2024-10-14 20:47:35 +02:00
Andreas Kling
cc4b3cbacc Meta: Update my e-mail address everywhere
Some checks are pending
CI / Lagom (false, FUZZ, ubuntu-24.04, Linux, Clang) (push) Waiting to run
CI / Lagom (false, NO_FUZZ, macos-14, macOS, Clang) (push) Waiting to run
CI / Lagom (false, NO_FUZZ, ubuntu-24.04, Linux, GNU) (push) Waiting to run
CI / Lagom (true, NO_FUZZ, ubuntu-24.04, Linux, Clang) (push) Waiting to run
Package the js repl as a binary artifact / build-and-package (macos-14, macOS, macOS-universal2) (push) Waiting to run
Package the js repl as a binary artifact / build-and-package (ubuntu-24.04, Linux, Linux-x86_64) (push) Waiting to run
Run test262 and test-wasm / run_and_update_results (push) Waiting to run
Lint Code / lint (push) Waiting to run
Push notes / build (push) Waiting to run
2024-10-04 13:19:50 +02:00
Andreas Kling
509c10d14d LibJS: Make GetById and GetByValue avoid get_identifier() in common case
We now defer looking up the various identifiers by IdentifierTableIndex
until the last moment. This allows us to avoid the retrieval in common
cases like when a property access is cached.

Knocks a ~12% item off the profile on https://ventrella.com/Clusters/
2024-07-09 14:16:11 +02:00
Andreas Kling
0aa8cb7dac LibJS/Bytecode: Display local variable names in bytecode dumps
Instead of displaying locals as "locN", we now show them as "name~N".
This makes it a lot easier to follow bytecode dumps, especially in
longer functions.

Note that we keep displaying the local index, to avoid confusion in case
there are multiple separate locals with the same name in one executable.
2024-06-14 16:08:02 +02:00
Andreas Kling
ae90e26315 LibJS/Bytecode: Make constant deduplication a bit smarter
Instead of scanning through the list of seen constants, we now have a
more structured storage of the constants true, false, null, undefined,
and every possible Int32 value.

This fixes an O(n^2) issue found by Kraken/json-stringify-tinderbox.js
2024-06-02 16:34:08 +02:00
Andreas Kling
97983275bc LibJS/Bytecode: Perform constant folding on binary expressions
This turns expressions like `(2 + 3) * 8 / 2` into a constant (20)
at bytecode compilation time instead of generating instructions
to calculate the value.
2024-06-02 16:34:08 +02:00
Andreas Kling
c372a084a2 LibJS/Bytecode: Add and use copy_if_needed_to_preserve_evaluation_order
This is a new Bytecode::Generator helper that takes an operand and
returns the same operand, or a copy of it, in case a copy is required
to preserve correct evaluation order.

This can be used in a bunch of places where we're worried about
clobbering some value after obtaining it.

Practically, locals are always copied, and temporary registers as well
as constants are returned as-is.
2024-06-02 16:34:08 +02:00
Andreas Kling
507f83a615 LibJS/Bytecode: Always resolve this binding into dedicated register
We already have a dedicated register slot for `this`, so instead of
having ResolveThisBinding take a `dst` operand, just write the value
directly into the `this` register every time.
2024-06-01 09:39:50 +02:00
Andreas Kling
9d57b55f24 LibJS/Bytecode: Make Generator aware of the function it's compiling 2024-06-01 09:39:50 +02:00
Andreas Kling
59c2637fdc LibJS/Bytecode: Rename emit_function_body_bytecode() -> compile()
This function isn't really one of the "emit_foo" family -- it's the main
compilation driver!
2024-06-01 09:39:50 +02:00
Hendiadyoin1
1de475b404 LibJS: Prepare yield object before re-routing it through finally 2024-05-18 18:11:10 +02:00
Hendiadyoin1
c8e4499b08 LibJS: Make return control flow more static
With this only `ContinuePendingUnwind` needs to dynamically check if a
scheduled return needs to go through a `finally` block, making the
interpreter loop a bit nicer
2024-05-15 04:25:14 +02:00
Andreas Kling
b7c04f999a LibJS/Bytecode: Split SetVariable into four separate instructions
Instead of SetVariable having 2x2 modes for variable/lexical and
initialize/set, those 4 modes are now separate instructions, which
makes each instruction much less branchy.
2024-05-14 21:46:36 +02:00
Andreas Kling
9265385807 LibJS/Bytecode: Don't bother propagating completion values in functions
The last completion value in a function is not exposed to the language,
since functions always either return something, or undefined.

Given this, we can avoid emitting code that propagates the completion
value from various statements, as long as we know we're generating code
for a context where the completion value is not accessible. In practical
terms, this means that function code gets to do less completion
shuffling, while global and eval code has to keep doing it.
2024-05-14 21:46:36 +02:00
Andreas Kling
855f6417df LibJS/Bytecode: Move environment variable caches into instructions
These were out-of-line because we had some ideas about marking
instruction streams PROT_READ only, but that seems pretty arbitrary and
there's a lot of performance to be gained by putting these inline.
2024-05-13 09:22:14 +02:00
Andreas Kling
b5a070e8ce LibJS/Bytecode: Don't create empty lexical environments
This patch stops emitting the BlockDeclarationInstantiation instruction
when there are no locals, and no function declarations in the scope.

We were spending 20% of CPU time on https://ventrella.com/Clusters/ just
creating empty environments for no reason.
2024-05-11 15:22:36 +02:00
Aliaksandr Kalenik
a4f70986a0 LibJS: Emit bytecode for function declaration instantiation
By doing that all instructions required for instantiation are emitted
once in compilation and then reused for subsequent calls, instead of
running generic instantiation process for each call.
2024-05-11 11:43:05 +02:00
Andreas Kling
7654da3851 LibJS/Bytecode: Do basic compare-and-jump peephole optimization
We now fuse sequences like [LessThan, JumpIf] to JumpLessThan.
This is only allowed for temporaries (i.e VM registers) with no other
references to them.
2024-05-10 15:03:24 +00:00
Andreas Kling
6873628317 LibJS/Bytecode: Make NewArray a variable-length instruction
This removes a layer of indirection in the bytecode where we had to make
sure all the initializer elements were laid out in sequential registers.

Array expressions no longer clobber registers permanently, and they can
be reused immediately afterwards.
2024-05-09 09:12:13 +02:00
Andreas Kling
cea59b6642 LibJS/Bytecode: Reuse bytecode registers
This patch adds a register freelist to Bytecode::Generator and switches
all operands inside the generator to a new ScopedOperand type that is
ref-counted and automatically frees the register when nothing uses it.

This dramatically reduces the size of bytecode executable register
windows, which were often in the several thousands of registers for
large functions. Most functions now use less than 100 registers.
2024-05-09 09:12:13 +02:00
Andreas Kling
0f70ff9a67 LibJS/Bytecode: Only emit ResolveThisBinding once per basic block
Once executed, this instruction will always produce the same result
in subsequent executions, so it's okay to cache it.

Unfortunately it may throw, so we can't just hoist it to the top of
every executable, since that would break observable execution order.
2024-05-09 09:12:13 +02:00
Hendiadyoin1
e1aecff2ab LibJS: Fail compilation earlier when trying to emit with wrong arguments
This makes the compilation backtraces a lot nicer, and allows clangd to
see the mistake as well.
2024-05-08 22:01:58 +02:00
Hendiadyoin1
af94e4c05d LibJS: Save and restore exceptions on yields in finalizers
Also removes a bunch of related old FIXMEs.
2024-05-08 22:01:58 +02:00
Andreas Kling
3a73eb99ac LibJS/Bytecode: Store labels as basic block index during compilation
Instead of storing a BasicBlock* and forcing the size of Label to be
sizeof(BasicBlock*), we now store the basic block index as a u32.

This means the final version of the bytecode is able to keep labels
at sizeof(u32), shrinking the size of many instructions. :^)
2024-05-07 09:15:40 +02:00
Andreas Kling
5a08544138 LibJS/Bytecode: Keep instruction source mappings in Executable
Instead of storing source offsets with each instruction, we now keep
them in a side table in Executable.

This shrinks each instruction by 8 bytes, further improving locality.
2024-05-07 09:15:40 +02:00
Hendiadyoin1
ada5027163 LibJS: Cleanup unwind state when transferring control out of a finalizer
This does two things:
* Clear exceptions when transferring control out of a finalizer
  Otherwise they would resurface at the end of the next finalizer
  (see test the new test case), or at the end of a function
* Pop one scheduled jump when transferring control out of a finalizer
  This removes one old FIXME
2024-05-02 07:27:45 +02:00
Hendiadyoin1
301a1fc763 LibJS: Propagate finalizers into nested try-catch blocks without them 2024-05-02 07:27:45 +02:00
Timothy Flynn
9bbd3103a8 LibJS: Include identifier information in nullish property read access
When a GetById / GetByValue bytecode operation results in accessing a
nullish object, we now include the name of the property and the object
being accessed in the exception message (if available). This should make
it easier to debug live websites.

For example, the following errors would all previously produce a generic
error message of "ToObject on null or undefined":

  > foo = null
  > foo.bar
  Uncaught exception:
  [TypeError] Cannot access property "bar" on null object "foo"
      at <unknown>

  > foo = { bar: undefined }
  > foo.bar.baz
  Uncaught exception:
  [TypeError] Cannot access property "baz" on undefined object "foo.bar"
      at <unknown>

Note we certainly don't capture all possible nullish property read
accesses here. This just covers cases I've seen most on live websites;
we can cover more cases as they arise.
2024-03-29 21:57:19 +01:00
Andreas Kling
5b69413c4b Revert "LibJS/Bytecode: Bring back the bytecode optimization pipeline"
This reverts commit 5b29974bfa.
2024-03-06 08:39:29 +01:00
Andreas Kling
5b29974bfa LibJS/Bytecode: Bring back the bytecode optimization pipeline
...minus the EliminateLoads pass, since it was not compatible with the
new bytecode format.
2024-03-04 20:54:51 +01:00
Andreas Kling
60a555e364 LibJS/Bytecode: Make NewPrimitiveArray a variable-length instruction
Instead of having a FixedArray with a separate heap allocation, we can
just bake the primitive values into the instruction itself.
2024-03-03 22:27:44 +01:00
Andreas Kling
46d209c55b LibJS/Bytecode: Make primitive strings be constants
Instead of emitting a NewString instruction to construct a primitive
string from a parsed literal, we now instantiate the PrimitiveString on
the heap during codegen.
2024-03-03 22:27:44 +01:00
Andreas Kling
e46b217e42 LibJS/Bytecode: Move to a new bytecode format
This patch moves us away from the accumulator-based bytecode format to
one with explicit source and destination registers.

The new format has multiple benefits:

- ~25% faster on the Kraken and Octane benchmarks :^)
- Fewer instructions to accomplish the same thing
- Much easier for humans to read(!)

Because this change requires a fundamental shift in how bytecode is
generated, it is quite comprehensive.

Main implementation mechanism: generate_bytecode() virtual function now
takes an optional "preferred dst" operand, which allows callers to
communicate when they have an operand that would be optimal for the
result to go into. It also returns an optional "actual dst" operand,
which is where the completion value (if any) of the AST node is stored
after the node has "executed".

One thing of note that's new: because instructions can now take locals
as operands, this means we got rid of the GetLocal instruction.
A side-effect of that is we have to think about the temporal deadzone
(TDZ) a bit differently for locals (GetLocal would previously check
for empty values and interpret that as a TDZ access and throw).
We now insert special ThrowIfTDZ instructions in places where a local
access may be in the TDZ, to maintain the correct behavior.

There are a number of progressions and regressions from this test:

A number of async generator tests have been accidentally fixed while
converting the implementation to the new bytecode format. It didn't
seem useful to preserve bugs in the original code when converting it.

Some "does eval() return the correct completion value" tests have
regressed, in particular ones related to propagating the appropriate
completion after control flow statements like continue and break.
These are all fairly obscure issues, and I believe we can continue
working on them separately.

The net test262 result is a progression though. :^)
2024-02-19 21:45:27 +01:00
Andreas Kling
7f1a62a1d3 LibJS/Bytecode: Add Operand in/out to all the bytecode codegen helpers
This is pure prep work for refactoring the bytecode to use more operands
instead of only registers.

generate_bytecode() virtuals now return an Optional<Operand>, and the
idea is to return an Operand referring to the value produced by this
AST node.

They also take an Optional<Operand> "preferred_dst" input. This is
intended to communicate the caller's preference for an output operand,
if any. This will be used to elide temporaries when we can store the
result directly in a local, for example.
2024-02-19 21:45:27 +01:00
Andreas Kling
e46de4eb59 LibJS/Bytecode: Add constants table to Bytecode::Executable 2024-02-19 21:45:27 +01:00
Ali Mohammad Pur
5e1499d104 Everywhere: Rename {Deprecated => Byte}String
This commit un-deprecates DeprecatedString, and repurposes it as a byte
string.
As the null state has already been removed, there are no other
particularly hairy blockers in repurposing this type as a byte string
(what it _really_ is).

This commit is auto-generated:
  $ xs=$(ack -l \bDeprecatedString\b\|deprecated_string AK Userland \
    Meta Ports Ladybird Tests Kernel)
  $ perl -pie 's/\bDeprecatedString\b/ByteString/g;
    s/deprecated_string/byte_string/g' $xs
  $ clang-format --style=file -i \
    $(git diff --name-only | grep \.cpp\|\.h)
  $ gn format $(git ls-files '*.gn' '*.gni')
2023-12-17 18:25:10 +03:30
Andreas Kling
350e6c54d7 LibJS: Remove dedicated iterator result instructions in favor of GetById
When iterating over an iterable, we get back a JS object with the fields
"value" and "done".

Before this change, we've had two dedicated instructions for retrieving
the two fields: IteratorResultValue and IteratorResultDone. These had no
fast path whatsoever and just did a generic [[Get]] access to fetch the
corresponding property values.

By replacing the instructions with GetById("value") and GetById("done"),
they instantly get caching and JIT fast paths for free, making iterating
over iterables much faster. :^)

26% speed-up on this microbenchmark:

    function go(a) {
        for (const p of a) {
        }
    }
    const a = [];
    a.length = 1_000_000;
    go(a);
2023-12-07 18:12:24 +01:00
Andreas Kling
ecfcc9aef3 LibJS: Make Bytecode::Executable GC-allocated
This is a step towards making ExecutionContext easier to allocate.
2023-11-29 09:48:18 +01:00
Andreas Kling
b1b2ca1485 LibJS: Add basic monomorphic caching for PutById property access
This patch makes it possible for JS::Object::internal_set() to populate
a CacheablePropertyMetadata, and uses this to implement a basic
monomorphic cache for the most common form of property write access.
2023-11-09 16:02:14 +01:00
Todderod
bb9230bbcd LibJS: Remove redundant Store op
If the property for GetByValue in Generator::load_from_reference
is a calculated value this would be stored in an allocated
register and returned from the function. Not all callers want
this information however, so now only give it out when asked for.

Reduced the instruction count for Kraken/ai-astar.js function
"neighbours" from 214 to 192.
2023-11-08 22:18:28 +01:00
Nick Hawke
67566e5017 LibJS: Migrate DeprecatedString to String
This changes BasicBlock's constructor and create().
2023-11-02 14:55:12 +01:00
Hendiadyoin1
73f347b75c LibJS: Create static unwind mappings for BasicBlocks
This is currently only used in the bytecode dump to annotate to where
unwinds lead per block, but will be hooked up to the virtual machine in
the next commit.
2023-10-30 13:10:08 +01:00
Andreas Kling
2e23f00a2f LibJS/Bytecode: Move environment coordinate caches to Executable
Moving them out of the respective instructions allows the bytecode
stream to be immutable.
2023-10-27 07:26:37 +02:00
Andreas Kling
732b39d120 LibJS: Don't evaluate computed MemberExpression LHS twice in assignments
The following snippet would cause "i" to be incremented twice(!):

    let a = []
    let i = 0
    a[++i] += 0

This patch solves the issue by remembering the base object and property
name for computed MemberExpression LHS in codegen. We the store the
result of the assignment to the same object and property (instead of
computing the LHS again).

3 new passes on test262. :^)
2023-10-04 18:58:29 +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
aeb8b5685f LibJS: Make Bytecode::Generator::emit() return void
There are no callers left that use the return value.
2023-09-28 14:52:03 +02:00
Andreas Kling
84850700a0 LibJS: Make BC::Generator::emit_with_extra_register_slots() return void
Nobody was using the return value.
2023-09-28 14:52:03 +02:00
Andreas Kling
d24e07579f LibJS: Use a Vector<u8> for BasicBlock instruction storage
This reduces the minimum size of a basic block from 4 KiB to 0 bytes.
With this change, memory usage at the end of Speedometer is 1.2 GiB,
down from 1.8 GiB.
2023-09-28 11:25:19 +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