1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 06:47:34 +00:00

LibJS: Avoid lots of string-to-int during global object construction

We were doing a *lot* of string-to-int conversion while creating a new
global object. This happened because Object::put() would try to convert
the property name (string) to an integer to see if it refers to an
indexed property.

Sidestep this issue by using PropertyName for the CommonPropertyNames
struct on VM (vm.names.foo), and giving PropertyName a flag that tells
us whether it's a string that *may be* a number.

All CommonPropertyNames are set up so they are known to not be numbers.
This commit is contained in:
Andreas Kling 2021-06-13 18:59:07 +02:00
parent 53a8a11973
commit 5eef07d232
25 changed files with 84 additions and 58 deletions

View file

@ -144,8 +144,8 @@ void MarkupGenerator::date_to_html(const Object& date, StringBuilder& html_outpu
void MarkupGenerator::error_to_html(const Object& object, StringBuilder& html_output, HashTable<Object*>&)
{
auto name = object.get_without_side_effects("name").value_or(JS::js_undefined());
auto message = object.get_without_side_effects("message").value_or(JS::js_undefined());
auto name = object.get_without_side_effects(PropertyName("name")).value_or(JS::js_undefined());
auto message = object.get_without_side_effects(PropertyName("message")).value_or(JS::js_undefined());
if (name.is_accessor() || name.is_native_property() || message.is_accessor() || message.is_native_property()) {
html_output.append(wrap_string_in_style(JS::Value(&object).to_string_without_side_effects(), StyleType::Invalid));
} else {

View file

@ -28,7 +28,7 @@ void ArrayBufferPrototype::initialize(GlobalObject& global_object)
define_native_property(vm.names.byteLength, byte_length_getter, {}, Attribute::Configurable);
// 25.1.5.4 ArrayBuffer.prototype [ @@toStringTag ], https://tc39.es/ecma262/#sec-arraybuffer.prototype-@@tostringtag
define_property(vm.well_known_symbol_to_string_tag(), js_string(vm.heap(), "ArrayBuffer"), Attribute::Configurable);
define_property(vm.well_known_symbol_to_string_tag(), js_string(vm.heap(), vm.names.ArrayBuffer.as_string()), Attribute::Configurable);
}
ArrayBufferPrototype::~ArrayBufferPrototype()

View file

@ -302,7 +302,7 @@ JS_DEFINE_NATIVE_FUNCTION(ArrayPrototype::to_locale_string)
auto* value_object = value.to_object(global_object);
if (!value_object)
return {};
auto locale_string_result = value_object->invoke(vm.names.toLocaleString);
auto locale_string_result = value_object->invoke(vm.names.toLocaleString.as_string());
if (vm.exception())
return {};
auto string = locale_string_result.to_string(global_object);

View file

@ -27,7 +27,7 @@ void BigIntPrototype::initialize(GlobalObject& global_object)
define_native_function(vm.names.valueOf, value_of, 0, attr);
// 21.2.3.5 BigInt.prototype [ @@toStringTag ], https://tc39.es/ecma262/#sec-bigint.prototype-@@tostringtag
define_property(vm.well_known_symbol_to_string_tag(), js_string(global_object.heap(), "BigInt"), Attribute::Configurable);
define_property(vm.well_known_symbol_to_string_tag(), js_string(global_object.heap(), vm.names.BigInt.as_string()), Attribute::Configurable);
}
BigIntPrototype::~BigIntPrototype()

View file

@ -295,18 +295,18 @@ namespace JS {
P(writable)
struct CommonPropertyNames {
FlyString catch_ { "catch" };
FlyString delete_ { "delete" };
FlyString for_ { "for" };
FlyString return_ { "return" };
FlyString throw_ { "throw" };
#define __ENUMERATE(x) FlyString x { #x };
PropertyName catch_ { "catch", PropertyName::StringMayBeNumber::No };
PropertyName delete_ { "delete", PropertyName::StringMayBeNumber::No };
PropertyName for_ { "for", PropertyName::StringMayBeNumber::No };
PropertyName return_ { "return", PropertyName::StringMayBeNumber::No };
PropertyName throw_ { "throw", PropertyName::StringMayBeNumber::No };
#define __ENUMERATE(x) PropertyName x { #x, PropertyName::StringMayBeNumber::No };
ENUMERATE_STANDARD_PROPERTY_NAMES(__ENUMERATE)
#undef __ENUMERATE
#define __JS_ENUMERATE(x, a, b, c, t) FlyString x { #x };
#define __JS_ENUMERATE(x, a, b, c, t) PropertyName x { #x, PropertyName::StringMayBeNumber::No };
JS_ENUMERATE_BUILTIN_TYPES
#undef __JS_ENUMERATE
#define __JS_ENUMERATE(x, a) FlyString x { #x };
#define __JS_ENUMERATE(x, a) PropertyName x { #x, PropertyName::StringMayBeNumber::No };
JS_ENUMERATE_WELL_KNOWN_SYMBOLS
#undef __JS_ENUMERATE
};

View file

@ -849,7 +849,7 @@ JS_DEFINE_NATIVE_FUNCTION(DatePrototype::to_json)
if (time_value.is_number() && !time_value.is_finite_number())
return js_null();
return this_object->invoke(vm.names.toISOString);
return this_object->invoke(vm.names.toISOString.as_string());
}
// 21.4.4.45 Date.prototype [ @@toPrimitive ] ( hint ), https://tc39.es/ecma262/#sec-date.prototype-@@toprimitive

View file

@ -52,9 +52,9 @@ protected:
virtual void visit_edges(Visitor&) override;
template<typename ConstructorType>
void initialize_constructor(const FlyString& property_name, ConstructorType*&, Object* prototype);
void initialize_constructor(PropertyName const&, ConstructorType*&, Object* prototype);
template<typename ConstructorType>
void add_constructor(const FlyString& property_name, ConstructorType*&, Object* prototype);
void add_constructor(PropertyName const&, ConstructorType*&, Object* prototype);
private:
virtual bool is_global_object() const final { return true; }
@ -94,11 +94,11 @@ private:
};
template<typename ConstructorType>
inline void GlobalObject::initialize_constructor(const FlyString& property_name, ConstructorType*& constructor, Object* prototype)
inline void GlobalObject::initialize_constructor(PropertyName const& property_name, ConstructorType*& constructor, Object* prototype)
{
auto& vm = this->vm();
constructor = heap().allocate<ConstructorType>(*this, *this);
constructor->define_property(vm.names.name, js_string(heap(), property_name), Attribute::Configurable);
constructor->define_property(vm.names.name, js_string(heap(), property_name.as_string()), Attribute::Configurable);
if (vm.exception())
return;
if (prototype) {
@ -109,7 +109,7 @@ inline void GlobalObject::initialize_constructor(const FlyString& property_name,
}
template<typename ConstructorType>
inline void GlobalObject::add_constructor(const FlyString& property_name, ConstructorType*& constructor, Object* prototype)
inline void GlobalObject::add_constructor(PropertyName const& property_name, ConstructorType*& constructor, Object* prototype)
{
// Some constructors are pre-initialized separately.
if (!constructor)

View file

@ -34,7 +34,7 @@ void MapPrototype::initialize(GlobalObject& global_object)
define_native_accessor(vm.names.size, size_getter, {}, Attribute::Configurable);
define_property(vm.well_known_symbol_iterator(), Object::get(vm.names.entries), attr);
define_property(vm.well_known_symbol_to_string_tag(), js_string(global_object.heap(), vm.names.Map), Attribute::Configurable);
define_property(vm.well_known_symbol_to_string_tag(), js_string(global_object.heap(), vm.names.Map.as_string()), Attribute::Configurable);
}
MapPrototype::~MapPrototype()

View file

@ -71,7 +71,7 @@ void MathObject::initialize(GlobalObject& global_object)
define_property(vm.names.SQRT2, Value(M_SQRT2), 0);
// 21.3.1.9 Math [ @@toStringTag ], https://tc39.es/ecma262/#sec-math-@@tostringtag
define_property(vm.well_known_symbol_to_string_tag(), js_string(vm.heap(), "Math"), Attribute::Configurable);
define_property(vm.well_known_symbol_to_string_tag(), js_string(vm.heap(), vm.names.Math.as_string()), Attribute::Configurable);
}
MathObject::~MathObject()

View file

@ -20,16 +20,16 @@ NativeFunction::NativeFunction(Object& prototype)
{
}
NativeFunction::NativeFunction(const FlyString& name, AK::Function<Value(VM&, GlobalObject&)> native_function, Object& prototype)
NativeFunction::NativeFunction(PropertyName const& name, AK::Function<Value(VM&, GlobalObject&)> native_function, Object& prototype)
: Function(prototype)
, m_name(name)
, m_name(name.as_string())
, m_native_function(move(native_function))
{
}
NativeFunction::NativeFunction(const FlyString& name, Object& prototype)
NativeFunction::NativeFunction(PropertyName const& name, Object& prototype)
: Function(prototype)
, m_name(name)
, m_name(name.as_string())
{
}

View file

@ -17,7 +17,7 @@ class NativeFunction : public Function {
public:
static NativeFunction* create(GlobalObject&, const FlyString& name, AK::Function<Value(VM&, GlobalObject&)>);
explicit NativeFunction(const FlyString& name, AK::Function<Value(VM&, GlobalObject&)>, Object& prototype);
explicit NativeFunction(PropertyName const& name, AK::Function<Value(VM&, GlobalObject&)>, Object& prototype);
virtual void initialize(GlobalObject&) override { }
virtual ~NativeFunction() override;
@ -30,7 +30,7 @@ public:
virtual bool is_strict_mode() const override;
protected:
NativeFunction(const FlyString& name, Object& prototype);
NativeFunction(PropertyName const& name, Object& prototype);
explicit NativeFunction(Object& prototype);
private:

View file

@ -190,7 +190,7 @@ bool Object::set_integrity_level(IntegrityLevel level)
case IntegrityLevel::Sealed:
for (auto& key : keys) {
auto property_name = PropertyName::from_value(global_object(), key);
if (property_name.is_string()) {
if (property_name.is_string() && property_name.string_may_be_number()) {
i32 property_index = property_name.as_string().to_int().value_or(-1);
if (property_index >= 0)
property_name = property_index;
@ -203,7 +203,7 @@ bool Object::set_integrity_level(IntegrityLevel level)
case IntegrityLevel::Frozen:
for (auto& key : keys) {
auto property_name = PropertyName::from_value(global_object(), key);
if (property_name.is_string()) {
if (property_name.is_string() && property_name.string_may_be_number()) {
i32 property_index = property_name.as_string().to_int().value_or(-1);
if (property_index >= 0)
property_name = property_index;
@ -389,7 +389,7 @@ Optional<PropertyDescriptor> Object::get_own_property_descriptor(const PropertyN
value = existing_value.value().value;
attributes = existing_value.value().attributes;
} else {
if (property_name.is_string()) {
if (property_name.is_string() && property_name.string_may_be_number()) {
i32 property_index = property_name.as_string().to_int().value_or(-1);
if (property_index >= 0)
return get_own_property_descriptor(property_index);
@ -537,7 +537,7 @@ bool Object::define_property(const PropertyName& property_name, Value value, Pro
if (property_name.is_number())
return put_own_property_by_index(property_name.as_number(), value, attributes, PutOwnPropertyMode::DefineProperty, throw_exceptions);
if (property_name.is_string()) {
if (property_name.is_string() && property_name.string_may_be_number()) {
i32 property_index = property_name.as_string().to_int().value_or(-1);
if (property_index >= 0)
return put_own_property_by_index(property_index, value, attributes, PutOwnPropertyMode::DefineProperty, throw_exceptions);
@ -545,7 +545,7 @@ bool Object::define_property(const PropertyName& property_name, Value value, Pro
return put_own_property(property_name.to_string_or_symbol(), value, attributes, PutOwnPropertyMode::DefineProperty, throw_exceptions);
}
bool Object::define_native_accessor(const StringOrSymbol& property_name, AK::Function<Value(VM&, GlobalObject&)> getter, AK::Function<Value(VM&, GlobalObject&)> setter, PropertyAttributes attribute)
bool Object::define_native_accessor(PropertyName const& property_name, AK::Function<Value(VM&, GlobalObject&)> getter, AK::Function<Value(VM&, GlobalObject&)> setter, PropertyAttributes attribute)
{
auto& vm = this->vm();
String formatted_property_name;
@ -749,7 +749,7 @@ bool Object::delete_property(const PropertyName& property_name)
if (property_name.is_number())
return m_indexed_properties.remove(property_name.as_number());
if (property_name.is_string()) {
if (property_name.is_string() && property_name.string_may_be_number()) {
i32 property_index = property_name.as_string().to_int().value_or(-1);
if (property_index >= 0)
return m_indexed_properties.remove(property_index);
@ -807,7 +807,7 @@ Value Object::get(const PropertyName& property_name, Value receiver, bool withou
if (property_name.is_number())
return get_by_index(property_name.as_number());
if (property_name.is_string()) {
if (property_name.is_string() && property_name.string_may_be_number()) {
auto& property_string = property_name.as_string();
i32 property_index = property_string.to_int().value_or(-1);
if (property_index >= 0)
@ -875,7 +875,7 @@ bool Object::put(const PropertyName& property_name, Value value, Value receiver)
VERIFY(!value.is_empty());
if (property_name.is_string()) {
if (property_name.is_string() && property_name.string_may_be_number()) {
auto& property_string = property_name.as_string();
i32 property_index = property_string.to_int().value_or(-1);
if (property_index >= 0)
@ -910,7 +910,7 @@ bool Object::put(const PropertyName& property_name, Value value, Value receiver)
return put_own_property(string_or_symbol, value, default_attributes, PutOwnPropertyMode::Put);
}
bool Object::define_native_function(const StringOrSymbol& property_name, AK::Function<Value(VM&, GlobalObject&)> native_function, i32 length, PropertyAttributes attribute)
bool Object::define_native_function(PropertyName const& property_name, AK::Function<Value(VM&, GlobalObject&)> native_function, i32 length, PropertyAttributes attribute)
{
auto& vm = this->vm();
String function_name;
@ -929,7 +929,7 @@ bool Object::define_native_function(const StringOrSymbol& property_name, AK::Fun
return define_property(property_name, function, attribute);
}
bool Object::define_native_property(const StringOrSymbol& property_name, AK::Function<Value(VM&, GlobalObject&)> getter, AK::Function<void(VM&, GlobalObject&, Value)> setter, PropertyAttributes attribute)
bool Object::define_native_property(PropertyName const& property_name, AK::Function<Value(VM&, GlobalObject&)> getter, AK::Function<void(VM&, GlobalObject&, Value)> setter, PropertyAttributes attribute)
{
return define_property(property_name, heap().allocate_without_global_object<NativeProperty>(move(getter), move(setter)), attribute);
}
@ -1016,7 +1016,7 @@ bool Object::has_own_property(const PropertyName& property_name) const
if (property_name.is_number())
return has_indexed_property(property_name.as_number());
if (property_name.is_string()) {
if (property_name.is_string() && property_name.string_may_be_number()) {
i32 property_index = property_name.as_string().to_int().value_or(-1);
if (property_index >= 0)
return has_indexed_property(property_index);
@ -1033,9 +1033,9 @@ Value Object::ordinary_to_primitive(Value::PreferredType preferred_type) const
Vector<FlyString, 2> method_names;
if (preferred_type == Value::PreferredType::String)
method_names = { vm.names.toString, vm.names.valueOf };
method_names = { vm.names.toString.as_string(), vm.names.valueOf.as_string() };
else
method_names = { vm.names.valueOf, vm.names.toString };
method_names = { vm.names.valueOf.as_string(), vm.names.toString.as_string() };
for (auto& method_name : method_names) {
auto method = get(method_name);

View file

@ -93,9 +93,9 @@ public:
bool define_property_without_transition(const PropertyName&, Value value, PropertyAttributes attributes = default_attributes, bool throw_exceptions = true);
bool define_accessor(const PropertyName&, Function* getter, Function* setter, PropertyAttributes attributes = default_attributes, bool throw_exceptions = true);
bool define_native_function(const StringOrSymbol& property_name, AK::Function<Value(VM&, GlobalObject&)>, i32 length = 0, PropertyAttributes attributes = default_attributes);
bool define_native_property(const StringOrSymbol& property_name, AK::Function<Value(VM&, GlobalObject&)> getter, AK::Function<void(VM&, GlobalObject&, Value)> setter, PropertyAttributes attributes = default_attributes);
bool define_native_accessor(StringOrSymbol const& property_name, AK::Function<Value(VM&, GlobalObject&)> getter, AK::Function<Value(VM&, GlobalObject&)> setter, PropertyAttributes attributes = default_attributes);
bool define_native_function(PropertyName const&, AK::Function<Value(VM&, GlobalObject&)>, i32 length = 0, PropertyAttributes attributes = default_attributes);
bool define_native_property(PropertyName const&, AK::Function<Value(VM&, GlobalObject&)> getter, AK::Function<void(VM&, GlobalObject&, Value)> setter, PropertyAttributes attributes = default_attributes);
bool define_native_accessor(PropertyName const&, AK::Function<Value(VM&, GlobalObject&)> getter, AK::Function<Value(VM&, GlobalObject&)> setter, PropertyAttributes attributes = default_attributes);
void define_properties(Value properties);

View file

@ -100,7 +100,7 @@ JS_DEFINE_NATIVE_FUNCTION(ObjectPrototype::to_locale_string)
auto* this_object = vm.this_value(global_object).to_object(global_object);
if (!this_object)
return {};
return this_object->invoke(vm.names.toString);
return this_object->invoke(vm.names.toString.as_string());
}
// 20.1.3.7 Object.prototype.valueOf ( ), https://tc39.es/ecma262/#sec-object.prototype.valueof

View file

@ -31,7 +31,7 @@ void PromisePrototype::initialize(GlobalObject& global_object)
define_native_function(vm.names.finally, finally, 1, attr);
// 27.2.5.5 Promise.prototype [ @@toStringTag ], https://tc39.es/ecma262/#sec-promise.prototype-@@tostringtag
define_property(vm.well_known_symbol_to_string_tag(), js_string(vm.heap(), "Promise"), Attribute::Configurable);
define_property(vm.well_known_symbol_to_string_tag(), js_string(vm.heap(), vm.names.Promise.as_string()), Attribute::Configurable);
}
static Promise* promise_from(VM& vm, GlobalObject& global_object)
@ -70,7 +70,7 @@ JS_DEFINE_NATIVE_FUNCTION(PromisePrototype::catch_)
if (!this_object)
return {};
auto on_rejected = vm.argument(0);
return this_object->invoke(vm.names.then, js_undefined(), on_rejected);
return this_object->invoke(vm.names.then.as_string(), js_undefined(), on_rejected);
}
// 27.2.5.3 Promise.prototype.finally ( onFinally ), https://tc39.es/ecma262/#sec-promise.prototype.finally
@ -103,7 +103,7 @@ JS_DEFINE_NATIVE_FUNCTION(PromisePrototype::finally)
auto* value_thunk = NativeFunction::create(global_object, "", [value](auto&, auto&) -> Value {
return value;
});
return promise->invoke(vm.names.then, value_thunk);
return promise->invoke(vm.names.then.as_string(), value_thunk);
});
then_finally_function->define_property(vm.names.length, Value(1));
@ -122,14 +122,14 @@ JS_DEFINE_NATIVE_FUNCTION(PromisePrototype::finally)
vm.throw_exception(global_object, reason);
return {};
});
return promise->invoke(vm.names.then, thrower);
return promise->invoke(vm.names.then.as_string(), thrower);
});
catch_finally_function->define_property(vm.names.length, Value(1));
then_finally = Value(then_finally_function);
catch_finally = Value(catch_finally_function);
}
return promise->invoke(vm.names.then, then_finally, catch_finally);
return promise->invoke(vm.names.then.as_string(), then_finally, catch_finally);
}
}

View file

@ -13,13 +13,18 @@ namespace JS {
class PropertyName {
public:
enum class Type {
enum class Type : u8 {
Invalid,
Number,
String,
Symbol,
};
enum class StringMayBeNumber {
Yes,
No,
};
static PropertyName from_value(GlobalObject& global_object, Value value)
{
if (value.is_empty())
@ -56,8 +61,9 @@ public:
VERIFY(!string.is_null());
}
PropertyName(FlyString const& string)
PropertyName(FlyString const& string, StringMayBeNumber string_may_be_number = StringMayBeNumber::Yes)
: m_type(Type::String)
, m_string_may_be_number(string_may_be_number == StringMayBeNumber::Yes)
, m_string(string)
{
VERIFY(!string.is_null());
@ -85,6 +91,7 @@ public:
bool is_number() const { return m_type == Type::Number; }
bool is_string() const { return m_type == Type::String; }
bool is_symbol() const { return m_type == Type::Symbol; }
bool string_may_be_number() const { return m_string_may_be_number; }
u32 as_number() const
{
@ -135,9 +142,22 @@ public:
private:
Type m_type { Type::Invalid };
bool m_string_may_be_number { true };
FlyString m_string;
Symbol* m_symbol { nullptr };
u32 m_number { 0 };
};
}
namespace AK {
template<>
struct Formatter<JS::PropertyName> : Formatter<StringView> {
void format(FormatBuilder& builder, JS::PropertyName const& value)
{
Formatter<StringView>::format(builder, value.to_string());
}
};
}

View file

@ -61,7 +61,7 @@ void ReflectObject::initialize(GlobalObject& global_object)
define_native_function(vm.names.setPrototypeOf, set_prototype_of, 2, attr);
// 28.1.14 Reflect [ @@toStringTag ], https://tc39.es/ecma262/#sec-reflect-@@tostringtag
Object::define_property(vm.well_known_symbol_to_string_tag(), js_string(vm.heap(), "Reflect"), Attribute::Configurable);
Object::define_property(vm.well_known_symbol_to_string_tag(), js_string(vm.heap(), vm.names.Reflect.as_string()), Attribute::Configurable);
}
ReflectObject::~ReflectObject()

View file

@ -37,7 +37,7 @@ void SetPrototype::initialize(GlobalObject& global_object)
define_property(vm.well_known_symbol_iterator(), get(vm.names.values), attr);
// 24.2.3.12 Set.prototype [ @@toStringTag ], https://tc39.es/ecma262/#sec-set.prototype-@@tostringtag
define_property(vm.well_known_symbol_to_string_tag(), js_string(global_object.heap(), vm.names.Set), Attribute::Configurable);
define_property(vm.well_known_symbol_to_string_tag(), js_string(vm.heap(), vm.names.Set.as_string()), Attribute::Configurable);
}
SetPrototype::~SetPrototype()

View file

@ -214,4 +214,9 @@ void Shape::add_property_without_transition(const StringOrSymbol& property_name,
++m_property_count;
}
FLATTEN void Shape::add_property_without_transition(PropertyName const& property_name, PropertyAttributes attributes)
{
add_property_without_transition(StringOrSymbol(property_name.as_string()), attributes);
}
}

View file

@ -58,6 +58,7 @@ public:
Shape* create_prototype_transition(Object* new_prototype);
void add_property_without_transition(const StringOrSymbol&, PropertyAttributes);
void add_property_without_transition(PropertyName const&, PropertyAttributes);
bool is_unique() const { return m_unique; }
Shape* create_unique_clone() const;

View file

@ -209,7 +209,7 @@ void TypedArrayBase::visit_edges(Visitor& visitor)
PrototypeName::~PrototypeName() { } \
\
ConstructorName::ConstructorName(GlobalObject& global_object) \
: TypedArrayConstructor(vm().names.ClassName, *global_object.typed_array_constructor()) \
: TypedArrayConstructor(vm().names.ClassName.as_string(), *global_object.typed_array_constructor()) \
{ \
} \
ConstructorName::~ConstructorName() { } \

View file

@ -331,7 +331,7 @@ void VM::assign(const NonnullRefPtr<BindingPattern>& target, Value value, Global
Value VM::get_variable(const FlyString& name, GlobalObject& global_object)
{
if (!m_call_stack.is_empty()) {
if (name == names.arguments && !call_frame().callee.is_empty()) {
if (name == names.arguments.as_string() && !call_frame().callee.is_empty()) {
// HACK: Special handling for the name "arguments":
// If the name "arguments" is defined in the current scope, for example via
// a function parameter, or by a local var declaration, we use that.

View file

@ -26,7 +26,7 @@ void WeakMapPrototype::initialize(GlobalObject& global_object)
define_native_function(vm.names.set, set, 2, attr);
// 24.3.3.6 WeakMap.prototype [ @@toStringTag ], https://tc39.es/ecma262/#sec-weakmap.prototype-@@tostringtag
define_property(vm.well_known_symbol_to_string_tag(), js_string(global_object.heap(), vm.names.WeakMap), Attribute::Configurable);
define_property(vm.well_known_symbol_to_string_tag(), js_string(vm.heap(), vm.names.WeakMap.as_string()), Attribute::Configurable);
}
WeakMapPrototype::~WeakMapPrototype()

View file

@ -20,7 +20,7 @@ void WeakRefPrototype::initialize(GlobalObject& global_object)
define_native_function(vm.names.deref, deref, 0, Attribute::Writable | Attribute::Configurable);
define_property(vm.well_known_symbol_to_string_tag(), js_string(global_object.heap(), vm.names.WeakRef), Attribute::Configurable);
define_property(vm.well_known_symbol_to_string_tag(), js_string(vm.heap(), vm.names.WeakRef.as_string()), Attribute::Configurable);
}
WeakRefPrototype::~WeakRefPrototype()

View file

@ -25,7 +25,7 @@ void WeakSetPrototype::initialize(GlobalObject& global_object)
define_native_function(vm.names.has, has, 1, attr);
// 24.4.3.5 WeakSet.prototype [ @@toStringTag ], https://tc39.es/ecma262/#sec-weakset.prototype-@@tostringtag
define_property(vm.well_known_symbol_to_string_tag(), js_string(global_object.heap(), vm.names.WeakSet), Attribute::Configurable);
define_property(vm.well_known_symbol_to_string_tag(), js_string(global_object.heap(), vm.names.WeakSet.as_string()), Attribute::Configurable);
}
WeakSetPrototype::~WeakSetPrototype()