mirror of
https://github.com/RGBCube/serenity
synced 2025-05-25 22:35:07 +00:00
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.
This commit is contained in:
parent
919fc7a814
commit
d3dfd55472
5 changed files with 24 additions and 4 deletions
|
@ -84,6 +84,13 @@ void GlobalObject::initialize()
|
||||||
m_object_prototype = heap().allocate_without_global_object<ObjectPrototype>(*this);
|
m_object_prototype = heap().allocate_without_global_object<ObjectPrototype>(*this);
|
||||||
m_function_prototype = heap().allocate_without_global_object<FunctionPrototype>(*this);
|
m_function_prototype = heap().allocate_without_global_object<FunctionPrototype>(*this);
|
||||||
|
|
||||||
|
m_new_object_shape = vm.heap().allocate<Shape>(*this, *this);
|
||||||
|
m_new_object_shape->set_prototype_without_transition(m_object_prototype);
|
||||||
|
|
||||||
|
m_new_script_function_prototype_object_shape = vm.heap().allocate<Shape>(*this, *this);
|
||||||
|
m_new_script_function_prototype_object_shape->set_prototype_without_transition(m_object_prototype);
|
||||||
|
m_new_script_function_prototype_object_shape->add_property_without_transition(vm.names.constructor, Attribute::Writable | Attribute::Configurable);
|
||||||
|
|
||||||
static_cast<FunctionPrototype*>(m_function_prototype)->initialize(*this);
|
static_cast<FunctionPrototype*>(m_function_prototype)->initialize(*this);
|
||||||
static_cast<ObjectPrototype*>(m_object_prototype)->initialize(*this);
|
static_cast<ObjectPrototype*>(m_object_prototype)->initialize(*this);
|
||||||
|
|
||||||
|
@ -143,6 +150,8 @@ void GlobalObject::visit_children(Visitor& visitor)
|
||||||
Object::visit_children(visitor);
|
Object::visit_children(visitor);
|
||||||
|
|
||||||
visitor.visit(m_empty_object_shape);
|
visitor.visit(m_empty_object_shape);
|
||||||
|
visitor.visit(m_new_object_shape);
|
||||||
|
visitor.visit(m_new_script_function_prototype_object_shape);
|
||||||
|
|
||||||
#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName) \
|
#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName) \
|
||||||
visitor.visit(m_##snake_name##_constructor);
|
visitor.visit(m_##snake_name##_constructor);
|
||||||
|
|
|
@ -45,6 +45,9 @@ public:
|
||||||
|
|
||||||
Shape* empty_object_shape() { return m_empty_object_shape; }
|
Shape* empty_object_shape() { return m_empty_object_shape; }
|
||||||
|
|
||||||
|
Shape* new_object_shape() { return m_new_object_shape; }
|
||||||
|
Shape* new_script_function_prototype_object_shape() { return m_new_script_function_prototype_object_shape; }
|
||||||
|
|
||||||
#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName) \
|
#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName) \
|
||||||
ConstructorName* snake_name##_constructor() { return m_##snake_name##_constructor; } \
|
ConstructorName* snake_name##_constructor() { return m_##snake_name##_constructor; } \
|
||||||
Object* snake_name##_prototype() { return m_##snake_name##_prototype; }
|
Object* snake_name##_prototype() { return m_##snake_name##_prototype; }
|
||||||
|
@ -71,6 +74,8 @@ private:
|
||||||
NonnullOwnPtr<Console> m_console;
|
NonnullOwnPtr<Console> m_console;
|
||||||
|
|
||||||
Shape* m_empty_object_shape { nullptr };
|
Shape* m_empty_object_shape { nullptr };
|
||||||
|
Shape* m_new_object_shape { nullptr };
|
||||||
|
Shape* m_new_script_function_prototype_object_shape { nullptr };
|
||||||
|
|
||||||
#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName) \
|
#define __JS_ENUMERATE(ClassName, snake_name, PrototypeName, ConstructorName) \
|
||||||
ConstructorName* m_##snake_name##_constructor { nullptr }; \
|
ConstructorName* m_##snake_name##_constructor { nullptr }; \
|
||||||
|
|
|
@ -84,7 +84,7 @@ PropertyDescriptor PropertyDescriptor::from_dictionary(VM& vm, const Object& obj
|
||||||
|
|
||||||
Object* Object::create_empty(GlobalObject& global_object)
|
Object* Object::create_empty(GlobalObject& global_object)
|
||||||
{
|
{
|
||||||
return global_object.heap().allocate<Object>(global_object, *global_object.object_prototype());
|
return global_object.heap().allocate<Object>(global_object, *global_object.new_object_shape());
|
||||||
}
|
}
|
||||||
|
|
||||||
Object::Object(GlobalObjectTag)
|
Object::Object(GlobalObjectTag)
|
||||||
|
@ -99,12 +99,17 @@ Object::Object(ConstructWithoutPrototypeTag, GlobalObject& global_object)
|
||||||
}
|
}
|
||||||
|
|
||||||
Object::Object(Object& prototype)
|
Object::Object(Object& prototype)
|
||||||
: Cell()
|
|
||||||
{
|
{
|
||||||
m_shape = prototype.global_object().empty_object_shape();
|
m_shape = prototype.global_object().empty_object_shape();
|
||||||
set_prototype(&prototype);
|
set_prototype(&prototype);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Object::Object(Shape& shape)
|
||||||
|
: m_shape(&shape)
|
||||||
|
{
|
||||||
|
m_storage.resize(shape.property_count());
|
||||||
|
}
|
||||||
|
|
||||||
void Object::initialize(GlobalObject&)
|
void Object::initialize(GlobalObject&)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,6 +63,7 @@ public:
|
||||||
static Object* create_empty(GlobalObject&);
|
static Object* create_empty(GlobalObject&);
|
||||||
|
|
||||||
explicit Object(Object& prototype);
|
explicit Object(Object& prototype);
|
||||||
|
explicit Object(Shape&);
|
||||||
virtual void initialize(GlobalObject&) override;
|
virtual void initialize(GlobalObject&) override;
|
||||||
virtual ~Object();
|
virtual ~Object();
|
||||||
|
|
||||||
|
|
|
@ -69,8 +69,8 @@ void ScriptFunction::initialize(GlobalObject& global_object)
|
||||||
auto& vm = this->vm();
|
auto& vm = this->vm();
|
||||||
Function::initialize(global_object);
|
Function::initialize(global_object);
|
||||||
if (!m_is_arrow_function) {
|
if (!m_is_arrow_function) {
|
||||||
Object* prototype = Object::create_empty(global_object);
|
Object* prototype = vm.heap().allocate<Object>(global_object, *global_object.new_script_function_prototype_object_shape());
|
||||||
prototype->define_property_without_transition(vm.names.constructor, this, Attribute::Writable | Attribute::Configurable);
|
prototype->define_property(vm.names.constructor, this, Attribute::Writable | Attribute::Configurable);
|
||||||
define_property(vm.names.prototype, prototype, 0);
|
define_property(vm.names.prototype, prototype, 0);
|
||||||
}
|
}
|
||||||
define_native_property(vm.names.length, length_getter, nullptr, Attribute::Configurable);
|
define_native_property(vm.names.length, length_getter, nullptr, Attribute::Configurable);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue