1 // Copyright © 2021-present 650 Industries, Inc. (aka Expo)
2
3 #include "JavaScriptObject.h"
4 #include "JavaScriptValue.h"
5 #include "JavaScriptFunction.h"
6 #include "JavaScriptRuntime.h"
7 #include "JSITypeConverter.h"
8 #include "ObjectDeallocator.h"
9 #include "JavaReferencesCache.h"
10 #include "JSIInteropModuleRegistry.h"
11
12 namespace expo {
registerNatives()13 void JavaScriptObject::registerNatives() {
14 registerHybrid({
15 makeNativeMethod("hasProperty", JavaScriptObject::jniHasProperty),
16 makeNativeMethod("getProperty", JavaScriptObject::jniGetProperty),
17 makeNativeMethod("getPropertyNames", JavaScriptObject::jniGetPropertyNames),
18 makeNativeMethod("setBoolProperty", JavaScriptObject::setProperty<bool>),
19 makeNativeMethod("setDoubleProperty", JavaScriptObject::setProperty<double>),
20 makeNativeMethod("setStringProperty",
21 JavaScriptObject::setProperty<jni::alias_ref<jstring>>),
22 makeNativeMethod("setJSValueProperty",
23 JavaScriptObject::setProperty<jni::alias_ref<JavaScriptValue::javaobject>>),
24 makeNativeMethod("setJSObjectProperty",
25 JavaScriptObject::setProperty<jni::alias_ref<JavaScriptObject::javaobject>>),
26 makeNativeMethod("unsetProperty", JavaScriptObject::unsetProperty),
27 makeNativeMethod("defineBoolProperty", JavaScriptObject::defineProperty<bool>),
28 makeNativeMethod("defineDoubleProperty",
29 JavaScriptObject::defineProperty<double>),
30 makeNativeMethod("defineStringProperty",
31 JavaScriptObject::defineProperty<jni::alias_ref<jstring>>),
32 makeNativeMethod("defineJSValueProperty",
33 JavaScriptObject::defineProperty<jni::alias_ref<JavaScriptValue::javaobject>>),
34 makeNativeMethod("defineJSObjectProperty",
35 JavaScriptObject::defineProperty<jni::alias_ref<JavaScriptObject::javaobject>>),
36 makeNativeMethod("defineNativeDeallocator",
37 JavaScriptObject::defineNativeDeallocator),
38 });
39 }
40
JavaScriptObject(std::weak_ptr<JavaScriptRuntime> runtime,std::shared_ptr<jsi::Object> jsObject)41 JavaScriptObject::JavaScriptObject(
42 std::weak_ptr<JavaScriptRuntime> runtime,
43 std::shared_ptr<jsi::Object> jsObject
44 ) : runtimeHolder(std::move(runtime)), jsObject(std::move(jsObject)) {
45 runtimeHolder.ensureRuntimeIsValid();
46 }
47
JavaScriptObject(WeakRuntimeHolder runtime,std::shared_ptr<jsi::Object> jsObject)48 JavaScriptObject::JavaScriptObject(
49 WeakRuntimeHolder runtime,
50 std::shared_ptr<jsi::Object> jsObject
51 ) : runtimeHolder(std::move(runtime)), jsObject(std::move(jsObject)) {
52 runtimeHolder.ensureRuntimeIsValid();
53 }
54
get()55 std::shared_ptr<jsi::Object> JavaScriptObject::get() {
56 return jsObject;
57 }
58
hasProperty(const std::string & name)59 bool JavaScriptObject::hasProperty(const std::string &name) {
60 auto &jsRuntime = runtimeHolder.getJSRuntime();
61 return jsObject->hasProperty(jsRuntime, name.c_str());
62 }
63
getProperty(const std::string & name)64 jsi::Value JavaScriptObject::getProperty(const std::string &name) {
65 auto &jsRuntime = runtimeHolder.getJSRuntime();
66 return jsObject->getProperty(jsRuntime, name.c_str());
67 }
68
jniHasProperty(jni::alias_ref<jstring> name)69 bool JavaScriptObject::jniHasProperty(jni::alias_ref<jstring> name) {
70 return hasProperty(name->toStdString());
71 }
72
jniGetProperty(jni::alias_ref<jstring> name)73 jni::local_ref<JavaScriptValue::javaobject> JavaScriptObject::jniGetProperty(
74 jni::alias_ref<jstring> name
75 ) {
76 auto result = std::make_shared<jsi::Value>(getProperty(name->toStdString()));
77 return JavaScriptValue::newInstance(
78 runtimeHolder.getModuleRegistry(),
79 runtimeHolder,
80 result
81 );
82 }
83
getPropertyNames()84 std::vector<std::string> JavaScriptObject::getPropertyNames() {
85 auto &jsRuntime = runtimeHolder.getJSRuntime();
86
87 jsi::Array properties = jsObject->getPropertyNames(jsRuntime);
88 auto size = properties.size(jsRuntime);
89
90 std::vector<std::string> names(size);
91 for (size_t i = 0; i < size; i++) {
92 auto propertyName = properties
93 .getValueAtIndex(jsRuntime, i)
94 .asString(jsRuntime)
95 .utf8(jsRuntime);
96 names[i] = propertyName;
97 }
98
99 return names;
100 }
101
jniGetPropertyNames()102 jni::local_ref<jni::JArrayClass<jstring>> JavaScriptObject::jniGetPropertyNames() {
103 std::vector<std::string> cResult = getPropertyNames();
104 auto paredResult = jni::JArrayClass<jstring>::newArray(cResult.size());
105 for (size_t i = 0; i < cResult.size(); i++) {
106 paredResult->setElement(i, jni::make_jstring(cResult[i]).get());
107 }
108
109 return paredResult;
110 }
111
jniAsFunction()112 jni::local_ref<JavaScriptFunction::javaobject> JavaScriptObject::jniAsFunction() {
113 auto &jsRuntime = runtimeHolder.getJSRuntime();
114 auto jsFuncion = std::make_shared<jsi::Function>(jsObject->asFunction(jsRuntime));
115 return JavaScriptFunction::newInstance(
116 runtimeHolder.getModuleRegistry(),
117 runtimeHolder,
118 jsFuncion
119 );
120 }
121
setProperty(const std::string & name,jsi::Value value)122 void JavaScriptObject::setProperty(const std::string &name, jsi::Value value) {
123 auto &jsRuntime = runtimeHolder.getJSRuntime();
124 jsObject->setProperty(jsRuntime, name.c_str(), value);
125 }
126
unsetProperty(jni::alias_ref<jstring> name)127 void JavaScriptObject::unsetProperty(jni::alias_ref<jstring> name) {
128 auto &jsRuntime = runtimeHolder.getJSRuntime();
129 auto cName = name->toStdString();
130 jsObject->setProperty(
131 jsRuntime,
132 cName.c_str(),
133 jsi::Value::undefined()
134 );
135 }
136
preparePropertyDescriptor(jsi::Runtime & jsRuntime,int options)137 jsi::Object JavaScriptObject::preparePropertyDescriptor(
138 jsi::Runtime &jsRuntime,
139 int options
140 ) {
141 jsi::Object descriptor(jsRuntime);
142 descriptor.setProperty(jsRuntime, "configurable", (bool) ((1 << 0) & options));
143 descriptor.setProperty(jsRuntime, "enumerable", (bool) ((1 << 1) & options));
144 if ((bool) (1 << 2 & options)) {
145 descriptor.setProperty(jsRuntime, "writable", true);
146 }
147 return descriptor;
148 }
149
newInstance(JSIInteropModuleRegistry * jsiInteropModuleRegistry,std::weak_ptr<JavaScriptRuntime> runtime,std::shared_ptr<jsi::Object> jsObject)150 jni::local_ref<JavaScriptObject::javaobject> JavaScriptObject::newInstance(
151 JSIInteropModuleRegistry *jsiInteropModuleRegistry,
152 std::weak_ptr<JavaScriptRuntime> runtime,
153 std::shared_ptr<jsi::Object> jsObject
154 ) {
155 auto object = JavaScriptObject::newObjectCxxArgs(std::move(runtime), std::move(jsObject));
156 jsiInteropModuleRegistry->jniDeallocator->addReference(object);
157 return object;
158 }
159
defineNativeDeallocator(jni::alias_ref<JNIFunctionBody::javaobject> deallocator)160 void JavaScriptObject::defineNativeDeallocator(
161 jni::alias_ref<JNIFunctionBody::javaobject> deallocator
162 ) {
163 auto &rt = runtimeHolder.getJSRuntime();
164 jni::global_ref<JNIFunctionBody::javaobject> globalRef = jni::make_global(deallocator);
165
166 common::setDeallocator(
167 rt,
168 jsObject,
169 [globalRef = std::move(globalRef)]() mutable {
170 auto args = jni::Environment::current()->NewObjectArray(
171 0,
172 JavaReferencesCache::instance()->getJClass("java/lang/Object").clazz,
173 nullptr
174 );
175 globalRef->invoke(args);
176 globalRef.reset();
177 },
178 "__expo_shared_object_deallocator__"
179 );
180 }
181 } // namespace expo
182