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