Commit graph

247 commits

Author SHA1 Message Date
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
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
Lenny Maiorani
d00b79568f Libraries: Use default constructors/destructors in LibJS
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#cother-other-default-operation-rules

"The compiler is more likely to get the default semantics right and
you cannot implement these functions better than the compiler."
2022-03-16 16:19:40 +00: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
0b8d2fb62f LibJS/Bytecode: Replace merged block references before copying them 2022-03-14 22:28:53 +01:00
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
e517cb505a LibJS/Bytecode: Make NewArray write directly to indexed properties
This follows how the regular AST interpreter creates arrays, as using
Array::create_from uses create_data_property_or_throw, which will crash
when it encounters an empty value. We require empty values to represent
array holes.
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
858bcac4c7 LibJS/Bytecode: Unwind environments before block terminating instruction
When we reach a block terminating instruction (e.g. Break, Throw),
we cannot generate anymore instructions after it. This would not allow
us to leave any lexical/variable environments.

This uses the mechanism introduced in ba9c49 to unwind environments
when we encounter these instructions.
2022-03-14 21:15:27 +03:30
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
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
Ali Mohammad Pur
57386ca839 LibJS: Initialize 'var' bindings to undefined on declaration
This is what CreateGlobalVarBinding does, so do the same thing in BC.
2022-03-13 17:50:21 +01:00
Ali Mohammad Pur
ba9c4959d6 LibJS: Leave the unwind context on break/continue/return in bytecode
Otherwise we'd keep the old unwind context, and end up never invoking
the other handlers up the stack.
2022-03-13 17:50:21 +01:00
Ali Mohammad Pur
41184c960d LibJS: Propagate abrupt completions in Bytecode::Op::Call
This was not handling the nullary call case correctly, remove the whole
nullary check as there's nothing particularly expensive in the catch-all
case anyway.
2022-03-13 17:50:21 +01:00
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
c7e6b65fd2 LibJS: Implement ClassExpression::generate_bytecode()
...and use that in ClassDeclaration::generate_bytecode().
2022-02-13 14:41:33 +00:00
Ali Mohammad Pur
75aa900b83 LibJS: Make ASTNode::generate_bytecode() fallible
Instead of crashing on the spot, return a descriptive error that will
eventually continue its days as a javascript "InternalError" exception.
This should make random crashes with BC less likely.
2022-02-13 14:41:33 +00:00
Ali Mohammad Pur
3a5f7cb524 LibJS: Don't emit a LeaveUnwindContext after a successful handler
The handler already comes with a nice and shiny FinishUnwind, doubling
up will leave two contexts instead.
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
Anonymous
d1cc67bbe1 LibJS: Avoid unnecessary ToObject conversion when resolving references
When performing GetValue on a primitive type we do not need to perform
the ToObject conversion as it will resolve to a property on the
prototype object.

To avoid this we skip the initial ToObject conversion on the base value
as it only serves to get the primitive's boxed prototype. We further
specialize on PrimitiveString in order to get efficient behaviour
behaviour for the direct properties.

Depending on the tests anywhere from 20 to 60%, with significant loop
overhead.
2022-02-13 14:44:36 +01:00
Linus Groh
bc183dbbcb LibJS: Replace uses of MarkedValueList with MarkedVector<Value>
This is effectively a drop-in replacement.
2022-02-09 12:25:27 +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
4136cbdb09 LibJS: Convert ScopeNode declaration functions to ThrowCompletionOr
This removes a number of vm.exception() checks which are now caught
directly by TRY. Make use of these checks in
{Global, Eval}DeclarationInstantiation and while we're here add spec
comments.
2022-02-08 09:12:42 +00:00
Linus Groh
6f20f49b21 Everywhere: Rename JS::PropertyKey variables from property_{name => key}
PropertyKey used to be called PropertyName, but got renamed. Let's
update all the variables of this type as well.
2022-02-06 22:02:45 +00:00
Andreas Kling
7a742b17da LibJS: Store ECMAScriptFunctionObject bytecode in an OwnPtr
Using an Optional was extremely wasteful for function objects that don't
even have a bytecode executable.

This allows ECMAScriptFunctionObject to fit in a smaller size class.
2022-01-31 16:19:23 +01:00
Andreas Kling
fc04465fa3 LibJS: Remove unnecessary GlobalObject pointer from Environment
As it turns out, we didn't actually need this pointer. :^)
2022-01-31 16:19:23 +01: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
mjz19910
1ef633472b Everywhere: Convert VM::call() to JS::call() 2022-01-23 15:24:45 +00:00
Linus Groh
1ee7e97e24 LibJS: Pass source text to ECMAScriptFunctionObject::create() 2022-01-19 20:33:08 +00:00
Linus Groh
0c73fbbba5 LibJS: Rename FunctionKind::{Regular => Normal}
This is what CreateDynamicFunction calls it.
2022-01-16 01:54:48 +01:00
Linus Groh
09a11fa6ea LibJS: Implement proper Iterator records
Instead of using plain objects as Iterator records, causes confusion
about the object itself actually being its [[Iterator]] slot, and
requires non-standard type conversion shenanigans fpr the [[NextValue]]
and [[Done]] internal slots,  implement a proper Iterator record struct
and use it throughout.

Also annotate the remaining Iterator AOs with spec comments while we're
here.
2022-01-09 22:02:43 +01: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
mjz19910
3102d8e160 Everywhere: Fix many spelling errors 2022-01-07 10:56:59 +01:00
Linus Groh
da856d7742 LibJS: Update AST to use completions :^)
This is another major milestone on our journey towards removing global
VM exception state :^)
Does pretty much exactly what it says on the tin: updating
ASTNode::execute() to return a Completion instead of a plain value. This
will *also* allow us to eventually remove the non-standard unwinding
mechanism and purely rely on the various completion types.
2022-01-03 21:50:50 +01:00
Linus Groh
85f0fc2b83 LibJS: Return Optional<T> from Completion::{value,target}(), not T
In the end this is a nicer API than having separate has_{value,target}()
and having to check those first, and then making another Optional from
the unwrapped value:

    completion.has_value() ? completion.value() : Optional<Value> {}
    //                       ^^^^^^^^^^^^^^^^^^
    //         Implicit creation of non-empty Optional<Value>

This way we need to unwrap the optional ourselves, but can easily pass
it to something else as well.

This is in anticipation of the AST using completions :^)
2022-01-03 21:50:50 +01:00
Ben Wiederhake
0c365fdfd3 LibJS: Avoid unnecessary copies in MergeBlocks codegen pass 2022-01-01 15:40:39 +01:00
Ben Wiederhake
a1aea5b9e0 LibJS: Avoid unnecessary copies in PlaceBlocks codegen pass 2022-01-01 15:40:39 +01:00
davidot
a24df37713 LibJS: Convert resolve_this_binding() to ThrowCompletionOr
Also add spec comments.
2021-12-31 00:03:20 +01:00
davidot
676554d3f8 LibJS: Convert resolve_binding() to ThrowCompletionOr
The spec has a note stating that resolve binding will always return a
reference whose [[ReferencedName]] field is name. However this is not
correct as the underlying method GetIdentifierReference may throw on
env.HasBinding(name) thus it can throw. However, there are some
scenarios where it cannot throw because the reference is known to exist
in that case we use MUST with a comment.
2021-12-30 15:29:33 +01:00
Andreas Kling
216e21a1fa AK: Convert AK::Format formatting helpers to returning ErrorOr<void>
This isn't a complete conversion to ErrorOr<void>, but a good chunk.
The end goal here is to propagate buffer allocation failures to the
caller, and allow the use of TRY() with formatting functions.
2021-11-17 00:21:13 +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