Commit graph

119 commits

Author SHA1 Message Date
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
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
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
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
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
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
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
Ali Mohammad Pur
b96118b5d1 LibJS: Fix codegen for nodes after try statements without 'finally'
Previously we were just dropping them on the ground :P
2021-11-12 13:01:59 +00:00
Idan Horowitz
1aaaf521b8 LibJS: Convert the PutValue AO to ThrowCompletionOr 2021-11-02 19:48:35 +01:00
Idan Horowitz
390a04a985 LibJS: Convert the GetValue AO to ThrowCompletionOr 2021-11-02 19:48:35 +01:00
Andreas Kling
a831cd9cc7 LibJS: Make bytecode VM throw TypeError on attempt to call non-callable
This isn't perfect, but allows us to progress instead of crashing in
the TODO().
2021-10-25 12:57:21 +02: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
Andreas Kling
715e7fada8 LibJS: Add the "fast non-local access" optimization to the bytecode VM
The GetVariable bytecode op now caches environment coordinates for fast
cross-scope variable lookup.
2021-10-24 17:18:07 +02:00
Andreas Kling
da98212001 LibJS: Add a separate "identifier table" to bytecode executables
This is a specialized string table for storing identifiers only.
Identifiers are always FlyStrings, which makes many common operations
faster by allowing O(1) comparison.
2021-10-24 17:18:07 +02:00
Andreas Kling
3117182c2e LibJS: Implement 'this' in the bytecode VM
ThisExpression now emits a "ResolveThisBinding" bytecode op, which
simply loads the VM's current 'this' binding into the accumulator.
2021-10-24 17:18:06 +02:00
Idan Horowitz
844be7a0a5 LibJS: Convert the RegExpCreate AO to ThrowCompletionOr 2021-10-23 18:01:51 +02:00
Idan Horowitz
e26d9f419b LibJS: Remove vm.construct and it's usages 2021-10-23 02:49:41 +03:00
Idan Horowitz
db5df26841 LibJS: Convert Array AOs to ThrowCompletionOr 2021-10-22 15:07:04 +03:00
Timothy Flynn
7b4814f74c LibJS: Convert IteratorValue AO to ThrowCompletionOr 2021-10-21 00:26:45 +01:00
Timothy Flynn
a64752cd34 LibJS: Convert IteratorComplete AO to ThrowCompletionOr 2021-10-21 00:26:45 +01:00
Timothy Flynn
c981d7b9bd LibJS: Convert IteratorNext AO to ThrowCompletionOr 2021-10-21 00:26:45 +01:00
Timothy Flynn
860a37640b LibJS: Convert GetIterator AO to ThrowCompletionOr 2021-10-21 00:26:45 +01:00
davidot
13ead80ee6 LibJS: Add PrivateEnvironment 2021-10-20 23:19:17 +01:00
Idan Horowitz
545d403f6b LibJS: Convert Value operator AOs to ThrowCompletionOr 2021-10-18 23:06:11 +01:00
Idan Horowitz
48ac15758e LibJS: Convert is_loosely_equal() to ThrowCompletionOr 2021-10-18 23:06:11 +01:00
Idan Horowitz
c488f5a59d LibJS: Convert to_property_key() to ThrowCompletionOr 2021-10-17 12:12:35 +01:00
Idan Horowitz
b8f101888b LibJS: Convert to_numeric() to ThrowCompletionOr 2021-10-17 12:12:35 +01:00
Linus Groh
52976bfac6 LibJS: Convert to_object() to ThrowCompletionOr 2021-10-13 09:55:10 +01: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
Linus Groh
364dd42fc8 LibJS: Convert create_data_property_or_throw() to ThrowCompletionOr 2021-10-03 20:14:03 +01:00
Linus Groh
1d45541278 LibJS: Convert Object::set() to ThrowCompletionOr 2021-10-03 20:14:03 +01:00
Linus Groh
b7e5f08e56 LibJS: Convert Object::get() to ThrowCompletionOr
To no one's surprise, this patch is pretty big - this is possibly the
most used AO of all of them. Definitely worth it though.
2021-10-03 20:14:03 +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
ee8380edea LibJS: Convert internal_own_property_keys() to ThrowCompletionOr 2021-09-29 23:49:53 +01:00
Linus Groh
e37cf73300 LibJS: Rename OrdinaryFunctionObject to ECMAScriptFunctionObject
The old name is the result of the perhaps somewhat confusingly named
abstract operation OrdinaryFunctionCreate(), which creates an "ordinary
object" (https://tc39.es/ecma262/#ordinary-object) in contrast to an
"exotic object" (https://tc39.es/ecma262/#exotic-object).

However, the term "Ordinary Function" is not used anywhere in the spec,
instead the created object is referred to as an "ECMAScript Function
Object" (https://tc39.es/ecma262/#sec-ecmascript-function-objects), so
let's call it that.

The "ordinary" vs. "exotic" distinction is important because there are
also "Built-in Function Objects", which can be either implemented as
ordinary ECMAScript function objects, or as exotic objects (our
NativeFunction).

More work needs to be done to move a lot of infrastructure to
ECMAScriptFunctionObject in order to make FunctionObject nothing more
than an interface for objects that implement [[Call]] and optionally
[[Construct]].
2021-09-25 17:51:30 +02:00
Linus Groh
580a7e0f7c LibJS: Rename abstract_eq() to is_loosely_equal()
This got turned into a proper AO with a new name recently.

See: https://github.com/tc39/ecma262/commit/c7d6d1c
2021-09-24 09:13:57 +02:00
Linus Groh
c7ff89891c LibJS: Rename strict_eq() to is_strictly_equal()
This got turned into a proper AO with a new name recently.

See: https://github.com/tc39/ecma262/commit/19d7ca4
2021-09-24 09:13:57 +02:00
Idan Horowitz
ab594e5f2f LibJS: Convert Value::invoke and VM::call to ThrowCompletionOr 2021-09-23 23:59:13 +03:00
Brian Gianforcaro
53166c10ca LibJS: Remove unused header includes 2021-08-01 08:10:16 +02:00
Timothy Flynn
a0c19deb80 LibJS: Implement RegExpCreate/RegExpInitialize closer to the spec
RegExpInitialize specifies how the pattern string should be created
before passing it to [[RegExpMatcher]]. Rather than passing it as-is,
the string should be converted to code points and back to a "List" (if
the Unicode flag is present), or as a "List" of UTF-16 code units.
Further. the spec requires that we keep both the original pattern string
and this parsed string in the RegExp object.

The caveat is that the LibRegex parser further requires any multi-byte
code units to be escaped (as "\unnnn"). Otherwise, the code unit is
recognized as individual UTF-8 bytes.
2021-07-23 23:06:57 +01:00
Idan Horowitz
8d01d43f5e LibJS: Replace the boolean argument of Object::set with an enum class
This is more serenity-esque and also makes pointing out missing
exception checks during reviews much easier.
2021-07-16 17:50:01 +01:00
Idan Horowitz
e3ef241108 LibJS: Remove the non-standard put helper and replace it's usages
This removes all usages of the non-standard put helper method and
replaces all of it's usages with the specification required alternative
or with define_direct_property where appropriate.
2021-07-06 14:20:30 +01:00
Idan Horowitz
a6b8291a9b LibJS: Add define_direct_property and remove the define_property helper
This removes all usages of the non-standard define_property helper
method and replaces all it's usages with the specification required
alternative or with define_direct_property where appropriate.
2021-07-06 14:20:30 +01:00
Linus Groh
9555ca99a0 LibJS: Remove unnecessary value_or() from get()
Object::get() never returns an empty value anymore, as per the spec, so
having a value_or() fallback is no longer needed.
2021-07-05 00:03:25 +02:00
Linus Groh
09bd5f8772 LibJS: Rewrite most of Object for spec compliance :^)
This is a huge patch, I know. In hindsight this perhaps could've been
done slightly more incremental, but I started and then fixed everything
until it worked, and here we are. I tried splitting of some completely
unrelated changes into separate commits, however. Anyway.

This is a rewrite of most of Object, and by extension large parts of
Array, Proxy, Reflect, String, TypedArray, and some other things.

What we already had worked fine for about 90% of things, but getting the
last 10% right proved to be increasingly difficult with the current code
that sort of grew organically and is only very loosely based on the
spec - this became especially obvious when we started fixing a large
number of test262 failures.

Key changes include:

- 1:1 matching function names and parameters of all object-related
  functions, to avoid ambiguity. Previously we had things like put(),
  which the spec doesn't have - as a result it wasn't always clear which
  need to be used.
- Better separation between object abstract operations and internal
  methods - the former are always the same, the latter can be overridden
  (and are therefore virtual). The internal methods (i.e. [[Foo]] in the
  spec) are now prefixed with 'internal_' for clarity - again, it was
  previously not always clear which AO a certain method represents,
  get() could've been both Get and [[Get]] (I don't know which one it
  was closer to right now).
  Note that some of the old names have been kept until all code relying
  on them is updated, but they are now simple wrappers around the
  closest matching standard abstract operation.
- Simplifications of the storage layer: functions that write values to
  storage are now prefixed with 'storage_' to make their purpose clear,
  and as they are not part of the spec they should not contain any steps
  specified by it. Much functionality is now covered by the layers above
  it and was removed (e.g. handling of accessors, attribute checks).
- PropertyAttributes has been greatly simplified, and is being replaced
  by PropertyDescriptor - a concept similar to the current
  implementation, but more aligned with the actual spec. See the commit
  message of the previous commit where it was introduced for details.
- As a bonus, and since I had to look at the spec a whole lot anyway, I
  introduced more inline comments with the exact steps from the spec -
  this makes it super easy to verify correctness.
- East-const all the things.

As a result of all of this, things are much more correct but a bit
slower now. Retaining speed wasn't a consideration at all, I have done
no profiling of the new code - there might be low hanging fruits, which
we can then harvest separately.

Special thanks to Idan for helping me with this by tracking down bugs,
updating everything outside of LibJS to work with these changes (LibWeb,
Spreadsheet, HackStudio), as well as providing countless patches to fix
regressions I introduced - there still are very few (we got it down to
5), but we also get many new passing test262 tests in return. :^)

Co-authored-by: Idan Horowitz <idan.horowitz@gmail.com>
2021-07-04 22:07:36 +01:00
Idan Horowitz
e480d69130 LibJS: Bring ArrayCreate and ArrayConstructor closer to spec
Specifically, this now explicitly takes the length, adds missing
exceptions checks to calls with user-supplied lengths, takes and uses
the prototype argument, and fixes some spec non-conformance in
ArrayConstructor and its native functions around the use of ArrayCreate
2021-07-04 00:51:43 +01:00
Andreas Kling
c52ea3dad5 LibJS: Try to fix Clang build (NewClass::m_class_expression is unused) 2021-07-01 17:46:45 +02:00