Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add default implementation for Object.create(prototype) #47946

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions packages/react-native/ReactCommon/jsi/jsi/decorator.h
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,10 @@ class RuntimeDecorator : public Base, private jsi::Instrumentation {
plain_.getPropNameIdData(sym, ctx, cb);
}

Object createObjectWithPrototype(const Value& prototype) override {
return plain_.createObjectWithPrototype(prototype);
}

Object createObject() override {
return plain_.createObject();
};
Expand Down Expand Up @@ -282,6 +286,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);
};
Expand Down Expand Up @@ -729,6 +741,11 @@ class WithRuntimeDecorator : public RuntimeDecorator<Plain, Base> {
return RD::createValueFromJsonUtf8(json, length);
};

Object createObjectWithPrototype(const Value& prototype) override {
Around around{with_};
return RD::createObjectWithPrototype(prototype);
}

Object createObject() override {
Around around{with_};
return RD::createObject();
Expand Down Expand Up @@ -760,6 +777,16 @@ class WithRuntimeDecorator : public RuntimeDecorator<Plain, Base> {
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);
Expand Down
4 changes: 4 additions & 0 deletions packages/react-native/ReactCommon/jsi/jsi/jsi-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
Expand Down
21 changes: 21 additions & 0 deletions packages/react-native/ReactCommon/jsi/jsi/jsi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,27 @@ 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);
}

Object Runtime::createObjectWithPrototype(const Value& prototype) {
auto createFn = global()
.getPropertyAsObject(*this, "Object")
.getPropertyAsFunction(*this, "create");
return createFn.call(*this, prototype).asObject(*this);
}

Pointer& Pointer::operator=(Pointer&& other) noexcept {
if (ptr_) {
ptr_->invalidate();
Expand Down
21 changes: 21 additions & 0 deletions packages/react-native/ReactCommon/jsi/jsi/jsi.h
Original file line number Diff line number Diff line change
Expand Up @@ -333,12 +333,18 @@ class JSI_EXPORT Runtime {
virtual std::shared_ptr<HostObject> getHostObject(const jsi::Object&) = 0;
virtual HostFunctionType& getHostFunction(const jsi::Function&) = 0;

// Creates a new Object with the custom prototype
virtual Object createObjectWithPrototype(const Value& prototype);

virtual bool hasNativeState(const jsi::Object&) = 0;
virtual std::shared_ptr<NativeState> getNativeState(const jsi::Object&) = 0;
virtual void setNativeState(
const jsi::Object&,
std::shared_ptr<NativeState> 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;
Expand Down Expand Up @@ -748,6 +754,11 @@ class JSI_EXPORT Object : public Pointer {
return runtime.createObject(ho);
}

/// Creates a new Object with the custom prototype
static Object create(Runtime& runtime, const Value& prototype) {
return runtime.createObjectWithPrototype(prototype);
}

/// \return whether this and \c obj are the same JSObject or not.
static bool strictEquals(Runtime& runtime, const Object& a, const Object& b) {
return runtime.strictEquals(a, b);
Expand All @@ -758,6 +769,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.
Expand Down
59 changes: 59 additions & 0 deletions packages/react-native/ReactCommon/jsi/jsi/test/testlib.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1664,6 +1664,65 @@ 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<Runtime, Runtime> {
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);
}

TEST_P(JSITest, ObjectCreateWithPrototype) {
// This Runtime Decorator is used to test the default implementation of
// Object.create(prototype)
class RD : public RuntimeDecorator<Runtime, Runtime> {
public:
RD(Runtime& rt) : RuntimeDecorator(rt) {}

Object createObjectWithPrototype(const Value& prototype) override {
return Runtime::createObjectWithPrototype(prototype);
}
};

RD rd = RD(rt);
Object prototypeObj(rd);
prototypeObj.setProperty(rd, "someProperty", 123);
Value prototype(rd, prototypeObj);

Object child = Object::create(rd, prototype);
EXPECT_EQ(child.getProperty(rd, "someProperty").getNumber(), 123);

// Tests null value as prototype
child = Object::create(rd, Value::null());
EXPECT_TRUE(child.getPrototype(rd).isNull());
}

INSTANTIATE_TEST_CASE_P(
Runtimes,
JSITest,
Expand Down
Loading