diff --git a/packages/react-native/ReactCommon/jsi/jsi/decorator.h b/packages/react-native/ReactCommon/jsi/jsi/decorator.h index d952ccbee0f..7136a27430d 100644 --- a/packages/react-native/ReactCommon/jsi/jsi/decorator.h +++ b/packages/react-native/ReactCommon/jsi/jsi/decorator.h @@ -282,6 +282,14 @@ class RuntimeDecorator : public Base, private jsi::Instrumentation { plain_.setExternalMemoryPressure(obj, amt); } + void setPrototypeOf(const Object& object, const Value& prototype) override { + plain_.setPrototypeOf(object, prototype); + } + + Value getPrototypeOf(const Object& object) override { + return plain_.getPrototypeOf(object); + } + Value getProperty(const Object& o, const PropNameID& name) override { return plain_.getProperty(o, name); }; @@ -760,6 +768,16 @@ class WithRuntimeDecorator : public RuntimeDecorator { RD::setNativeState(o, state); }; + void setPrototypeOf(const Object& object, const Value& prototype) override { + Around around{with_}; + RD::setPrototypeOf(object, prototype); + } + + Value getPrototypeOf(const Object& object) override { + Around around{with_}; + return RD::getPrototypeOf(object); + } + Value getProperty(const Object& o, const PropNameID& name) override { Around around{with_}; return RD::getProperty(o, name); diff --git a/packages/react-native/ReactCommon/jsi/jsi/jsi-inl.h b/packages/react-native/ReactCommon/jsi/jsi/jsi-inl.h index 111a4702881..6076c4955be 100644 --- a/packages/react-native/ReactCommon/jsi/jsi/jsi-inl.h +++ b/packages/react-native/ReactCommon/jsi/jsi/jsi-inl.h @@ -84,6 +84,10 @@ inline const Runtime::PointerValue* Runtime::getPointerValue( return value.data_.pointer.ptr_; } +Value Object::getPrototype(Runtime& runtime) const { + return runtime.getPrototypeOf(*this); +} + inline Value Object::getProperty(Runtime& runtime, const char* name) const { return getProperty(runtime, String::createFromAscii(runtime, name)); } diff --git a/packages/react-native/ReactCommon/jsi/jsi/jsi.cpp b/packages/react-native/ReactCommon/jsi/jsi/jsi.cpp index bce1e27f0ec..b386565906f 100644 --- a/packages/react-native/ReactCommon/jsi/jsi/jsi.cpp +++ b/packages/react-native/ReactCommon/jsi/jsi/jsi.cpp @@ -274,6 +274,20 @@ void Runtime::getPropNameIdData( cb(ctx, false, utf16Str.data(), utf16Str.size()); } +void Runtime::setPrototypeOf(const Object& object, const Value& prototype) { + auto setPrototypeOfFn = global() + .getPropertyAsObject(*this, "Object") + .getPropertyAsFunction(*this, "setPrototypeOf"); + setPrototypeOfFn.call(*this, object, prototype).asObject(*this); +} + +Value Runtime::getPrototypeOf(const Object& object) { + auto setPrototypeOfFn = global() + .getPropertyAsObject(*this, "Object") + .getPropertyAsFunction(*this, "getPrototypeOf"); + return setPrototypeOfFn.call(*this, object); +} + Pointer& Pointer::operator=(Pointer&& other) noexcept { if (ptr_) { ptr_->invalidate(); diff --git a/packages/react-native/ReactCommon/jsi/jsi/jsi.h b/packages/react-native/ReactCommon/jsi/jsi/jsi.h index 4e997aa7fd6..9196510c64b 100644 --- a/packages/react-native/ReactCommon/jsi/jsi/jsi.h +++ b/packages/react-native/ReactCommon/jsi/jsi/jsi.h @@ -339,6 +339,9 @@ class JSI_EXPORT Runtime { const jsi::Object&, std::shared_ptr state) = 0; + virtual void setPrototypeOf(const Object& object, const Value& prototype); + virtual Value getPrototypeOf(const Object& object); + virtual Value getProperty(const Object&, const PropNameID& name) = 0; virtual Value getProperty(const Object&, const String& name) = 0; virtual bool hasProperty(const Object&, const PropNameID& name) = 0; @@ -758,6 +761,16 @@ class JSI_EXPORT Object : public Pointer { return rt.instanceOf(*this, ctor); } + /// Sets \p prototype as the prototype of the object. The prototype must be + /// either an Object or null. If the prototype was not set successfully, this + /// method will throw. + void setPrototype(Runtime& runtime, const Value& prototype) const { + return runtime.setPrototypeOf(*this, prototype); + } + + /// \return the prototype of the object + inline Value getPrototype(Runtime& runtime) const; + /// \return the property of the object with the given ascii name. /// If the name isn't a property on the object, returns the /// undefined value. diff --git a/packages/react-native/ReactCommon/jsi/jsi/test/testlib.cpp b/packages/react-native/ReactCommon/jsi/jsi/test/testlib.cpp index 5f779427d0f..3f1613b382b 100644 --- a/packages/react-native/ReactCommon/jsi/jsi/test/testlib.cpp +++ b/packages/react-native/ReactCommon/jsi/jsi/test/testlib.cpp @@ -1664,6 +1664,40 @@ TEST_P(JSITest, GetStringDataTest) { EXPECT_EQ(buf, str.utf16(rd)); } +TEST_P(JSITest, ObjectSetPrototype) { + // This Runtime Decorator is used to test the default implementation of + // Object.setPrototypeOf + class RD : public RuntimeDecorator { + public: + explicit RD(Runtime& rt) : RuntimeDecorator(rt) {} + + void setPrototypeOf(const Object& object, const Value& prototype) override { + return Runtime::setPrototypeOf(object, prototype); + } + + Value getPrototypeOf(const Object& object) override { + return Runtime::getPrototypeOf(object); + } + }; + + RD rd = RD(rt); + Object child(rd); + + // Tests null value as prototype + child.setPrototype(rd, Value::null()); + EXPECT_TRUE(child.getPrototype(rd).isNull()); + + Object prototypeObj(rd); + prototypeObj.setProperty(rd, "someProperty", 123); + Value prototype(rd, prototypeObj); + + child.setPrototype(rd, prototype); + EXPECT_EQ(child.getProperty(rd, "someProperty").getNumber(), 123); + + auto getPrototypeRes = child.getPrototype(rd).asObject(rd); + EXPECT_EQ(getPrototypeRes.getProperty(rd, "someProperty").getNumber(), 123); +} + INSTANTIATE_TEST_CASE_P( Runtimes, JSITest,