Commit graph

78 commits

Author SHA1 Message Date
Andreas Kling
13d7c09125 Libraries: Move to Userland/Libraries/ 2021-01-12 12:17:46 +01:00
Andreas Kling
d2613403e0 LibJS+LibWeb: Stop generating is_foo_wrapper() for JS DOM wrappers 2021-01-01 18:06:38 +01:00
Andreas Kling
f48751a739 LibJS: Remove hand-rolled Object is_foo() helpers in favor of RTTI 2021-01-01 17:46:39 +01:00
Andreas Kling
8333055c3d LibJS: Use RTTI for inheritance checks
This replaces the hand-rolled string-based inheritance check tech.
2021-01-01 17:00:20 +01:00
asynts
2981f10a5e LibWeb: Apply suggested fixes. 2020-12-09 21:05:06 +01:00
Linus Groh
909f430612 LibJS: Move is_script_function() to Object
Every Object should be able to tell us if it is a ScriptFunction, not
only Function objects!
2020-12-05 10:05:28 +01:00
Linus Groh
32571dfa53 LibJS: Add ArrayBuffer 2020-12-02 23:49:00 +01:00
Andreas Kling
3565d3c60c LibJS: Add six typed arrays (signed and unsigned 8/16/32-bit)
This patch adds six of the standard type arrays and tries to share as
much code as possible:

- Uint8Array
- Uint16Array
- Uint32Array
- Int8Array
- Int16Array
- Int32Array
2020-12-01 21:05:25 +01:00
Andreas Kling
93feb7a81f LibJS: Have Uint8ClampedArray delegate OOB accesses to JS::Object
Uint8ClampedArray itself only cares about legitimate in-bounds accesses
since that's what where the specialization happens.
2020-12-01 17:12:04 +01:00
Andreas Kling
c3fe9b4df8 LibJS: Add a scope object abstraction
Both GlobalObject and LexicalEnvironment now inherit from ScopeObject,
and the VM's call frames point to a ScopeObject chain rather than just
a LexicalEnvironment chain.

This gives us much more flexibility to implement things like "with",
and also unifies some of the code paths that previously required
special handling of the global object.

There's a bunch of more cleanup that can be done in the wake of this
change, and there might be some oversights in the handling of the
"super" keyword, but this generally seems like a good architectural
improvement. :^)
2020-11-28 17:16:48 +01:00
Andreas Kling
98f2da9834 LibJS: Rename Cell::visit_children() => Cell::visit_edges()
The GC heap is really a graph of cells, so "children" didn't quite feel
appropriate here.
2020-11-28 17:16:48 +01:00
Andreas Kling
97a05ac9ac LibJS: Allow Shape without a global object
It would be nice to be able to cache some shapes globally in the VM,
but then they can't be tied to a specific global object. So let's just
get rid of the requirement that shapes are tied to a global object.
2020-11-28 17:16:48 +01:00
Linus Groh
48369194d2 LibJS: Forward receiver value to native property getters/setters
There's no reason why only (user-defined) accessors would have set the
receiver as this value for their getters/setters, this is an oversight.
2020-11-22 19:00:19 +01:00
Linus Groh
c52739ea4b LibJS: Make call_native_property_{g,s}etter() take a NativeProperty&
Passing in a plain Value and expecting it to be a native property is
error prone, let's use a more narrow type and pass a NativeProperty
reference directly.
2020-11-22 19:00:19 +01:00
Linus Groh
fb89c324c5 LibJS: Implement spec-compliant OrdinaryToPrimitive
This renames Object::to_primitive() to Object::ordinary_to_primitive()
for two reasons:

- No confusion with Value::to_primitive()
- To match the spec's name

Also change existing uses of Object::to_primitive() to
Value::to_primitive() when the spec uses the latter (which will still
call Object::ordinary_to_primitive()). Object::to_string() has been
removed as it's not needed anymore (and nothing the spec uses).

This makes it possible to overwrite an object's toString and valueOf and
have them provide results for anything that uses to_primitive() - e.g.:

    const o = { toString: undefined, valueOf: () => 42 };
    Number(o) // 42, previously NaN
    ["foo", o].toString(); // "foo,42", previously "foo,[object Object]"
    ++o // 43, previously NaN

etc.
2020-11-04 19:33:49 +01:00
Andreas Kling
d3dfd55472 LibJS: Prebake the empty object ({}) with a prototype
Instead of performing a prototype transition for every new object we
create via {}, prebake the object returned by Object::create_empty()
with a shape with ObjectPrototype as the prototype.

We also prebake the shape for the object assigned to the "prototype"
property of new ScriptFunction objects, since those are extremely
common and that code broke from this change anyway.

This avoid a large number of transitions and is a small speed-up on
test-js.
2020-10-17 23:23:53 +02:00
Andreas Kling
4c33209011 LibJS: Add Object::define_property_without_transition() helper
This allows us to avoid transitioning in two common cases, saving some
time during object construction.
2020-10-06 17:43:51 +02:00
Andreas Kling
69bae3fd9a LibJS: Prevent object shape transitions during runtime object buildup
While initialization common runtime objects like functions, prototypes,
etc, we don't really care about tracking transitions for each and every
property added to them.

This patch puts objects into a "disable transitions" mode while we call
initialize() on them. After that, adding more properties will cause new
transitions to be generated and added to the chain.

This gives a ~10% speed-up on test-js. :^)
2020-10-05 20:53:00 +02:00
Andreas Kling
ec55490198 LibJS: Make global objects have unique shape from the start
There's no point in trying to achieve shape sharing for global objects,
so we can simply make the shape unique from the start and avoid making
a transition chain.
2020-10-04 22:56:45 +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
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
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
c831fb17bf LibJS: Add StringIterator 2020-07-13 15:07:29 +02:00
Matthew Olsson
2ea85355fe LibJS: Start implementing iterable framework, add ArrayIterator
With the addition of symbol keys, work can now be done on starting to
implement the well-known symbol functionality. The most important of
these well-known symbols is by far Symbol.iterator.

This patch adds IteratorPrototype, as well as ArrayIterator and
ArrayIteratorPrototype. In the future, sometime after StringIterator has
also been added, this will allow us to use Symbol.iterator directly in
for..of loops, enabling the use of custom iterator objects. Also makes
adding iterator support to native objects much easier (as will have to
be done for Map and Set, when they get added).
2020-07-11 18:54:13 +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
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
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
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
af51dc105a LibJS+LibWeb: Add JS::Object::inherits(class_name)
To allow implementing the DOM class hierarchy in JS bindings, this
patch adds an inherits() function that can be used to ask an Object
if it inherits from a specific C++ class (by name).

The necessary overrides are baked into each Object subclass by the
new JS_OBJECT macro, which works similarly to C_OBJECT in LibCore.

Thanks to @Dexesttp for suggesting this approach. :^)
2020-06-21 15:15:52 +02:00
Andreas Kling
94fdf4fa5a LibWeb+LibJS: Add a naive way to check if a wrapper "is" a certain type
Instead of only checking the class_name(), we now generate an is_foo()
virtual in the wrapper generator. (It's currently something we override
on Bindings::Wrapper, which is not really scalable.)

Longer term we'll need to think up something smarter for verifying that
one wrapper "is" another type of wrapper.
2020-06-21 00:58:55 +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
Matthew Olsson
39576b2238 LibJS: Add JSON.stringify 2020-06-13 12:43:22 +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
Linus Groh
0ff9d7e189 LibJS: Add BigInt 2020-06-07 19:29:40 +02:00
Matthew Olsson
61ac1d3ffa LibJS: Lex and parse regex literals, add RegExp objects
This adds regex parsing/lexing, as well as a relatively empty
RegExpObject. The purpose of this patch is to allow the engine to not
get hung up on parsing regexes. This will aid in finding new syntax
errors (say, from google or twitter) without having to replace all of
their regexes first!
2020-06-07 19:06:55 +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
mattco98
4ced126704 LibJS: Add symbol objects
This commit adds the following classes: SymbolObject, SymbolConstructor,
SymbolPrototype, and Symbol. This commit does not introduce any
new functionality to the Object class, so they cannot be used as
property keys in objects.
2020-05-17 18:05:15 +02:00