Commit graph

59 commits

Author SHA1 Message Date
Andreas Kling
18c54d8d40 LibJS: Make Cell::initialize() return void
Stop worrying about tiny OOMs.

Work towards #20405
2023-08-08 07:39:11 +02:00
Shannon Booth
930dd2948f LibJS: Make AsyncFunctionStart and AsyncBlockStart templates
This will allow implementing a version of these functions that accepts a
JS::SafeFunction, which is needed for the implementation of
Array.fromAsync.
2023-07-16 14:56:10 +01:00
Shannon Booth
7b5362fea6 LibJS: Make AsyncFunctionStart a standalone AO
This function may be called by places outside of
ECMAScriptFunctionObject.
2023-07-16 14:56:10 +01:00
Timothy Flynn
c911781c21 Everywhere: Remove needless trailing semi-colons after functions
This is a new option in clang-format-16.
2023-07-08 10:32:56 +01:00
Aliaksandr Kalenik
7765ebb5f2 LibJS+LibWeb: Plumb local variables names to ECMAScriptFunctionObject
Saving vector of local variables names in ECMAScriptFunctionObject
will allow to get a name by index in case message of ReferenceError
needs to contain a variable name.
2023-07-05 21:03:01 +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
bd5d8e9d35 LibJS: Make RefPtr and NonnullRefPtr usage const-correct
This mainly affected the AST, which is now const throughout.
2023-02-21 00:54:04 +01:00
Timothy Flynn
2692db8699 LibJS+Everywhere: Allow Cell::initialize overrides to throw OOM errors
Note that as of this commit, there aren't any such throwers, and the
call site in Heap::allocate will drop exceptions on the floor. This
commit only serves to change the declaration of the overrides, make sure
they return an empty value, and to propagate OOM errors frm their base
initialize invocations.
2023-01-29 00:02:45 +00: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
Linus Groh
03acbf0beb LibJS: Convert FunctionObject::internal_construct() to NonnullGCPtr 2022-12-15 06:56:37 -05:00
Linus Groh
73efdb1cc4 LibJS: Convert ECMAScriptFunctionObject::create() to NonnullGCPtr 2022-12-14 09:59:45 +00:00
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
Andreas Kling
d16b808e71 LibJS: Make ECMAScriptFunctionObject.h not include AST.h 2022-11-23 16:05:59 +00:00
Andreas Kling
835d7aac96 LibJS: Make FunctionNode::Parameter be a standalone FunctionParameter
This will allow us to forward declare it and avoid including AST.h in a
number of places.
2022-11-23 16:05:59 +00:00
Andreas Kling
35c9aa7c05 LibJS: Hide all the constructors!
Now that the GC allocator is able to invoke Cell subclass constructors
directly via friendship, we no longer need to keep them public. :^)
2022-08-29 03:24:54 +02:00
Linus Groh
b99cc7d050 LibJS+LibWeb: Replace GlobalObject with Realm in create() functions
This is a continuation of the previous two commits.

As allocating a JS cell already primarily involves a realm instead of a
global object, and we'll need to pass one to the allocate() function
itself eventually (it's bridged via the global object right now), the
create() functions need to receive a realm as well.
The plan is for this to be the highest-level function that actually
receives a realm and passes it around, AOs on an even higher level will
use the "current realm" concept via VM::current_realm() as that's what
the spec assumes; passing around realms (or global objects, for that
matter) on higher AO levels is pointless and unlike for allocating
individual objects, which may happen outside of regular JS execution, we
don't need control over the specific realm that is being used there.
2022-08-23 13:58:30 +01:00
Linus Groh
5dd5896588 LibJS+LibWeb: Replace GlobalObject with Realm in initialize() functions
This is a continuation of the previous commit.

Calling initialize() is the first thing that's done after allocating a
cell on the JS heap - and in the common case of allocating an object,
that's where properties are assigned and intrinsics occasionally
accessed.
Since those are supposed to live on the realm eventually, this is
another step into that direction.
2022-08-23 13:58:30 +01:00
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
Linus Groh
e815d3f9ce LibJS: De-duplicate ClassFieldDefinition Records
This was defined twice, despite being the very same thing:
- ClassElement::ClassFieldDefinition
- ECMAScriptFunctionObject::InstanceField

Move the former to a new header and use it everywhere. Also update the
define_field() AO to take a single field instead of separate name and
initializer arguments.
2022-04-20 00:08:32 +02:00
Luke Wilde
34f902fb52 LibJS: Add missing steps and spec comments to PerformEval
While adding spec comments to PerformEval, I noticed we were missing
multiple steps.

Namely, these were:
- Checking if the host will allow us to compile the string
  (allowing LibWeb to perform CSP for eval)
- The parser's initial state depending on the environment around us
  on direct eval:
   - Allowing new.target via eval in functions
   - Allowing super calls and super properties via eval in classes
   - Disallowing the use of the arguments object in class field
     initializers at eval's parse time
- Setting ScriptOrModule of eval's execution context

The spec allows us to apply the additional parsing steps in any order.
The method I have gone with is passing in a struct to the parser's
constructor, which overrides the parser's initial state to (dis)allow
the things stated above from the get-go.
2022-04-11 21:23:36 +01:00
Idan Horowitz
086969277e Everywhere: Run clang-format 2022-04-01 21:24:45 +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
Ali Mohammad Pur
d75cf27e02 LibJS: Implement default values for function parameters in BC 2022-03-14 22:28:53 +01:00
Andreas Kling
515594c667 LibJS: Add fast_is<T>() for things that were hot in RTTI
This gives a ~4% speedup when parsing the largest Discord JS file.
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
Luke Wilde
f71f404e0c LibWeb: Introduce the Environment Settings Object
The environment settings object is effectively the context a piece of
script is running under, for example, it contains the origin,
responsible document, realm, global object and event loop for the
current context. This effectively replaces ScriptExecutionContext, but
it cannot be removed in this commit as EventTarget still depends on it.

https://html.spec.whatwg.org/multipage/webappapis.html#environment-settings-object
2022-02-08 17:47:44 +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
8d3f92c844 LibJS: Make JS::ECMAScriptFunctionObject smaller by reordering members
...and making heavy use of bitfields.
2022-01-31 16:19:23 +01:00
davidot
57c5a59cab LibJS: Add ScriptOrModule to execution context and track it everywhere 2022-01-22 01:21:18 +00:00
davidot
39b134e8c1 LibJS: Move async_block_start out of ECMAScriptFunctionObject 2022-01-22 01:21:18 +00:00
Linus Groh
1ee7e97e24 LibJS: Pass source text to ECMAScriptFunctionObject::create() 2022-01-19 20:33:08 +00:00
Linus Groh
13fe4e8c64 LibJS: Allow passing prototype to ECMAScriptFunctionObject::create()
This should have been the default as it roughly represents the
OrdinaryFunctionCreate AO.
For now, keep two overloads and continue to guess the required prototype
from the function kind in most cases. The prototype needs to be passed
in explicitly when it may be derived from user code, such as in the
CreateDynamicFunction AO.
2022-01-16 01:54:48 +01: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
7204b292c5 LibJS: Implement and use the MakeMethod AO
Two direct uses of the set_home_object() setter remain, we should fix
those up and remove it eventually.
2021-12-29 10:34:34 +01:00
davidot
5d0f666f22 LibJS: Don't set a prototype property on async functions
This is now as defined in the spec. However since we execute async
functions in bytecode by transforming it to a generator function it must
have a prototype for the GeneratorObject. We check whether it is an
async function and in that case use the hardcoded generator object
prototype. This also ensures that user code cannot override this
property thus preventing exposing internal implementation details.
2021-11-21 21:46:39 +00:00
Linus Groh
7cdca08090 LibJS: Convert prepare_for_ordinary_call() to ThrowCompletionOr 2021-11-14 16:14:38 +00:00
Idan Horowitz
681787de76 LibJS: Add support for async functions
This commit adds support for the most bare bones version of async
functions, support for async generator functions, async arrow functions
and await expressions are TODO.
2021-11-10 08:48:27 +00:00
Andreas Kling
398c181c79 LibJS: Rename PropertyName to PropertyKey
Let's use the same name as the spec. :^)
2021-10-24 17:18:07 +02:00
davidot
4c8090a45d LibJS: Use ClassFieldInitializerStatement for class fields
This is necessary as we might have to perform named evaluation with the
field name.
Ideally we would also skip some setup parts of the function like
function_declaration_instantiation however this would require bigger
changes to ECMAScriptFunctionObject.
2021-10-20 23:19:17 +01:00
davidot
16cc82460f LibJS: Add parsing and evaluation of private fields and methods 2021-10-20 23:19:17 +01:00
davidot
13ead80ee6 LibJS: Add PrivateEnvironment 2021-10-20 23:19:17 +01:00
davidot
1245512c50 LibJS: Make class definition evaluation more spec like in ordering 2021-10-20 23:19:17 +01:00
Linus Groh
fe5c2b7bb9 LibJS: Decouple new_function_environment() from FunctionObject
Now that only ECMAScriptFunctionObject uses this, we can remove the
FunctionObject::new_function_environment() pure virtual method and just
implement it as a standalone AO with an ECMAScriptFunctionObject
parameter, next to the other NewFooEnvironment AOs.
2021-10-09 14:29:20 +01:00
Linus Groh
53af66d57d LibJS: Move ordinary_call_bind_this() to ECMAScriptFunctionObject
Now that it only needs to deal with ECMAScriptFunctionObject via
internal_call() / internal_construct(), we can:

- Remove the generic FunctionObject parameter
- Move it from the VM to ECMAScriptFunctionObject
- Make it private
2021-10-09 14:29:20 +01:00
Linus Groh
25bcd36116 LibJS: Move prepare_for_ordinary_call() to ECMAScriptFunctionObject
Now that it only needs to deal with ECMAScriptFunctionObject via
internal_call() / internal_construct(), we can:

- Remove the generic FunctionObject parameter
- Move it from the VM to ECMAScriptFunctionObject
- Make it private
2021-10-09 14:29:20 +01:00
Linus Groh
cf168fac50 LibJS: Implement [[Call]] and [[Construct]] internal slots properly
This patch implements:

- Spec compliant [[Call]] and [[Construct]] internal slots, as virtual
  FunctionObject::internal_{call,construct}(). These effectively replace
  the old virtual FunctionObject::{call,construct}(), but with several
  advantages:
  - Clear and consistent naming, following the object internal methods
  - Use of completions
  - internal_construct() returns an Object, and not Value! This has been
    a source of confusion for a long time, since in the spec there's
    always an Object returned but the Value return type in LibJS meant
    that this could not be fully trusted and something could screw you
    over.
  - Arguments are passed explicitly in form of a MarkedValueList,
    allowing manipulation (BoundFunction). We still put them on the
    execution context as a lot of code depends on it (VM::arguments()),
    but not from the Call() / Construct() AOs anymore, which now allows
    for bypassing them and invoking [[Call]] / [[Construct]] directly.
    Nothing but Call() / Construct() themselves do that at the moment,
    but future additions to ECMA262 or already existing web specs might.
- Spec compliant, standalone Call() and Construct() AOs: currently the
  closest we have is VM::{call,construct}(), but those try to cater to
  all the different function object subclasses at once, resulting in a
  horrible mess and calling AOs with functions they should never be
  called with; most prominently PrepareForOrdinaryCall and
  OrdinaryCallBindThis, which are only for ECMAScriptFunctionObject.

As a result this also contains an implicit optimization: we no longer
need to create a new function environment for NativeFunctions - which,
worth mentioning, is what started this whole crusade in the first place
:^)
2021-10-09 14:29:20 +01:00
Andreas Kling
b2de563166 LibJS: Propagate "contains direct call to eval()" flag from parser
We now propagate this flag to FunctionDeclaration, and then also into
ECMAScriptFunctionObject.

This will be used to disable optimizations that aren't safe in the
presence of direct eval().
2021-10-08 12:43:38 +02:00
Linus Groh
4fa5748093 LibJS: Add an optimization to avoid needless arguments object creation
This gives FunctionNode a "might need arguments object" boolean flag and
sets it based on the simplest possible heuristic for this: if we
encounter an identifier called "arguments" or "eval" up to the next
(nested) function declaration or expression, we won't need an arguments
object. Otherwise, we *might* need one - the final decision is made in
the FunctionDeclarationInstantiation AO.

Now, this is obviously not perfect. Even if you avoid eval, something
like `foo.arguments` will still trigger a false positive - but it's a
start and already massively cuts down on needlessly allocated objects,
especially in real-world code that is often minified, and so a full
"arguments" identifier will be an actual arguments object more often
than not.

To illustrate the actual impact of this change, here's the number of
allocated arguments objects during a full test-js run:

Before:
- Unmapped arguments objects: 78765
- Mapped arguments objects: 2455

After:
- Unmapped arguments objects: 18
- Mapped arguments objects: 37

This results in a ~5% speedup of test-js on my Linux host machine, and
about 3.5% on i686 Serenity in QEMU (warm runs, average of 5).

The following microbenchmark (calling an empty function 1M times) runs
25% faster on Linux and 45% on Serenity:

    function foo() {}
    for (var i = 0; i < 1_000_000; ++i)
        foo();

test262 reports no changes in either direction, apart from a speedup :^)
2021-10-05 10:15:14 +01: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
Linus Groh
38157a6093 LibJS: Move has_constructor() from NativeFunction to FunctionObject
At a later point this will indicate whether some FunctionObject "has a
[[Construct]] internal method" (separate from the current FunctionObject
call() / construct()), to help with a more spec-compliant implementation
of [[Call]] and [[Construct]].
This means that it is no longer relevant to just NativeFunction.
2021-09-25 17:51:30 +02:00