164f5c95fSŁukasz Kosmaty // Copyright © 2021-present 650 Industries, Inc. (aka Expo)
264f5c95fSŁukasz Kosmaty 
364f5c95fSŁukasz Kosmaty #pragma once
464f5c95fSŁukasz Kosmaty 
529e8b6f8SŁukasz Kosmaty #include "JNIDeallocator.h"
629e8b6f8SŁukasz Kosmaty 
764f5c95fSŁukasz Kosmaty #include <jsi/jsi.h>
8a416e6dbSŁukasz Kosmaty #include <fbjni/fbjni.h>
9a416e6dbSŁukasz Kosmaty #include <ReactCommon/CallInvoker.h>
1064f5c95fSŁukasz Kosmaty 
1164f5c95fSŁukasz Kosmaty namespace jsi = facebook::jsi;
12a416e6dbSŁukasz Kosmaty namespace jni = facebook::jni;
13a416e6dbSŁukasz Kosmaty namespace react = facebook::react;
1464f5c95fSŁukasz Kosmaty 
1514c0f05dSŁukasz Kosmaty namespace expo {
16db6683c6SKudo Chien 
1714c0f05dSŁukasz Kosmaty class JavaScriptValue;
18*12cf8561Slukmccall 
1914c0f05dSŁukasz Kosmaty class JavaScriptObject;
20*12cf8561Slukmccall 
21879827bbSŁukasz Kosmaty class JSIInteropModuleRegistry;
22879827bbSŁukasz Kosmaty 
23db6683c6SKudo Chien #if REACT_NATIVE_TARGET_VERSION >= 73
24db6683c6SKudo Chien using NativeMethodCallInvokerCompatible = react::NativeMethodCallInvoker;
25db6683c6SKudo Chien #else
26db6683c6SKudo Chien using NativeMethodCallInvokerCompatible = react::CallInvoker;
27db6683c6SKudo Chien #endif
28e3d1d66aSŁukasz Kosmaty 
29e3d1d66aSŁukasz Kosmaty /**
30a416e6dbSŁukasz Kosmaty  * A wrapper for the jsi::Runtime.
31a416e6dbSŁukasz Kosmaty  * This class is used as a bridge between CPP and Kotlin and to encapsulate common runtime helper functions.
32a416e6dbSŁukasz Kosmaty  *
33a416e6dbSŁukasz Kosmaty  * Instances of this class should be managed using a shared smart pointer.
34a416e6dbSŁukasz Kosmaty  * To pass runtime information to all of `JavaScriptValue` and `JavaScriptObject` we use `weak_from_this()`
35a416e6dbSŁukasz Kosmaty  * that requires that the object is held via a smart pointer. Otherwise, `weak_from_this()` returns `nullptr`.
36a416e6dbSŁukasz Kosmaty  */
37a416e6dbSŁukasz Kosmaty class JavaScriptRuntime : public std::enable_shared_from_this<JavaScriptRuntime> {
3864f5c95fSŁukasz Kosmaty public:
39a416e6dbSŁukasz Kosmaty   /**
40a416e6dbSŁukasz Kosmaty    * Initializes a runtime that is independent from React Native and its runtime initialization.
41e3d1d66aSŁukasz Kosmaty    * This flow is mostly intended for tests. The JS call invoker is set to `SyncCallInvoker`.
42db6683c6SKudo Chien    * See **JavaScriptRuntime.cpp** for the `SyncCallInvoker` implementation.
43a416e6dbSŁukasz Kosmaty    */
44879827bbSŁukasz Kosmaty   JavaScriptRuntime(
45879827bbSŁukasz Kosmaty     JSIInteropModuleRegistry *jsiInteropModuleRegistry
46879827bbSŁukasz Kosmaty   );
4764f5c95fSŁukasz Kosmaty 
48a416e6dbSŁukasz Kosmaty   JavaScriptRuntime(
49879827bbSŁukasz Kosmaty     JSIInteropModuleRegistry *jsiInteropModuleRegistry,
50a416e6dbSŁukasz Kosmaty     jsi::Runtime *runtime,
51a416e6dbSŁukasz Kosmaty     std::shared_ptr<react::CallInvoker> jsInvoker,
52db6683c6SKudo Chien     std::shared_ptr<NativeMethodCallInvokerCompatible> nativeInvoker
53a416e6dbSŁukasz Kosmaty   );
54a416e6dbSŁukasz Kosmaty 
55a416e6dbSŁukasz Kosmaty   /**
56a416e6dbSŁukasz Kosmaty    * Returns the underlying runtime object.
57a416e6dbSŁukasz Kosmaty    */
58256b5942SŁukasz Kosmaty   jsi::Runtime &get() const;
5964f5c95fSŁukasz Kosmaty 
60a416e6dbSŁukasz Kosmaty   /**
61a416e6dbSŁukasz Kosmaty    * Evaluates given JavaScript source code.
62a416e6dbSŁukasz Kosmaty    * @throws if the input format is unknown, or evaluation causes an error,
63a416e6dbSŁukasz Kosmaty    * a jni::JniException<JavaScriptEvaluateException> will be thrown.
64a416e6dbSŁukasz Kosmaty    */
6529e8b6f8SŁukasz Kosmaty   jni::local_ref<jni::HybridClass<JavaScriptValue, Destructible>::javaobject> evaluateScript(
66e3d1d66aSŁukasz Kosmaty     const std::string &script
67e3d1d66aSŁukasz Kosmaty   );
68a416e6dbSŁukasz Kosmaty 
69a416e6dbSŁukasz Kosmaty   /**
70a416e6dbSŁukasz Kosmaty    * Returns the runtime global object for use in Kotlin.
71a416e6dbSŁukasz Kosmaty    */
7229e8b6f8SŁukasz Kosmaty   jni::local_ref<jni::HybridClass<JavaScriptObject, Destructible>::javaobject> global();
73a416e6dbSŁukasz Kosmaty 
74342f32d0SŁukasz Kosmaty   /**
75342f32d0SŁukasz Kosmaty    * Creates a new object for use in Kotlin.
76342f32d0SŁukasz Kosmaty    */
7729e8b6f8SŁukasz Kosmaty   jni::local_ref<jni::HybridClass<JavaScriptObject, Destructible>::javaobject> createObject();
78342f32d0SŁukasz Kosmaty 
79a89667b6SŁukasz Kosmaty   /**
80a89667b6SŁukasz Kosmaty    * Drains the JavaScript VM internal Microtask (a.k.a. event loop) queue.
81a89667b6SŁukasz Kosmaty    */
82a89667b6SŁukasz Kosmaty   void drainJSEventLoop();
83a89667b6SŁukasz Kosmaty 
84*12cf8561Slukmccall   void installMainObject();
85*12cf8561Slukmccall 
86a416e6dbSŁukasz Kosmaty   std::shared_ptr<react::CallInvoker> jsInvoker;
87db6683c6SKudo Chien   std::shared_ptr<NativeMethodCallInvokerCompatible> nativeInvoker;
88dedc0ffdSŁukasz Kosmaty 
89dedc0ffdSŁukasz Kosmaty   std::shared_ptr<jsi::Object> getMainObject();
90879827bbSŁukasz Kosmaty 
91879827bbSŁukasz Kosmaty   JSIInteropModuleRegistry *getModuleRegistry();
92*12cf8561Slukmccall 
936095fdc7SŁukasz Kosmaty private:
946095fdc7SŁukasz Kosmaty   std::shared_ptr<jsi::Runtime> runtime;
95dedc0ffdSŁukasz Kosmaty   std::shared_ptr<jsi::Object> mainObject;
96879827bbSŁukasz Kosmaty   JSIInteropModuleRegistry *jsiInteropModuleRegistry;
9764f5c95fSŁukasz Kosmaty };
9864f5c95fSŁukasz Kosmaty } // namespace expo
99