Переглянути джерело

LibJS: Make ObjectPrototype an immutable prototype exotic object

To make this happen, this patch implements the SetImmutablePrototype
abstract operation (as a method on Object) and then overrides
[[SetPrototypeOf]] on ObjectPrototype.
Linus Groh 4 роки тому
батько
коміт
cb20baebae

+ 20 - 0
Userland/Libraries/LibJS/Runtime/Object.cpp

@@ -870,6 +870,26 @@ MarkedValueList Object::internal_own_property_keys() const
     return keys;
     return keys;
 }
 }
 
 
+// 10.4.7.2 SetImmutablePrototype ( O, V ), https://tc39.es/ecma262/#sec-set-immutable-prototype
+bool Object::set_immutable_prototype(Object* prototype)
+{
+    auto& vm = this->vm();
+
+    // 1. Assert: Either Type(V) is Object or Type(V) is Null.
+
+    // 2. Let current be ? O.[[GetPrototypeOf]]().
+    auto* current = internal_get_prototype_of();
+    if (vm.exception())
+        return {};
+
+    // 3. If SameValue(V, current) is true, return true.
+    if (prototype == current)
+        return true;
+
+    // 4. Return false.
+    return false;
+}
+
 Optional<ValueAndAttributes> Object::storage_get(PropertyName const& property_name, CallNativeProperty call_native_property) const
 Optional<ValueAndAttributes> Object::storage_get(PropertyName const& property_name, CallNativeProperty call_native_property) const
 {
 {
     VERIFY(property_name.is_valid());
     VERIFY(property_name.is_valid());

+ 4 - 0
Userland/Libraries/LibJS/Runtime/Object.h

@@ -100,6 +100,10 @@ public:
     virtual bool internal_delete(PropertyName const&);
     virtual bool internal_delete(PropertyName const&);
     virtual MarkedValueList internal_own_property_keys() const;
     virtual MarkedValueList internal_own_property_keys() const;
 
 
+    // 10.4.7 Immutable Prototype Exotic Objects, https://tc39.es/ecma262/#sec-immutable-prototype-exotic-objects
+
+    bool set_immutable_prototype(Object* prototype);
+
     // 20.1 Object Objects, https://tc39.es/ecma262/#sec-object-objects
     // 20.1 Object Objects, https://tc39.es/ecma262/#sec-object-objects
 
 
     Object* define_properties(Value properties);
     Object* define_properties(Value properties);

+ 6 - 0
Userland/Libraries/LibJS/Runtime/ObjectPrototype.cpp

@@ -50,6 +50,12 @@ ObjectPrototype::~ObjectPrototype()
 {
 {
 }
 }
 
 
+// 10.4.7.1 [[SetPrototypeOf]] ( V ), https://tc39.es/ecma262/#sec-immutable-prototype-exotic-objects-setprototypeof-v
+bool ObjectPrototype::internal_set_prototype_of(Object* prototype)
+{
+    return set_immutable_prototype(prototype);
+}
+
 // 20.1.3.2 Object.prototype.hasOwnProperty ( V ), https://tc39.es/ecma262/#sec-object.prototype.hasownproperty
 // 20.1.3.2 Object.prototype.hasOwnProperty ( V ), https://tc39.es/ecma262/#sec-object.prototype.hasownproperty
 JS_DEFINE_NATIVE_FUNCTION(ObjectPrototype::has_own_property)
 JS_DEFINE_NATIVE_FUNCTION(ObjectPrototype::has_own_property)
 {
 {

+ 4 - 0
Userland/Libraries/LibJS/Runtime/ObjectPrototype.h

@@ -18,6 +18,10 @@ public:
     virtual void initialize(GlobalObject&) override;
     virtual void initialize(GlobalObject&) override;
     virtual ~ObjectPrototype() override;
     virtual ~ObjectPrototype() override;
 
 
+    // 10.4.7 Immutable Prototype Exotic Objects, https://tc39.es/ecma262/#sec-immutable-prototype-exotic-objects
+
+    virtual bool internal_set_prototype_of(Object* prototype) override;
+
     // public to serve as intrinsic function %Object.prototype.toString%
     // public to serve as intrinsic function %Object.prototype.toString%
     JS_DECLARE_NATIVE_FUNCTION(to_string);
     JS_DECLARE_NATIVE_FUNCTION(to_string);
 
 

+ 7 - 0
Userland/Libraries/LibJS/Tests/builtins/Object/Object.prototype.js

@@ -3,3 +3,10 @@ test("basic functionality", () => {
     Object.prototype.foo = 123;
     Object.prototype.foo = 123;
     expect(o.foo).toBe(123);
     expect(o.foo).toBe(123);
 });
 });
+
+test("is an immutable prototype exotic object", () => {
+    const p = Object.create(null);
+    expect(() => {
+        Object.setPrototypeOf(Object.prototype, p);
+    }).toThrowWithMessage(TypeError, "Object's [[SetPrototypeOf]] method returned false");
+});