1313#include < sstream>
1414#include < nan.h>
1515
16+ #define DYNAMIC_PROXY_NO_SUCH_METHOD_ERROR -1
17+ #define DYNAMIC_PROXY_NOT_A_FUNCTION_ERROR -2
18+ #define DYNAMIC_PROXY_NO_ENV_ERROR -3
19+
1620long v8ThreadId;
1721
1822/* static*/ v8::Persistent<v8::FunctionTemplate> Java::s_ct;
@@ -1006,7 +1010,13 @@ void EIO_AfterCallJs(uv_work_t* req) {
10061010 }
10071011 dynamicProxyData->result = NULL ;
10081012
1009- JNIEnv* env = dynamicProxyData->env ;
1013+ JNIEnv* env;
1014+ int ret = dynamicProxyData->java ->getJvm ()->GetEnv ((void **)&env, JNI_VERSION_1_6);
1015+ if (ret != JNI_OK) {
1016+ printf (" ERROR: jvm->GetEnv returned %d\n " , ret);
1017+ dynamicProxyData->done = DYNAMIC_PROXY_NO_ENV_ERROR;
1018+ return ;
1019+ }
10101020
10111021 NanScope ();
10121022 v8::Array* v8Args;
@@ -1020,12 +1030,12 @@ void EIO_AfterCallJs(uv_work_t* req) {
10201030 v8::Local<v8::Object> dynamicProxyDataFunctions = NanNew (dynamicProxyData->functions );
10211031 v8::Local<v8::Value> fnObj = dynamicProxyDataFunctions->Get (NanNew<v8::String>(dynamicProxyData->methodName .c_str ()));
10221032 if (fnObj->IsUndefined () || fnObj->IsNull ()) {
1023- printf ( " ERROR: Could not find method %s \n " , dynamicProxyData->methodName . c_str ()) ;
1024- goto CleanUp ;
1033+ dynamicProxyData->done = DYNAMIC_PROXY_NO_SUCH_METHOD_ERROR ;
1034+ return ;
10251035 }
10261036 if (!fnObj->IsFunction ()) {
1027- printf ( " ERROR: %s is not a function. \n " , dynamicProxyData->methodName . c_str ()) ;
1028- goto CleanUp ;
1037+ dynamicProxyData->done = DYNAMIC_PROXY_NOT_A_FUNCTION_ERROR ;
1038+ return ;
10291039 }
10301040
10311041 fn = v8::Function::Cast (*fnObj);
@@ -1049,25 +1059,31 @@ void EIO_AfterCallJs(uv_work_t* req) {
10491059 javaResult = v8ToJava (env, v8Result);
10501060 if (javaResult == NULL ) {
10511061 dynamicProxyData->result = NULL ;
1052- dynamicProxyData->resultGlobalRef = NULL ;
10531062 } else {
1054- dynamicProxyData->result = javaResult;
1055- dynamicProxyData->resultGlobalRef = env->NewGlobalRef (javaResult);
1063+ dynamicProxyData->result = env->NewGlobalRef (javaResult);
10561064 }
10571065
1058- CleanUp:
10591066 dynamicProxyData->done = true ;
10601067}
10611068
1069+ void throwNewThrowable (JNIEnv* env, const char * excClassName, std::string msg) {
1070+ jclass newExcCls = env->FindClass (excClassName);
1071+ jthrowable throwable = env->ExceptionOccurred ();
1072+ if (throwable != NULL ) {
1073+ env->Throw (throwable); // this should only be Errors, according to the docs
1074+ }
1075+ env->ThrowNew (newExcCls, msg.c_str ());
1076+ }
1077+
10621078JNIEXPORT jobject JNICALL Java_node_NodeDynamicProxyClass_callJs (JNIEnv *env, jobject src, jlong ptr, jobject method, jobjectArray args) {
10631079 long myThreadId = my_getThreadId ();
1080+ bool hasArgsGlobalRef = false ;
10641081
1082+ // args needs to be global, you can't send env across thread boundaries
10651083 DynamicProxyData* dynamicProxyData = (DynamicProxyData*)ptr;
1066- dynamicProxyData->env = env;
10671084 dynamicProxyData->args = args;
10681085 dynamicProxyData->done = false ;
10691086 dynamicProxyData->result = NULL ;
1070- dynamicProxyData->resultGlobalRef = NULL ;
10711087
10721088 jclass methodClazz = env->FindClass (" java/lang/reflect/Method" );
10731089 jmethodID method_getName = env->GetMethodID (methodClazz, " getName" , " ()Ljava/lang/String;" );
@@ -1083,6 +1099,12 @@ JNIEXPORT jobject JNICALL Java_node_NodeDynamicProxyClass_callJs(JNIEnv *env, jo
10831099 EIO_AfterCallJs (req);
10841100#endif
10851101 } else {
1102+ if (args) {
1103+ // if args is not null and we have to kick this across the thread boundary, make it a global ref
1104+ dynamicProxyData->args = (jobjectArray) env->NewGlobalRef (args);
1105+ hasArgsGlobalRef = true ;
1106+ }
1107+
10861108 uv_queue_work (uv_default_loop (), req, EIO_CallJs, (uv_after_work_cb)EIO_AfterCallJs);
10871109
10881110 while (!dynamicProxyData->done ) {
@@ -1091,12 +1113,31 @@ JNIEXPORT jobject JNICALL Java_node_NodeDynamicProxyClass_callJs(JNIEnv *env, jo
10911113 }
10921114
10931115 if (!dynamicProxyDataVerify (dynamicProxyData)) {
1094- return NULL ;
1116+ throwNewThrowable (env, " java/lang/IllegalStateException" , " dynamicProxyData was corrupted" );
1117+ }
1118+ if (hasArgsGlobalRef) {
1119+ env->DeleteGlobalRef (dynamicProxyData->args );
10951120 }
1121+
1122+ switch (dynamicProxyData->done ) {
1123+ case DYNAMIC_PROXY_NO_SUCH_METHOD_ERROR:
1124+ throwNewThrowable (env, " java/lang/NoSuchMethodError" , " Could not find js function " + dynamicProxyData->methodName );
1125+ break ;
1126+ case DYNAMIC_PROXY_NOT_A_FUNCTION_ERROR:
1127+ throwNewThrowable (env, " java/lang/IllegalStateException" , dynamicProxyData->methodName + " is not a function" );
1128+ break ;
1129+ case DYNAMIC_PROXY_NO_ENV_ERROR:
1130+ throwNewThrowable (env, " java/lang/IllegalStateException" , " Could not retrieve JNIEnv" );
1131+ break ;
1132+ }
1133+
1134+ jobject result = NULL ;
10961135 if (dynamicProxyData->result ) {
1097- env->DeleteGlobalRef (dynamicProxyData->resultGlobalRef );
1136+ // need to retain a local ref so that we can return it, otherwise the returned object gets corrupted
1137+ result = env->NewLocalRef (dynamicProxyData->result );
1138+ env->DeleteGlobalRef (dynamicProxyData->result );
10981139 }
1099- return dynamicProxyData-> result ;
1140+ return result;
11001141}
11011142
11021143JNIEXPORT void JNICALL Java_node_NodeDynamicProxyClass_unref (JNIEnv *env, jobject src, jlong ptr) {
0 commit comments