-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
/
V8Object.cpp
281 lines (232 loc) Β· 9.49 KB
/
V8Object.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
/**
* Appcelerator Titanium Mobile
* Copyright (c) 2009-2016 by Appcelerator, Inc. All Rights Reserved.
* Licensed under the terms of the Apache Public License
* Please see the LICENSE included with this distribution for details.
*/
#include <jni.h>
#include <stdio.h>
#include <v8.h>
#include "AndroidUtil.h"
#include "EventEmitter.h"
#include "JNIUtil.h"
#include "TypeConverter.h"
#include "Proxy.h"
#include "ProxyFactory.h"
#include "V8Runtime.h"
#include "V8Util.h"
#include "org_appcelerator_kroll_runtime_v8_V8Object.h"
#define TAG "V8Object"
using namespace titanium;
using namespace v8;
#ifdef __cplusplus
extern "C" {
#endif
JNIEXPORT void JNICALL
Java_org_appcelerator_kroll_runtime_v8_V8Object_nativeInitObject
(JNIEnv *env, jclass clazz, jclass proxyClass, jobject proxyObject)
{
HandleScope scope(V8Runtime::v8_isolate);
JNIScope jniScope(env);
ProxyFactory::createV8Proxy(V8Runtime::v8_isolate, proxyClass, proxyObject);
}
JNIEXPORT void JNICALL
Java_org_appcelerator_kroll_runtime_v8_V8Object_nativeSetProperty
(JNIEnv *env, jobject object, jlong ptr, jstring name, jobject value)
{
HandleScope scope(V8Runtime::v8_isolate);
titanium::JNIScope jniScope(env);
Local<Object> jsObject;
if (ptr != 0) {
titanium::Proxy* proxy = (titanium::Proxy*) ptr;
jsObject = proxy->handle(V8Runtime::v8_isolate);
} else {
LOGE(TAG, "!!! Attempting to set a property on a Java object with no/deleted Proxy on C++ side! Attempting to revive it from Java object.");
jobject proxySupportField = env->GetObjectField(object, JNIUtil::krollObjectProxySupportField);
if (!proxySupportField) {
return;
}
static jmethodID getMethodID = NULL;
if (!getMethodID) {
getMethodID = env->GetMethodID(env->FindClass("java/lang/ref/WeakReference"), "get", "()Ljava/lang/Object;");
}
jobject proxySupport = (jobject)env->CallObjectMethodA(proxySupportField, getMethodID, NULL);
if (!proxySupport) {
return;
}
jsObject = TypeConverter::javaObjectToJsValue(V8Runtime::v8_isolate, env, proxySupport).As<Object>();
}
Local<Object> properties = jsObject->Get(titanium::Proxy::propertiesSymbol.Get(V8Runtime::v8_isolate)).As<Object>();
Local<Value> jsName = TypeConverter::javaStringToJsString(V8Runtime::v8_isolate, env, name);
Local<Value> jsValue = TypeConverter::javaObjectToJsValue(V8Runtime::v8_isolate, env, value);
jsObject->SetAccessor(jsName->ToString(V8Runtime::v8_isolate), titanium::Proxy::getProperty, titanium::Proxy::onPropertyChanged);
properties->Set(jsName, jsValue);
}
JNIEXPORT jboolean JNICALL
Java_org_appcelerator_kroll_runtime_v8_V8Object_nativeFireEvent
(JNIEnv *env, jobject jEmitter, jlong ptr, jobject jsource, jlong sourcePtr, jstring event, jobject data, jboolean bubble, jboolean reportSuccess, jint code, jstring errorMessage)
{
HandleScope scope(V8Runtime::v8_isolate);
JNIScope jniScope(env);
Local<Value> jsEvent = TypeConverter::javaStringToJsString(V8Runtime::v8_isolate, env, event);
#ifdef TI_DEBUG
v8::String::Utf8Value eventName(jsEvent);
LOGV(TAG, "firing event \"%s\"", *eventName);
#endif
Local<Object> emitter;
if (ptr != 0) {
titanium::Proxy* proxy = (titanium::Proxy*) ptr;
emitter = proxy->handle(V8Runtime::v8_isolate);
} else {
emitter = TypeConverter::javaObjectToJsValue(V8Runtime::v8_isolate, env, jEmitter).As<Object>();
}
Local<String> symbol = EventEmitter::emitSymbol.Get(V8Runtime::v8_isolate);
if (emitter.IsEmpty() || symbol.IsEmpty()) {
return JNI_FALSE;
}
Local<Value> fireEventValue = emitter->Get(symbol);
if (fireEventValue.IsEmpty() || !fireEventValue->IsFunction()) {
return JNI_FALSE;
}
Local<Object> source;
if ((jsource == NULL) || (jsource == jEmitter)) {
source = emitter;
} else if (sourcePtr != 0) {
titanium::Proxy* proxy = (titanium::Proxy*) sourcePtr;
source = proxy->handle(V8Runtime::v8_isolate);
} else {
source = TypeConverter::javaObjectToJsValue(V8Runtime::v8_isolate, env, jsource).As<Object>();
}
Local<Function> fireEvent = fireEventValue.As<Function>();
Local<Object> jsData = TypeConverter::javaHashMapToJsValue(V8Runtime::v8_isolate, env, data);
jsData->Set(NEW_SYMBOL(V8Runtime::v8_isolate, "bubbles"), TypeConverter::javaBooleanToJsBoolean(V8Runtime::v8_isolate, bubble));
jsData->Set(NEW_SYMBOL(V8Runtime::v8_isolate, "source"), source);
if (reportSuccess || code != 0) {
jsData->Set(NEW_SYMBOL(V8Runtime::v8_isolate, "success"), TypeConverter::javaBooleanToJsBoolean(V8Runtime::v8_isolate, code == 0));
jsData->Set(NEW_SYMBOL(V8Runtime::v8_isolate, "code"), TypeConverter::javaIntToJsNumber(V8Runtime::v8_isolate, code));
}
if (errorMessage != NULL) {
jsData->Set(NEW_SYMBOL(V8Runtime::v8_isolate, "error"), TypeConverter::javaStringToJsString(V8Runtime::v8_isolate, env, errorMessage));
}
TryCatch tryCatch(V8Runtime::v8_isolate);
Local<Value> args[] = { jsEvent, jsData };
MaybeLocal<Value> result = fireEvent->Call(V8Runtime::v8_isolate->GetCurrentContext(), emitter, 2, args);
if (tryCatch.HasCaught()) {
V8Util::openJSErrorDialog(V8Runtime::v8_isolate, tryCatch);
V8Util::reportException(V8Runtime::v8_isolate, tryCatch);
} else if (result.IsEmpty()) {
return JNI_FALSE;
} else if (result.ToLocalChecked()->IsTrue()) {
return JNI_TRUE;
}
return JNI_FALSE;
}
JNIEXPORT jobject JNICALL
Java_org_appcelerator_kroll_runtime_v8_V8Object_nativeCallProperty
(JNIEnv* env, jobject javaObject, jlong ptr, jstring propertyName, jobjectArray args)
{
HandleScope scope(V8Runtime::v8_isolate);
JNIScope jniScope(env);
Local<Value> jsPropertyName = TypeConverter::javaStringToJsString(V8Runtime::v8_isolate, env, propertyName);
Local<Object> jsObject;
if (ptr != 0) {
titanium::Proxy* proxy = (titanium::Proxy*) ptr;
jsObject = proxy->handle(V8Runtime::v8_isolate);
} else {
LOGE(TAG, "!!! Attempting to call a property on a Java object with no/deleted Proxy on C++ side! Attempting to revive it from Java object.");
jobject proxySupportField = env->GetObjectField(javaObject, JNIUtil::krollObjectProxySupportField);
if (!proxySupportField) {
return JNIUtil::undefinedObject;
}
static jmethodID getMethodID = NULL;
if (!getMethodID) {
getMethodID = env->GetMethodID(env->FindClass("java/lang/ref/WeakReference"), "get", "()Ljava/lang/Object;");
}
jobject proxySupport = (jobject)env->CallObjectMethodA(proxySupportField, getMethodID, NULL);
if (proxySupport) {
jsObject = TypeConverter::javaObjectToJsValue(V8Runtime::v8_isolate, env, proxySupport).As<Object>();
}
}
if (jsObject.IsEmpty()) {
LOGW(TAG, "Unable to get the JSObject representing this Java object, returning undefined.");
return JNIUtil::undefinedObject;
}
Local<Value> property = jsObject->Get(jsPropertyName);
if (property.IsEmpty() || !property->IsFunction()) {
return JNIUtil::undefinedObject;
}
int argc = 0;
Local<Value>* argv = NULL;
if (args) {
argv = TypeConverter::javaObjectArrayToJsArguments(V8Runtime::v8_isolate, args, &argc);
}
TryCatch tryCatch(V8Runtime::v8_isolate);
Local<Function> function = property.As<Function>();
MaybeLocal<Value> returnValue = function->Call(V8Runtime::v8_isolate->GetCurrentContext(), jsObject, argc, argv);
if (argv) {
delete[] argv;
}
if (tryCatch.HasCaught()) {
V8Util::openJSErrorDialog(V8Runtime::v8_isolate, tryCatch);
V8Util::reportException(V8Runtime::v8_isolate, tryCatch);
return JNIUtil::undefinedObject;
} else if (returnValue.IsEmpty()) {
return JNIUtil::undefinedObject;
}
bool isNew;
return TypeConverter::jsValueToJavaObject(V8Runtime::v8_isolate, env, returnValue.ToLocalChecked(), &isNew);
}
JNIEXPORT jboolean JNICALL
Java_org_appcelerator_kroll_runtime_v8_V8Object_nativeRelease
(JNIEnv *env, jclass clazz, jlong refPointer)
{
LOGD(TAG, "V8Object::nativeRelease");
HandleScope scope(V8Runtime::v8_isolate);
JNIScope jniScope(env);
if (refPointer) {
// FIXME What's the right way to cast the long long int as a pointer?
// Maybe we can move to more correct smart pointer usage?
// http://stackoverflow.com/questions/26375215/c-shared-ptr-and-java-native-object-ownership
titanium::Proxy* proxy = (titanium::Proxy*) refPointer;
if (proxy && proxy->isDetached()) {
// if the proxy is detached, delete it
// This means we have already received notification from V8 that the JS side of the proxy can be deleted
LOGD(TAG, "deleting titanium::Proxy with pointer value: %p", refPointer);
delete proxy;
return JNI_TRUE;
}
}
return JNI_FALSE;
}
JNIEXPORT void JNICALL
Java_org_appcelerator_kroll_runtime_v8_V8Object_nativeSetWindow
(JNIEnv *env, jobject javaKrollWindow, jlong ptr, jobject javaWindow)
{
HandleScope scope(V8Runtime::v8_isolate);
titanium::JNIScope jniScope(env);
Local<Object> jsKrollWindow;
if (ptr != 0) {
titanium::Proxy* proxy = (titanium::Proxy*) ptr;
jsKrollWindow = proxy->handle(V8Runtime::v8_isolate);
} else {
jsKrollWindow = TypeConverter::javaObjectToJsValue(V8Runtime::v8_isolate, env, javaKrollWindow).As<Object>();
}
Local<Value> setWindowValue = jsKrollWindow->Get(STRING_NEW(V8Runtime::v8_isolate, "setWindow"));
if (!setWindowValue->IsFunction()) {
return;
}
Local<Function> setWindow = setWindowValue.As<Function>();
Local<Value> jsWindow = TypeConverter::javaObjectToJsValue(V8Runtime::v8_isolate, env, javaWindow);
TryCatch tryCatch(V8Runtime::v8_isolate);
if (!jsWindow->IsNull()) {
Local<Value> args[] = { jsWindow };
setWindow->Call(V8Runtime::v8_isolate->GetCurrentContext(), jsKrollWindow, 1, args);
}
if (tryCatch.HasCaught()) {
V8Util::openJSErrorDialog(V8Runtime::v8_isolate, tryCatch);
V8Util::reportException(V8Runtime::v8_isolate, tryCatch);
}
}
#ifdef __cplusplus
}
#endif