1 // Copyright © 2021-present 650 Industries, Inc. (aka Expo)
2 
3 #include "JavaScriptFunction.h"
4 #include "types/JNIToJSIConverter.h"
5 #include "types/AnyType.h"
6 
7 namespace expo {
8 
9 void JavaScriptFunction::registerNatives() {
10   registerHybrid({
11                    makeNativeMethod("invoke", JavaScriptFunction::invoke),
12                  });
13 }
14 
15 JavaScriptFunction::JavaScriptFunction(
16   std::weak_ptr<JavaScriptRuntime> runtime,
17   std::shared_ptr<jsi::Function> jsFunction
18 ) : runtimeHolder(std::move(runtime)), jsFunction(std::move(jsFunction)) {
19   runtimeHolder.ensureRuntimeIsValid();
20 }
21 
22 JavaScriptFunction::JavaScriptFunction(
23   WeakRuntimeHolder runtime,
24   std::shared_ptr<jsi::Function> jsFunction
25 ) : runtimeHolder(std::move(runtime)), jsFunction(std::move(jsFunction)) {
26   runtimeHolder.ensureRuntimeIsValid();
27 }
28 
29 std::shared_ptr<jsi::Function> JavaScriptFunction::get() {
30   return jsFunction;
31 }
32 
33 jobject JavaScriptFunction::invoke(
34   jni::alias_ref<jni::JArrayClass<jni::JObject>> args,
35   jni::alias_ref<ExpectedType::javaobject> expectedReturnType
36 ) {
37   auto &rt = runtimeHolder.getJSRuntime();
38   auto moduleRegistry = runtimeHolder.getModuleRegistry();
39   JNIEnv *env = jni::Environment::current();
40 
41   size_t size = args->size();
42   std::vector<jsi::Value> convertedArgs;
43   convertedArgs.reserve(size);
44 
45   for (size_t i = 0; i < size; i++) {
46     jni::local_ref<jni::JObject> arg = args->getElement(i);
47     convertedArgs.push_back(convert(moduleRegistry, env, rt, std::move(arg)));
48   }
49 
50   // TODO(@lukmccall): add better error handling
51   jsi::Value result = jsFunction->call(rt, (const jsi::Value *) convertedArgs.data(), size);
52   auto converter = AnyType(jni::make_local(expectedReturnType)).converter;
53   auto convertedResult = converter->convert(rt, env, moduleRegistry, result);
54   return convertedResult;
55 }
56 
57 jni::local_ref<JavaScriptFunction::javaobject> JavaScriptFunction::newInstance(
58   JSIInteropModuleRegistry *jsiInteropModuleRegistry,
59   std::weak_ptr<JavaScriptRuntime> runtime,
60   std::shared_ptr<jsi::Function> jsFunction
61 ) {
62   auto function = JavaScriptFunction::newObjectCxxArgs(
63     std::move(runtime),
64     std::move(jsFunction)
65   );
66   jsiInteropModuleRegistry->jniDeallocator->addReference(function);
67   return function;
68 }
69 } // namespace expo
70