mirror of
https://github.com/RGBCube/serenity
synced 2025-05-30 23:58:12 +00:00
LibJS: Replace Object's create_empty() with create() taking a prototype
This now matches the spec's OrdinaryObjectCreate() across the board: instead of implicitly setting the created object's prototype to %Object.prototype% and then in many cases setting it to a nullptr right away, it now has an 'Object* prototype' parameter with _no default value_. This makes the code easier to compare with the spec, very clear in terms of what prototype is being used as well as avoiding unnecessary shape transitions. Also fixes a couple of cases were we weren't setting the correct prototype. There's no reason to assume that the object would not be empty (as in having own properties), so let's follow our existing pattern of Type::create(...) and simply call it 'create'.
This commit is contained in:
parent
7489189645
commit
317b88a8c3
14 changed files with 42 additions and 35 deletions
|
@ -263,7 +263,7 @@ JS_DEFINE_NATIVE_FUNCTION(SheetGlobalObject::parse_cell_name)
|
||||||
if (!position.has_value())
|
if (!position.has_value())
|
||||||
return JS::js_undefined();
|
return JS::js_undefined();
|
||||||
|
|
||||||
auto object = JS::Object::create_empty(global_object);
|
auto object = JS::Object::create(global_object, global_object.object_prototype());
|
||||||
object->put("column", JS::js_string(vm, sheet_object->m_sheet.column(position.value().column)));
|
object->put("column", JS::js_string(vm, sheet_object->m_sheet.column(position.value().column)));
|
||||||
object->put("row", JS::Value((unsigned)position.value().row));
|
object->put("row", JS::Value((unsigned)position.value().row));
|
||||||
|
|
||||||
|
@ -293,7 +293,7 @@ JS_DEFINE_NATIVE_FUNCTION(SheetGlobalObject::current_cell_position)
|
||||||
|
|
||||||
auto position = current_cell->position();
|
auto position = current_cell->position();
|
||||||
|
|
||||||
auto object = JS::Object::create_empty(global_object);
|
auto object = JS::Object::create(global_object, global_object.object_prototype());
|
||||||
object->put("column", JS::js_string(vm, sheet_object->m_sheet.column(position.column)));
|
object->put("column", JS::js_string(vm, sheet_object->m_sheet.column(position.column)));
|
||||||
object->put("row", JS::Value((unsigned)position.row));
|
object->put("row", JS::Value((unsigned)position.row));
|
||||||
|
|
||||||
|
@ -377,7 +377,7 @@ JS_DEFINE_NATIVE_FUNCTION(SheetGlobalObject::column_arithmetic)
|
||||||
}
|
}
|
||||||
|
|
||||||
WorkbookObject::WorkbookObject(Workbook& workbook)
|
WorkbookObject::WorkbookObject(Workbook& workbook)
|
||||||
: JS::Object(*JS::Object::create_empty(workbook.global_object()))
|
: JS::Object(*JS::Object::create(workbook.global_object(), workbook.global_object().object_prototype()))
|
||||||
, m_workbook(workbook)
|
, m_workbook(workbook)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
@ -773,7 +773,6 @@ Value ClassExpression::execute(Interpreter& interpreter, GlobalObject& global_ob
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
class_constructor->set_constructor_kind(Function::ConstructorKind::Derived);
|
class_constructor->set_constructor_kind(Function::ConstructorKind::Derived);
|
||||||
Object* prototype = Object::create_empty(global_object);
|
|
||||||
|
|
||||||
Object* super_constructor_prototype = nullptr;
|
Object* super_constructor_prototype = nullptr;
|
||||||
if (!super_constructor.is_null()) {
|
if (!super_constructor.is_null()) {
|
||||||
|
@ -787,7 +786,7 @@ Value ClassExpression::execute(Interpreter& interpreter, GlobalObject& global_ob
|
||||||
if (super_constructor_prototype_value.is_object())
|
if (super_constructor_prototype_value.is_object())
|
||||||
super_constructor_prototype = &super_constructor_prototype_value.as_object();
|
super_constructor_prototype = &super_constructor_prototype_value.as_object();
|
||||||
}
|
}
|
||||||
prototype->set_prototype(super_constructor_prototype);
|
auto* prototype = Object::create(global_object, super_constructor_prototype);
|
||||||
|
|
||||||
prototype->define_property(vm.names.constructor, class_constructor, 0);
|
prototype->define_property(vm.names.constructor, class_constructor, 0);
|
||||||
if (interpreter.exception())
|
if (interpreter.exception())
|
||||||
|
@ -1683,7 +1682,7 @@ Value ObjectExpression::execute(Interpreter& interpreter, GlobalObject& global_o
|
||||||
{
|
{
|
||||||
InterpreterNodeScope node_scope { interpreter, *this };
|
InterpreterNodeScope node_scope { interpreter, *this };
|
||||||
|
|
||||||
auto* object = Object::create_empty(global_object);
|
auto* object = Object::create(global_object, global_object.object_prototype());
|
||||||
for (auto& property : m_properties) {
|
for (auto& property : m_properties) {
|
||||||
auto key = property.key().execute(interpreter, global_object);
|
auto key = property.key().execute(interpreter, global_object);
|
||||||
if (interpreter.exception())
|
if (interpreter.exception())
|
||||||
|
|
|
@ -130,7 +130,7 @@ void NewString::execute_impl(Bytecode::Interpreter& interpreter) const
|
||||||
|
|
||||||
void NewObject::execute_impl(Bytecode::Interpreter& interpreter) const
|
void NewObject::execute_impl(Bytecode::Interpreter& interpreter) const
|
||||||
{
|
{
|
||||||
interpreter.accumulator() = Object::create_empty(interpreter.global_object());
|
interpreter.accumulator() = Object::create(interpreter.global_object(), interpreter.global_object().object_prototype());
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConcatString::execute_impl(Bytecode::Interpreter& interpreter) const
|
void ConcatString::execute_impl(Bytecode::Interpreter& interpreter) const
|
||||||
|
@ -307,7 +307,7 @@ void PushLexicalEnvironment::execute_impl(Bytecode::Interpreter& interpreter) co
|
||||||
void Yield::execute_impl(Bytecode::Interpreter& interpreter) const
|
void Yield::execute_impl(Bytecode::Interpreter& interpreter) const
|
||||||
{
|
{
|
||||||
auto yielded_value = interpreter.accumulator().value_or(js_undefined());
|
auto yielded_value = interpreter.accumulator().value_or(js_undefined());
|
||||||
auto object = JS::Object::create_empty(interpreter.global_object());
|
auto object = JS::Object::create(interpreter.global_object(), nullptr);
|
||||||
object->put("result", yielded_value);
|
object->put("result", yielded_value);
|
||||||
if (m_continuation_label.has_value())
|
if (m_continuation_label.has_value())
|
||||||
object->put("continuation", Value(static_cast<double>(reinterpret_cast<u64>(&m_continuation_label->block()))));
|
object->put("continuation", Value(static_cast<double>(reinterpret_cast<u64>(&m_continuation_label->block()))));
|
||||||
|
|
|
@ -75,8 +75,7 @@ void ArrayPrototype::initialize(GlobalObject& global_object)
|
||||||
define_property(vm.well_known_symbol_iterator(), get(vm.names.values), attr);
|
define_property(vm.well_known_symbol_iterator(), get(vm.names.values), attr);
|
||||||
|
|
||||||
// 23.1.3.34 Array.prototype [ @@unscopables ], https://tc39.es/ecma262/#sec-array.prototype-@@unscopables
|
// 23.1.3.34 Array.prototype [ @@unscopables ], https://tc39.es/ecma262/#sec-array.prototype-@@unscopables
|
||||||
Object* unscopable_list = create_empty(global_object);
|
auto* unscopable_list = Object::create(global_object, nullptr);
|
||||||
unscopable_list->set_prototype(nullptr);
|
|
||||||
unscopable_list->put(vm.names.copyWithin, Value(true));
|
unscopable_list->put(vm.names.copyWithin, Value(true));
|
||||||
unscopable_list->put(vm.names.entries, Value(true));
|
unscopable_list->put(vm.names.entries, Value(true));
|
||||||
unscopable_list->put(vm.names.fill, Value(true));
|
unscopable_list->put(vm.names.fill, Value(true));
|
||||||
|
|
|
@ -86,7 +86,7 @@ Value GeneratorObject::next_impl(VM& vm, GlobalObject& global_object, Optional<V
|
||||||
if (vm.exception())
|
if (vm.exception())
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
auto result = Object::create_empty(global_object);
|
auto result = Object::create(global_object, global_object.object_prototype());
|
||||||
result->put("value", previous_generated_value);
|
result->put("value", previous_generated_value);
|
||||||
|
|
||||||
if (m_done) {
|
if (m_done) {
|
||||||
|
|
|
@ -124,7 +124,7 @@ MarkedValueList iterable_to_list(GlobalObject& global_object, Value iterable, Va
|
||||||
Value create_iterator_result_object(GlobalObject& global_object, Value value, bool done)
|
Value create_iterator_result_object(GlobalObject& global_object, Value value, bool done)
|
||||||
{
|
{
|
||||||
auto& vm = global_object.vm();
|
auto& vm = global_object.vm();
|
||||||
auto* object = Object::create_empty(global_object);
|
auto* object = Object::create(global_object, global_object.object_prototype());
|
||||||
object->define_property(vm.names.value, value);
|
object->define_property(vm.names.value, value);
|
||||||
object->define_property(vm.names.done, Value(done));
|
object->define_property(vm.names.done, Value(done));
|
||||||
return object;
|
return object;
|
||||||
|
|
|
@ -106,7 +106,7 @@ String JSONObject::stringify_impl(GlobalObject& global_object, Value value, Valu
|
||||||
state.gap = String::empty();
|
state.gap = String::empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* wrapper = Object::create_empty(global_object);
|
auto* wrapper = Object::create(global_object, global_object.object_prototype());
|
||||||
wrapper->define_property(String::empty(), value);
|
wrapper->define_property(String::empty(), value);
|
||||||
if (vm.exception())
|
if (vm.exception())
|
||||||
return {};
|
return {};
|
||||||
|
@ -396,11 +396,12 @@ JS_DEFINE_NATIVE_FUNCTION(JSONObject::parse)
|
||||||
}
|
}
|
||||||
Value result = parse_json_value(global_object, json.value());
|
Value result = parse_json_value(global_object, json.value());
|
||||||
if (reviver.is_function()) {
|
if (reviver.is_function()) {
|
||||||
auto* holder_object = Object::create_empty(global_object);
|
auto* root = Object::create(global_object, global_object.object_prototype());
|
||||||
holder_object->define_property(String::empty(), result);
|
auto root_name = String::empty();
|
||||||
|
root->define_property(root_name, result);
|
||||||
if (vm.exception())
|
if (vm.exception())
|
||||||
return {};
|
return {};
|
||||||
return internalize_json_property(global_object, holder_object, String::empty(), reviver.as_function());
|
return internalize_json_property(global_object, root, root_name, reviver.as_function());
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -426,7 +427,7 @@ Value JSONObject::parse_json_value(GlobalObject& global_object, const JsonValue&
|
||||||
|
|
||||||
Object* JSONObject::parse_json_object(GlobalObject& global_object, const JsonObject& json_object)
|
Object* JSONObject::parse_json_object(GlobalObject& global_object, const JsonObject& json_object)
|
||||||
{
|
{
|
||||||
auto* object = Object::create_empty(global_object);
|
auto* object = Object::create(global_object, global_object.object_prototype());
|
||||||
json_object.for_each_member([&](auto& key, auto& value) {
|
json_object.for_each_member([&](auto& key, auto& value) {
|
||||||
object->define_property(key, parse_json_value(global_object, value));
|
object->define_property(key, parse_json_value(global_object, value));
|
||||||
});
|
});
|
||||||
|
@ -443,6 +444,7 @@ Array* JSONObject::parse_json_array(GlobalObject& global_object, const JsonArray
|
||||||
return array;
|
return array;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 25.5.1.1 InternalizeJSONProperty ( holder, name, reviver ), https://tc39.es/ecma262/#sec-internalizejsonproperty
|
||||||
Value JSONObject::internalize_json_property(GlobalObject& global_object, Object* holder, const PropertyName& name, Function& reviver)
|
Value JSONObject::internalize_json_property(GlobalObject& global_object, Object* holder, const PropertyName& name, Function& reviver)
|
||||||
{
|
{
|
||||||
auto& vm = global_object.vm();
|
auto& vm = global_object.vm();
|
||||||
|
|
|
@ -65,9 +65,15 @@ PropertyDescriptor PropertyDescriptor::from_dictionary(VM& vm, const Object& obj
|
||||||
return descriptor;
|
return descriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
Object* Object::create_empty(GlobalObject& global_object)
|
// 10.1.12 OrdinaryObjectCreate ( proto [ , additionalInternalSlotsList ] ), https://tc39.es/ecma262/#sec-ordinaryobjectcreate
|
||||||
|
Object* Object::create(GlobalObject& global_object, Object* prototype)
|
||||||
{
|
{
|
||||||
return global_object.heap().allocate<Object>(global_object, *global_object.new_object_shape());
|
if (!prototype)
|
||||||
|
return global_object.heap().allocate<Object>(global_object, *global_object.empty_object_shape());
|
||||||
|
else if (prototype == global_object.object_prototype())
|
||||||
|
return global_object.heap().allocate<Object>(global_object, *global_object.new_object_shape());
|
||||||
|
else
|
||||||
|
return global_object.heap().allocate<Object>(global_object, *prototype);
|
||||||
}
|
}
|
||||||
|
|
||||||
Object::Object(GlobalObjectTag)
|
Object::Object(GlobalObjectTag)
|
||||||
|
@ -425,12 +431,14 @@ Value Object::get_own_property_descriptor_object(const PropertyName& property_na
|
||||||
VERIFY(property_name.is_valid());
|
VERIFY(property_name.is_valid());
|
||||||
|
|
||||||
auto& vm = this->vm();
|
auto& vm = this->vm();
|
||||||
|
auto& global_object = this->global_object();
|
||||||
|
|
||||||
auto descriptor_opt = get_own_property_descriptor(property_name);
|
auto descriptor_opt = get_own_property_descriptor(property_name);
|
||||||
if (!descriptor_opt.has_value())
|
if (!descriptor_opt.has_value())
|
||||||
return js_undefined();
|
return js_undefined();
|
||||||
auto descriptor = descriptor_opt.value();
|
auto descriptor = descriptor_opt.value();
|
||||||
|
|
||||||
auto* descriptor_object = Object::create_empty(global_object());
|
auto* descriptor_object = Object::create(global_object, global_object.object_prototype());
|
||||||
if (descriptor.is_data_descriptor()) {
|
if (descriptor.is_data_descriptor()) {
|
||||||
descriptor_object->define_property(vm.names.value, descriptor.value.value_or(js_undefined()));
|
descriptor_object->define_property(vm.names.value, descriptor.value.value_or(js_undefined()));
|
||||||
descriptor_object->define_property(vm.names.writable, Value(descriptor.attributes.is_writable()));
|
descriptor_object->define_property(vm.names.writable, Value(descriptor.attributes.is_writable()));
|
||||||
|
|
|
@ -40,7 +40,7 @@ struct PropertyDescriptor {
|
||||||
|
|
||||||
class Object : public Cell {
|
class Object : public Cell {
|
||||||
public:
|
public:
|
||||||
static Object* create_empty(GlobalObject&);
|
static Object* create(GlobalObject&, Object* prototype);
|
||||||
|
|
||||||
explicit Object(Object& prototype);
|
explicit Object(Object& prototype);
|
||||||
explicit Object(Shape&);
|
explicit Object(Shape&);
|
||||||
|
|
|
@ -62,10 +62,13 @@ ObjectConstructor::~ObjectConstructor()
|
||||||
// 20.1.1.1 Object ( [ value ] ), https://tc39.es/ecma262/#sec-object-value
|
// 20.1.1.1 Object ( [ value ] ), https://tc39.es/ecma262/#sec-object-value
|
||||||
Value ObjectConstructor::call()
|
Value ObjectConstructor::call()
|
||||||
{
|
{
|
||||||
auto value = vm().argument(0);
|
auto& vm = this->vm();
|
||||||
|
auto& global_object = this->global_object();
|
||||||
|
|
||||||
|
auto value = vm.argument(0);
|
||||||
if (value.is_nullish())
|
if (value.is_nullish())
|
||||||
return Object::create_empty(global_object());
|
return Object::create(global_object, global_object.object_prototype());
|
||||||
return value.to_object(global_object());
|
return value.to_object(global_object);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 20.1.1.1 Object ( [ value ] ), https://tc39.es/ecma262/#sec-object-value
|
// 20.1.1.1 Object ( [ value ] ), https://tc39.es/ecma262/#sec-object-value
|
||||||
|
@ -191,8 +194,7 @@ JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::from_entries)
|
||||||
if (vm.exception())
|
if (vm.exception())
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
auto* object = Object::create_empty(global_object);
|
auto* object = Object::create(global_object, global_object.object_prototype());
|
||||||
object->set_prototype(global_object.object_prototype());
|
|
||||||
|
|
||||||
get_iterator_values(global_object, iterable, [&](Value iterator_value) {
|
get_iterator_values(global_object, iterable, [&](Value iterator_value) {
|
||||||
if (vm.exception())
|
if (vm.exception())
|
||||||
|
@ -344,8 +346,7 @@ JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::create)
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* object = Object::create_empty(global_object);
|
auto* object = Object::create(global_object, prototype);
|
||||||
object->set_prototype(prototype);
|
|
||||||
|
|
||||||
if (!properties.is_undefined()) {
|
if (!properties.is_undefined()) {
|
||||||
object->define_properties(properties);
|
object->define_properties(properties);
|
||||||
|
|
|
@ -81,7 +81,7 @@ JS_DEFINE_NATIVE_FUNCTION(ProxyConstructor::revocable)
|
||||||
});
|
});
|
||||||
revoker->define_property(vm.names.length, Value(0));
|
revoker->define_property(vm.names.length, Value(0));
|
||||||
|
|
||||||
auto* result = Object::create_empty(global_object);
|
auto* result = Object::create(global_object, global_object.object_prototype());
|
||||||
result->define_property(vm.names.proxy, proxy);
|
result->define_property(vm.names.proxy, proxy);
|
||||||
result->define_property(vm.names.revoke, revoker);
|
result->define_property(vm.names.revoke, revoker);
|
||||||
return result;
|
return result;
|
||||||
|
|
|
@ -191,7 +191,7 @@ JS_DEFINE_NATIVE_FUNCTION(RegExpPrototype::exec)
|
||||||
|
|
||||||
Value groups = js_undefined();
|
Value groups = js_undefined();
|
||||||
if (result.n_named_capture_groups > 0) {
|
if (result.n_named_capture_groups > 0) {
|
||||||
auto groups_object = create_empty(global_object);
|
auto groups_object = Object::create(global_object, nullptr);
|
||||||
for (auto& entry : result.named_capture_group_matches[0])
|
for (auto& entry : result.named_capture_group_matches[0])
|
||||||
groups_object->define_property(entry.key, js_string(vm, entry.value.view.to_string()));
|
groups_object->define_property(entry.key, js_string(vm, entry.value.view.to_string()));
|
||||||
groups = move(groups_object);
|
groups = move(groups_object);
|
||||||
|
|
|
@ -286,8 +286,7 @@ void VM::assign(const NonnullRefPtr<BindingPattern>& target, Value value, Global
|
||||||
VERIFY(!property.pattern);
|
VERIFY(!property.pattern);
|
||||||
JS::Value value_to_assign;
|
JS::Value value_to_assign;
|
||||||
if (property.is_rest) {
|
if (property.is_rest) {
|
||||||
auto* rest_object = Object::create_empty(global_object);
|
auto* rest_object = Object::create(global_object, nullptr);
|
||||||
rest_object->set_prototype(nullptr);
|
|
||||||
for (auto& property : object->shape().property_table()) {
|
for (auto& property : object->shape().property_table()) {
|
||||||
if (!property.value.attributes.has_enumerable())
|
if (!property.value.attributes.has_enumerable())
|
||||||
continue;
|
continue;
|
||||||
|
@ -406,7 +405,7 @@ Value VM::construct(Function& function, Function& new_target, Optional<MarkedVal
|
||||||
|
|
||||||
Object* new_object = nullptr;
|
Object* new_object = nullptr;
|
||||||
if (function.constructor_kind() == Function::ConstructorKind::Base) {
|
if (function.constructor_kind() == Function::ConstructorKind::Base) {
|
||||||
new_object = Object::create_empty(global_object);
|
new_object = Object::create(global_object, nullptr);
|
||||||
if (environment)
|
if (environment)
|
||||||
environment->bind_this_value(global_object, new_object);
|
environment->bind_this_value(global_object, new_object);
|
||||||
if (exception())
|
if (exception())
|
||||||
|
|
|
@ -362,8 +362,7 @@ void WebAssemblyInstanceObject::initialize(JS::GlobalObject& global_object)
|
||||||
Object::initialize(global_object);
|
Object::initialize(global_object);
|
||||||
|
|
||||||
VERIFY(!m_exports_object);
|
VERIFY(!m_exports_object);
|
||||||
m_exports_object = JS::Object::create_empty(global_object);
|
m_exports_object = JS::Object::create(global_object, nullptr);
|
||||||
m_exports_object->set_prototype(nullptr);
|
|
||||||
auto& instance = this->instance();
|
auto& instance = this->instance();
|
||||||
for (auto& export_ : instance.exports()) {
|
for (auto& export_ : instance.exports()) {
|
||||||
export_.value().visit(
|
export_.value().visit(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue