Commit graph

97 commits

Author SHA1 Message Date
Linus Groh
2e2571743b LibJS: Use string::formatted() in to_string() functions 2020-10-04 19:22:02 +02:00
Linus Groh
f9eaac62d9 LibJS: Use String::formatted() for throw_exception() message 2020-10-04 19:22:02 +02:00
Andreas Kling
a007b3c379 LibJS: Move "strict mode" state to the call stack
Each call frame now knows whether it's executing in strict mode.
It's no longer necessary to access the scope stack to find this mode.
2020-10-04 17:03:33 +02:00
Andreas Kling
063acda76e LibJS: Remove a bunch of unnecessary uses of Cell::interpreter()
We'll want to get rid of all uses of this, to free up the engine from
the old assumption that there's always an Interpreter available.
2020-09-27 20:26:58 +02:00
Andreas Kling
a61ede51e2 LibJS: Don't require Interpreter& for constructing an Accessor 2020-09-27 20:26:58 +02:00
Andreas Kling
c59a8d84d3 LibJS: Reduce Interpreter& usage in the Object class 2020-09-27 20:26:58 +02:00
Andreas Kling
b9793e603c LibJS: Don't require Interpreter& in PropertyName and StringOrSymbol 2020-09-27 20:26:58 +02:00
Andreas Kling
340a115dfe LibJS: Make native function/property callbacks take VM, not Interpreter
More work on decoupling the general runtime from Interpreter. The goal
is becoming clearer. Interpreter should be one possible way to execute
code inside a VM. In the future we might have other ways :^)
2020-09-27 20:26:58 +02:00
Andreas Kling
1ff9d33131 LibJS: Make Function::call() not require an Interpreter&
This makes a difference inside ScriptFunction::call(), which will now
instantiate a temporary Interpreter if one is not attached to the VM.
2020-09-27 20:26:58 +02:00
Andreas Kling
6861c619c6 LibJS: Move most of Interpreter into VM
This patch moves the exception state, call stack and scope stack from
Interpreter to VM. I'm doing this to help myself discover what the
split between Interpreter and VM should be, by shuffling things around
and seeing what falls where.

With these changes, we no longer have a persistent lexical environment
for the current global object on the Interpreter's call stack. Instead,
we push/pop that environment on Interpreter::run() enter/exit.
Since it should only be used to find the global "this", and not for
variable storage (that goes directly into the global object instead!),
I had to insert some short-circuiting when walking the environment
parent chain during variable lookup.

Note that this is a "stepping stone" commit, not a final design.
2020-09-27 20:26:58 +02:00
Andreas Kling
676cb87a8f LibJS: Use VM::exception() instead of Interpreter::exception() a bunch
There's a lot more of these things to fix. We'll also want to move from
passing Interpreter& around to VM& instead wherever that is enough.
2020-09-22 20:10:20 +02:00
Andreas Kling
976e55e942 LibJS: Remove some unnecessary indirection in Object constructors 2020-09-20 19:18:05 +02:00
Andreas Kling
4036ff9d91 LibJS: Remove unused argument in NativeFunction constructor 2020-09-20 19:11:11 +02:00
Ben Wiederhake
d8e22fedc3 Libraries: Unbreak building with extra debug macros 2020-08-30 09:43:49 +02:00
Andreas Kling
bbe2d4a2d9 LibJS+LibWeb: Clear exceptions after call'ing JavaScript functions
Decorated Interpreter::call() with [[nodiscard]] to provoke thinking
about the returned value at each call site. This is definitely not
perfect and we should really start thinking about slimming down the
public-facing LibJS interpreter API.

Fixes #3136.
2020-08-14 17:31:07 +02:00
Andreas Kling
3ee6ed965f LibJS: Use allocate_without_global_object for primitive cell types
More steps towards multiple global object support. Primitive cells
like strings, bigints, etc, don't actually have any connection to
the global object. Use the explicit API to clarify this.
2020-07-25 13:12:17 +02:00
Andreas Kling
aaf6014ae1 LibJS: Simplify Cell::initialize()
Remove the Interpreter& argument and pass only GlobalObject&. We can
find everything we need via the global object anyway.
2020-07-23 17:31:08 +02:00
Matthew Olsson
51bfc6c6b3 LibJS: Renamed Object::GetOwnPropertyReturnMode to Object::PropertyKind
This enum will be used by iterators, so it makes sense to use a more
general name.
2020-07-11 18:54:13 +02:00
Linus Groh
7241b9ca0c LibJS: Remove a few superfluous exception checks
We don't need to check for exceptions when defining properties on an
array we literally created ourselves a few lines earlier.
2020-07-11 18:38:51 +02:00
Matthew Olsson
7a1d485b19 LibJS: Integrate Symbols into objects as valid keys
This allows objects properties to be created for symbol keys in addition
to just plain strings/numbers
2020-07-09 23:33:00 +02:00
Matthew Olsson
93ebd320ef LibJS: Object.preventExtensions should allow property modfication
Existing properties on a non-extensible object should be changable and
deletable.
2020-07-07 10:47:10 +02:00
Matthew Olsson
5e971c91e3 LibJS: Hide some debug output behind flags
This hides some Object.cpp output, as well as removing the "debugger"
debug output.
2020-07-06 23:40:35 +02:00
Jack Karamanian
7533fd8b02 LibJS: Initial class implementation; allow super expressions in object
literal methods; add EnvrionmentRecord fields and methods to
LexicalEnvironment

Adding EnvrionmentRecord's fields and methods lets us throw an exception
when |this| is not initialized, which occurs when the super constructor
in a derived class has not yet been called, or when |this| has already
been initialized (the super constructor was already called).
2020-06-29 17:54:54 +02:00
Jack Karamanian
a535d58cac LibJS: Add Object::define_accessor()
This is a helper function based on the getter/setter definition logic from
ObjectExpression::execute() to look up an Accessor property if it already
exists, define a new Accessor property if it doesn't exist, and set the getter or
setter function on the Accessor.
2020-06-29 17:54:54 +02:00
Linus Groh
afcfea2001 LibJS: Handle "receiver" argument in Reflect.{get,set}() 2020-06-25 15:51:47 +02:00
Andreas Kling
675e7c0e6f LibJS: Explicitly invoke Cell constructor in Object(Object& prototype) 2020-06-23 18:28:28 +02:00
Andreas Kling
0166a1fa74 LibJS: Make NativeProperty a plain Cell instead of an Object
This removes the need for NativeProperty objects to have a prototype,
which just made things confusing.
2020-06-23 17:56:57 +02:00
Andreas Kling
ba641e97d9 LibJS: Clarify Object (base class) construction somewhat
Divide the Object constructor into three variants:

- The regular one (takes an Object& prototype)
- One for use by GlobalObject
- One for use by objects without a prototype (e.g ObjectPrototype)
2020-06-23 17:21:53 +02:00
Andreas Kling
e1f9da142e LibJS: NativeProperty get/put should take a GlobalObject& 2020-06-20 17:50:48 +02:00
Andreas Kling
a9e4babdaf LibJS: Pass GlobalObject& when constructing an Accessor 2020-06-20 17:50:48 +02:00
Andreas Kling
64513f3c23 LibJS: Move native objects towards two-pass construction
To make sure that everything is set up correctly in objects before we
start adding properties to them, we split cell allocation into 3 steps:

1. Allocate a cell of appropriate size from the Heap
2. Call the C++ constructor on the cell
3. Call initialize() on the constructed object

The job of initialize() is to define all the initial properties.
Doing it in a second pass guarantees that the Object has a valid Shape
and can find its own GlobalObject.
2020-06-20 15:46:30 +02:00
Andreas Kling
e4add19915 LibJS: Pass GlobalObject& to native functions and property accessors
More work towards supporting multiple global objects. Native C++ code
now get a GlobalObject& and don't have to ask the Interpreter for it.

I've added macros for declaring and defining native callbacks since
this was pretty tedious and this makes it easier next time we want to
change any of these signatures.
2020-06-20 15:45:07 +02:00
Andreas Kling
fdfda6dec2 AK: Make string-to-number conversion helpers return Optional
Get rid of the weird old signature:

- int StringType::to_int(bool& ok) const

And replace it with sensible new signature:

- Optional<int> StringType::to_int() const
2020-06-12 21:28:55 +02:00
Matthew Olsson
78155a6668 LibJS: Consolidate error messages into ErrorTypes.h
Now, exceptions can be thrown with
interpreter.throw_exception<T>(ErrorType:TYPE, "format", "args",
"here").
2020-06-11 07:46:20 +02:00
Andreas Kling
affc479e83 LibJS+LibWeb: Remove a bunch of calls to Interpreter::global_object()
Objects should get the GlobalObject from themselves instead. However,
it's not yet available during construction so this only switches code
that happens after construction.

To support multiple global objects, Interpreter needs to stop holding
on to "the" global object and let each object graph own their global.
2020-06-08 12:25:45 +02:00
Andreas Kling
ff8bb962b6 LibJS: Always keep a reference to the global object in Shape
We need to move towards supporting multiple global objects, which will
be a large refactoring. To keep it manageable, let's do it in steps,
starting with giving Object a way to find the GlobalObject it lives
inside by asking its Shape for it.
2020-06-08 12:15:58 +02:00
Matthew Olsson
4e33fbdb67 LibJS: Add interpreter exception checks 2020-06-08 09:57:29 +02:00
Matthew Olsson
39ad42defd LibJS: Add Proxy objects
Includes all traps except the following: [[Call]], [[Construct]],
[[OwnPropertyKeys]].

An important implication of this commit is that any call to any virtual
Object method has the potential to throw an exception. These methods
were not checked in this commit -- a future commit will have to protect
these various method calls throughout the codebase.
2020-06-06 22:13:01 +02:00
Matthew Olsson
79958f4520 LibJS: Add PropertyDescriptor object
This new struct is now returned from get_own_property_descriptor. To
preserve the old functionality of returning an object, there is now a
get_own_property_descriptor_object method, for use in
{Object,Reflect}.getOwnPropertyDescriptor().

This change will be useful for the implementation of Proxies, which do a
lot of descriptor checks. We want to avoid as many object gets and puts
as possible.
2020-06-06 22:13:01 +02:00
Matthew Olsson
5ad5322f6a LibJS: Distinguish between omitted descriptor attributes and false ones
When calling Object.defineProperty, there is now a difference between
omitting a descriptor attribute and specifying that it is false. For
example, "{}" and "{ configurable: false }" will have different
attribute values.
2020-06-06 22:13:01 +02:00
Linus Groh
b958e4f573 LibJS: Disallow changing the prototype of non-extensible objects
Object::set_prototype() now returns a boolean indicating success.
Setting the prototype to an identical object is always considered
successful, even if the object is non-extensible.
2020-06-02 13:51:02 +02:00
Matthew Olsson
d5ae73a63b LibJS: Add Object.{isExtensible,preventExtensions}() 2020-06-02 08:50:26 +02:00
Matthew Olsson
4e331a1fcf LibJS: Object.getOwnPropertyDescriptor works properly with accessors 2020-05-30 10:32:52 +02:00
Linus Groh
688ca7b196 LibJS: Make Object::invoke() non-const
As suggested in #2431's code review.
2020-05-29 15:55:40 +02:00
Linus Groh
9755f8d297 LibJS: Add Object::invoke() 2020-05-29 08:00:02 +02:00
Marcin Gasperowicz
eadce65e04
LibJS: Implement standard semantics for relational operators (#2417)
Previously, the relational operators where casting any value to double
and comparing the results according to C++ semantics.

This patch makes the relational operators in JS behave according to the
standard specification.

Since we don't have BigInt yet, the implementation doesn't take it into
account. 

Moved PreferredType from Object to Value. Value::to_primitive now
passes preferred_type to Object::to_primitive.
2020-05-28 17:19:59 +02:00
Matthew Olsson
5ae9419a06 LibJS: Object index properties have descriptors; Handle sparse indices
This patch adds an IndexedProperties object for storing indexed
properties within an Object. This accomplishes two goals: indexed
properties now have an associated descriptor, and objects now gracefully
handle sparse properties.

The IndexedProperties class is a wrapper around two other classes, one
for simple indexed properties storage, and one for general indexed
property storage. Simple indexed property storage is the common-case,
and is simply a vector of properties which all have attributes of
default_attributes (writable, enumerable, and configurable).

General indexed property storage is for a collection of indexed
properties where EITHER one or more properties have attributes other
than default_attributes OR there is a property with a large index (in
particular, large is '200' or higher).

Indexed properties are now treated relatively the same as storage within
the various Object methods. Additionally, there is a custom iterator
class for IndexedProperties which makes iteration easy. The iterator
skips empty values by default, but can be configured otherwise.
Likewise, it evaluates getters by default, but can be set not to.
2020-05-28 17:17:13 +02:00
Matthew Olsson
dd08c992e8 LibJS: Simplify and normalize publicly-exposed Object functions
Previously, the Object class had many different types of functions for
each action. For example: get_by_index, get(PropertyName),
get(FlyString). This is a bit verbose, so these methods have been
shortened to simply use the PropertyName structure. The methods then
internally call _by_index if necessary. Note that the _by_index
have been made private to enforce this change.

Secondly, a clear distinction has been made between "putting" and
"defining" an object property. "Putting" should mean modifying a
(potentially) already existing property. This is akin to doing "a.b =
'foo'".

This implies two things about put operations:
    - They will search the prototype chain for setters and call them, if
      necessary.
    - If no property exists with a particular key, the put operation
      should create a new property with the default attributes
      (configurable, writable, and enumerable).

In contrast, "defining" a property should completely overwrite any
existing value without calling setters (if that property is
configurable, of course).

Thus, all of the many JS objects have had any "put" calls changed to
"define_property" calls. Additionally, "put_native_function" and
"put_native_property" have had their "put" replaced with "define".

Finally, "put_own_property" has been made private, as all necessary
functionality should be exposed with the put and define_property
methods.
2020-05-27 13:17:35 +02:00
Linus Groh
9c8d390682 LibJS: Refactor Accessor
This changes Accessor's m_{getter,setter} from Value to Function* which
seems like a better API to me - a getter/setter must either be a
function or missing, and the creation of an accessor with other values
must be prevented by the parser and Object.defineProperty() anyway.

Also add Accessor::set_{getter,setter}() so we can reuse an already
created accessor when evaluating an ObjectExpression with getter/setter
shorthand syntax.
2020-05-24 18:49:58 +02:00
Matthew Olsson
45dfa094e9 LibJS: Add getter/setter support
This patch adds a GetterSetterPair object. Values can now store pointers
to objects of this type. These objects are created when using
Object.defineProperty and providing an accessor descriptor.
2020-05-21 22:56:18 +02:00