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

Added disposing/release mechanism to the system #131

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
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
6 changes: 3 additions & 3 deletions cpp/WKTJsRuntimeFactory.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@
// Hermes
#include <hermes/hermes.h>
#elif __has_include(<React-jsc/JSCRuntime.h>)
// JSC
#include <React-jsc/JSCRuntime.h>
// JSC
#include <React-jsc/JSCRuntime.h>
#else
#include <jsc/JSCRuntime.h>
#include <jsc/JSCRuntime.h>
#endif

namespace RNWorklet {
Expand Down
28 changes: 23 additions & 5 deletions cpp/WKTJsiWorklet.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ class JsiWorklet : public JsiHostObject,
JsiWorklet(jsi::Runtime &runtime, std::shared_ptr<jsi::Function> func) {
createWorklet(runtime, func);
}

~JsiWorklet() {
JsiHostObject::dispose();
}

JSI_HOST_FUNCTION(isWorklet) { return isWorklet(); }

Expand Down Expand Up @@ -233,6 +237,15 @@ class JsiWorklet : public JsiHostObject,
}
}

protected:
void dispose(bool disposed) override {
if (!disposed) {
if (_closureWrapper != nullptr) {
_closureWrapper->release_wrapped_resources();
}
}
}

private:
/**
Installs the worklet function into the worklet runtime
Expand Down Expand Up @@ -301,14 +314,19 @@ class JsiWorklet : public JsiHostObject,
.asString(runtime)
.utf8(runtime);
}

// Double-check if the code property is valid.
bool isCodeEmpty = std::all_of(_code.begin(), _code.end(), std::isspace);
if (isCodeEmpty) {
std::string error = "Failed to create Worklet, the provided code is empty. Tips:\n"
"* Is the babel plugin correctly installed?\n"
"* If you are using react-native-reanimated, make sure the react-native-reanimated plugin does not override the react-native-worklets-core/plugin.\n"
"* Make sure the JS Worklet contains a \"" + std::string(PropNameWorkletInitDataCode) + "\" property with the function's code.";
std::string error =
"Failed to create Worklet, the provided code is empty. Tips:\n"
"* Is the babel plugin correctly installed?\n"
"* If you are using react-native-reanimated, make sure the "
"react-native-reanimated plugin does not override the "
"react-native-worklets-core/plugin.\n"
"* Make sure the JS Worklet contains a \"" +
std::string(PropNameWorkletInitDataCode) +
"\" property with the function's code.";
throw jsi::JSError(runtime, error);
}

Expand Down
7 changes: 4 additions & 3 deletions cpp/WKTJsiWorkletApi.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,9 +132,10 @@ class JsiWorkletApi : public JsiHostObject {

JSI_PROPERTY_GET(currentContext) {
auto current = JsiWorkletContext::getCurrent(runtime);
if (!current) return jsi::Value::undefined();
return jsi::Object::createFromHostObject(
runtime, current->shared_from_this());
if (!current)
return jsi::Value::undefined();
return jsi::Object::createFromHostObject(runtime,
current->shared_from_this());
}

JSI_EXPORT_PROPERTY_GETTERS(JSI_EXPORT_PROP_GET(JsiWorkletApi,
Expand Down
7 changes: 7 additions & 0 deletions cpp/base/WKTJsiHostObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,13 @@ JsiHostObject::~JsiHostObject() {
#endif
}

void JsiHostObject::dispose() {
if (!_disposed) {
dispose(_disposed);
_disposed = true;
}
}

void JsiHostObject::set(jsi::Runtime &rt, const jsi::PropNameID &name,
const jsi::Value &value) {

Expand Down
11 changes: 11 additions & 0 deletions cpp/base/WKTJsiHostObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,11 @@ class JsiHostObject : public jsi::HostObject {
JsiHostObject();
~JsiHostObject();

/**
Disposes and releases all used resources
*/
void dispose();

protected:
/**
Override to return map of name/functions
Expand Down Expand Up @@ -194,7 +199,13 @@ class JsiHostObject : public jsi::HostObject {
*/
std::vector<jsi::PropNameID> getPropertyNames(jsi::Runtime &runtime) override;

/**
Override to dispose
*/
virtual void dispose(bool disposed) {}

private:
std::map<void *, std::map<std::string, jsi::Function>> _hostFunctionCache;
std::atomic<bool> _disposed = {false};
};
} // namespace RNWorklet
13 changes: 13 additions & 0 deletions cpp/sharedvalues/WKTJsiSharedValue.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ class JsiSharedValue : public JsiHostObject {
*/
~JsiSharedValue() { _valueWrapper = nullptr; }

JSI_HOST_FUNCTION(dispose) {
JsiHostObject::dispose();
return jsi::Value::undefined();
}

JSI_HOST_FUNCTION(toString) {
return jsi::String::createFromUtf8(runtime,
_valueWrapper->toString(runtime));
Expand Down Expand Up @@ -100,6 +105,7 @@ class JsiSharedValue : public JsiHostObject {
}

JSI_EXPORT_FUNCTIONS(JSI_EXPORT_FUNC(JsiSharedValue, toString),
JSI_EXPORT_FUNC(JsiSharedValue, dispose),
JSI_EXPORT_FUNC(JsiSharedValue, addListener))

JSI_EXPORT_PROPERTY_GETTERS(JSI_EXPORT_PROP_GET(JsiSharedValue, value))
Expand All @@ -122,6 +128,13 @@ class JsiSharedValue : public JsiHostObject {
_valueWrapper->removeListener(listenerId);
}

protected:
void dispose(bool disposed) override {
if (!disposed) {
_valueWrapper->release_wrapped_resources();
}
}

private:
std::shared_ptr<JsiWrapper> _valueWrapper;
std::shared_ptr<JsiWorkletContext> _context;
Expand Down
6 changes: 6 additions & 0 deletions cpp/wrappers/WKTArgumentsWrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ class ArgumentsWrapper {
}
}

~ArgumentsWrapper() {
for (size_t i = 0; i < _arguments.size(); i++) {
_arguments[i]->release_wrapped_resources();
}
}

size_t getCount() const { return _count; }

std::vector<jsi::Value> getArguments(jsi::Runtime &runtime) const {
Expand Down
19 changes: 19 additions & 0 deletions cpp/wrappers/WKTJsiArrayWrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ class JsiArrayWrapper : public JsiHostObject,
JsiWrapper *parent)
: JsiWrapper(runtime, value, parent, JsiWrapperType::Array) {}

~JsiArrayWrapper() { JsiHostObject::dispose(); }

JSI_HOST_FUNCTION(toStringImpl) {
return jsi::String::createFromUtf8(runtime, toString(runtime));
}
Expand Down Expand Up @@ -413,6 +415,23 @@ class JsiArrayWrapper : public JsiHostObject,

const std::vector<std::shared_ptr<JsiWrapper>> &getArray() { return _array; }

/**
Overridden dispose - release our array resources!
*/
void release_wrapped_resources() override {
for (size_t i = 0; i < _array.size(); i++) {
_array[i]->release_wrapped_resources();
}
}

protected:
// Release resources when the owning JS engine calls dispose on this object
void dispose(bool disposed) override {
if (!disposed) {
release_wrapped_resources();
}
}

private:
/**
Creates a proxy for the host object so that we can make the runtime trust
Expand Down
18 changes: 18 additions & 0 deletions cpp/wrappers/WKTJsiObjectWrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ class JsiObjectWrapper : public JsiHostObject,
JsiWrapper *parent)
: JsiWrapper(runtime, value, parent) {}

~JsiObjectWrapper() { JsiHostObject::dispose(); }

JSI_HOST_FUNCTION(toStringImpl) {
return jsi::String::createFromUtf8(runtime, toString(runtime));
}
Expand Down Expand Up @@ -156,7 +158,23 @@ class JsiObjectWrapper : public JsiHostObject,
}
}

/**
Overridden dispose - release our array resources!
*/
void release_wrapped_resources() override {
for (auto it = _properties.begin(); it != _properties.end(); it++) {
it->second->release_wrapped_resources();
}
}

protected:
// Release resources when the owning JS engine calls dispose on this object
void dispose(bool disposed) override {
if (!disposed) {
release_wrapped_resources();
}
}

jsi::Value getAsProxyOrValue(jsi::Runtime &runtime) override {
if (getType() == JsiWrapperType::Object) {
return getObjectAsProxy(runtime, shared_from_this());
Expand Down
21 changes: 20 additions & 1 deletion cpp/wrappers/WKTJsiPromiseWrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,20 @@ class JsiPromiseWrapper

explicit JsiPromiseWrapper(jsi::Runtime &runtime);

~JsiPromiseWrapper() {}
~JsiPromiseWrapper() { JsiHostObject::dispose(); }

/**
Overridden dispose - release our array resources!
*/
void release_wrapped_resources() override {
if (_reason != nullptr) {
_reason->release_wrapped_resources();
}
if (_value != nullptr) {
_value->release_wrapped_resources();
}
}

/**
Returns true if the object is a thenable object - ie. an object with a then
function. Which is basically what a promise is.
Expand Down Expand Up @@ -138,6 +151,12 @@ class JsiPromiseWrapper
}

protected:
void dispose(bool disposed) override {
if (!disposed) {
release_wrapped_resources();
}
}

jsi::Value then(jsi::Runtime &runtime, const jsi::Value &thisValue,
const jsi::Value *thenFn, const jsi::Value *catchFn);

Expand Down
10 changes: 7 additions & 3 deletions cpp/wrappers/WKTJsiWrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,11 @@ class JsiWrapper {
*/
void removeListener(size_t listenerId) { _listeners.erase(listenerId); }

/**
Override to ensure releasing resources correctly
*/
virtual void release_wrapped_resources() {}

protected:
/**
* Returns a wrapper for the value
Expand Down Expand Up @@ -185,7 +190,6 @@ class JsiWrapper {
const jsi::Value &thisValue,
const jsi::Value *arguments, size_t count);

protected:
/**
* Sets the value from a JS value
* @param runtime runtime for the value
Expand Down Expand Up @@ -253,10 +257,10 @@ class JsiWrapper {
* @param parent Parent wrapper
*/
explicit JsiWrapper(JsiWrapper *parent) : _parent(parent) {
_readWriteMutex = new std::mutex();
_readWriteMutex = std::make_shared<std::mutex>();
}

std::mutex *_readWriteMutex;
std::shared_ptr<std::mutex> _readWriteMutex;
JsiWrapper *_parent;

JsiWrapperType _type;
Expand Down
7 changes: 6 additions & 1 deletion src/hooks/useSharedValue.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useRef } from "react";
import { useEffect, useRef } from "react";
import type { ISharedValue } from "../types";

/**
Expand All @@ -11,5 +11,10 @@ export function useSharedValue<T>(initialValue: T): ISharedValue<T> {
if (ref.current == null) {
ref.current = Worklets.createSharedValue(initialValue);
}
// Free on unmount
useEffect(() => {
return ref.current?.dispose;
}, []);

return ref.current;
}
1 change: 1 addition & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export interface ISharedValue<T> {
get value(): T;
set value(v: T);
addListener(listener: () => void): () => void;
dispose: () => void;
}

export interface IWorklet {
Expand Down