1 // Copyright © 2021-present 650 Industries, Inc. (aka Expo)
2 
3 #include "JavaScriptRuntime.h"
4 #include "JavaScriptValue.h"
5 #include "JavaScriptObject.h"
6 #include "Exceptions.h"
7 
8 #if FOR_HERMES
9 
10 #include <hermes/hermes.h>
11 
12 #include <utility>
13 
14 #else
15 
16 #include <jsi/JSCRuntime.h>
17 
18 #endif
19 
20 namespace jsi = facebook::jsi;
21 
22 namespace expo {
23 
24 
25 JavaScriptRuntime::JavaScriptRuntime() {
26 #if FOR_HERMES
27   auto config = ::hermes::vm::RuntimeConfig::Builder().withEnableSampleProfiling(false);
28   runtime = facebook::hermes::makeHermesRuntime(config.build());
29 #else
30   runtime = facebook::jsc::makeJSCRuntime();
31 #endif
32 }
33 
34 JavaScriptRuntime::JavaScriptRuntime(
35   jsi::Runtime *runtime,
36   std::shared_ptr<react::CallInvoker> jsInvoker,
37   std::shared_ptr<react::CallInvoker> nativeInvoker
38 ) : jsInvoker(std::move(jsInvoker)), nativeInvoker(std::move(nativeInvoker)) {
39   // Creating a shared pointer that points to the runtime but doesn't own it, thus doesn't release it.
40   // In this code flow, the runtime should be owned by something else like the CatalystInstance.
41   // See explanation for constructor (8): https://en.cppreference.com/w/cpp/memory/shared_ptr/shared_ptr
42   this->runtime = std::shared_ptr<jsi::Runtime>(std::shared_ptr<jsi::Runtime>(), runtime);
43 }
44 
45 jsi::Runtime *JavaScriptRuntime::get() {
46   return runtime.get();
47 }
48 
49 jni::local_ref<JavaScriptValue::javaobject>
50 JavaScriptRuntime::evaluateScript(const std::string &script) {
51   auto scriptBuffer = std::make_shared<jsi::StringBuffer>(script);
52   std::shared_ptr<jsi::Value> result;
53   try {
54     result = std::make_shared<jsi::Value>(
55       runtime->evaluateJavaScript(scriptBuffer, "<<evaluated>>")
56     );
57   } catch (const jsi::JSError &error) {
58     jni::throwNewJavaException(
59       JavaScriptEvaluateException::create(
60         error.getMessage(),
61         error.getStack()
62       ).get()
63     );
64   } catch (const jsi::JSIException &error) {
65     jni::throwNewJavaException(
66       JavaScriptEvaluateException::create(
67         error.what(),
68         ""
69       ).get()
70     );
71   }
72 
73   return JavaScriptValue::newObjectCxxArgs(weak_from_this(), result);
74 }
75 
76 jni::local_ref<JavaScriptObject::javaobject> JavaScriptRuntime::global() {
77   auto global = std::make_shared<jsi::Object>(runtime->global());
78   return JavaScriptObject::newObjectCxxArgs(weak_from_this(), global);
79 }
80 
81 jni::local_ref<JavaScriptObject::javaobject> JavaScriptRuntime::createObject() {
82   auto newObject = std::make_shared<jsi::Object>(*runtime);
83   return JavaScriptObject::newObjectCxxArgs(weak_from_this(), newObject);
84 }
85 
86 void JavaScriptRuntime::drainJSEventLoop() {
87   while (!runtime->drainMicrotasks()) {}
88 }
89 } // namespace expo
90