From 363e226763091585551a3bef18bc3082159f1500 Mon Sep 17 00:00:00 2001 From: Neil Dhar Date: Wed, 29 Nov 2023 15:50:08 -0800 Subject: [PATCH] Add JSI method for setting external memory size (#41436) Summary: Add a JSI API for associating some native memory with a JS object. This is intended to provide a mechanism to trigger more frequent garbage collection when JS retains large external memory allocations, in order to avoid memory buildup. This diff just adds the JSI method, without any implementations. Changelog: [General][Added] - Added JSI method for reporting native memory to the GC. Reviewed By: tmikov Differential Revision: D50524912 --- .../react-native/ReactCommon/jsc/JSCRuntime.cpp | 3 +++ .../react-native/ReactCommon/jsi/jsi/decorator.h | 4 ++++ .../react-native/ReactCommon/jsi/jsi/jsi-inl.h | 5 +++++ packages/react-native/ReactCommon/jsi/jsi/jsi.h | 15 +++++++++++++++ 4 files changed, 27 insertions(+) diff --git a/packages/react-native/ReactCommon/jsc/JSCRuntime.cpp b/packages/react-native/ReactCommon/jsc/JSCRuntime.cpp index 40633656596873..c42d4f3008e4a6 100644 --- a/packages/react-native/ReactCommon/jsc/JSCRuntime.cpp +++ b/packages/react-native/ReactCommon/jsc/JSCRuntime.cpp @@ -233,6 +233,7 @@ class JSCRuntime : public jsi::Runtime { bool strictEquals(const jsi::String& a, const jsi::String& b) const override; bool strictEquals(const jsi::Object& a, const jsi::Object& b) const override; bool instanceOf(const jsi::Object& o, const jsi::Function& f) override; + void setExternalMemoryPressure(const jsi::Object&, size_t) override; private: // Basically convenience casts @@ -1392,6 +1393,8 @@ bool JSCRuntime::instanceOf(const jsi::Object& o, const jsi::Function& f) { return res; } +void JSCRuntime::setExternalMemoryPressure(const jsi::Object&, size_t) {} + jsi::Runtime::PointerValue* JSCRuntime::makeSymbolValue( JSValueRef symbolRef) const { #ifndef NDEBUG diff --git a/packages/react-native/ReactCommon/jsi/jsi/decorator.h b/packages/react-native/ReactCommon/jsi/jsi/decorator.h index baece80fe71d0f..7bddd1fad80a52 100644 --- a/packages/react-native/ReactCommon/jsi/jsi/decorator.h +++ b/packages/react-native/ReactCommon/jsi/jsi/decorator.h @@ -252,6 +252,10 @@ class RuntimeDecorator : public Base, private jsi::Instrumentation { plain_.setNativeState(o, state); } + void setExternalMemoryPressure(const Object& obj, size_t amt) override { + plain_.setExternalMemoryPressure(obj, amt); + } + Value getProperty(const Object& o, const PropNameID& name) override { return plain_.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 4ce00adb883c59..f3955815e41f06 100644 --- a/packages/react-native/ReactCommon/jsi/jsi/jsi-inl.h +++ b/packages/react-native/ReactCommon/jsi/jsi/jsi-inl.h @@ -227,6 +227,11 @@ inline void Object::setNativeState( runtime.setNativeState(*this, state); } +inline void Object::setExternalMemoryPressure(Runtime& runtime, size_t amt) + const { + runtime.setExternalMemoryPressure(*this, amt); +} + inline Array Object::getPropertyNames(Runtime& runtime) const { return runtime.getPropertyNames(*this); } diff --git a/packages/react-native/ReactCommon/jsi/jsi/jsi.h b/packages/react-native/ReactCommon/jsi/jsi/jsi.h index e5112b753b69d1..962dae93609423 100644 --- a/packages/react-native/ReactCommon/jsi/jsi/jsi.h +++ b/packages/react-native/ReactCommon/jsi/jsi/jsi.h @@ -387,6 +387,11 @@ class JSI_EXPORT Runtime { virtual bool instanceOf(const Object& o, const Function& f) = 0; + /// See Object::setExternalMemoryPressure. + virtual void setExternalMemoryPressure( + const jsi::Object& obj, + size_t amount) = 0; + // These exist so derived classes can access the private parts of // Value, Symbol, String, and Object, which are all friends of Runtime. template @@ -834,6 +839,16 @@ class JSI_EXPORT Object : public Pointer { /// works. I only need it in one place.) Array getPropertyNames(Runtime& runtime) const; + /// Inform the runtime that there is additional memory associated with a given + /// JavaScript object that is not visible to the GC. This can be used if an + /// object is known to retain some native memory, and may be used to guide + /// decisions about when to run garbage collection. + /// This method may be invoked multiple times on an object, and subsequent + /// calls will overwrite any previously set value. Once the object is garbage + /// collected, the associated external memory will be considered freed and may + /// no longer factor into GC decisions. + void setExternalMemoryPressure(Runtime& runtime, size_t amt) const; + protected: void setPropertyValue( Runtime& runtime,