LibJS: Add Object::get_without_side_effects()
Similar to Value::to_string_without_side_effects() this is mostly a regular object property lookup, but with the guarantee that it will be side-effect free, i.e. no accessors or native property functions will be called. This is needed when we want to access user-controlled object properties for debug logging, for example. The specific use case will be error objects which will soon no longer have internal name/message properties, so we need to guarantee that printing an error, which may already be the result of an exception, won't blow up in our face :^)
This commit is contained in:
parent
9ec4defdd2
commit
6e9eb0a284
Notes:
sideshowbarker
2024-07-18 20:29:43 +09:00
Author: https://github.com/linusg Commit: https://github.com/SerenityOS/serenity/commit/6e9eb0a2846 Pull-request: https://github.com/SerenityOS/serenity/pull/6254 Reviewed-by: https://github.com/awesomekling
4 changed files with 23 additions and 11 deletions
|
@ -234,7 +234,7 @@ bool Object::test_integrity_level(IntegrityLevel level)
|
|||
return true;
|
||||
}
|
||||
|
||||
Value Object::get_own_property(const PropertyName& property_name, Value receiver) const
|
||||
Value Object::get_own_property(const PropertyName& property_name, Value receiver, bool without_side_effects) const
|
||||
{
|
||||
VERIFY(property_name.is_valid());
|
||||
VERIFY(!receiver.is_empty());
|
||||
|
@ -254,10 +254,12 @@ Value Object::get_own_property(const PropertyName& property_name, Value receiver
|
|||
}
|
||||
|
||||
VERIFY(!value_here.is_empty());
|
||||
if (value_here.is_accessor())
|
||||
return value_here.as_accessor().call_getter(receiver);
|
||||
if (value_here.is_native_property())
|
||||
return call_native_property_getter(value_here.as_native_property(), receiver);
|
||||
if (!without_side_effects) {
|
||||
if (value_here.is_accessor())
|
||||
return value_here.as_accessor().call_getter(receiver);
|
||||
if (value_here.is_native_property())
|
||||
return call_native_property_getter(value_here.as_native_property(), receiver);
|
||||
}
|
||||
return value_here;
|
||||
}
|
||||
|
||||
|
@ -769,7 +771,7 @@ Value Object::get_by_index(u32 property_index) const
|
|||
return {};
|
||||
}
|
||||
|
||||
Value Object::get(const PropertyName& property_name, Value receiver) const
|
||||
Value Object::get(const PropertyName& property_name, Value receiver, bool without_side_effects) const
|
||||
{
|
||||
VERIFY(property_name.is_valid());
|
||||
|
||||
|
@ -788,7 +790,7 @@ Value Object::get(const PropertyName& property_name, Value receiver) const
|
|||
|
||||
const Object* object = this;
|
||||
while (object) {
|
||||
auto value = object->get_own_property(property_name, receiver);
|
||||
auto value = object->get_own_property(property_name, receiver, without_side_effects);
|
||||
if (vm().exception())
|
||||
return {};
|
||||
if (!value.is_empty())
|
||||
|
@ -800,6 +802,11 @@ Value Object::get(const PropertyName& property_name, Value receiver) const
|
|||
return {};
|
||||
}
|
||||
|
||||
Value Object::get_without_side_effects(const PropertyName& property_name) const
|
||||
{
|
||||
return get(property_name, {}, true);
|
||||
}
|
||||
|
||||
bool Object::put_by_index(u32 property_index, Value value)
|
||||
{
|
||||
VERIFY(!value.is_empty());
|
||||
|
|
|
@ -94,14 +94,15 @@ public:
|
|||
|
||||
GlobalObject& global_object() const { return *shape().global_object(); }
|
||||
|
||||
virtual Value get(const PropertyName&, Value receiver = {}) const;
|
||||
virtual Value get(const PropertyName&, Value receiver = {}, bool without_side_effects = false) const;
|
||||
Value get_without_side_effects(const PropertyName&) const;
|
||||
|
||||
virtual bool has_property(const PropertyName&) const;
|
||||
bool has_own_property(const PropertyName&) const;
|
||||
|
||||
virtual bool put(const PropertyName&, Value, Value receiver = {});
|
||||
|
||||
Value get_own_property(const PropertyName&, Value receiver) const;
|
||||
Value get_own_property(const PropertyName&, Value receiver, bool without_side_effects = false) const;
|
||||
MarkedValueList get_own_properties(PropertyKind, bool only_enumerable_properties = false, GetOwnPropertyReturnType = GetOwnPropertyReturnType::All) const;
|
||||
MarkedValueList get_enumerable_own_property_names(PropertyKind) const;
|
||||
virtual Optional<PropertyDescriptor> get_own_property_descriptor(const PropertyName&) const;
|
||||
|
|
|
@ -325,9 +325,13 @@ bool ProxyObject::has_property(const PropertyName& name) const
|
|||
return trap_result.to_boolean();
|
||||
}
|
||||
|
||||
Value ProxyObject::get(const PropertyName& name, Value receiver) const
|
||||
Value ProxyObject::get(const PropertyName& name, Value receiver, bool without_side_effects) const
|
||||
{
|
||||
auto& vm = this->vm();
|
||||
if (without_side_effects) {
|
||||
// Sorry, we're not going to call anything on this proxy.
|
||||
return js_string(vm, "<ProxyObject>");
|
||||
}
|
||||
if (m_is_revoked) {
|
||||
vm.throw_exception<TypeError>(global_object(), ErrorType::ProxyRevoked);
|
||||
return {};
|
||||
|
|
|
@ -55,7 +55,7 @@ public:
|
|||
virtual Optional<PropertyDescriptor> get_own_property_descriptor(const PropertyName&) const override;
|
||||
virtual bool define_property(const StringOrSymbol& property_name, const Object& descriptor, bool throw_exceptions = true) override;
|
||||
virtual bool has_property(const PropertyName& name) const override;
|
||||
virtual Value get(const PropertyName& name, Value receiver) const override;
|
||||
virtual Value get(const PropertyName& name, Value receiver, bool without_side_effects = false) const override;
|
||||
virtual bool put(const PropertyName& name, Value value, Value receiver) override;
|
||||
virtual bool delete_property(const PropertyName& name) override;
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue