Commit graph

118 commits

Author SHA1 Message Date
Andreas Kling
13d7c09125 Libraries: Move to Userland/Libraries/ 2021-01-12 12:17:46 +01:00
Andreas Kling
fdd974b7ef LibJS: Fix UB downcast during GlobalObject construction
When constructing a GlobalObject, it has to pass itself as the global
object to its own Shape. Since this is done in the Object constructor,
and Object is a base class of GlobalObject, it's not yet valid to cast
"this" to a GlobalObject*.

Fix this by having Shape store the global object as an Object& and move
Shape::global_object() to GlobalObject.h where we can at least perform a
valid static_cast in the getter.

Found by oss-fuzz: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=29267
2021-01-05 12:02:59 +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
6c4b823cef LibJS: Make marking object indexed properties less allocation-heavy
We were building up a vector with all the values in an object's indexed
property storage, and then iterating over the vector to mark values.
Instead of this, simply iterate over the property storage directly. :^)
2020-12-08 17:49:02 +01:00
Linus Groh
5eb1f752ab LibJS: Use new format functions everywhere
This changes the remaining uses of the following functions across LibJS:

- String::format() => String::formatted()
- dbg() => dbgln()
- printf() => out(), outln()
- fprintf() => warnln()

I also removed the relevant 'LogStream& operator<<' overloads as they're
not needed anymore.
2020-12-06 18:52:52 +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
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
a02b9983f9 LibJS: Throw RuntimeError when reaching the end of the stack
This prevents stack overflows when calling infinite/deep recursive
functions, e.g.:

    const f = () => f(); f();
    JSON.stringify({}, () => ({ foo: "bar" }));
    new Proxy({}, { get: (_, __, p) => p.foo }).foo;

The VM caches a StackInfo object to not slow down function calls
considerably. VM::push_call_frame() will throw an exception if
necessary (plain Error with "RuntimeError" as its .name).
2020-11-08 16:51:54 +01:00
Andreas Kling
43ff2ea8d8 LibJS: Use regular stack for VM call frames instead of Vector storage
Keeping the VM call frames in a Vector could cause them to move around
underneath us due to Vector resizing. Avoid this issue by allocating
CallFrame objects on the stack and having the VM simply keep a list
of pointers to each CallFrame, instead of the CallFrames themselves.

Fixes #3830.
Fixes #3951.
2020-11-07 13:58:28 +01:00
Linus Groh
0bb66890c8 LibJS: Fix Object::delete_property() with numeric string property
- We have to check if the property name is a string before calling
  as_string() on it
- We can't as_number() the same property name but have to use the parsed
  index number

Fixes #3950.
2020-11-05 19:15:00 +01:00
Linus Groh
8d96f428ef LibJS: ASSERT(property_name.is_valid()) in more Object methods 2020-11-05 19:15:00 +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
77c1957961 LibJS: Use allocate_without_global_object for allocating Shapes 2020-10-17 23:47:07 +02: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
1d96ecf148 Everywhere: Add missing <AK/TemporaryChange.h> includes
Don't rely on HashTable.h pulling this in.
2020-10-15 23:49:53 +02:00
Andreas Kling
8f535435dc LibJS: Avoid property lookups during object initialization
When we're initializing objects, we're just adding a bunch of new
properties, without transition, and without overlap (we never add
the same property twice.)

Take advantage of this by skipping lookups entirely (no need to see
if we're overwriting an existing property) during initialization.

Another nice test-js speedup :^)
2020-10-13 23:57:45 +02:00
Andreas Kling
7b863330dc LibJS: Cache commonly used FlyStrings in the VM
Roughly 7% of test-js runtime was spent creating FlyStrings from string
literals. This patch frontloads that work and caches all the commonly
used names in LibJS on a CommonPropertyNames struct that hangs off VM.
2020-10-13 23:57:45 +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
Linus Groh
123f98201e LibJS: Use String::formatted() in various other places 2020-10-04 19:22:02 +02:00
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