diff options
-rw-r--r-- | Libraries/LibJS/Runtime/Object.cpp | 9 | ||||
-rw-r--r-- | Libraries/LibJS/Runtime/Object.h | 1 | ||||
-rw-r--r-- | Libraries/LibJS/Runtime/ObjectConstructor.cpp | 14 | ||||
-rw-r--r-- | Libraries/LibJS/Runtime/Value.cpp | 15 | ||||
-rw-r--r-- | Libraries/LibJS/Tests/instanceof-basic.js | 31 |
5 files changed, 53 insertions, 17 deletions
diff --git a/Libraries/LibJS/Runtime/Object.cpp b/Libraries/LibJS/Runtime/Object.cpp index 3be6803712..1c4e70f5ea 100644 --- a/Libraries/LibJS/Runtime/Object.cpp +++ b/Libraries/LibJS/Runtime/Object.cpp @@ -44,6 +44,15 @@ Object::~Object() { } +bool Object::has_prototype(const Object* prototype) const +{ + for (auto* object = m_prototype; object; object = object->prototype()) { + if (object == prototype) + return true; + } + return false; +} + Optional<Value> Object::get_own_property(const Object& this_object, const FlyString& property_name) const { auto value_here = m_properties.get(property_name); diff --git a/Libraries/LibJS/Runtime/Object.h b/Libraries/LibJS/Runtime/Object.h index 041ea089ba..aa2d887cbe 100644 --- a/Libraries/LibJS/Runtime/Object.h +++ b/Libraries/LibJS/Runtime/Object.h @@ -62,6 +62,7 @@ public: Object* prototype() { return m_prototype; } const Object* prototype() const { return m_prototype; } void set_prototype(Object* prototype) { m_prototype = prototype; } + bool has_prototype(const Object* prototype) const; bool has_own_property(const FlyString& property_name) const; enum class PreferredType { diff --git a/Libraries/LibJS/Runtime/ObjectConstructor.cpp b/Libraries/LibJS/Runtime/ObjectConstructor.cpp index 998cb4b512..11a36da59c 100644 --- a/Libraries/LibJS/Runtime/ObjectConstructor.cpp +++ b/Libraries/LibJS/Runtime/ObjectConstructor.cpp @@ -45,6 +45,20 @@ ObjectConstructor::ObjectConstructor() return {}; return object.as_object()->prototype(); }); + + put_native_function("setPrototypeOf", [this](Object*, const Vector<Value>& arguments) -> Value { + if (arguments.size() < 2) + return {}; + auto object = arguments[0].to_object(heap()); + if (interpreter().exception()) + return {}; + if (!object.is_object()) + return {}; + if (!arguments[1].is_object()) + return {}; + const_cast<Object*>(object.as_object())->set_prototype(const_cast<Object*>(arguments[1].as_object())); + return {}; + }); } ObjectConstructor::~ObjectConstructor() diff --git a/Libraries/LibJS/Runtime/Value.cpp b/Libraries/LibJS/Runtime/Value.cpp index c36d358213..fd5671aa10 100644 --- a/Libraries/LibJS/Runtime/Value.cpp +++ b/Libraries/LibJS/Runtime/Value.cpp @@ -259,20 +259,11 @@ Value instance_of(Value lhs, Value rhs) if (!lhs.is_object() || !rhs.is_object()) return Value(false); - auto* instance_prototype = lhs.as_object()->prototype(); - - if (!instance_prototype) + auto constructor_prototype_property = rhs.as_object()->get("prototype"); + if (!constructor_prototype_property.has_value() || !constructor_prototype_property.value().is_object()) return Value(false); - for (auto* constructor_object = rhs.as_object(); constructor_object; constructor_object = constructor_object->prototype()) { - auto prototype_property = constructor_object->get_own_property(*constructor_object, "prototype"); - if (!prototype_property.has_value()) - continue; - if (prototype_property.value().is_object() && prototype_property.value().as_object() == instance_prototype) - return Value(true); - } - - return Value(false); + return Value(lhs.as_object()->has_prototype(constructor_prototype_property.value().as_object())); } const LogStream& operator<<(const LogStream& stream, const Value& value) diff --git a/Libraries/LibJS/Tests/instanceof-basic.js b/Libraries/LibJS/Tests/instanceof-basic.js index 468da2f7fd..5fa9805aa6 100644 --- a/Libraries/LibJS/Tests/instanceof-basic.js +++ b/Libraries/LibJS/Tests/instanceof-basic.js @@ -1,7 +1,28 @@ -function Foo() { - this.x = 123; -} +function assert(x) { if (!x) throw 1; } + +try { + function Foo() { + this.x = 123; + } + + var foo = new Foo(); + assert(foo instanceof Foo); + + function Base() { + this.is_base = true; + } + + function Derived() { + this.is_derived = true; + } + + Object.setPrototypeOf(Derived.prototype, Base.prototype); + + var d = new Derived(); + assert(d instanceof Derived); + assert(d instanceof Base); -var foo = new Foo(); -if (foo instanceof Foo) console.log("PASS"); +} catch(e) { + console.log("FAIL: " + e); +} |