Commit graph

277 commits

Author SHA1 Message Date
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
32932f83be LibJS: Rename {Abstract,Typed => Loosely,Strictly}{Equals,Inequals}
This affects the AST's BinaryOp enum as well as the Bytecode's
ENUMERATE_BYTECODE_OPS and JS_ENUMERATE_COMMON_BINARY_OPS macros.
2021-09-24 09:13:57 +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
Idan Horowitz
1da8faebf5 LibJS: Convert perform_eval to ThrowCompletionOr 2021-09-21 23:28:38 +03:00
Idan Horowitz
02a88c5063 LibJS: Convert make_super_property_reference to ThrowCompletionOr 2021-09-21 23:28:38 +03:00
Linus Groh
568296d0cc LibJS: Use ThrowCompletionOr in require_object_coercible() 2021-09-15 23:46:53 +01:00
Ali Mohammad Pur
72ddaa31e3 LibJS: Implement parsing and execution of optional chains 2021-09-14 20:03:27 +01:00
Ali Mohammad Pur
4f7e14e0aa LibJS: Reorder the global eval function call detection conditions a bit
This just makes it clearer, since the actual check is off-screen, making
the reader wonder what that check is for.
2021-09-14 20:03:27 +01:00
Linus Groh
99f9609e45 LibJS: Evaluate function arguments before checking callee type
In the spec, this happens in the EvaluateCall abstract operation
(https://tc39.es/ecma262/#sec-evaluatecall), and the order is defined
as:

    3. Let argList be ? ArgumentListEvaluation of arguments.
    4. If Type(func) is not Object, throw a TypeError exception.
    5. If IsCallable(func) is false, throw a TypeError exception.

In LibJS this is handled by CallExpression::execute(), which had the
callee function check first and would therefore never evaluate the
arguments for a non-function callee.
2021-09-13 17:44:08 +01:00
Andreas Kling
0d2c3f62d3 LibJS: Use move semantics more when creating Reference objects
Turns a bunch of FlyString copies into moves.
2021-09-11 20:38:45 +02:00
davidot
db0a48d34c LibJS: Restore the environment if an exception is thrown in 'with' block 2021-09-08 20:37:39 +01:00
Ali Mohammad Pur
97e97bccab Everywhere: Make ByteBuffer::{create_*,copy}() OOM-safe 2021-09-06 01:53:26 +02:00
davidot
def8b44c40 LibJS: Add support for public fields in classes 2021-09-01 13:39:14 +01:00
davidot
020bfc9d93 LibJS: Parse and partially execute import and export statements
We produce the import and export entries as per the spec. However we do
not yet verify that named things that are exported are declared
somewhere.
2021-08-15 23:51:47 +01:00
Timothy Flynn
f1dd770a8a LibJS: Parse RegExp literals at AST creation time, not execution time
The spec requires that invalid RegExp literals must cause a Syntax Error
before the JavaScript is executed. See:
https://tc39.es/ecma262/#sec-patterns-static-semantics-early-errors

This is explicitly tested in the RegExp/property-escapes test262 tests.
For example, see unsupported-property-Line_Break.js:

    $DONOTEVALUATE();
    /\p{Line_Break}/u;

That RegExp literal is invalid because Line_Break is not a supported
Unicode property. $DONOTEVALUATE() just throws an exception when it is
executed. The test expects that this file will fail to be parsed.

Note that RegExp patterns can still be parsed at execution time by way
of "new RegExp(...)".
2021-07-30 21:26:31 +01:00
Timothy Flynn
c6e9c6d6ab LibJS: Follow the spec more closely when determining the this value
Co-authored-by: davidot <david.tuin@gmail.com>
2021-07-20 23:45:28 +02:00
davidot
a394aa5830 LibJS: Fix that vm.in_strict_mode was propagated to eval and functions
For eval it depends on the CallerMode and for a created function it
depends on the function itself.
2021-07-20 23:45:28 +02:00
Ali Mohammad Pur
77a5144264 LibJS: Add support for binding patterns in catch clauses
`try { ... } catch({a=foo}) {}` is valid, and now we parse and evaluate
it correctly :^)
2021-07-11 21:41:54 +01:00
Ali Mohammad Pur
1a9518ebe3 LibJS: Implement parsing and evaluation for AssignmentPatterns
e.g. `[...foo] = bar` can now be evaluated :^)
2021-07-11 21:41:54 +01:00
Hendi
0dc4e722e6 LibJS: Make FunctionExpression more spec-compliant 2021-07-07 23:31:51 +01:00
Idan Horowitz
306d59276a LibJS: Stop using a native property for RegExp's lastIndex property
This is not a functional change, the exposed (incorrect) behaviour is
the same as it was before, this simply removes the last user of
NativeProperties, allowing us to remove them completely from LibJS.
2021-07-07 21:47:22 +01:00
Hendi
37c4fbb6ca LibJS: Don't hoist functions under certain circumstances
When a lexical declaration with the same name as a function exists,
the function is not hoisted (annex B).
2021-07-06 22:55:16 +01:00
Linus Groh
0ba81dc0b7 LibJS: Remove Object::is_array() in favor of Value::is_array() and RTTI
It's way too easy to get this wrong: for the IsArray abstract operation,
Value::is_array() needs to be called. Since we have RTTI, the virtual
Object::is_array() method is not needed anymore - if we need to know
whether something is *actually* a JS::Array (we currently check in more
cases than we should, I think) and not a Proxy with an Array target, we
should do that in a way that doesn't look like an abstract operation.
2021-07-06 14:26:18 +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
3faeabf1dc Revert "LibJS: Don't hoist functions under certain circumstances"
This reverts commit 3411d50737.

It was causing LeakSanitizer on CI to fail, possibly due to a circular
reference.
2021-07-06 13:25:37 +01:00
Hendi
3411d50737 LibJS: Don't hoist functions under certain circumstances
When a lexical declaration with the same name as a function exists,
the function is not hoisted (annex B).
2021-07-06 00:15:37 +01:00
Hendi
38fd980b0c LibJS: Improve function hoisting across blocks
The parser now keeps track of a scope chain so that it can hoist
function declarations to the closest function scope.
2021-07-06 00:15:37 +01:00
Hendi
72f8d90dc5 LibJS: Remove variables from FunctionNode
They weren't consumed anywhere outside the AST and went
against the usual concept of having declaration in ScopeNode.
2021-07-06 00:15:37 +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
Andreas Kling
d114ba4c4e LibJS: Make the with statement evaluation follow the spec even more
This was almost entirely up-to-spec already, just missing exception
checks, and we now leave the lexical environment in the modified state
if an exception occurs during statement evaluation.
2021-07-04 18:56:08 +02: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
e8430cf0d3 LibJS: Don't allow delete super.property
This should throw a ReferenceError, since `delete` is not allowed
on super references.
2021-07-03 01:30:30 +02:00
Andreas Kling
1270df257b LibJS: Bring the super keyword in line with the spec
This patch implements spec-compliant runtime semantics for the following
constructs:

- super.property
- super[property]

The MakeSuperPropertyReference AO is added to support this. :^)
2021-07-03 01:12:12 +02:00
Andreas Kling
fd43d1e205 LibJS: Improve ResolveBinding + add GetIdentifierReference
ResolveBinding now matches the spec, while the non-conforming parts
are moved to GetIdentifierReference.

Implementing this properly requires variable bindings.
2021-07-02 22:22:21 +02:00
Andreas Kling
71fc7ac7ac LibJS: Make SuperCall a proper AST node and clean up evaluation 2021-07-02 19:39:09 +02:00
Andreas Kling
d81f4d5228 LibJS: NewExpression doesn't need compute_this_and_callee()
Now that NewExpression is separated from CallExpression, it doesn't
have to use the ad-hoc compute_this_and_callee() logic.
2021-07-02 18:43:25 +02:00
Andreas Kling
814549b846 LibJS: Split out NewExpression evaluation from CallExpression
This patch adds an override for NewExpression::execute() in the AST
interpreter to separate the logic from CallExpression. As a result,
both evaluation functions are simplified.

Both expressions are still largely non-conforming, but this makes
it easier to work on improving that since we can now deal with them
separately. :^)
2021-07-02 18:25:32 +02:00
Andreas Kling
bad1acf137 LibJS: Break out ArgumentListEvaluation AO from CallExpression 2021-07-02 17:54:34 +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
Idan Horowitz
005d75656e LibCrypto: Replace from_base{2,8,10,16}() & to_base10 with from_base(N)
This allows us to support parsing and serializing BigIntegers to and
from any base N (such that 2 <= N <= 36).
2021-06-29 16:55:54 +01:00
Andreas Kling
c8270dbe2e LibJS: Rename ScriptFunction => OrdinaryFunctionObject
These are basically what the spec calls "ordinary function objects",
so let's have the name reflect that. :^)
2021-06-27 22:36:04 +02:00
Andreas Kling
ba9d5c4d54 LibJS: Rename Function => FunctionObject 2021-06-27 22:36:04 +02:00
Andreas Kling
7b28fa99ba LibJS: Rename Reference methods to match the spec
- get -> get_value (GetValue in the spec)
- put -> put_value (PutValue in the spec)

Also add spec links. :^)
2021-06-25 17:20:23 +02:00
Andreas Kling
bce7fdba81 LibJS: Bring Reference records a bit closer to the ECMAScript spec
Our Reference class now has the same fields as the spec:

- Base (a non-nullish value, an environment record, or `unresolvable`)
- Referenced Name (the name of the binding)
- Strict (whether the reference originated in strict mode code)
- ThisValue (if non-empty, the reference represents a `super` keyword)

The main difference from before is that we now resolve the environment
record that a reference interacts with. Previously we simply resolved
to either "local variable" or "global variable".

The associated abstract operations are still largely non-conforming,
since we don't yet implement proper variable bindings. But this patch
should at least fix a handful of test262 cases. :^)

There's one minor regression: some TypeError message strings get
a little worse due to doing a RequireObjectCoercible earlier in the
evaluation of MemberExpression.
2021-06-25 16:58:36 +02:00
Andreas Kling
6e1932e8b2 LibJS: Evaluate this in terms of ResolveThisBinding 2021-06-25 16:58:36 +02:00
Andreas Kling
07acdc7be2 LibJS: Rename VM::get_reference() => resolve_binding()
This function maps to the ResolveBinding operation from the spec,
so let's rename it to match.
2021-06-25 16:58:36 +02:00
Andreas Kling
e59bf87374 Userland: Replace VERIFY(is<T>) with verify_cast<T>
Instead of doing a VERIFY(is<T>(x)) and *then* casting it to T, we can
just do the cast right away with verify_cast<T>. :^)
2021-06-24 21:13:09 +02:00
Andreas Kling
c2ad599783 LibJS: Rename CallFrame => ExecutionContext
This struct represents what the ECMAScript specification calls an
"execution context" so let's use the same terminology. :^)
2021-06-24 19:28:00 +02:00
Anonymous
2822da8c8f LibJS: Correct behaviour of direct vs. indirect eval
eval only has direct access to the local scope when accessed through
the name eval. This includes locals named eval, because of course it
does.
2021-06-23 09:38:33 +01:00
Andreas Kling
8a3c9d9851 LibJS: Remove direct argument loading since it was buggy
The parser doesn't always track lexical scopes correctly, so let's not
rely on that for direct argument loading.

This reverts the LoadArguments bytecode instruction as well. We can
bring these things back when the parser can reliably tell us that
a given Identifier is indeed a function argument.
2021-06-22 22:20:17 +02:00
Andreas Kling
1d20380859 LibJS: Split the per-call-frame environment into lexical and variable
To better follow the spec, we need to distinguish between the current
execution context's lexical environment and variable environment.

This patch moves us to having two record pointers, although both of
them point at the same environment records for now.
2021-06-22 18:44:53 +02:00
Andreas Kling
aabd82d508 LibJS: Bring function environment records closer to the spec
This patch adds FunctionEnvironmentRecord as a subclass of the existing
DeclarativeEnvironmentRecord. Things that are specific to function
environment records move into there, simplifying the base.

Most of the abstract operations related to function environment records
are rewritten to match the spec exactly. I also had to implement
GetThisEnvironment() and GetSuperConstructor() to keep tests working
after the changes, so that's nice as well. :^)
2021-06-22 18:44:53 +02:00
Andreas Kling
395bee07e0 LibJS: Implement the NewObjectEnvironment() abstract operation 2021-06-22 01:17:15 +02:00
Andreas Kling
08510a0c80 LibJS: Rename VM::current_scope() => current_environment_record()
And rename some related functions that wrapped this as well.
2021-06-21 23:49:50 +02:00
Andreas Kling
d407f247b7 LibJS: Rename virtuals in EnvironmentRecord
This patch makes the following renames:

- get_from_scope() => get_from_environment_record()
- put_to_scope() => put_into_environment_record()
- delete_from_scope() => delete_from_environment_record()
2021-06-21 23:49:50 +02:00
Andreas Kling
5edd259b0a LibJS: Rename EnvironmentRecord::parent() => outer_environment()
This name matches the spec (corresponds to the [[OuterEnv]] slot.)
2021-06-21 23:49:50 +02:00
Andreas Kling
6c6dbcfc36 LibJS: Rename Environment Records so they match the spec :^)
This patch makes the following name changes:

- ScopeObject => EnvironmentRecord
- LexicalEnvironment => DeclarativeEnvironmentRecord
- WithScope => ObjectEnvironmentRecord
2021-06-21 23:49:50 +02:00
Andreas Kling
5b16b5d7c1 LibJS: Fix spelling mistake in VariableDeclaration::execute() 2021-06-21 20:58:55 +02:00
Matthew Olsson
ce04c2259f LibJS: Restructure and fully implement BindingPatterns 2021-06-19 09:38:26 +02:00
Idan Horowitz
d6df955305 LibJS: Add missing to_property_key exception check in ClassExpression 2021-06-17 10:56:11 +02:00
Linus Groh
317b88a8c3 LibJS: Replace Object's create_empty() with create() taking a prototype
This now matches the spec's OrdinaryObjectCreate() across the board:
instead of implicitly setting the created object's prototype to
%Object.prototype% and then in many cases setting it to a nullptr right
away, it now has an 'Object* prototype' parameter with _no default
value_. This makes the code easier to compare with the spec, very clear
in terms of what prototype is being used as well as avoiding unnecessary
shape transitions.

Also fixes a couple of cases were we weren't setting the correct
prototype.

There's no reason to assume that the object would not be empty (as in
having own properties), so let's follow our existing pattern of
Type::create(...) and simply call it 'create'.
2021-06-16 22:49:04 +01:00
Andreas Kling
6e0e8a8242 LibJS: Teach Reference to access call frame arguments directly 2021-06-14 11:26:12 +02:00
Andreas Kling
848944113c LibJS: Access function arguments directly in AST interpreter
Instead of doing a generic scoped variable lookup, function arguments
now go directly to the call frame arguments list.

This is a huge speedup on everything that uses arguments. :^)
2021-06-14 11:26:12 +02:00
Andreas Kling
481cef59b6 LibJS: Track which Identifier nodes refer to function arguments
This patch adds an "argument index" field to Identifier AST nodes.
If the Identifier refers to a function parameter in the currently
open function scope, we stash the index of the parameter here.

This will allow us to implement much faster direct access to function
argument variables.
2021-06-14 11:26:12 +02:00
Idan Horowitz
690eb3bb8a LibJS: Add support for hex, octal & binary big integer literals 2021-06-14 01:45:04 +01:00
Andreas Kling
dc65f54c06 AK: Rename Vector::append(Vector) => Vector::extend(Vector)
Let's make it a bit more clear when we're appending the elements from
one vector to the end of another vector.
2021-06-12 13:24:45 +02:00
Ali Mohammad Pur
8b3f8879c1 LibJS: Use an enum class instead of 'bool is_generator'
This avoid confusion in the order of the multiple boolean parameters
that exist.
2021-06-11 19:42:58 +04:30
Andreas Kling
749a3b9245 LibJS: Move is_arrow_function() from FunctionExpression to FunctionNode
This will make it easier to write bytecode generation for function
expressions in just a moment.
2021-06-11 10:45:49 +02:00
Linus Groh
17da54d49c LibJS: Fix two accidentally incorrect ScriptFunction constructions
The addition of an is_generator parameter broke this, as is_strict was
being passed in, causing an assertion.
This is being addressed by changing it to an enum in #7981, but in the
meantime let's just fix these two cases.
2021-06-11 01:21:46 +01:00
Ali Mohammad Pur
b47246ec70 LibJS: Switch AST.{h,cpp} to east const 2021-06-11 00:30:09 +02:00
Ali Mohammad Pur
3234697eca LibJS: Implement generator functions (only in bytecode mode) 2021-06-11 00:30:09 +02:00
Andreas Kling
93a07ba962 LibJS: Remove GlobalObject& argument from VM::construct()
We can just get the global object from the constructor function.
2021-06-10 23:17:29 +02:00
Linus Groh
83be39c91a LibJS: Handle Proxy with Array target in IsArray() abstract operation
This was missing from Value::is_array(), which is equivalent to the
spec's IsArray() abstract operation - it treats a Proxy value with an
Array target object as being an Array.
It can throw, so needs both the global object and an exception check
now.
2021-06-08 23:53:13 +02:00
Marcin Gasperowicz
624ceec04f LibJS: Make SwitchStatement::execute() return undefined for empty blocks
Previously SwitchStatement::execute() would return <empty> when hitting
break, continue or empty consequent block. This was not in line with
the standard.
2021-06-08 21:41:46 +01:00
Idan Horowitz
064ed8279e LibJS: Support deleting local variables with operator delete
To make this cleaner i also moved the logic into Reference::delete_.
2021-06-08 15:31:46 +01:00
Idan Horowitz
af58779def LibJS: Return undefined from a with statement if no value was generated
Co-authored-by: Linus Groh <mail@linusgroh.de>
2021-06-08 15:31:46 +01:00
Idan Horowitz
98897ff676 LibJS: Return the last value from a with statement 2021-06-08 15:31:46 +01:00
Andreas Kling
0553e0b048 LibJS: Move AST bytecode generation virtuals to separate cpp file
This will hopefully make it a bit more pleasant to edit this, as things
will just get larger and larger.
2021-06-07 18:11:59 +02:00
Andreas Kling
2b9fbd10ed LibJS: Add Sub bytecode instruction (subtract values) 2021-06-07 18:11:59 +02:00
Andreas Kling
37cb70836b LibJS: Some more opcodes for the bytecode VM
- NewString (allocates a new PrimitiveString from the GC heap)
- GetVariable (retrieves a variable in the current scope)
- SetVariable (assigns a variable in the current scope)
2021-06-07 18:11:59 +02:00
Andreas Kling
69dddd4ef5 LibJS: Start fleshing out a bytecode for the JavaScript engine :^)
This patch begins the work of implementing JavaScript execution in a
bytecode VM instead of an AST tree-walk interpreter.

It's probably quite naive, but we have to start somewhere.

The basic idea is that you call Bytecode::Generator::generate() on an
AST node and it hands you back a Bytecode::Block filled with
instructions that can then be interpreted by a Bytecode::Interpreter.

This first version only implements two instructions: Load and Add. :^)

Each bytecode block has infinity registers, and the interpreter resizes
its register file to fit the block being executed.

Two new `js` options are added in this patch as well:

`-d` will dump the generated bytecode
`-b` will execute the generated bytecode

Note that unless `-d` and/or `-b` are specified, none of the bytecode
related stuff in LibJS runs at all. This is implemented in parallel
with the existing AST interpreter. :^)
2021-06-07 18:11:59 +02:00
Idan Horowitz
eb0b1c432a LibJS: Replace StringOrSymbol::from_value with Value::to_property_key
This is a more specification compliant implementation of the
abstract operation 7.1.19 ToPropertyKey which should handle boxed
symbols correctly.
2021-06-05 14:15:28 +01:00
Ryan Chandler
c66b281856 LibJS: Fix functions binding this to global object in strict mode
This fixes an issue where this would be bound to the global object
by default when operating in strict mode.

According to the specification, the expected value for |this| when
no binding is provided is undefined.
2021-06-04 13:00:37 +01:00
Andreas Kling
bf8fd4c193 Everywhere: Remove accidental '\n' from various outln() invocations
Also convert outln(stderr, ...) to warnln(...)
2021-06-03 22:50:21 +02:00
Ali Mohammad Pur
7a00d6d9c8 LibJS: Implement destructuring assignments and function parameters 2021-05-29 23:02:23 +04:30
Linus Groh
0a329d2d70 LibJS: Make super() in catch block work
The TryStatement handler execution creates a new LexicalEnvironment
without a current function set, which we were not accounting for when
trying to get the super constructor while executing a SuperExpression.
This makes it work but isn't pretty - this needs some refactoring to be
close to the spec for that to happen.

Fixes #7045.
2021-05-11 23:31:30 +01:00
Linus Groh
c93c2dc72c LibJS: Rename RegExpLiteral m_content to m_pattern
This is what we call it elsewhere, let's be consistent.
2021-05-10 11:57:35 +01:00
FalseHonesty
bee16bb83a LibJS: Don't suppress GlobalObject variable lookup exceptions
In HackStudio's Debugger a custom GlobalObject is used to reflect
debugger variables into the JS scope by overriding GlobalObject's
get method. However, when throwing a custom error during that lookup
it was replaced with the generic "not found" js exception. This patch
makes it instead pass along the custom error.
2021-04-25 19:03:57 +02:00
Andreas Kling
3a4d42bbbb LibJS: Remove stray '%' from MemberExpression AST dump 2021-04-24 18:50:12 +02:00
Linus Groh
ebdeed087c Everywhere: Use linusg@serenityos.org for my copyright headers 2021-04-22 22:51:19 +02:00
Brian Gianforcaro
1682f0b760 Everything: Move to SPDX license identifiers in all files.
SPDX License Identifiers are a more compact / standardized
way of representing file license information.

See: https://spdx.dev/resources/use/#identifiers

This was done with the `ambr` search and replace tool.

 ambr --no-parent-ignore --key-from-file --rep-from-file key.txt rep.txt *
2021-04-22 11:22:27 +02:00
Linus Groh
726d631527 LibJS: Use references in CallExpression::compute_this_and_callee()
This has the nice side effect of giving us a decent error message for
something like undefined.foo() - another useless "ToObject on null or
undefined" gone. :^)
Also turn the various ternary operators into two separate if branches,
they don't really share that much.
2021-04-15 09:45:20 +02:00
Linus Groh
73a92c79b8 LibJS: Use reference in MemberExpression::execute()
This was basically duplicated code.
2021-04-14 22:37:12 +02:00
Linus Groh
4ee965f916 LibJS: Add set_exception() and change throw_exception() to take a reference
Sometimes we just want to set m_exception to some value we stored
previously, without really "throwing" it again - that's what
set_exception() does now. Since we have clear_exception(), it does take
a reference, i.e. you don't set_exception(nullptr). For consistency I
updated throw_exception() to do the same.
2021-04-13 15:40:52 +02:00
Linus Groh
f2abe42ecb LibJS: Update empty TryStatement result value to undefined
It's what the spec wants us to do, although I'm not sure if it has an
observable effect anywhere, as we don't expose empty values. Let's do it
anyway.
2021-04-13 15:40:52 +02:00
Linus Groh
7cbede4342 LibJS: Fix return value of TryStatement with finalizer
Previously we would always return the result of executing the finalizer,
however the spec dictates the finalizer result must only be returned for
a non-normal completion.
I added some more comments along the way, which should make it more
clear what's going on - the unwinding and exception flow isn't super
straightforward here.
2021-04-13 15:40:52 +02:00
Linus Groh
2172e51246 LibJS: Implicitly break for..in loop if the RHS result is nullish
This implements the missing step 6a of 14.7.5.6 ForIn/OfHeadEvaluation:

    a. If exprValue is undefined or null, then
        i. Return Completion { [[Type]]: break, [[Value]]: empty, [[Target]]: empty }.

In other words, this should just do nothing instead of throwing during
the undefined to object coercion:

    for (const x in undefined);
2021-04-10 21:00:04 +02:00
Linus Groh
275da6fcc9 LibJS: Update Object::define_accessor() to take both getter and setter
This replaces the current 'function plus boolean indicating the type'
API, which makes it easier to set both getter and setter at once.
This was already possible before but required two calls of this
function, which wasn't intuitive:

    define_accessor(name, getter, true, ...);
    define_accessor(name, setter, false, ...);

Which now becomes:

    define_accessor(name, getter, setter, ...);
2021-04-10 21:00:04 +02:00
Linus Groh
ec62783af9 LibJS: Let Object::delete_property() return a bool, not Value
Just like the various define_property functions, this should return a
bool directly and let the caller deal with wrapping it in a Value, if
necessary.
2021-04-10 21:00:04 +02:00
Linus Groh
1c3eef5317 LibJS: Use MarkedValueList for internal own properties getter functions
Letting these create and return a JS::Array directly is pretty awkward
since we then need to go through the indexed properties for iteration.
Just use a MarkedValueList (i.e. Vector<Value>) for this and add a new
Array::create_from() function to turn the Vector into a returnable
Array as we did before.

This brings it a lot closer to the spec as well, which uses the
CreateArrayFromList abstract operation to do exactly this.

There's an optimization opportunity for the future here, since we know
the Vector's size we could prepare the newly created Array accordingly,
e.g. by switching to generic storage upfront if needed.
2021-04-07 09:05:01 +02:00
Linus Groh
1416027486 LibJS: Add Object::get_enumerable_own_property_names() and use it
Object::get_own_properties() is a bit unwieldy to use - especially as
StringOnly is about to no longer be the default value. The spec has an
abstract operation specifically for this (EnumerateObjectProperties),
so let's use that. No functionality change.
2021-04-05 19:30:30 +02:00
Linus Groh
afc86abe24 LibJS: Remove this_object parameter from get/put own property functions
Specifically:

- Object::get_own_properties()
- Object::put_own_property()
- Object::put_own_property_by_index()

These APIs make no sense (and are inconsistent, get_own_property()
didn't have this parameter, for example) - and as expected we were
always passing in the same object we were calling the method on anyway.
2021-04-05 19:30:30 +02:00
Linus Groh
f1fde01025 LibJS: Fix returning from try statement
Not sure if this regressed at some point or just never worked, it
definitely wasn't tested at all. We would always return undefined when
returning from a try statement block, handler, or finalizer.
2021-04-03 16:34:34 +02:00
Linus Groh
d6cffb82a2 LibJS: Move 'typeof' string functionality from AST to Value
We should be able to get the 'typeof' string for any value directly, so
this is now a standalone Value::typeof() method instead of being part of
UnaryExpression::execute().
2021-04-02 22:24:30 +02:00
Andreas Kling
0255c8d976 Only apply auto-naming of function expressions based on syntax
The auto naming of function expressions is a purely syntactic
decision, so shouldn't be decided based on the dynamic type of
an assignment. This moves the decision making into the parser.

One icky hack is that we add a field to FunctionExpression to
indicate whether we can autoname. The real solution is to actually
generate a CompoundExpression node so that the parser can make
the correct decision, however this would have a potentially
significant run time cost.

This does not correct the behaviour for class expressions.

Patch from Anonymous.
2021-03-22 12:44:07 +01:00
Andreas Kling
c8382c32e9 LibJS: Split Value::Type::Number into Int32 and Double
We now store 32-bit integers as 32-bit integers directly which avoids
having to convert them from doubles when they're only used as 32-bit
integers anyway. :^)

This patch feels a bit incomplete and there's a lot of opportunities
to take advantage of this information. We'll have to find and exploit
them eventually.
2021-03-21 21:39:39 +01:00
Andreas Kling
e0abfcb27d LibJS: Don't track executing AST nodes in a Vector
Instead just link together the InterpreterNodeScopes in a linked list.
This was surprisingly hot on CanvasCycle.
2021-03-21 21:39:39 +01:00
Andreas Kling
dc8817638e LibJS: Only update anonymous function names when necessary
Previously we would generate function names for anonymous functions
on every AssignmentExpression, even if we weren't assigning a function.

We were also setting names of anonymous functions in arrays, which is
apparently a SpiderMonkey specific behavior not supported by V8, JSC
or required by ECMA262. This patch removes that behavior.

This is a huge performance improvement on the CanvasCycle demo! :^)
2021-03-21 21:39:39 +01:00
Andreas Kling
1603623772 LibJS: Move AST node stack from VM to Interpreter 2021-03-21 16:02:11 +01:00
Andreas Kling
0bfdf95af6 LibJS: Make an RAII helper for entering/exiting AST nodes 2021-03-16 10:51:55 +01:00
Linus Groh
c499239137 LibJS: Implement non-value-producing statements properly
For various statements the spec states:

    Return NormalCompletion(empty).

In those cases we have been returning undefined so far, which is
incorrect.

In other cases it states:

    Return Completion(UpdateEmpty(stmtCompletion, undefined)).

Which essentially means a statement is evaluated and its completion
value returned if non-empty, and undefined otherwise.

While not actually noticeable in normal scripts as the VM's "last value"
can't be accessed from JS code directly (with the exception of eval(),
see below), it provided an inconsistent experience in the REPL:

    > if (true) 42;
    42
    > if (true) { 42; }
    undefined

This also fixes the case where eval() would return undefined if the last
executed statement is not a value-producing one:

    eval("1;;;;;")
    eval("1;{}")
    eval("1;var a;")

As a consequence of the changes outlined above, these now all correctly
return 1.

See https://tc39.es/ecma262/#sec-block-runtime-semantics-evaluation,
"NOTE 2".

Fixes #3609.
2021-03-16 10:08:07 +01:00
Andreas Kling
8fd69e9e56 LibJS: Fix a handful of clang-tidy complaints in AST.cpp 2021-03-03 22:57:45 +01:00
Jean-Baptiste Boric
6f668ca3a4 LibJS: Fix crash due to AST node tracking inside call stack 2021-03-01 22:27:27 +01:00
Jean-Baptiste Boric
6172cb3599 LibJS: Keep track of current AST node inside the call stack 2021-03-01 11:14:36 +01:00
speles
f7d64e9fa8 LibJS: Set declared for-in and for-of variables as first time.
These declarations might be const, and now when we're handling it
properly, we have to set values to them correctly.
2021-02-26 16:59:37 +01:00
Andreas Kling
5d180d1f99 Everywhere: Rename ASSERT => VERIFY
(...and ASSERT_NOT_REACHED => VERIFY_NOT_REACHED)

Since all of these checks are done in release builds as well,
let's rename them to VERIFY to prevent confusion, as everyone is
used to assertions being compiled out in release.

We can introduce a new ASSERT macro that is specifically for debug
checks, but I'm doing this wholesale conversion first since we've
accumulated thousands of these already, and it's not immediately
obvious which ones are suitable for ASSERT.
2021-02-23 20:56:54 +01:00
Andreas Kling
70bd1724db LibJS: Include <typeinfo> in AST.cpp again
Linus points out that oss-fuzz wants this to be there.
2021-02-10 12:21:14 +01:00
Andreas Kling
635a5eec75 LibJS: Remove a whole bunch of unnecessary #includes 2021-02-10 09:13:29 +01:00
Linus Groh
509e5a3045 LibJS: Fix crash when printing error for missing class extends value prototype
If it's missing we get an empty value, but we can't use that with
to_string_without_side_effects() so we have to use undefined as the
default.

Fixes #5142.
2021-01-28 10:24:18 +01:00
Linus Groh
f37d3f25e6 LibJS: Remove redundant exception check from ClassExpression::execute()
as_object() cannot fail, leftover from ea55453.
2021-01-24 00:40:22 +01:00
Linus Groh
766f30f593 LibJS: Check if class extends value has a valid prototype
If we have a function as class extends value, we still cannot assume
that it has a prototype property and that property has a function or
null as its value - blindly calling to_object() on it may fail.

Fixes #5075.
2021-01-24 00:09:18 +01:00
Nico Weber
8ccd8b4a6f LibJS: Include <typeinfo> in AST.cpp
Without this, the oss-fuzz build says:

../Userland/Libraries/LibJS/AST.cpp:58:34: error: member access into incomplete type 'const std::type_info'
    return demangle(typeid(*this).name()).substring(4);
                                 ^
2021-01-20 21:00:27 +01:00
Andreas Kling
4da913bfab LibJS: Replace ASTNode::class_name() with RTTI
This is only used for debugging anyway, so performance doesn't matter
too much.
2021-01-17 14:36:53 +01:00
Andreas Kling
13d7c09125 Libraries: Move to Userland/Libraries/ 2021-01-12 12:17:46 +01:00
Renamed from Libraries/LibJS/AST.cpp (Browse further)