Commit graph

23 commits

Author SHA1 Message Date
Linus Groh
acda12597a LibJS: Rename scope to environment
This is an editorial change in the ECMA-262 spec.

See: https://github.com/tc39/ecma262/commit/3246553
2022-05-01 22:47:38 +02: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
Timothy Flynn
27904b1060 LibJS: Add a fast path for creating per-iteration DeclarativeEnvironment
The steps for creating a DeclarativeEnvironment for each iteration of a
for-loop can be done equivalently to the spec without following the spec
directly. For each binding creating in the loop's init expression, we:

    1. Create a new binding in the new environment.
    2. Grab the current value of the binding in the old environment.
    3. Set the value in the new environment to the old value.

This can be replaced by initializing the bindings vector in the new
environment directly with the bindings in the old environment (but only
copying the bindings of the init statement).
2022-03-14 16:33:15 +01:00
Timothy Flynn
f56bf610c4 LibJS: Allow pre-allocating DeclarativeEnvironment's bindings list 2022-03-08 23:02:12 +01:00
Timothy Flynn
435f49d98e LibJS: Allow direct index-based initialization of a declarative binding
Similar to the direct getter and setter in DeclarativeEnvironment, there
are cases where we already know the index of a binding and can avoid a
O(n) lookup to re-find that index.
2022-03-08 23:02:12 +01:00
Timothy Flynn
533170fbfa LibJS: Combine DeclarativeEnvironment's bindings and names into one list
This reduces the size of the DeclarativeEnvironment from 72 bytes to 48
bytes. This savings helps in the context of nested for-loops which use
'let' to bind the initial variable declarations. In this case, the spec
dicates we create a new environment for each loop iteration by way of
the CreatePerIterationEnvironment AO.

In particular, test262's generated RegExp tests contains many loops of
the form:

    for (let i = 0; i < a_number_on_the_order_of_10; ++i)
        for (let j = 0; j < a_number_on_the_order_of_10_thousand; ++j)

This results in creating hundreds of thousands of environments.
2022-03-08 23:02:12 +01:00
Andreas Kling
ff60e8ffc6 LibJS: Use Vector instead of HashMap in DeclarativeEnvironment
Constructing the HashMap in DeclarativeEnvironment was by far the most
expensive thing when making JavaScript function calls.

As it turns out, we don't really need this to be a HashMap in the first
place, as lookups are cached (by EnvironmentCoordinate) after the first
access, so after that we were not even looking in the HashMap, going
directly to the bindings Vector instead.

This reduces function_declaration_instantiation() from 16% to 9% when
idling in "Biolab Disaster". It also reduces has_binding() from 3% to
1% on the same content.

With these changes, we now actually get to idle a little bit between
game frames on my machine. :^)
2022-03-07 14:49: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
Linus Groh
01370136ee LibJS: Convert delete_binding() to ThrowCompletionOr
Also add spec step comments to it while we're here.
2021-10-09 21:53:47 +01:00
Linus Groh
f35e268024 LibJS: Convert get_binding_value() to ThrowCompletionOr
Also add spec step comments to it while we're here.
2021-10-09 21:53:47 +01:00
Linus Groh
7652138ce0 LibJS: Convert set_mutable_binding() to ThrowCompletionOr
Also add spec step comments to it while we're here.
2021-10-09 21:53:47 +01:00
Linus Groh
ae397541fb LibJS: Convert initialize_binding() to ThrowCompletionOr
Also add spec step comments to it while we're here.
2021-10-09 21:53:47 +01:00
Linus Groh
2691c65639 LibJS: Convert create_immutable_binding() to ThrowCompletionOr
Also add spec step comments to it while we're here.
2021-10-09 21:53:47 +01:00
Linus Groh
4baf3a91e8 LibJS: Convert create_mutable_binding() to ThrowCompletionOr
Also add spec step comments to it while we're here.
2021-10-09 21:53:47 +01:00
Linus Groh
fbb176c926 LibJS: Convert has_binding() to ThrowCompletionOr
Also add spec step comments to it while we're here.
2021-10-09 21:53:47 +01:00
Andreas Kling
540ce075b6 LibJS: Add direct (indexed) binding accessors to DeclarativeEnvironment
This patch adds two DeclarativeEnvironment APIs:

- get_binding_value_direct()
- set_mutable_binding_direct()

These work identically to their non-direct-suffixed counterparts, but
take an index instead of a bound name. This will allow someone who has
a binding index to get/set that binding directly without any additional
hash lookups.
2021-10-07 00:23:36 +02:00
Andreas Kling
cb696eff08 LibJS: Make Environment::has_binding() optionally return binding index
If the caller wants to use the binding index for anything, if there is
such a thing, it can now be obtained via an optional out-parameter.
2021-10-07 00:23:36 +02:00
Andreas Kling
6ef5464015 LibJS: Make DeclarativeEnvironment store bindings in a Vector
The previous storage for DeclarativeEnvironment looked like this:

    HashMap<FlyString, Binding> m_bindings;

This patch changes that to:

    HashMap<FlyString, size_t> m_names;
    Vector<Binding> m_bindings;

The main goal here is to give each binding an index that can ultimately
be cached and used for optimized environment accesses.
2021-10-07 00:23:36 +02:00
davidot
f4f1397735 js: Allow for completion of lexically declared variables
This does require us to have a method which lists all the bindings in
a declarative environment which is not in the spec.
2021-10-03 17:42:05 +02:00
davidot
830ea0414c LibJS: Make scoping follow the spec
Before this we used an ad-hoc combination of references and 'variables'
stored in a hashmap. This worked in most cases but is not spec like.
Additionally hoisting, dynamically naming functions and scope analysis
was not done properly.

This patch fixes all of that by:
  - Implement BindingInitialization for destructuring assignment.
  - Implementing a new ScopePusher which tracks the lexical and var
    scoped declarations. This hoists functions to the top level if no
    lexical declaration name overlaps. Furthermore we do checking of
    redeclarations in the ScopePusher now requiring less checks all over
    the place.
  - Add methods for parsing the directives and statement lists instead
    of having that code duplicated in multiple places. This allows
    declarations to pushed to the appropriate scope more easily.
  - Remove the non spec way of storing 'variables' in
    DeclarativeEnvironment and make Reference follow the spec instead of
    checking both the bindings and 'variables'.
  - Remove all scoping related things from the Interpreter. And instead
    use environments as specified by the spec. This also includes fixing
    that NativeFunctions did not produce a valid FunctionEnvironment
    which could cause issues with callbacks and eval. All
    FunctionObjects now have a valid NewFunctionEnvironment
    implementation.
  - Remove execute_statements from Interpreter and instead use
    ASTNode::execute everywhere this simplifies AST.cpp as you no longer
    need to worry about which method to call.
  - Make ScopeNodes setup their own environment. This uses four
    different methods specified by the spec
    {Block, Function, Eval, Global}DeclarationInstantiation with the
    annexB extensions.
  - Implement and use NamedEvaluation where specified.

Additionally there are fixes to things exposed by these changes to eval,
{for, for-in, for-of} loops and assignment.

Finally it also fixes some tests in test-js which where passing before
but not now that we have correct behavior :^).
2021-09-30 08:16:32 +01:00
Andreas Kling
80170887db LibJS: Make Environment::put_into_environment() return a success bool
This code is non-conforming and will eventually get cleaned out once
we implement proper variable bindings. However, this will aid us in
improving other parts of the code right now.
2021-07-02 00:26:31 +02:00
Andreas Kling
0fa141d058 LibJS: Move Binding struct into the DeclarativeEnvironment class
Nobody on the outside needs to access this.
2021-07-01 12:31:39 +02:00
Andreas Kling
44221756ab LibJS: Drop "Record" suffix from all the *Environment record classes
"Records" in the spec are basically C++ classes, so let's drop this
mouthful of a suffix.
2021-07-01 12:28:57 +02:00
Renamed from Userland/Libraries/LibJS/Runtime/DeclarativeEnvironmentRecord.h (Browse further)