Commit graph

166 commits

Author SHA1 Message Date
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