Passing a Heap& to it only to then call interpreter() on that is weird.
Let's just give it the Interpreter& directly, like some of the other
to_something() functions.
There are now two API's on Value:
- Value::to_string(Interpreter&) -- may throw.
- Value::to_string_without_side_effects() -- will never throw.
These are some pretty big sweeping changes, so it's possible that I did
some part the wrong way. We'll work it out as we go. :^)
Fixes#2123.
The ECMAScript spec defines multiple equality operations which are used
all over the spec; this patch introduces them. Of course, the two
primary equality operations are AbtractEquals ('==') and StrictEquals
('==='), which have been renamed to 'abstract_eq' and 'strict_eq' in
this patch.
In support of the two operations mentioned above, the following have
also been added: SameValue, SameValueZero, and SameValueNonNumeric.
These are important to have, because they are used elsewhere in the spec
aside from the two primary equality comparisons.
This commit introduces a way to get an object's own properties in the
correct order. The "correct order" for JS object properties is first all
array-like index properties (numeric keys) sorted by insertion order,
followed by all string properties sorted by insertion order.
Objects also now print correctly in the repl! Before this commit:
courage ~/js-tests $ js
> ({ foo: 1, bar: 2, baz: 3 })
{ bar: 2, foo: 1, baz: 3 }
After:
courage ~/js-tests $ js
> ({ foo: 1, bar: 2, baz: 3 })
{ foo: 1, bar: 2, baz: 3 }
Added the ability to include a u8 attributes parameter with all of the
various put methods in the Object class. They can be omitted, in which
case it defaults to "Writable | Enumerable | Configurable", just like
before this commit.
All of the attribute values for each property were gathered from
SpiderMonkey in the Firefox console. Some properties (e.g. all of the
canvas element properties) have undefined property descriptors... not
quite sure what that means. Those were left as the default specified
above.
It turns out "delete" is actually a unary op :)
This patch implements deletion of object properties, it doesn't yet
work for casually deleting properties from the global object.
When deleting a property from an object, we switch that object to
having a unique shape, no longer sharing shapes with others.
Once an object has a unique shape, it no longer needs to care about
shape transitions.
JS::Value already has the empty state ({} or Value() gives you one.)
Use this instead of wrapping Value in Optional in some places.
I've also added Value::value_or(Value) so you can easily provide a
fallback value when one is not present.
Everyone who constructs an Object must now pass a prototype object when
applicable. There's still a fair amount of code that passes something
fetched from the Interpreter, but this brings us closer to being able
to detach prototypes from Interpreter eventually.
Let's start moving towards native JS objects taking their prototype as
a constructor argument.
This will eventually allow us to move prototypes off of Interpreter and
into GlobalObject.
The output of FunctionPrototype::to_string is now more in line
with the output in Firefox. The builtin constructors have been
extended to include their function name in the output.
Object.defineProperty() can now change the attributes of a property
already on the object. Internally this becomes a shape transition with
the TransitionType::Configure. Such transitions don't expand the
property storage capacity, but rather simply keep attributes up to date
when generating a property table.
We now care (a little bit) about the "configurable" and "writable"
property attributes.
Property attributes are stored together with the property name in
the Shape object. Forward transitions are not attribute-savvy and will
cause poor Shape reuse in the case of multiple same-name properties
with different attributes.
Oh, and this patch also adds Object.getOwnPropertyDescriptor() :^)
This patch adds a new kind of JS::Value, the empty value.
It's what you get when you do JSValue() (or most commonly, {} in C++.)
An empty Value signifies the absence of a value, and should never be
visible to JavaScript itself. As of right now, it's used for array
holes and as a return value when an exception has been thrown and we
just want to unwind.
This patch is a bit of a mess as I had to fix a whole bunch of code
that was relying on JSValue() being undefined, etc.
Objects can have both named and indexed properties. Previously we kept
all property names as strings. This patch separates named and indexed
properties and splits them between Object::m_storage and m_elements.
This allows us to do much faster array-style access using numeric
indices. It also makes the Array class much less special, since all
Objects now have number-indexed storage. :^)
This patch adds JS::Shape, which implements a transition tree for our
Object class. Object property keys, prototypes and attributes are now
stored in a Shape, and each Object has a Shape.
When adding a property to an Object, we make a transition from the old
Shape to a new Shape. If we've made the same exact transition in the
past (with another Object), we reuse the same transition and both
objects may now share a Shape.
This will become the foundation of inline caching and other engine
optimizations in the future. :^)
Let's move towards using references over pointers in LibJS as well.
I had originally steered away from it because that's how I've seen
things done in other engines. But this is not the other engines. :^)
This adds Function::construct() for constructor function calls via `new`
keyword. NativeFunction doesn't have constructor behaviour by default,
ScriptFunction simply calls call() in construct()
Native functions now only get the Interpreter& as an argument. They can
then extract |this| along with any indexed arguments it wants from it.
This forces functions that want |this| to actually deal with calling
interpreter.this_value().to_object(), and dealing with the possibility
of a non-object |this|.
This is still not great but let's keep massaging it forward.
Fix the "instanceof" operator to check if the constructor's prototype
property occurs anywhere in the prototype chain of the instance object.
This patch also adds Object.setPrototypeOf() to make it possible to
create a test for this bug.
Thanks to DexesTTP for pointing this out! :^)