summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Libraries/LibJS/Runtime/Object.cpp9
-rw-r--r--Libraries/LibJS/Runtime/Object.h1
-rw-r--r--Libraries/LibJS/Runtime/ObjectConstructor.cpp14
-rw-r--r--Libraries/LibJS/Runtime/Value.cpp15
-rw-r--r--Libraries/LibJS/Tests/instanceof-basic.js31
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);
+}