Skip to content

Commit

Permalink
Statically cache the String value of g_internal_field for a small per…
Browse files Browse the repository at this point in the history
…formance gain (#4863)

* Statically cache the String value of g_internal_field for a small performance gain

* Fix lint

* Update src/jsi/jsi_class.hpp

Co-authored-by: Mathias Stearn <redbeard0531@gmail.com>

* Update src/jsi/jsi_class.hpp

Co-authored-by: Mathias Stearn <redbeard0531@gmail.com>

* Change to empty string for internal field name

Co-authored-by: Mathias Stearn <redbeard0531@gmail.com>
  • Loading branch information
2 people authored and kraenhansen committed Sep 9, 2022
1 parent 5cbb631 commit 4e2ccbc
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 4 deletions.
21 changes: 21 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,24 @@
## vNext (TBD)

### Enhancements
* Small improvement to performance by caching JSI property String object [#4863](https://github.com/realm/realm-js/pull/4863)

### Fixed
* <How to hit and notice issue? what was the impact?> ([#????](https://github.com/realm/realm-js/issues/????), since v?.?.?)
* None.

### Compatibility
* React Native >= v0.64.0
* Atlas App Services.
* Realm Studio v12.0.0.
* APIs are backwards compatible with all previous releases of Realm JavaScript in the 10.5.x series.
* File format: generates Realms with format v22 (reads and upgrades file format v5 or later for non-synced Realm, upgrades file format v10 or later for synced Realms).

### Internal
<!-- * Either mention core version or upgrade -->
<!-- * Using Realm Core vX.Y.Z -->
<!-- * Upgraded Realm Core from vX.Y.Z to vA.B.C -->

## 10.21.0 (2022-09-09)

### Enhancements
Expand Down
20 changes: 16 additions & 4 deletions src/jsi/jsi_class.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,10 @@ inline void copyProperty(JsiEnv env, const fbjsi::Object& from, const fbjsi::Obj
defineProperty(env, to, name, *prop);
}

inline constexpr const char g_internal_field[] = "__Realm_internal";
// The name used for the property on the JS object which stores the reference to the corresponding C++ object.
// We use an empty string as testing showed it was 1% faster with JSC and 4% faster with Hermes than using
// an actual string, and also has the benefit that it is not a valid Realm object key name.
inline constexpr const char g_internal_field[] = "";

template <typename T>
using ClassDefinition = js::ClassDefinition<js::realmjsi::Types, T>;
Expand Down Expand Up @@ -240,6 +243,10 @@ class ObjectWrap {
// Also, may need to suppress destruction.
inline static std::optional<JsiFunc> s_ctor;

// Cache the JSI String instance representing the field name of the internal
// C++ object for the lifetime of the current env, as this is a hot path
inline static std::optional<fbjsi::String> s_js_internal_field_name;

/**
* @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 @@ -310,9 +317,10 @@ class ObjectWrap {
.asFunction(env));

js::Context<js::realmjsi::Types>::register_invalidator([] {
// 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.
// Ensure the static constructor and JSI String reference are destructed when the runtime goes away.
// This is to avoid reassignment and destruction throwing because the runtime has disappeared.
s_ctor.reset();
s_js_internal_field_name.reset();
});

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

static Internal* get_internal(JsiEnv env, const JsiObj& object)
{
auto internal = object->getProperty(env, g_internal_field);
if (REALM_UNLIKELY(!s_js_internal_field_name)) {
s_js_internal_field_name = fbjsi::String::createFromAscii(env, g_internal_field);
}

auto internal = object->getProperty(env, *s_js_internal_field_name);
if (internal.isUndefined()) {
// In the case of a user opening a Realm with a class-based model,
// the user defined constructor will get called before the "internal" property has been set.
Expand Down

0 comments on commit 4e2ccbc

Please sign in to comment.