Skip to content

Commit

Permalink
Cache whether native state API is supported or not
Browse files Browse the repository at this point in the history
  • Loading branch information
Tom Duncalf committed Sep 5, 2022
1 parent af59f26 commit 2a8cceb
Showing 1 changed file with 40 additions and 11 deletions.
51 changes: 40 additions & 11 deletions src/jsi/jsi_class.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "js_util.hpp"

#include <ctype.h>
#include <stdexcept>
#include <unordered_set>
#include <vector>
#include <functional>
Expand Down Expand Up @@ -254,6 +255,8 @@ class ObjectWrap {
// Also, may need to suppress destruction.
inline static std::optional<JsiFunc> s_ctor;

inline static std::optional<bool> s_native_state_supported;

/**
* @brief callback for invalid access to index setters
* Throws an error when a users attemps to write to an index on a type that
Expand Down Expand Up @@ -327,6 +330,8 @@ class ObjectWrap {
// Ensure the static constructor is destructed when the runtime goes away.
// This is to avoid the reassignment of s_ctor throwing because the runtime has disappeared.
s_ctor.reset();

s_native_state_supported.reset();
});

for (auto&& [name, prop] : s_type.static_properties) {
Expand Down Expand Up @@ -504,7 +509,11 @@ class ObjectWrap {

static Internal* get_internal(JsiEnv env, const JsiObj& object)
{
try {
if (!s_native_state_supported) {
throw std::runtime_error("Tried to get_internal before calling set_internal");
}

if (*s_native_state_supported) {
Internal* internal = (Internal*)(object->getNativeState<WrappedState<Internal*>>(env)).get();

if (!internal) {
Expand All @@ -517,7 +526,7 @@ class ObjectWrap {

return internal;
}
catch (std::logic_error) {
else {
// Fallback to property access (see set_internal)
auto internal = object->getProperty(env, g_internal_field);
if (internal.isUndefined()) {
Expand All @@ -542,16 +551,36 @@ class ObjectWrap {

static void set_internal(JsiEnv env, const JsiObj& object, Internal* data)
{
try {
object->setNativeState(env, std::make_shared<WrappedState<Internal*>>(data));
// The first time we try to set_internal, we want to check whether we can use the
// JSC NativeState API or not (which depends on the Hermes runtime being used).
// In future, we want to skip this check as try/catch is expensive, so we store
// the result in a static variable.
if (!s_native_state_supported) {
try {
object->setNativeState(env, std::make_shared<WrappedState<Internal*>>(data));
s_native_state_supported = true;
}
catch (std::logic_error) {
// NativeState API is not implemented for the JSC Runtime and will throw a logic_error,
// so fall back to storing the object as a property (which is much slower, but works)
auto desc = fbjsi::Object(env);
desc.setProperty(env, "value", wrapUnique(env, data));
desc.setProperty(env, "configurable", true);
defineProperty(env, object, g_internal_field, desc);
s_native_state_supported = false;
}
}
catch (std::logic_error) {
// NativeState API is not implemented for the JSC Runtime and will throw a logic_error,
// so fall back to storing the object as a property (which is much slower, but works)
auto desc = fbjsi::Object(env);
desc.setProperty(env, "value", wrapUnique(env, data));
desc.setProperty(env, "configurable", true);
defineProperty(env, object, g_internal_field, desc);
else {
if (*s_native_state_supported) {
object->setNativeState(env, std::make_shared<WrappedState<Internal*>>(data));
}
else {
auto desc = fbjsi::Object(env);
desc.setProperty(env, "value", wrapUnique(env, data));
desc.setProperty(env, "configurable", true);
defineProperty(env, object, g_internal_field, desc);
s_native_state_supported = false;
}
}
}

Expand Down

0 comments on commit 2a8cceb

Please sign in to comment.