1*023bc8eaSKudo Chien #include <cxxabi.h>
2*023bc8eaSKudo Chien #include <utility>
3*023bc8eaSKudo Chien 
4*023bc8eaSKudo Chien #include "FrozenObject.h"
5*023bc8eaSKudo Chien #include "MutableValue.h"
6*023bc8eaSKudo Chien #include "MutableValueSetterProxy.h"
7*023bc8eaSKudo Chien #include "RemoteObject.h"
8*023bc8eaSKudo Chien #include "RuntimeDecorator.h"
9*023bc8eaSKudo Chien #include "RuntimeManager.h"
10*023bc8eaSKudo Chien #include "ShareableValue.h"
11*023bc8eaSKudo Chien #include "SharedParent.h"
12*023bc8eaSKudo Chien 
13*023bc8eaSKudo Chien namespace reanimated {
14*023bc8eaSKudo Chien class ShareableValue;
15*023bc8eaSKudo Chien const char *HIDDEN_HOST_OBJECT_PROP = "__reanimatedHostObjectRef";
16*023bc8eaSKudo Chien const char *ALREADY_CONVERTED = "__alreadyConverted";
17*023bc8eaSKudo Chien const char *CALL_ASYNC = "__callAsync";
18*023bc8eaSKudo Chien const char *PRIMAL_FUNCTION = "__primalFunction";
19*023bc8eaSKudo Chien const char *CALLBACK_ERROR_SUFFIX =
20*023bc8eaSKudo Chien     "\n\nPossible solutions are:\n"
21*023bc8eaSKudo Chien     "a) If you want to synchronously execute this method, mark it as a Worklet\n"
22*023bc8eaSKudo Chien     "b) If you want to execute this method on the JS thread, wrap it using runOnJS";
23*023bc8eaSKudo Chien 
addHiddenProperty(jsi::Runtime & rt,jsi::Value && value,const jsi::Object & obj,const char * name)24*023bc8eaSKudo Chien void addHiddenProperty(
25*023bc8eaSKudo Chien     jsi::Runtime &rt,
26*023bc8eaSKudo Chien     jsi::Value &&value,
27*023bc8eaSKudo Chien     const jsi::Object &obj,
28*023bc8eaSKudo Chien     const char *name) {
29*023bc8eaSKudo Chien   jsi::Object globalObject = rt.global().getPropertyAsObject(rt, "Object");
30*023bc8eaSKudo Chien   jsi::Function defineProperty =
31*023bc8eaSKudo Chien       globalObject.getPropertyAsFunction(rt, "defineProperty");
32*023bc8eaSKudo Chien   jsi::String internalPropName = jsi::String::createFromUtf8(rt, name);
33*023bc8eaSKudo Chien   jsi::Object paramForDefineProperty(rt);
34*023bc8eaSKudo Chien   paramForDefineProperty.setProperty(rt, "enumerable", false);
35*023bc8eaSKudo Chien   paramForDefineProperty.setProperty(rt, "value", value);
36*023bc8eaSKudo Chien   defineProperty.call(rt, obj, internalPropName, paramForDefineProperty);
37*023bc8eaSKudo Chien }
38*023bc8eaSKudo Chien 
freeze(jsi::Runtime & rt,const jsi::Object & obj)39*023bc8eaSKudo Chien void freeze(jsi::Runtime &rt, const jsi::Object &obj) {
40*023bc8eaSKudo Chien   jsi::Object globalObject = rt.global().getPropertyAsObject(rt, "Object");
41*023bc8eaSKudo Chien   jsi::Function freeze = globalObject.getPropertyAsFunction(rt, "freeze");
42*023bc8eaSKudo Chien   freeze.call(rt, obj);
43*023bc8eaSKudo Chien }
44*023bc8eaSKudo Chien 
adaptCache(jsi::Runtime & rt,const jsi::Value & value)45*023bc8eaSKudo Chien void ShareableValue::adaptCache(jsi::Runtime &rt, const jsi::Value &value) {
46*023bc8eaSKudo Chien   // when adapting from host object we can assign cached value immediately such
47*023bc8eaSKudo Chien   // that we avoid running `toJSValue` in the future when given object is
48*023bc8eaSKudo Chien   // accessed
49*023bc8eaSKudo Chien   if (RuntimeDecorator::isWorkletRuntime(rt)) {
50*023bc8eaSKudo Chien     if (remoteValue.expired()) {
51*023bc8eaSKudo Chien       remoteValue = getWeakRef(rt);
52*023bc8eaSKudo Chien     }
53*023bc8eaSKudo Chien     (*remoteValue.lock()) = jsi::Value(rt, value);
54*023bc8eaSKudo Chien   } else {
55*023bc8eaSKudo Chien     hostValue = std::make_unique<jsi::Value>(rt, value);
56*023bc8eaSKudo Chien   }
57*023bc8eaSKudo Chien }
58*023bc8eaSKudo Chien 
adapt(jsi::Runtime & rt,const jsi::Value & value,ValueType objectType)59*023bc8eaSKudo Chien void ShareableValue::adapt(
60*023bc8eaSKudo Chien     jsi::Runtime &rt,
61*023bc8eaSKudo Chien     const jsi::Value &value,
62*023bc8eaSKudo Chien     ValueType objectType) {
63*023bc8eaSKudo Chien   if (value.isObject()) {
64*023bc8eaSKudo Chien     jsi::Object object = value.asObject(rt);
65*023bc8eaSKudo Chien     jsi::Value hiddenValue = object.getProperty(rt, HIDDEN_HOST_OBJECT_PROP);
66*023bc8eaSKudo Chien     if (!(hiddenValue.isUndefined())) {
67*023bc8eaSKudo Chien       jsi::Object hiddenProperty = hiddenValue.asObject(rt);
68*023bc8eaSKudo Chien       if (hiddenProperty.isHostObject<FrozenObject>(rt)) {
69*023bc8eaSKudo Chien         type = ValueType::FrozenObjectType;
70*023bc8eaSKudo Chien         if (object.hasProperty(rt, "__workletHash") && object.isFunction(rt)) {
71*023bc8eaSKudo Chien           type = ValueType::WorkletFunctionType;
72*023bc8eaSKudo Chien         }
73*023bc8eaSKudo Chien         valueContainer = std::make_unique<FrozenObjectWrapper>(
74*023bc8eaSKudo Chien             hiddenProperty.getHostObject<FrozenObject>(rt));
75*023bc8eaSKudo Chien         if (object.hasProperty(rt, ALREADY_CONVERTED)) {
76*023bc8eaSKudo Chien           adaptCache(rt, value);
77*023bc8eaSKudo Chien         }
78*023bc8eaSKudo Chien         return;
79*023bc8eaSKudo Chien       }
80*023bc8eaSKudo Chien     }
81*023bc8eaSKudo Chien   }
82*023bc8eaSKudo Chien 
83*023bc8eaSKudo Chien   if (objectType == ValueType::MutableValueType) {
84*023bc8eaSKudo Chien     type = ValueType::MutableValueType;
85*023bc8eaSKudo Chien     valueContainer =
86*023bc8eaSKudo Chien         std::make_unique<MutableValueWrapper>(std::make_shared<MutableValue>(
87*023bc8eaSKudo Chien             rt, value, runtimeManager, runtimeManager->scheduler));
88*023bc8eaSKudo Chien   } else if (value.isUndefined()) {
89*023bc8eaSKudo Chien     type = ValueType::UndefinedType;
90*023bc8eaSKudo Chien   } else if (value.isNull()) {
91*023bc8eaSKudo Chien     type = ValueType::NullType;
92*023bc8eaSKudo Chien   } else if (value.isBool()) {
93*023bc8eaSKudo Chien     type = ValueType::BoolType;
94*023bc8eaSKudo Chien     valueContainer = std::make_unique<BooleanValueWrapper>(value.getBool());
95*023bc8eaSKudo Chien   } else if (value.isNumber()) {
96*023bc8eaSKudo Chien     type = ValueType::NumberType;
97*023bc8eaSKudo Chien     valueContainer = std::make_unique<NumberValueWrapper>(value.asNumber());
98*023bc8eaSKudo Chien   } else if (value.isString()) {
99*023bc8eaSKudo Chien     type = ValueType::StringType;
100*023bc8eaSKudo Chien     valueContainer =
101*023bc8eaSKudo Chien         std::make_unique<StringValueWrapper>(value.asString(rt).utf8(rt));
102*023bc8eaSKudo Chien   } else if (value.isObject()) {
103*023bc8eaSKudo Chien     auto object = value.asObject(rt);
104*023bc8eaSKudo Chien     if (object.isFunction(rt)) {
105*023bc8eaSKudo Chien       if (object.getProperty(rt, "__workletHash").isUndefined()) {
106*023bc8eaSKudo Chien         // not a worklet, we treat this as a host function
107*023bc8eaSKudo Chien         type = ValueType::HostFunctionType;
108*023bc8eaSKudo Chien         containsHostFunction = true;
109*023bc8eaSKudo Chien 
110*023bc8eaSKudo Chien         // Check if it's a hostFunction wrapper
111*023bc8eaSKudo Chien         jsi::Value primalFunction = object.getProperty(rt, PRIMAL_FUNCTION);
112*023bc8eaSKudo Chien         if (!primalFunction.isUndefined()) {
113*023bc8eaSKudo Chien           jsi::Object handlerAsObject = primalFunction.asObject(rt);
114*023bc8eaSKudo Chien           std::shared_ptr<HostFunctionHandler> handler =
115*023bc8eaSKudo Chien               handlerAsObject.getHostObject<HostFunctionHandler>(rt);
116*023bc8eaSKudo Chien           valueContainer = std::make_unique<HostFunctionWrapper>(handler);
117*023bc8eaSKudo Chien         } else {
118*023bc8eaSKudo Chien           valueContainer = std::make_unique<HostFunctionWrapper>(
119*023bc8eaSKudo Chien               std::make_shared<HostFunctionHandler>(
120*023bc8eaSKudo Chien                   std::make_shared<jsi::Function>(object.asFunction(rt)), rt));
121*023bc8eaSKudo Chien         }
122*023bc8eaSKudo Chien 
123*023bc8eaSKudo Chien       } else {
124*023bc8eaSKudo Chien         // a worklet
125*023bc8eaSKudo Chien         type = ValueType::WorkletFunctionType;
126*023bc8eaSKudo Chien         valueContainer = std::make_unique<FrozenObjectWrapper>(
127*023bc8eaSKudo Chien             std::make_shared<FrozenObject>(rt, object, runtimeManager));
128*023bc8eaSKudo Chien         auto &frozenObject = ValueWrapper::asFrozenObject(valueContainer);
129*023bc8eaSKudo Chien         containsHostFunction |= frozenObject->containsHostFunction;
130*023bc8eaSKudo Chien         if (RuntimeDecorator::isReactRuntime(rt) && !containsHostFunction) {
131*023bc8eaSKudo Chien           addHiddenProperty(
132*023bc8eaSKudo Chien               rt,
133*023bc8eaSKudo Chien               createHost(rt, frozenObject),
134*023bc8eaSKudo Chien               object,
135*023bc8eaSKudo Chien               HIDDEN_HOST_OBJECT_PROP);
136*023bc8eaSKudo Chien         }
137*023bc8eaSKudo Chien       }
138*023bc8eaSKudo Chien     } else if (object.isArray(rt)) {
139*023bc8eaSKudo Chien       type = ValueType::FrozenArrayType;
140*023bc8eaSKudo Chien       auto array = object.asArray(rt);
141*023bc8eaSKudo Chien       valueContainer = std::make_unique<FrozenArrayWrapper>();
142*023bc8eaSKudo Chien       auto &frozenArray = ValueWrapper::asFrozenArray(valueContainer);
143*023bc8eaSKudo Chien       for (size_t i = 0, size = array.size(rt); i < size; i++) {
144*023bc8eaSKudo Chien         auto sv = adapt(rt, array.getValueAtIndex(rt, i), runtimeManager);
145*023bc8eaSKudo Chien         containsHostFunction |= sv->containsHostFunction;
146*023bc8eaSKudo Chien         frozenArray.push_back(sv);
147*023bc8eaSKudo Chien       }
148*023bc8eaSKudo Chien     } else if (object.isHostObject<MutableValue>(rt)) {
149*023bc8eaSKudo Chien       type = ValueType::MutableValueType;
150*023bc8eaSKudo Chien       valueContainer = std::make_unique<MutableValueWrapper>(
151*023bc8eaSKudo Chien           object.getHostObject<MutableValue>(rt));
152*023bc8eaSKudo Chien       adaptCache(rt, value);
153*023bc8eaSKudo Chien     } else if (object.isHostObject<RemoteObject>(rt)) {
154*023bc8eaSKudo Chien       type = ValueType::RemoteObjectType;
155*023bc8eaSKudo Chien       valueContainer = std::make_unique<RemoteObjectWrapper>(
156*023bc8eaSKudo Chien           object.getHostObject<RemoteObject>(rt));
157*023bc8eaSKudo Chien       adaptCache(rt, value);
158*023bc8eaSKudo Chien     } else if (objectType == ValueType::RemoteObjectType) {
159*023bc8eaSKudo Chien       type = ValueType::RemoteObjectType;
160*023bc8eaSKudo Chien       valueContainer =
161*023bc8eaSKudo Chien           std::make_unique<RemoteObjectWrapper>(std::make_shared<RemoteObject>(
162*023bc8eaSKudo Chien               rt, object, runtimeManager, runtimeManager->scheduler));
163*023bc8eaSKudo Chien     } else {
164*023bc8eaSKudo Chien       // create frozen object based on a copy of a given object
165*023bc8eaSKudo Chien       type = ValueType::FrozenObjectType;
166*023bc8eaSKudo Chien       valueContainer = std::make_unique<FrozenObjectWrapper>(
167*023bc8eaSKudo Chien           std::make_shared<FrozenObject>(rt, object, runtimeManager));
168*023bc8eaSKudo Chien       auto &frozenObject = ValueWrapper::asFrozenObject(valueContainer);
169*023bc8eaSKudo Chien       containsHostFunction |= frozenObject->containsHostFunction;
170*023bc8eaSKudo Chien       if (RuntimeDecorator::isReactRuntime(rt)) {
171*023bc8eaSKudo Chien         if (!containsHostFunction) {
172*023bc8eaSKudo Chien           addHiddenProperty(
173*023bc8eaSKudo Chien               rt,
174*023bc8eaSKudo Chien               createHost(rt, frozenObject),
175*023bc8eaSKudo Chien               object,
176*023bc8eaSKudo Chien               HIDDEN_HOST_OBJECT_PROP);
177*023bc8eaSKudo Chien         }
178*023bc8eaSKudo Chien         freeze(rt, object);
179*023bc8eaSKudo Chien       }
180*023bc8eaSKudo Chien     }
181*023bc8eaSKudo Chien   } else if (value.isSymbol()) {
182*023bc8eaSKudo Chien     type = ValueType::StringType;
183*023bc8eaSKudo Chien     valueContainer =
184*023bc8eaSKudo Chien         std::make_unique<StringValueWrapper>(value.asSymbol(rt).toString(rt));
185*023bc8eaSKudo Chien   } else {
186*023bc8eaSKudo Chien     throw "Invalid value type";
187*023bc8eaSKudo Chien   }
188*023bc8eaSKudo Chien }
189*023bc8eaSKudo Chien 
adapt(jsi::Runtime & rt,const jsi::Value & value,RuntimeManager * runtimeManager,ValueType valueType)190*023bc8eaSKudo Chien std::shared_ptr<ShareableValue> ShareableValue::adapt(
191*023bc8eaSKudo Chien     jsi::Runtime &rt,
192*023bc8eaSKudo Chien     const jsi::Value &value,
193*023bc8eaSKudo Chien     RuntimeManager *runtimeManager,
194*023bc8eaSKudo Chien     ValueType valueType) {
195*023bc8eaSKudo Chien   auto sv = std::shared_ptr<ShareableValue>(
196*023bc8eaSKudo Chien       new ShareableValue(runtimeManager, runtimeManager->scheduler));
197*023bc8eaSKudo Chien   sv->adapt(rt, value, valueType);
198*023bc8eaSKudo Chien   return sv;
199*023bc8eaSKudo Chien }
200*023bc8eaSKudo Chien 
getValue(jsi::Runtime & rt)201*023bc8eaSKudo Chien jsi::Value ShareableValue::getValue(jsi::Runtime &rt) {
202*023bc8eaSKudo Chien   // TODO: maybe we can cache toJSValue results on a per-runtime basis, need to
203*023bc8eaSKudo Chien   // avoid ref loops
204*023bc8eaSKudo Chien   if (&rt == runtimeManager->runtime.get()) {
205*023bc8eaSKudo Chien     // Getting value on the same runtime where it was created, prepare
206*023bc8eaSKudo Chien     // remoteValue
207*023bc8eaSKudo Chien     if (remoteValue.expired()) {
208*023bc8eaSKudo Chien       remoteValue = getWeakRef(rt);
209*023bc8eaSKudo Chien     }
210*023bc8eaSKudo Chien 
211*023bc8eaSKudo Chien     if (remoteValue.lock()->isUndefined()) {
212*023bc8eaSKudo Chien       (*remoteValue.lock()) = toJSValue(rt);
213*023bc8eaSKudo Chien     }
214*023bc8eaSKudo Chien     return jsi::Value(rt, *remoteValue.lock());
215*023bc8eaSKudo Chien   } else {
216*023bc8eaSKudo Chien     // Getting value on a different runtime than where it was created from,
217*023bc8eaSKudo Chien     // prepare hostValue
218*023bc8eaSKudo Chien     if (hostValue.get() == nullptr) {
219*023bc8eaSKudo Chien       hostValue = std::make_unique<jsi::Value>(toJSValue(rt));
220*023bc8eaSKudo Chien     }
221*023bc8eaSKudo Chien     return jsi::Value(rt, *hostValue);
222*023bc8eaSKudo Chien   }
223*023bc8eaSKudo Chien }
224*023bc8eaSKudo Chien 
createHost(jsi::Runtime & rt,std::shared_ptr<jsi::HostObject> host)225*023bc8eaSKudo Chien jsi::Object ShareableValue::createHost(
226*023bc8eaSKudo Chien     jsi::Runtime &rt,
227*023bc8eaSKudo Chien     std::shared_ptr<jsi::HostObject> host) {
228*023bc8eaSKudo Chien   return jsi::Object::createFromHostObject(rt, host);
229*023bc8eaSKudo Chien }
230*023bc8eaSKudo Chien 
createFrozenWrapper(jsi::Runtime & rt,std::shared_ptr<FrozenObject> frozenObject)231*023bc8eaSKudo Chien jsi::Value createFrozenWrapper(
232*023bc8eaSKudo Chien     jsi::Runtime &rt,
233*023bc8eaSKudo Chien     std::shared_ptr<FrozenObject> frozenObject) {
234*023bc8eaSKudo Chien   jsi::Object __reanimatedHiddenHost =
235*023bc8eaSKudo Chien       jsi::Object::createFromHostObject(rt, frozenObject);
236*023bc8eaSKudo Chien   jsi::Object obj = frozenObject->shallowClone(rt);
237*023bc8eaSKudo Chien   jsi::Object globalObject = rt.global().getPropertyAsObject(rt, "Object");
238*023bc8eaSKudo Chien   jsi::Function freeze = globalObject.getPropertyAsFunction(rt, "freeze");
239*023bc8eaSKudo Chien   if (!frozenObject->containsHostFunction) {
240*023bc8eaSKudo Chien     addHiddenProperty(
241*023bc8eaSKudo Chien         rt, std::move(__reanimatedHiddenHost), obj, HIDDEN_HOST_OBJECT_PROP);
242*023bc8eaSKudo Chien     addHiddenProperty(rt, true, obj, ALREADY_CONVERTED);
243*023bc8eaSKudo Chien   }
244*023bc8eaSKudo Chien   return freeze.call(rt, obj);
245*023bc8eaSKudo Chien }
246*023bc8eaSKudo Chien 
toJSValue(jsi::Runtime & rt)247*023bc8eaSKudo Chien jsi::Value ShareableValue::toJSValue(jsi::Runtime &rt) {
248*023bc8eaSKudo Chien   switch (type) {
249*023bc8eaSKudo Chien     case ValueType::UndefinedType:
250*023bc8eaSKudo Chien       return jsi::Value::undefined();
251*023bc8eaSKudo Chien     case ValueType::NullType:
252*023bc8eaSKudo Chien       return jsi::Value::null();
253*023bc8eaSKudo Chien     case ValueType::BoolType:
254*023bc8eaSKudo Chien       return jsi::Value(ValueWrapper::asBoolean(valueContainer));
255*023bc8eaSKudo Chien     case ValueType::NumberType:
256*023bc8eaSKudo Chien       return jsi::Value(ValueWrapper::asNumber(valueContainer));
257*023bc8eaSKudo Chien     case ValueType::StringType: {
258*023bc8eaSKudo Chien       auto &stringValue = ValueWrapper::asString(valueContainer);
259*023bc8eaSKudo Chien       return jsi::Value(rt, jsi::String::createFromUtf8(rt, stringValue));
260*023bc8eaSKudo Chien     }
261*023bc8eaSKudo Chien     case ValueType::FrozenObjectType: {
262*023bc8eaSKudo Chien       auto &frozenObject = ValueWrapper::asFrozenObject(valueContainer);
263*023bc8eaSKudo Chien       return createFrozenWrapper(rt, frozenObject);
264*023bc8eaSKudo Chien     }
265*023bc8eaSKudo Chien     case ValueType::FrozenArrayType: {
266*023bc8eaSKudo Chien       auto &frozenArray = ValueWrapper::asFrozenArray(valueContainer);
267*023bc8eaSKudo Chien       jsi::Array array(rt, frozenArray.size());
268*023bc8eaSKudo Chien       for (size_t i = 0; i < frozenArray.size(); i++) {
269*023bc8eaSKudo Chien         array.setValueAtIndex(rt, i, frozenArray[i]->toJSValue(rt));
270*023bc8eaSKudo Chien       }
271*023bc8eaSKudo Chien       return array;
272*023bc8eaSKudo Chien     }
273*023bc8eaSKudo Chien     case ValueType::RemoteObjectType: {
274*023bc8eaSKudo Chien       auto &remoteObject = ValueWrapper::asRemoteObject(valueContainer);
275*023bc8eaSKudo Chien       if (RuntimeDecorator::isWorkletRuntime(rt)) {
276*023bc8eaSKudo Chien         remoteObject->maybeInitializeOnWorkletRuntime(rt);
277*023bc8eaSKudo Chien       }
278*023bc8eaSKudo Chien       return createHost(rt, remoteObject);
279*023bc8eaSKudo Chien     }
280*023bc8eaSKudo Chien     case ValueType::MutableValueType: {
281*023bc8eaSKudo Chien       auto &mutableObject = ValueWrapper::asMutableValue(valueContainer);
282*023bc8eaSKudo Chien       return createHost(rt, mutableObject);
283*023bc8eaSKudo Chien     }
284*023bc8eaSKudo Chien     case ValueType::HostFunctionType: {
285*023bc8eaSKudo Chien       auto hostFunctionWrapper =
286*023bc8eaSKudo Chien           ValueWrapper::asHostFunctionWrapper(valueContainer);
287*023bc8eaSKudo Chien       auto &hostRuntime = hostFunctionWrapper->value->hostRuntime;
288*023bc8eaSKudo Chien       if (hostRuntime == &rt) {
289*023bc8eaSKudo Chien         // function is accessed from the same runtime it was crated, we just
290*023bc8eaSKudo Chien         // return same function obj
291*023bc8eaSKudo Chien         return jsi::Value(
292*023bc8eaSKudo Chien             rt, *hostFunctionWrapper->value->getPureFunction().get());
293*023bc8eaSKudo Chien       } else {
294*023bc8eaSKudo Chien         // function is accessed from a different runtime, we wrap function in
295*023bc8eaSKudo Chien         // host func that'd enqueue call on an appropriate thread
296*023bc8eaSKudo Chien 
297*023bc8eaSKudo Chien         auto runtimeManager = this->runtimeManager;
298*023bc8eaSKudo Chien         auto hostFunction = hostFunctionWrapper->value;
299*023bc8eaSKudo Chien 
300*023bc8eaSKudo Chien         auto warnFunction = [runtimeManager, hostFunction](
301*023bc8eaSKudo Chien                                 jsi::Runtime &rt,
302*023bc8eaSKudo Chien                                 const jsi::Value &thisValue,
303*023bc8eaSKudo Chien                                 const jsi::Value *args,
304*023bc8eaSKudo Chien                                 size_t count) -> jsi::Value {
305*023bc8eaSKudo Chien           jsi::Value jsThis = rt.global().getProperty(rt, "jsThis");
306*023bc8eaSKudo Chien           std::string workletLocation = jsThis.asObject(rt)
307*023bc8eaSKudo Chien                                             .getProperty(rt, "__location")
308*023bc8eaSKudo Chien                                             .toString(rt)
309*023bc8eaSKudo Chien                                             .utf8(rt);
310*023bc8eaSKudo Chien           std::string exceptionMessage = "Tried to synchronously call ";
311*023bc8eaSKudo Chien           if (hostFunction->functionName.empty()) {
312*023bc8eaSKudo Chien             exceptionMessage += "anonymous function";
313*023bc8eaSKudo Chien           } else {
314*023bc8eaSKudo Chien             exceptionMessage += "function {" + hostFunction->functionName + "}";
315*023bc8eaSKudo Chien           }
316*023bc8eaSKudo Chien           exceptionMessage +=
317*023bc8eaSKudo Chien               " from a different thread.\n\nOccurred in worklet location: ";
318*023bc8eaSKudo Chien           exceptionMessage += workletLocation;
319*023bc8eaSKudo Chien           exceptionMessage += CALLBACK_ERROR_SUFFIX;
320*023bc8eaSKudo Chien           runtimeManager->errorHandler->setError(exceptionMessage);
321*023bc8eaSKudo Chien           runtimeManager->errorHandler->raise();
322*023bc8eaSKudo Chien 
323*023bc8eaSKudo Chien           return jsi::Value::undefined();
324*023bc8eaSKudo Chien         };
325*023bc8eaSKudo Chien 
326*023bc8eaSKudo Chien         auto clb = [runtimeManager, hostFunction, hostRuntime](
327*023bc8eaSKudo Chien                        jsi::Runtime &rt,
328*023bc8eaSKudo Chien                        const jsi::Value &thisValue,
329*023bc8eaSKudo Chien                        const jsi::Value *args,
330*023bc8eaSKudo Chien                        size_t count) -> jsi::Value {
331*023bc8eaSKudo Chien           // TODO: we should find thread based on runtime such that we could
332*023bc8eaSKudo Chien           // also call UI methods from RN and not only RN methods from UI
333*023bc8eaSKudo Chien 
334*023bc8eaSKudo Chien           std::vector<std::shared_ptr<ShareableValue>> params;
335*023bc8eaSKudo Chien           for (int i = 0; i < count; ++i) {
336*023bc8eaSKudo Chien             params.push_back(
337*023bc8eaSKudo Chien                 ShareableValue::adapt(rt, args[i], runtimeManager));
338*023bc8eaSKudo Chien           }
339*023bc8eaSKudo Chien 
340*023bc8eaSKudo Chien           std::function<void()> job = [hostFunction, hostRuntime, params] {
341*023bc8eaSKudo Chien             jsi::Value *args = new jsi::Value[params.size()];
342*023bc8eaSKudo Chien             for (int i = 0; i < params.size(); ++i) {
343*023bc8eaSKudo Chien               args[i] = params[i]->getValue(*hostRuntime);
344*023bc8eaSKudo Chien             }
345*023bc8eaSKudo Chien             jsi::Value returnedValue =
346*023bc8eaSKudo Chien                 hostFunction->getPureFunction().get()->call(
347*023bc8eaSKudo Chien                     *hostRuntime,
348*023bc8eaSKudo Chien                     static_cast<const jsi::Value *>(args),
349*023bc8eaSKudo Chien                     static_cast<size_t>(params.size()));
350*023bc8eaSKudo Chien 
351*023bc8eaSKudo Chien             delete[] args;
352*023bc8eaSKudo Chien             // ToDo use returned value to return promise
353*023bc8eaSKudo Chien           };
354*023bc8eaSKudo Chien 
355*023bc8eaSKudo Chien           runtimeManager->scheduler->scheduleOnJS(job);
356*023bc8eaSKudo Chien           return jsi::Value::undefined();
357*023bc8eaSKudo Chien         };
358*023bc8eaSKudo Chien         jsi::Function wrapperFunction = jsi::Function::createFromHostFunction(
359*023bc8eaSKudo Chien             rt, jsi::PropNameID::forAscii(rt, "hostFunction"), 0, warnFunction);
360*023bc8eaSKudo Chien         jsi::Function res = jsi::Function::createFromHostFunction(
361*023bc8eaSKudo Chien             rt, jsi::PropNameID::forAscii(rt, "hostFunction"), 0, clb);
362*023bc8eaSKudo Chien         addHiddenProperty(rt, std::move(res), wrapperFunction, CALL_ASYNC);
363*023bc8eaSKudo Chien         jsi::Object functionHandler =
364*023bc8eaSKudo Chien             createHost(rt, hostFunctionWrapper->value);
365*023bc8eaSKudo Chien         addHiddenProperty(
366*023bc8eaSKudo Chien             rt, std::move(functionHandler), wrapperFunction, PRIMAL_FUNCTION);
367*023bc8eaSKudo Chien         return wrapperFunction;
368*023bc8eaSKudo Chien       }
369*023bc8eaSKudo Chien     }
370*023bc8eaSKudo Chien     case ValueType::WorkletFunctionType: {
371*023bc8eaSKudo Chien       auto runtimeManager = this->runtimeManager;
372*023bc8eaSKudo Chien       auto &frozenObject = ValueWrapper::asFrozenObject(this->valueContainer);
373*023bc8eaSKudo Chien       if (RuntimeDecorator::isWorkletRuntime(rt)) {
374*023bc8eaSKudo Chien         // when running on worklet thread we prep a function
375*023bc8eaSKudo Chien 
376*023bc8eaSKudo Chien         auto jsThis = std::make_shared<jsi::Object>(
377*023bc8eaSKudo Chien             frozenObject->shallowClone(*runtimeManager->runtime));
378*023bc8eaSKudo Chien         std::shared_ptr<jsi::Function> funPtr(
379*023bc8eaSKudo Chien             runtimeManager->workletsCache->getFunction(rt, frozenObject));
380*023bc8eaSKudo Chien         auto name = funPtr->getProperty(rt, "name").asString(rt).utf8(rt);
381*023bc8eaSKudo Chien 
382*023bc8eaSKudo Chien         auto clb = [=](jsi::Runtime &rt,
383*023bc8eaSKudo Chien                        const jsi::Value &thisValue,
384*023bc8eaSKudo Chien                        const jsi::Value *args,
385*023bc8eaSKudo Chien                        size_t count) mutable -> jsi::Value {
386*023bc8eaSKudo Chien           const jsi::String jsThisName =
387*023bc8eaSKudo Chien               jsi::String::createFromAscii(rt, "jsThis");
388*023bc8eaSKudo Chien           jsi::Object global = rt.global();
389*023bc8eaSKudo Chien           jsi::Value oldJSThis = global.getProperty(rt, jsThisName);
390*023bc8eaSKudo Chien           global.setProperty(rt, jsThisName, *jsThis); // set jsThis
391*023bc8eaSKudo Chien 
392*023bc8eaSKudo Chien           jsi::Value res = jsi::Value::undefined();
393*023bc8eaSKudo Chien           try {
394*023bc8eaSKudo Chien             if (thisValue.isObject()) {
395*023bc8eaSKudo Chien               res =
396*023bc8eaSKudo Chien                   funPtr->callWithThis(rt, thisValue.asObject(rt), args, count);
397*023bc8eaSKudo Chien             } else {
398*023bc8eaSKudo Chien               res = funPtr->call(rt, args, count);
399*023bc8eaSKudo Chien             }
400*023bc8eaSKudo Chien           } catch (std::exception &e) {
401*023bc8eaSKudo Chien             std::string str = e.what();
402*023bc8eaSKudo Chien             runtimeManager->errorHandler->setError(str);
403*023bc8eaSKudo Chien             runtimeManager->errorHandler->raise();
404*023bc8eaSKudo Chien           } catch (...) {
405*023bc8eaSKudo Chien             if (demangleExceptionName(
406*023bc8eaSKudo Chien                     abi::__cxa_current_exception_type()->name()) ==
407*023bc8eaSKudo Chien                 "facebook::jsi::JSError") {
408*023bc8eaSKudo Chien               throw jsi::JSError(rt, "Javascript worklet error");
409*023bc8eaSKudo Chien             }
410*023bc8eaSKudo Chien             // TODO find out a way to get the error's message on hermes
411*023bc8eaSKudo Chien             jsi::Value location = jsThis->getProperty(rt, "__location");
412*023bc8eaSKudo Chien             std::string str = "Javascript worklet error";
413*023bc8eaSKudo Chien             if (location.isString()) {
414*023bc8eaSKudo Chien               str += "\nIn file: " + location.asString(rt).utf8(rt);
415*023bc8eaSKudo Chien             }
416*023bc8eaSKudo Chien             runtimeManager->errorHandler->setError(str);
417*023bc8eaSKudo Chien             runtimeManager->errorHandler->raise();
418*023bc8eaSKudo Chien           }
419*023bc8eaSKudo Chien           global.setProperty(rt, jsThisName, oldJSThis); // clean jsThis
420*023bc8eaSKudo Chien           return res;
421*023bc8eaSKudo Chien         };
422*023bc8eaSKudo Chien         return jsi::Function::createFromHostFunction(
423*023bc8eaSKudo Chien             rt, jsi::PropNameID::forAscii(rt, name.c_str()), 0, clb);
424*023bc8eaSKudo Chien       } else {
425*023bc8eaSKudo Chien         // when run outside of UI thread we enqueue a call on the UI thread
426*023bc8eaSKudo Chien         auto clb = [=](jsi::Runtime &rt,
427*023bc8eaSKudo Chien                        const jsi::Value &thisValue,
428*023bc8eaSKudo Chien                        const jsi::Value *args,
429*023bc8eaSKudo Chien                        size_t count) -> jsi::Value {
430*023bc8eaSKudo Chien           // TODO: we should find thread based on runtime such that we could
431*023bc8eaSKudo Chien           // also call UI methods from RN and not only RN methods from UI
432*023bc8eaSKudo Chien 
433*023bc8eaSKudo Chien           std::vector<std::shared_ptr<ShareableValue>> params;
434*023bc8eaSKudo Chien           for (int i = 0; i < count; ++i) {
435*023bc8eaSKudo Chien             params.push_back(
436*023bc8eaSKudo Chien                 ShareableValue::adapt(rt, args[i], runtimeManager));
437*023bc8eaSKudo Chien           }
438*023bc8eaSKudo Chien 
439*023bc8eaSKudo Chien           runtimeManager->scheduler->scheduleOnUI([=] {
440*023bc8eaSKudo Chien             jsi::Runtime &rt = *runtimeManager->runtime.get();
441*023bc8eaSKudo Chien             auto jsThis = createFrozenWrapper(rt, frozenObject).getObject(rt);
442*023bc8eaSKudo Chien             auto code =
443*023bc8eaSKudo Chien                 jsThis.getProperty(rt, "asString").asString(rt).utf8(rt);
444*023bc8eaSKudo Chien             std::shared_ptr<jsi::Function> funPtr(
445*023bc8eaSKudo Chien                 runtimeManager->workletsCache->getFunction(rt, frozenObject));
446*023bc8eaSKudo Chien 
447*023bc8eaSKudo Chien             jsi::Value *args = new jsi::Value[params.size()];
448*023bc8eaSKudo Chien             for (int i = 0; i < params.size(); ++i) {
449*023bc8eaSKudo Chien               args[i] = params[i]->getValue(rt);
450*023bc8eaSKudo Chien             }
451*023bc8eaSKudo Chien 
452*023bc8eaSKudo Chien             jsi::Value returnedValue;
453*023bc8eaSKudo Chien             const jsi::String jsThisName =
454*023bc8eaSKudo Chien                 jsi::String::createFromAscii(rt, "jsThis");
455*023bc8eaSKudo Chien             jsi::Object global = rt.global();
456*023bc8eaSKudo Chien             jsi::Value oldJSThis = global.getProperty(rt, jsThisName);
457*023bc8eaSKudo Chien             global.setProperty(rt, jsThisName, jsThis); // set jsThis
458*023bc8eaSKudo Chien             try {
459*023bc8eaSKudo Chien               returnedValue = funPtr->call(
460*023bc8eaSKudo Chien                   rt,
461*023bc8eaSKudo Chien                   static_cast<const jsi::Value *>(args),
462*023bc8eaSKudo Chien                   static_cast<size_t>(params.size()));
463*023bc8eaSKudo Chien             } catch (std::exception &e) {
464*023bc8eaSKudo Chien               std::string str = e.what();
465*023bc8eaSKudo Chien               runtimeManager->errorHandler->setError(str);
466*023bc8eaSKudo Chien               runtimeManager->errorHandler->raise();
467*023bc8eaSKudo Chien             } catch (...) {
468*023bc8eaSKudo Chien               if (demangleExceptionName(
469*023bc8eaSKudo Chien                       abi::__cxa_current_exception_type()->name()) ==
470*023bc8eaSKudo Chien                   "facebook::jsi::JSError") {
471*023bc8eaSKudo Chien                 throw jsi::JSError(rt, "Javascript worklet error");
472*023bc8eaSKudo Chien               }
473*023bc8eaSKudo Chien               // TODO find out a way to get the error's message on hermes
474*023bc8eaSKudo Chien               jsi::Value location = jsThis.getProperty(rt, "__location");
475*023bc8eaSKudo Chien               std::string str = "Javascript worklet error";
476*023bc8eaSKudo Chien               if (location.isString()) {
477*023bc8eaSKudo Chien                 str += "\nIn file: " + location.asString(rt).utf8(rt);
478*023bc8eaSKudo Chien               }
479*023bc8eaSKudo Chien               runtimeManager->errorHandler->setError(str);
480*023bc8eaSKudo Chien               runtimeManager->errorHandler->raise();
481*023bc8eaSKudo Chien             }
482*023bc8eaSKudo Chien             global.setProperty(rt, jsThisName, oldJSThis); // clean jsThis
483*023bc8eaSKudo Chien 
484*023bc8eaSKudo Chien             delete[] args;
485*023bc8eaSKudo Chien             // ToDo use returned value to return promise
486*023bc8eaSKudo Chien           });
487*023bc8eaSKudo Chien           return jsi::Value::undefined();
488*023bc8eaSKudo Chien         };
489*023bc8eaSKudo Chien         return jsi::Function::createFromHostFunction(
490*023bc8eaSKudo Chien             rt, jsi::PropNameID::forAscii(rt, "_workletFunction"), 0, clb);
491*023bc8eaSKudo Chien       }
492*023bc8eaSKudo Chien     }
493*023bc8eaSKudo Chien     default: {
494*023bc8eaSKudo Chien       throw "Unable to find conversion method for this type";
495*023bc8eaSKudo Chien     }
496*023bc8eaSKudo Chien   }
497*023bc8eaSKudo Chien   throw "convert error";
498*023bc8eaSKudo Chien }
499*023bc8eaSKudo Chien 
demangleExceptionName(std::string toDemangle)500*023bc8eaSKudo Chien std::string ShareableValue::demangleExceptionName(std::string toDemangle) {
501*023bc8eaSKudo Chien   int status = 0;
502*023bc8eaSKudo Chien   char *buff =
503*023bc8eaSKudo Chien       __cxxabiv1::__cxa_demangle(toDemangle.c_str(), nullptr, nullptr, &status);
504*023bc8eaSKudo Chien   if (!buff) {
505*023bc8eaSKudo Chien     return toDemangle;
506*023bc8eaSKudo Chien   }
507*023bc8eaSKudo Chien   std::string demangled = buff;
508*023bc8eaSKudo Chien   std::free(buff);
509*023bc8eaSKudo Chien   return demangled;
510*023bc8eaSKudo Chien }
511*023bc8eaSKudo Chien 
512*023bc8eaSKudo Chien } // namespace reanimated
513