diff --git a/src/jni/Android.mk b/src/jni/Android.mk index 24f54cb4a..4eb38bfb4 100644 --- a/src/jni/Android.mk +++ b/src/jni/Android.mk @@ -62,17 +62,19 @@ include $(PREBUILT_STATIC_LIBRARY) include $(CLEAR_VARS) LOCAL_CPPFLAGS += -std=c++11 LOCAL_MODULE := NativeScript -LOCAL_SRC_FILES := com_tns_AssetExtractor.cpp com_tns_Platform.cpp com_tns_JsDebugger.cpp com_tns_NativeScriptActity.cpp \ - JEnv.cpp DirectBuffer.cpp \ +LOCAL_SRC_FILES := com_tns_AssetExtractor.cpp AssetExtractor.cpp\ + com_tns_Platform.cpp NativePlatform.cpp \ + com_tns_JsDebugger.cpp com_tns_NativeScriptActity.cpp \ + JEnv.cpp DirectBuffer.cpp NativeScriptException.cpp \ JsDebugger.cpp SimpleAllocator.cpp \ NativeScriptRuntime.cpp MetadataNode.cpp MetadataTreeNode.cpp MetadataReader.cpp \ MethodCache.cpp JavaObjectArrayCache.cpp \ JniLocalRef.cpp JniSignatureParser.cpp \ ArgConverter.cpp JsArgToArrayConverter.cpp JsArgConverter.cpp V8GlobalHelpers.cpp V8StringConstants.cpp \ FieldAccessor.cpp ArrayElementAccessor.cpp \ - ExceptionUtil.cpp Util.cpp Logger.cpp Profiler.cpp \ + Util.cpp Logger.cpp Profiler.cpp \ ObjectManager.cpp NumericCasts.cpp WeakRef.cpp \ - MetadataMethodInfo.cpp SimpleProfiler.cpp JType.cpp File.cpp Module.cpp Constants.cpp + MetadataMethodInfo.cpp SimpleProfiler.cpp JType.cpp File.cpp Module.cpp Constants.cpp LOCAL_C_INCLUDES := $(LOCAL_PATH)/include LOCAL_LDLIBS := -llog -landroid -lz diff --git a/src/jni/Application.mk b/src/jni/Application.mk index 3bf1654e0..a621e2568 100644 --- a/src/jni/Application.mk +++ b/src/jni/Application.mk @@ -9,4 +9,7 @@ APP_OPTIM := debug #The new ndks require this or build fails APP_CFLAGS += -Wno-error=format-security -APP_CFLAGS += -g \ No newline at end of file +APP_CFLAGS += -g + +#Turn on C++ exceptions +APP_CPPFLAGS += -fexceptions \ No newline at end of file diff --git a/src/jni/ArgConverter.cpp b/src/jni/ArgConverter.cpp index 09ed4df86..79e457095 100644 --- a/src/jni/ArgConverter.cpp +++ b/src/jni/ArgConverter.cpp @@ -5,6 +5,7 @@ #include "V8GlobalHelpers.h" #include "V8StringConstants.h" #include "NativeScriptAssert.h" +#include "NativeScriptException.h" #include "JType.h" #include #include @@ -32,23 +33,53 @@ void ArgConverter::Init(JavaVM *jvm) void ArgConverter::NativeScriptLongValueOfFunctionCallback(const v8::FunctionCallbackInfo& args) { + try { auto isolate = Isolate::GetCurrent(); args.GetReturnValue().Set(Number::New(isolate, numeric_limits::quiet_NaN())); + } catch (NativeScriptException& e) { + e.ReThrowToV8(); + } + catch (exception e) { + DEBUG_WRITE("Error: c++ exception: %s", e.what()); + } + catch (...) { + DEBUG_WRITE("Error: c++ exception!"); + } } void ArgConverter::NativeScriptLongToStringFunctionCallback(const v8::FunctionCallbackInfo& args) { + try { args.GetReturnValue().Set(args.This()->Get(V8StringConstants::GetValue())); + } catch (NativeScriptException& e) { + e.ReThrowToV8(); + } + catch (exception e) { + DEBUG_WRITE("Error: c++ exception: %s", e.what()); + } + catch (...) { + DEBUG_WRITE("Error: c++ exception!"); + } } void ArgConverter::NativeScriptLongFunctionCallback(const v8::FunctionCallbackInfo& args) { + try { auto isolate = Isolate::GetCurrent(); args.This()->SetHiddenValue(V8StringConstants::GetJavaLong(), Boolean::New(isolate, true)); args.This()->SetHiddenValue(V8StringConstants::GetMarkedAsLong(), args[0]); args.This()->Set(V8StringConstants::GetValue(), args[0]); args.This()->SetPrototype(Local::New(Isolate::GetCurrent(), *NAN_NUMBER_OBJECT)); + } catch (NativeScriptException& e) { + e.ReThrowToV8(); + } + catch (exception e) { + DEBUG_WRITE("Error: c++ exception: %s", e.what()); + } + catch (...) { + DEBUG_WRITE("Error: c++ exception!"); + } } diff --git a/src/jni/ArrayElementAccessor.cpp b/src/jni/ArrayElementAccessor.cpp index e4b59eff5..c5dd61aa2 100644 --- a/src/jni/ArrayElementAccessor.cpp +++ b/src/jni/ArrayElementAccessor.cpp @@ -5,6 +5,7 @@ #include "Util.h" #include "V8GlobalHelpers.h" #include "NativeScriptAssert.h" +#include "NativeScriptException.h" #include "JType.h" #include @@ -39,14 +40,14 @@ Local ArrayElementAccessor::GetArrayElement(const Local& array, u jbooleanArray boolArr = reinterpret_cast(arr); jboolean boolArrValue; env.GetBooleanArrayRegion(boolArr, startIndex, length, &boolArrValue); - value = CheckForArrayAccessException(env, elementSignature, &boolArrValue); + value = ConvertToJsValue(env, elementSignature, &boolArrValue); } else if (elementSignature == "B") { jbyteArray byteArr = reinterpret_cast(arr); jbyte byteArrValue; env.GetByteArrayRegion(byteArr, startIndex, length, &byteArrValue); - value = CheckForArrayAccessException(env, elementSignature, &byteArrValue); + value = ConvertToJsValue(env, elementSignature, &byteArrValue); } else if (elementSignature == "C") { @@ -55,7 +56,7 @@ Local ArrayElementAccessor::GetArrayElement(const Local& array, u env.GetCharArrayRegion(charArr, startIndex, length, &charArrValue); JniLocalRef s(env.NewString(&charArrValue, 1)); const char* singleChar = env.GetStringUTFChars(s, &isCopy); - value = CheckForArrayAccessException(env, elementSignature, singleChar); + value = ConvertToJsValue(env, elementSignature, singleChar); env.ReleaseStringUTFChars(s, singleChar); } else if (elementSignature == "S") @@ -63,40 +64,40 @@ Local ArrayElementAccessor::GetArrayElement(const Local& array, u jshortArray shortArr = reinterpret_cast(arr); jshort shortArrValue; env.GetShortArrayRegion(shortArr, startIndex, length, &shortArrValue); - value = CheckForArrayAccessException(env, elementSignature, &shortArrValue); + value = ConvertToJsValue(env, elementSignature, &shortArrValue); } else if (elementSignature == "I") { jintArray intArr = reinterpret_cast(arr); jint intArrValue; env.GetIntArrayRegion(intArr, startIndex, length, &intArrValue); - value = CheckForArrayAccessException(env, elementSignature, &intArrValue); + value = ConvertToJsValue(env, elementSignature, &intArrValue); } else if (elementSignature == "J") { jlongArray longArr = reinterpret_cast(arr); jlong longArrValue; env.GetLongArrayRegion(longArr, startIndex, length, &longArrValue); - value = CheckForArrayAccessException(env, elementSignature, &longArrValue); + value = ConvertToJsValue(env, elementSignature, &longArrValue); } else if (elementSignature == "F") { jfloatArray floatArr = reinterpret_cast(arr); jfloat floatArrValue; env.GetFloatArrayRegion(floatArr, startIndex, length, &floatArrValue); - value = CheckForArrayAccessException(env, elementSignature, &floatArrValue); + value = ConvertToJsValue(env, elementSignature, &floatArrValue); } else if (elementSignature == "D") { jdoubleArray doubleArr = reinterpret_cast(arr); jdouble doubleArrValue; env.GetDoubleArrayRegion(doubleArr, startIndex, length, &doubleArrValue); - value = CheckForArrayAccessException(env, elementSignature, &doubleArrValue); + value = ConvertToJsValue(env, elementSignature, &doubleArrValue); } else { jobject result = env.GetObjectArrayElement(reinterpret_cast(arr), index); - value = CheckForArrayAccessException(env, elementSignature, &result); + value = ConvertToJsValue(env, elementSignature, &result); env.DeleteLocalRef(result); } @@ -116,19 +117,19 @@ void ArrayElementAccessor::SetArrayElement(const Local& array, uint32_t const string elementSignature = arraySignature.substr(1); jboolean isCopy = false; - if (elementSignature == "Z") + if (elementSignature == "Z") //bool { jboolean boolElementValue = (jboolean) value->BooleanValue(); jbooleanArray boolArr = reinterpret_cast(arr); env.SetBooleanArrayRegion(boolArr, index, 1, &boolElementValue); } - else if (elementSignature == "B") + else if (elementSignature == "B") //byte { jbyte byteElementValue = (jbyte) value->Int32Value(); jbyteArray byteArr = reinterpret_cast(arr); env.SetByteArrayRegion(byteArr, index, 1, &byteElementValue); } - else if (elementSignature == "C") + else if (elementSignature == "C") //char { String::Utf8Value utf8(value->ToString()); JniLocalRef s(env.NewString((jchar*) *utf8, 1)); @@ -138,19 +139,19 @@ void ArrayElementAccessor::SetArrayElement(const Local& array, uint32_t jcharArray charArr = reinterpret_cast(arr); env.SetCharArrayRegion(charArr, index, 1, &charElementValue); } - else if (elementSignature == "S") + else if (elementSignature == "S") //short { jshort shortElementValue = (jshort) value->Int32Value(); jshortArray shortArr = reinterpret_cast(arr); env.SetShortArrayRegion(shortArr, index, 1, &shortElementValue); } - else if (elementSignature == "I") + else if (elementSignature == "I") //int { jint intElementValue = value->Int32Value(); jintArray intArr = reinterpret_cast(arr); env.SetIntArrayRegion(intArr, index, 1, &intElementValue); } - else if (elementSignature == "J") + else if (elementSignature == "J") //long { jlong longElementValue; if (value->IsObject()) @@ -164,19 +165,19 @@ void ArrayElementAccessor::SetArrayElement(const Local& array, uint32_t jlongArray longArr = reinterpret_cast(arr); env.SetLongArrayRegion(longArr, index, 1, &longElementValue); } - else if (elementSignature == "F") + else if (elementSignature == "F") //float { jfloat floatElementValue = (jfloat) value->NumberValue(); jfloatArray floatArr = reinterpret_cast(arr); env.SetFloatArrayRegion(floatArr, index, 1, &floatElementValue); } - else if (elementSignature == "D") + else if (elementSignature == "D") //double { jdouble doubleElementValue = (jdouble) value->NumberValue(); jdoubleArray doubleArr = reinterpret_cast(arr); env.SetDoubleArrayRegion(doubleArr, index, 1, &doubleElementValue); } - else + else //string or object { bool isReferenceType = value->IsObject() || value->IsString(); if (isReferenceType) @@ -193,35 +194,23 @@ void ArrayElementAccessor::SetArrayElement(const Local& array, uint32_t else { JsArgToArrayConverter::Error err = argConverter.GetError(); - ExceptionUtil::GetInstance()->ThrowExceptionToJs(err.msg); - return; + throw NativeScriptException(string(err.msg)); } } else { - ExceptionUtil::GetInstance()->ThrowExceptionToJs("Cannot assign primitive value to array of objects."); - return; + throw NativeScriptException(string("Cannot assign primitive value to array of objects.")); } } } -Local ArrayElementAccessor::CheckForArrayAccessException(JEnv& env, const string& elementSignature, const void *value) +Local ArrayElementAccessor::ConvertToJsValue(JEnv& env, const string& elementSignature, const void *value) { Local jsValue; auto isolate = Isolate::GetCurrent(); - JniLocalRef exc(env.ExceptionOccurred()); - if (nullptr != (jthrowable) exc) - { - DEBUG_WRITE("Error during getting array element"); - // env.ExceptionDescribe(); We will print this manually in the ExceptionUtil - env.ExceptionClear(); - string errMsg; - ExceptionUtil::GetInstance()->GetExceptionMessage(env, exc, errMsg); - ExceptionUtil::GetInstance()->ThrowExceptionToJs(errMsg); - } - else if (elementSignature == "Z") + if (elementSignature == "Z") { jsValue = Boolean::New(isolate, *(jboolean*) value); } diff --git a/src/jni/ArrayElementAccessor.h b/src/jni/ArrayElementAccessor.h index 523682ccf..4f832c176 100644 --- a/src/jni/ArrayElementAccessor.h +++ b/src/jni/ArrayElementAccessor.h @@ -5,7 +5,6 @@ #include "v8.h" #include #include "ObjectManager.h" -#include "ExceptionUtil.h" namespace tns { @@ -19,7 +18,7 @@ namespace tns void SetArrayElement(const v8::Local& array, uint32_t index, const std::string& arraySignature, v8::Local& value); private: - v8::Local CheckForArrayAccessException(JEnv& env, const std::string& elementSignature, const void *value); + v8::Local ConvertToJsValue(JEnv& env, const std::string& elementSignature, const void *value); JavaVM *jvm; diff --git a/src/jni/AssetExtractor.cpp b/src/jni/AssetExtractor.cpp new file mode 100644 index 000000000..62de7e90d --- /dev/null +++ b/src/jni/AssetExtractor.cpp @@ -0,0 +1,118 @@ +#include "jni.h" +#include "zip.h" +#include "ArgConverter.h" +#include "NativeScriptAssert.h" +#include +#include +#include +#include +#include +#include "AssetExtractor.h" + +using namespace tns; + +std::string jstringToString(JNIEnv *env, jstring value); +void mkdir_rec(const char *dir); + +void AssetExtractor::ExtractAssets(JNIEnv *env, jobject obj, jstring apk, jstring outputDir, jboolean _forceOverwrite) +{ + auto forceOverwrite = JNI_TRUE == _forceOverwrite; + auto strApk = jstringToString(env, apk); + auto baseDir = jstringToString(env, outputDir); + int err = 0; + auto z = zip_open(strApk.c_str(), 0, &err); + assert(z != nullptr); + zip_int64_t num = zip_get_num_entries(z, 0); + struct zip_stat sb; + struct zip_file *zf; + char buf[65536]; + auto pathcopy = new char[1024]; + for (zip_int64_t i = 0; i < num; i++) + { + zip_stat_index(z, i, ZIP_STAT_MTIME, &sb); + if (strstr(sb.name, "assets/") == sb.name) + { + auto name = sb.name + 7; // strlen("assets/") == 7 + + std::string assetFullname(baseDir); + assetFullname.append(name); + + struct stat attrib; + auto shouldOverwrite = true; + int ret = stat(assetFullname.c_str(), &attrib); + if (ret == 0 /* file exists */) + { + auto diff = difftime(sb.mtime, attrib.st_mtime); + shouldOverwrite = diff > 0; + } + + if (shouldOverwrite || forceOverwrite) + { + //DEBUG_WRITE("write asset %s", assetFullname.c_str()); + strcpy(pathcopy, name); + auto path = dirname(pathcopy); + std::string dirFullname(baseDir); + dirFullname.append(path); + mkdir_rec(dirFullname.c_str()); + + zf = zip_fopen_index(z, i, 0); + assert(zf != nullptr); + + auto fd = fopen(assetFullname.c_str(), "w"); + + zip_int64_t sum = 0; + while (sum != sb.size) + { + zip_int64_t len = zip_fread(zf, buf, sizeof(buf)); + assert(len > 0); + + fwrite(buf, 1, len, fd); + sum += len; + } + fclose(fd); + utimbuf t; + t.modtime = sb.mtime; + ret = utime(assetFullname.c_str(), &t); + zip_fclose(zf); + } + } + } + delete[] pathcopy; + zip_close(z); +} + +void AssetExtractor::mkdir_rec(const char *dir) +{ + char opath[256]; + snprintf(opath, sizeof(opath), "%s", dir); + size_t len = strlen(opath); + + if(opath[len - 1] == '/') + opath[len - 1] = 0; + + for (char *p = opath + 1; *p; p++) + { + if (*p == '/') + { + *p = 0; + mkdir(opath, S_IRWXU); + *p = '/'; + } + } + + mkdir(opath, S_IRWXU); +} + +std::string AssetExtractor::jstringToString(JNIEnv *env, jstring value) +{ + if (value == nullptr) { + return std::string(); + } + + jboolean f = false; + const char* chars = env->GetStringUTFChars(value, &f); + std::string s(chars); + env->ReleaseStringUTFChars(value, chars); + + return s; +} diff --git a/src/jni/AssetExtractor.h b/src/jni/AssetExtractor.h new file mode 100644 index 000000000..f53b8e07c --- /dev/null +++ b/src/jni/AssetExtractor.h @@ -0,0 +1,16 @@ +#ifndef ASSETEXTRACTOR_ +#define ASSETEXTRACTOR_ + +#include "JEnv.h" + +namespace tns { + class AssetExtractor { + public: + static void ExtractAssets(JNIEnv *env, jobject obj, jstring apk, jstring outputDir, jboolean _forceOverwrite); + + private: + static std::string jstringToString(JNIEnv *env, jstring value); + static void mkdir_rec(const char *dir); + }; +} +#endif /* ASSETEXTRACTOR_ */ diff --git a/src/jni/JEnv.cpp b/src/jni/JEnv.cpp index aa52ed3c7..f0ae6942a 100644 --- a/src/jni/JEnv.cpp +++ b/src/jni/JEnv.cpp @@ -1,9 +1,12 @@ #include "JEnv.h" +#include "NativeScriptAssert.h" #include #include #include + // #include "Util.h" +#include "NativeScriptException.h" using namespace tns; using namespace std; @@ -58,418 +61,567 @@ JEnv::operator JNIEnv*() const jmethodID JEnv::GetMethodID(jclass clazz, const string& name, const string& sig) { - return m_env->GetMethodID(clazz, name.c_str(), sig.c_str()); + jmethodID mid = m_env->GetMethodID(clazz, name.c_str(), sig.c_str()); + CheckForJavaException(); + return mid; } jmethodID JEnv::GetStaticMethodID(jclass clazz, const string& name, const string& sig) { - return m_env->GetStaticMethodID(clazz, name.c_str(), sig.c_str()); + jmethodID mid = m_env->GetStaticMethodID(clazz, name.c_str(), sig.c_str()); + CheckForJavaException(); + return mid; } jfieldID JEnv::GetFieldID(jclass clazz, const string& name, const string& sig) { - return m_env->GetFieldID(clazz, name.c_str(), sig.c_str()); + jfieldID fid = m_env->GetFieldID(clazz, name.c_str(), sig.c_str()); + CheckForJavaException(); + return fid; } jfieldID JEnv::GetStaticFieldID(jclass clazz, const string& name, const string& sig) { - return m_env->GetStaticFieldID(clazz, name.c_str(), sig.c_str()); + jfieldID fid = m_env->GetStaticFieldID(clazz, name.c_str(), sig.c_str()); + CheckForJavaException(); + return fid; } - void JEnv::CallStaticVoidMethodA(jclass clazz, jmethodID methodID, jvalue* args) { m_env->CallStaticVoidMethodA(clazz, methodID, args); + CheckForJavaException(); } void JEnv::CallNonvirtualVoidMethodA(jobject obj, jclass clazz, jmethodID methodID, jvalue* args) { m_env->CallNonvirtualVoidMethodA(obj, clazz, methodID, args); + CheckForJavaException(); } void JEnv::CallVoidMethodA(jobject obj, jmethodID methodID, jvalue* args) { m_env->CallVoidMethodA(obj, methodID, args); + CheckForJavaException(); } jboolean JEnv::CallStaticBooleanMethodA(jclass clazz, jmethodID methodID, jvalue* args) { - return m_env->CallStaticBooleanMethodA(clazz, methodID, args); + jboolean jbl = m_env->CallStaticBooleanMethodA(clazz, methodID, args); + CheckForJavaException(); + return jbl; } jboolean JEnv::CallNonvirtualBooleanMethodA(jobject obj, jclass clazz, jmethodID methodID, jvalue* args) { - return m_env->CallNonvirtualBooleanMethodA(obj, clazz, methodID, args); + jboolean jbl = m_env->CallNonvirtualBooleanMethodA(obj, clazz, methodID, args); + CheckForJavaException(); + return jbl; } jboolean JEnv::CallBooleanMethodA(jobject obj, jmethodID methodID, jvalue* args) { - return m_env->CallBooleanMethodA(obj, methodID, args); + jboolean jbl = m_env->CallBooleanMethodA(obj, methodID, args); + CheckForJavaException(); + return jbl; } jbyte JEnv::CallStaticByteMethodA(jclass clazz, jmethodID methodID, jvalue* args) { - return m_env->CallStaticByteMethodA(clazz, methodID, args); + jbyte jbt = m_env->CallStaticByteMethodA(clazz, methodID, args); + CheckForJavaException(); + return jbt; } jbyte JEnv::CallNonvirtualByteMethodA(jobject obj, jclass clazz, jmethodID methodID, jvalue* args) { - return m_env->CallNonvirtualByteMethodA(obj, clazz, methodID, args); + jbyte jbt = m_env->CallNonvirtualByteMethodA(obj, clazz, methodID, args); + CheckForJavaException(); + return jbt; } jbyte JEnv::CallByteMethodA(jobject obj, jmethodID methodID, jvalue* args) { - return m_env->CallByteMethodA(obj, methodID, args); + jbyte jbt = m_env->CallByteMethodA(obj, methodID, args); + CheckForJavaException(); + return jbt; } jchar JEnv::CallStaticCharMethodA(jclass clazz, jmethodID methodID, jvalue* args) { - return m_env->CallStaticCharMethodA(clazz, methodID, args); + jchar jch = m_env->CallStaticCharMethodA(clazz, methodID, args); + CheckForJavaException(); + return jch; } jchar JEnv::CallNonvirtualCharMethodA(jobject obj, jclass clazz, jmethodID methodID, jvalue* args) { - return m_env->CallNonvirtualCharMethodA(obj, clazz, methodID, args); + jchar jch = m_env->CallNonvirtualCharMethodA(obj, clazz, methodID, args); + CheckForJavaException(); + return jch; } jchar JEnv::CallCharMethodA(jobject obj, jmethodID methodID, jvalue* args) { - return m_env->CallCharMethodA(obj, methodID, args); + jchar jch = m_env->CallCharMethodA(obj, methodID, args); + CheckForJavaException(); + return jch; } jshort JEnv::CallStaticShortMethodA(jclass clazz, jmethodID methodID, jvalue* args) { - return m_env->CallStaticShortMethodA(clazz, methodID, args); + jshort jsh = m_env->CallStaticShortMethodA(clazz, methodID, args); + CheckForJavaException(); + return jsh; + } jshort JEnv::CallNonvirtualShortMethodA(jobject obj, jclass clazz, jmethodID methodID, jvalue* args) { - return m_env->CallNonvirtualShortMethodA(obj, clazz, methodID, args); + jshort jsh = m_env->CallNonvirtualShortMethodA(obj, clazz, methodID, args); + CheckForJavaException(); + return jsh; } jshort JEnv::CallShortMethodA(jobject obj, jmethodID methodID, jvalue* args) { - return m_env->CallShortMethodA(obj, methodID, args); + jshort jsh = m_env->CallShortMethodA(obj, methodID, args); + CheckForJavaException(); + return jsh; } jint JEnv::CallStaticIntMethodA(jclass clazz, jmethodID methodID, jvalue* args) { - return m_env->CallStaticIntMethodA(clazz, methodID, args); + jint ji = m_env->CallStaticIntMethodA(clazz, methodID, args); + CheckForJavaException(); + return ji; + } jint JEnv::CallNonvirtualIntMethodA(jobject obj, jclass clazz, jmethodID methodID, jvalue* args) { - return m_env->CallNonvirtualIntMethodA(obj, clazz, methodID, args); + jint ji = m_env->CallNonvirtualIntMethodA(obj, clazz, methodID, args); + CheckForJavaException(); + return ji; } jint JEnv::CallIntMethodA(jobject obj, jmethodID methodID, jvalue* args) { - return m_env->CallIntMethodA(obj, methodID, args); + jint ji = m_env->CallIntMethodA(obj, methodID, args); + CheckForJavaException(); + return ji; } jlong JEnv::CallStaticLongMethodA(jclass clazz, jmethodID methodID, jvalue* args) { - return m_env->CallStaticLongMethodA(clazz, methodID, args); + jlong jl = m_env->CallStaticLongMethodA(clazz, methodID, args); + CheckForJavaException(); + return jl; } jlong JEnv::CallNonvirtualLongMethodA(jobject obj, jclass clazz, jmethodID methodID, jvalue* args) { - return m_env->CallNonvirtualLongMethodA(obj, clazz, methodID, args); + jlong jl = m_env->CallNonvirtualLongMethodA(obj, clazz, methodID, args); + CheckForJavaException(); + return jl; } jlong JEnv::CallLongMethodA(jobject obj, jmethodID methodID, jvalue* args) { - return m_env->CallLongMethodA(obj, methodID, args); + jlong jl = m_env->CallLongMethodA(obj, methodID, args); + CheckForJavaException(); + return jl; } jfloat JEnv::CallStaticFloatMethodA(jclass clazz, jmethodID methodID, jvalue* args) { - return m_env->CallStaticFloatMethodA(clazz, methodID, args); + jfloat jfl = m_env->CallStaticFloatMethodA(clazz, methodID, args); + CheckForJavaException(); + return jfl; } jfloat JEnv::CallNonvirtualFloatMethodA(jobject obj, jclass clazz, jmethodID methodID, jvalue* args) { - return m_env->CallNonvirtualFloatMethodA(obj, clazz, methodID, args); + jfloat jfl = m_env->CallNonvirtualFloatMethodA(obj, clazz, methodID, args); + CheckForJavaException(); + return jfl; } jfloat JEnv::CallFloatMethodA(jobject obj, jmethodID methodID, jvalue* args) { - return m_env->CallFloatMethodA(obj, methodID, args); + jfloat jfl = m_env->CallFloatMethodA(obj, methodID, args); + CheckForJavaException(); + return jfl; } jdouble JEnv::CallStaticDoubleMethodA(jclass clazz, jmethodID methodID, jvalue* args) { - return m_env->CallStaticDoubleMethodA(clazz, methodID, args); + jdouble jdb = m_env->CallStaticDoubleMethodA(clazz, methodID, args); + CheckForJavaException(); + return jdb; } jdouble JEnv::CallNonvirtualDoubleMethodA(jobject obj, jclass clazz, jmethodID methodID, jvalue* args) { - return m_env->CallNonvirtualDoubleMethodA(obj, clazz, methodID, args); + jdouble jdb = m_env->CallNonvirtualDoubleMethodA(obj, clazz, methodID, args); + CheckForJavaException(); + return jdb; } jdouble JEnv::CallDoubleMethodA(jobject obj, jmethodID methodID, jvalue* args) { - return m_env->CallDoubleMethodA(obj, methodID, args); + jdouble jdb = m_env->CallDoubleMethodA(obj, methodID, args); + CheckForJavaException(); + return jdb; } jobject JEnv::CallStaticObjectMethodA(jclass clazz, jmethodID methodID, jvalue* args) { - return m_env->CallStaticObjectMethodA(clazz, methodID, args); + jobject jo = m_env->CallStaticObjectMethodA(clazz, methodID, args); + CheckForJavaException(); + return jo; } jobject JEnv::CallNonvirtualObjectMethodA(jobject obj, jclass clazz, jmethodID methodID, jvalue* args) { - return m_env->CallNonvirtualObjectMethodA(obj, clazz, methodID, args); + jobject jo = m_env->CallNonvirtualObjectMethodA(obj, clazz, methodID, args); + CheckForJavaException(); + return jo; } jobject JEnv::CallObjectMethodA(jobject obj, jmethodID methodID, jvalue* args) { - return m_env->CallObjectMethodA(obj, methodID, args); + jobject jo = m_env->CallObjectMethodA(obj, methodID, args); + CheckForJavaException(); + return jo; } jobject JEnv::GetStaticObjectField(jclass clazz, jfieldID fieldID) { - return m_env->GetStaticObjectField(clazz, fieldID); + jobject jo = m_env->GetStaticObjectField(clazz, fieldID); + CheckForJavaException(); + return jo; } jboolean JEnv::GetStaticBooleanField(jclass clazz, jfieldID fieldID) { - return m_env->GetStaticBooleanField(clazz, fieldID); + jboolean jbl = m_env->GetStaticBooleanField(clazz, fieldID); + CheckForJavaException(); + return jbl; } jbyte JEnv::GetStaticByteField(jclass clazz, jfieldID fieldID) { - return m_env->GetStaticByteField(clazz, fieldID); + jbyte jbt = m_env->GetStaticByteField(clazz, fieldID); + CheckForJavaException(); + return jbt; } jchar JEnv::GetStaticCharField(jclass clazz, jfieldID fieldID) { - return m_env->GetStaticCharField(clazz, fieldID); + jchar jch = m_env->GetStaticCharField(clazz, fieldID); + CheckForJavaException(); + return jch; } jshort JEnv::GetStaticShortField(jclass clazz, jfieldID fieldID) { - return m_env->GetStaticShortField(clazz, fieldID); + jshort jsh = m_env->GetStaticShortField(clazz, fieldID); + CheckForJavaException(); + return jsh; } jint JEnv::GetStaticIntField(jclass clazz, jfieldID fieldID) { - return m_env->GetStaticIntField(clazz, fieldID); + jint ji = m_env->GetStaticIntField(clazz, fieldID); + CheckForJavaException(); + return ji; } jlong JEnv::GetStaticLongField(jclass clazz, jfieldID fieldID) { - return m_env->GetStaticLongField(clazz, fieldID); + jlong jl = m_env->GetStaticLongField(clazz, fieldID); + CheckForJavaException(); + return jl; } jfloat JEnv::GetStaticFloatField(jclass clazz, jfieldID fieldID) { - return m_env->GetStaticFloatField(clazz, fieldID); + jfloat jfl = m_env->GetStaticFloatField(clazz, fieldID); + CheckForJavaException(); + return jfl; } jdouble JEnv::GetStaticDoubleField(jclass clazz, jfieldID fieldID) { - return m_env->GetStaticDoubleField(clazz, fieldID); + jdouble jd = m_env->GetStaticDoubleField(clazz, fieldID); + CheckForJavaException(); + return jd; } void JEnv::SetStaticObjectField(jclass clazz, jfieldID fieldID, jobject value) { m_env->SetStaticObjectField(clazz, fieldID, value); + CheckForJavaException(); } void JEnv::SetStaticBooleanField(jclass clazz, jfieldID fieldID, jboolean value) { m_env->SetStaticBooleanField(clazz, fieldID, value); + CheckForJavaException(); } void JEnv::SetStaticByteField(jclass clazz, jfieldID fieldID, jbyte value) { m_env->SetStaticByteField(clazz, fieldID, value); + CheckForJavaException(); } void JEnv::SetStaticCharField(jclass clazz, jfieldID fieldID, jchar value) { m_env->SetStaticCharField(clazz, fieldID, value); + CheckForJavaException(); } void JEnv::SetStaticShortField(jclass clazz, jfieldID fieldID, jshort value) { m_env->SetStaticShortField(clazz, fieldID, value); + CheckForJavaException(); } void JEnv::SetStaticIntField(jclass clazz, jfieldID fieldID, jint value) { m_env->SetStaticIntField(clazz, fieldID, value); + CheckForJavaException(); } void JEnv::SetStaticLongField(jclass clazz, jfieldID fieldID, jlong value) { m_env->SetStaticLongField(clazz, fieldID, value); + CheckForJavaException(); } void JEnv::SetStaticFloatField(jclass clazz, jfieldID fieldID, jfloat value) { m_env->SetStaticFloatField(clazz, fieldID, value); + CheckForJavaException(); } void JEnv::SetStaticDoubleField(jclass clazz, jfieldID fieldID, jdouble value) { m_env->SetStaticDoubleField(clazz, fieldID, value); + CheckForJavaException(); } jobject JEnv::GetObjectField(jobject obj, jfieldID fieldID) { - return m_env->GetObjectField(obj, fieldID); + jobject jo = m_env->GetObjectField(obj, fieldID); + CheckForJavaException(); + return jo; } jboolean JEnv::GetBooleanField(jobject obj, jfieldID fieldID) { - return m_env->GetBooleanField(obj, fieldID); + jboolean jbl = m_env->GetBooleanField(obj, fieldID); + CheckForJavaException(); + return jbl; } jbyte JEnv::GetByteField(jobject obj, jfieldID fieldID) { - return m_env->GetByteField(obj, fieldID); + jbyte jbt = m_env->GetByteField(obj, fieldID); + CheckForJavaException(); + return jbt; } jchar JEnv::GetCharField(jobject obj, jfieldID fieldID) { - return m_env->GetCharField(obj, fieldID); + jchar jch = m_env->GetCharField(obj, fieldID); + CheckForJavaException(); + return jch; } jshort JEnv::GetShortField(jobject obj, jfieldID fieldID) { - return m_env->GetShortField(obj, fieldID); + jshort jsh = m_env->GetShortField(obj, fieldID); + CheckForJavaException(); + return jsh; } jint JEnv::GetIntField(jobject obj, jfieldID fieldID) { - return m_env->GetIntField(obj, fieldID); + jint ji = m_env->GetIntField(obj, fieldID); + CheckForJavaException(); + return ji; } jlong JEnv::GetLongField(jobject obj, jfieldID fieldID) { - return m_env->GetLongField(obj, fieldID); + jlong jl = m_env->GetLongField(obj, fieldID); + CheckForJavaException(); + return jl; } jfloat JEnv::GetFloatField(jobject obj, jfieldID fieldID) { - return m_env->GetFloatField(obj, fieldID); + jfloat jfl = m_env->GetFloatField(obj, fieldID); + CheckForJavaException(); + return jfl; } jdouble JEnv::GetDoubleField(jobject obj, jfieldID fieldID) { - return m_env->GetDoubleField(obj, fieldID); + jdouble jd = m_env->GetDoubleField(obj, fieldID); + CheckForJavaException(); + return jd; } void JEnv::SetObjectField(jobject obj, jfieldID fieldID, jobject value) { m_env->SetObjectField(obj, fieldID, value); + CheckForJavaException(); } void JEnv::SetBooleanField(jobject obj, jfieldID fieldID, jboolean value) { m_env->SetBooleanField(obj, fieldID, value); + CheckForJavaException(); } void JEnv::SetByteField(jobject obj, jfieldID fieldID, jbyte value) { m_env->SetByteField(obj, fieldID, value); + CheckForJavaException(); } void JEnv::SetCharField(jobject obj, jfieldID fieldID, jchar value) { m_env->SetCharField(obj, fieldID, value); + CheckForJavaException(); } void JEnv::SetShortField(jobject obj, jfieldID fieldID, jshort value) { m_env->SetShortField(obj, fieldID, value); + CheckForJavaException(); } void JEnv::SetIntField(jobject obj, jfieldID fieldID, jint value) { m_env->SetIntField(obj, fieldID, value); + CheckForJavaException(); } void JEnv::SetLongField(jobject obj, jfieldID fieldID, jlong value) { m_env->SetLongField(obj, fieldID, value); + CheckForJavaException(); } void JEnv::SetFloatField(jobject obj, jfieldID fieldID, jfloat value) { m_env->SetFloatField(obj, fieldID, value); + CheckForJavaException(); } void JEnv::SetDoubleField(jobject obj, jfieldID fieldID, jdouble value) { m_env->SetDoubleField(obj, fieldID, value); + CheckForJavaException(); } jstring JEnv::NewString(const jchar* unicodeChars, jsize len) { - return m_env->NewString(unicodeChars, len); + jstring jst = m_env->NewString(unicodeChars, len); + CheckForJavaException(); + return jst; } jstring JEnv::NewStringUTF(const char* bytes) { - return m_env->NewStringUTF(bytes); + jstring jst = m_env->NewStringUTF(bytes); + CheckForJavaException(); + return jst; } jobjectArray JEnv::NewObjectArray(jsize length, jclass elementClass, jobject initialElement) { - return m_env->NewObjectArray(length, elementClass, initialElement); + jobjectArray joa = m_env->NewObjectArray(length, elementClass, initialElement); + CheckForJavaException(); + return joa; } jobject JEnv::GetObjectArrayElement(jobjectArray array, jsize index) { - return m_env->GetObjectArrayElement(array, index); + jobject jo = m_env->GetObjectArrayElement(array, index); + CheckForJavaException(); + return jo; } void JEnv::SetObjectArrayElement(jobjectArray array, jsize index, jobject value) { m_env->SetObjectArrayElement(array, index, value); + CheckForJavaException(); } const char* JEnv::GetStringUTFChars(jstring str, jboolean* isCopy) { - return m_env->GetStringUTFChars(str, isCopy); + const char* cc = m_env->GetStringUTFChars(str, isCopy); + CheckForJavaException(); + return cc; } void JEnv::ReleaseStringUTFChars(jstring str, const char* utf) { m_env->ReleaseStringUTFChars(str, utf); + CheckForJavaException(); } const jchar* JEnv::GetStringChars(jstring str, jboolean* isCopy) { - return m_env->GetStringChars(str, isCopy); + const jchar* cjc = m_env->GetStringChars(str, isCopy); + CheckForJavaException(); + return cjc; } void JEnv::ReleaseStringChars(jstring str, const jchar* chars) { m_env->ReleaseStringChars(str, chars); + CheckForJavaException(); } const int JEnv::GetStringLength(jstring str) { - return m_env->GetStringLength(str); + const int ci = m_env->GetStringLength(str); + CheckForJavaException(); + return ci; } const int JEnv::GetStringUTFLength(jstring str) { - return m_env->GetStringUTFLength(str); + const int ci = m_env->GetStringUTFLength(str); + CheckForJavaException(); + return ci; } void JEnv::GetStringUTFRegion(jstring str, jsize start, jsize len, char *buf) { m_env->GetStringUTFRegion(str, start, len, buf); + CheckForJavaException(); } - jint JEnv::Throw(jthrowable obj) { return m_env->Throw(obj); } -jboolean JEnv::ExceptionCheck() -{ - return m_env->ExceptionCheck(); -} + jthrowable JEnv::ExceptionOccurred() { - return m_env->ExceptionOccurred(); + jthrowable jt = m_env->ExceptionOccurred(); + return jt; } void JEnv::ExceptionDescribe() { m_env->ExceptionDescribe(); + CheckForJavaException(); } void JEnv::ExceptionClear() { m_env->ExceptionClear(); } - jboolean JEnv::IsInstanceOf(jobject obj, jclass clazz) { - return m_env->IsInstanceOf(obj, clazz); + jboolean jbl = m_env->IsInstanceOf(obj, clazz); + CheckForJavaException(); + return jbl; } jobjectRefType JEnv::GetObjectRefType(jobject obj) { - return m_env->GetObjectRefType(obj); + jobjectRefType ort = m_env->GetObjectRefType(obj); + CheckForJavaException(); + return ort; } jobject JEnv::NewGlobalRef(jobject obj) { - return m_env->NewGlobalRef(obj); + jobject jo = m_env->NewGlobalRef(obj); +// CheckForJavaException(); + return jo; } jweak JEnv::NewWeakGlobalRef(jobject obj) { - return m_env->NewWeakGlobalRef(obj); + jweak jw = m_env->NewWeakGlobalRef(obj); + CheckForJavaException(); + return jw; } void JEnv::DeleteGlobalRef(jobject globalRef) { m_env->DeleteGlobalRef(globalRef); + CheckForJavaException(); } void JEnv::DeleteWeakGlobalRef(jweak obj) { m_env->DeleteWeakGlobalRef(obj); + CheckForJavaException(); } jobject JEnv::NewLocalRef(jobject ref) { - return m_env->NewLocalRef(ref); + jobject jo = m_env->NewLocalRef(ref); + CheckForJavaException(); + return jo; } void JEnv::DeleteLocalRef(jobject localRef) { @@ -478,113 +630,148 @@ void JEnv::DeleteLocalRef(jobject localRef) jbyteArray JEnv::NewByteArray(jsize length) { - return m_env->NewByteArray(length); + jbyteArray jba = m_env->NewByteArray(length); + CheckForJavaException(); + return jba; } jbooleanArray JEnv::NewBooleanArray(jsize length) { - return m_env->NewBooleanArray(length); + jbooleanArray jba = m_env->NewBooleanArray(length); + CheckForJavaException(); + return jba; } jcharArray JEnv::NewCharArray(jsize length) { - return m_env->NewCharArray(length); + jcharArray jca = m_env->NewCharArray(length); + CheckForJavaException(); + return jca; } jshortArray JEnv::NewShortArray(jsize length) { - return m_env->NewShortArray(length); + jshortArray jsa = m_env->NewShortArray(length); + CheckForJavaException(); + return jsa; } jintArray JEnv::NewIntArray(jsize length) { - return m_env->NewIntArray(length); + jintArray jia = m_env->NewIntArray(length); + CheckForJavaException(); + return jia; } jlongArray JEnv::NewLongArray(jsize length) { - return m_env->NewLongArray(length); + jlongArray jla = m_env->NewLongArray(length); + CheckForJavaException(); + return jla; } jfloatArray JEnv::NewFloatArray(jsize length) { - return m_env->NewFloatArray(length); + jfloatArray jfa = m_env->NewFloatArray(length); + CheckForJavaException(); + return jfa; } jdoubleArray JEnv::NewDoubleArray(jsize length) { - return m_env->NewDoubleArray(length); + jdoubleArray jda = m_env->NewDoubleArray(length); + CheckForJavaException(); + return jda; } jbyte* JEnv::GetByteArrayElements(jbyteArray array, jboolean* isCopy) { - return m_env->GetByteArrayElements(array, isCopy); + jbyte* jbt = m_env->GetByteArrayElements(array, isCopy); + CheckForJavaException(); + return jbt; } void JEnv::ReleaseByteArrayElements(jbyteArray array, jbyte* elems, jint mode) { m_env->ReleaseByteArrayElements(array, elems, mode); + CheckForJavaException(); } void JEnv::GetBooleanArrayRegion(jbooleanArray array, jsize start, jsize len, jboolean* buf) { m_env->GetBooleanArrayRegion(array, start, len, buf); + CheckForJavaException(); } void JEnv::GetByteArrayRegion(jbyteArray array, jsize start, jsize len, jbyte* buf) { m_env->GetByteArrayRegion(array, start, len, buf); + CheckForJavaException(); } void JEnv::GetCharArrayRegion(jcharArray array, jsize start, jsize len, jchar* buf) { m_env->GetCharArrayRegion(array, start, len, buf); + CheckForJavaException(); } void JEnv::GetShortArrayRegion(jshortArray array, jsize start, jsize len, jshort* buf) { m_env->GetShortArrayRegion(array, start, len, buf); + CheckForJavaException(); } void JEnv::GetIntArrayRegion(jintArray array, jsize start, jsize len, jint* buf) { m_env->GetIntArrayRegion(array, start, len, buf); + CheckForJavaException(); } void JEnv::GetLongArrayRegion(jlongArray array, jsize start, jsize len, jlong* buf) { m_env->GetLongArrayRegion(array, start, len, buf); + CheckForJavaException(); } void JEnv::GetFloatArrayRegion(jfloatArray array, jsize start, jsize len, jfloat* buf) { m_env->GetFloatArrayRegion(array, start, len, buf); + CheckForJavaException(); } void JEnv::GetDoubleArrayRegion(jdoubleArray array, jsize start, jsize len, jdouble* buf) { m_env->GetDoubleArrayRegion(array, start, len, buf); + CheckForJavaException(); } + void JEnv::SetByteArrayRegion(jbyteArray array, jsize start, jsize len, const jbyte* buf) { m_env->SetByteArrayRegion(array, start, len, buf); + CheckForJavaException(); } void JEnv::SetBooleanArrayRegion(jbooleanArray array, jsize start, jsize len, const jboolean* buf) { m_env->SetBooleanArrayRegion(array, start, len, buf); + CheckForJavaException(); } void JEnv::SetCharArrayRegion(jcharArray array, jsize start, jsize len, const jchar* buf) { m_env->SetCharArrayRegion(array, start, len, buf); + CheckForJavaException(); } void JEnv::SetShortArrayRegion(jshortArray array, jsize start, jsize len, const jshort* buf) { m_env->SetShortArrayRegion(array, start, len, buf); + CheckForJavaException(); } void JEnv::SetIntArrayRegion(jintArray array, jsize start, jsize len, const jint* buf) { m_env->SetIntArrayRegion(array, start, len, buf); + CheckForJavaException(); } void JEnv::SetLongArrayRegion(jlongArray array, jsize start, jsize len, const jlong* buf) { m_env->SetLongArrayRegion(array, start, len, buf); + CheckForJavaException(); } void JEnv::SetFloatArrayRegion(jfloatArray array, jsize start, jsize len, const jfloat* buf) { m_env->SetFloatArrayRegion(array, start, len, buf); + CheckForJavaException(); } void JEnv::SetDoubleArrayRegion(jdoubleArray array, jsize start, jsize len, const jdouble* buf) { m_env->SetDoubleArrayRegion(array, start, len, buf); + CheckForJavaException(); } - jclass JEnv::FindClass(const string& className) { jclass klass; @@ -619,19 +806,29 @@ jclass JEnv::FindClass(const string& className) jobject JEnv::NewDirectByteBuffer(void* address, jlong capacity) { - return m_env->NewDirectByteBuffer(address, capacity); + jobject jo = m_env->NewDirectByteBuffer(address, capacity); + CheckForJavaException(); + return jo; } void* JEnv::GetDirectBufferAddress(jobject buf) { - return m_env->GetDirectBufferAddress(buf); + void* v = m_env->GetDirectBufferAddress(buf); + CheckForJavaException(); + return v; } jlong JEnv::GetDirectBufferCapacity(jobject buf) { - return m_env->GetDirectBufferCapacity(buf); + jlong jl = m_env->GetDirectBufferCapacity(buf); + CheckForJavaException(); + return jl; } - +jboolean JEnv::IsAssignableFrom(jclass clazz1, jclass clazz2) { + jboolean jbl = m_env->IsAssignableFrom(clazz1, clazz2); + CheckForJavaException(); + return jbl; +} void JEnv::Init(JavaVM *jvm) { @@ -645,17 +842,34 @@ void JEnv::Init(JavaVM *jvm) assert(GET_CACHED_CLASS_METHOD_ID != nullptr); } - jclass JEnv::GetObjectClass(jobject obj) { - return m_env->GetObjectClass(obj); + jclass jcl = m_env->GetObjectClass(obj); + CheckForJavaException(); + return jcl; } jsize JEnv::GetArrayLength(jarray array) { - return m_env->GetArrayLength(array); + jsize jsz = m_env->GetArrayLength(array); + CheckForJavaException(); + return jsz; +} + +//recursion if we put: CheckForJavaException(); +//in this method +jboolean JEnv::ExceptionCheck() +{ + return m_env->ExceptionCheck(); } +void JEnv::CheckForJavaException() +{ + if (ExceptionCheck() == JNI_TRUE) + { + throw NativeScriptException(*this); + } +} JavaVM* JEnv::s_jvm = nullptr; map JEnv::s_classCache; diff --git a/src/jni/JEnv.h b/src/jni/JEnv.h index 3f7c39680..d5a34d3bb 100644 --- a/src/jni/JEnv.h +++ b/src/jni/JEnv.h @@ -182,15 +182,25 @@ namespace tns void* GetDirectBufferAddress(jobject buf); jlong GetDirectBufferCapacity(jobject buf); + jboolean IsAssignableFrom(jclass clazz1, jclass clazz2); + template void CallVoidMethod(jobject obj, jmethodID methodID, Args... args) { m_env->CallVoidMethod(obj, methodID, args...); + CheckForJavaException(); } template void CallStaticVoidMethod(jclass clazz, jmethodID methodID, Args... args) + { + m_env->CallStaticVoidMethod(clazz, methodID, args...); + CheckForJavaException(); + } + + template + void CallAppFail(jclass clazz, jmethodID methodID, Args... args) { m_env->CallStaticVoidMethod(clazz, methodID, args...); } @@ -198,90 +208,121 @@ namespace tns template jint CallStaticIntMethod(jclass clazz, jmethodID methodID, Args... args) { - return m_env->CallStaticIntMethod(clazz, methodID, args...); + jint ji = m_env->CallStaticIntMethod(clazz, methodID, args...); + CheckForJavaException(); + return ji; } template jlong CallStaticLongMethod(jclass clazz, jmethodID methodID, Args... args) { - return m_env->CallStaticLongMethod(clazz, methodID, args...); + jlong jd = m_env->CallStaticLongMethod(clazz, methodID, args...); + CheckForJavaException(); + return jd; } template jobject CallStaticObjectMethod(jclass clazz, jmethodID methodID, Args... args) { - return m_env->CallStaticObjectMethod(clazz, methodID, args...); + jobject jo = m_env->CallStaticObjectMethod(clazz, methodID, args...); + CheckForJavaException(); + return jo; } template jboolean CallStaticBooleanMethod(jclass clazz, jmethodID methodID, Args... args) { - return m_env->CallStaticBooleanMethod(clazz, methodID, args...); + jboolean jbl = m_env->CallStaticBooleanMethod(clazz, methodID, args...); + CheckForJavaException(); + return jbl; } template jobject CallObjectMethod(jobject obj, jmethodID methodID, Args... args) { - return m_env->CallObjectMethod(obj, methodID, args...); + jobject jo = m_env->CallObjectMethod(obj, methodID, args...); + CheckForJavaException(); + return jo; } template jboolean CallBooleanMethod(jobject obj, jmethodID methodID, Args... args) { - return m_env->CallBooleanMethod(obj, methodID, args...); + jboolean jbl = m_env->CallBooleanMethod(obj, methodID, args...); + CheckForJavaException(); + return jbl; } template jchar CallCharMethod(jobject obj, jmethodID methodID, Args... args) { - return m_env->CallCharMethod(obj, methodID, args...); + jchar jc = m_env->CallCharMethod(obj, methodID, args...); + CheckForJavaException(); + return jc; } template jbyte CallByteMethod(jobject obj, jmethodID methodID, Args... args) { - return m_env->CallByteMethod(obj, methodID, args...); + jbyte jbt = m_env->CallByteMethod(obj, methodID, args...); + CheckForJavaException(); + return jbt; } template jshort CallShortMethod(jobject obj, jmethodID methodID, Args... args) { - return m_env->CallShortMethod(obj, methodID, args...); + jshort jsh = m_env->CallShortMethod(obj, methodID, args...); + CheckForJavaException(); + return jsh; } template jint CallIntMethod(jobject obj, jmethodID methodID, Args... args) { - return m_env->CallIntMethod(obj, methodID, args...); + jint ji = m_env->CallIntMethod(obj, methodID, args...); + CheckForJavaException(); + return ji; } template jlong CallLongMethod(jobject obj, jmethodID methodID, Args... args) { - return m_env->CallLongMethod(obj, methodID, args...); + jlong jl = m_env->CallLongMethod(obj, methodID, args...); + CheckForJavaException(); + return jl; } template jfloat CallFloatMethod(jobject obj, jmethodID methodID, Args... args) { - return m_env->CallFloatMethod(obj, methodID, args...); + jfloat jf = m_env->CallFloatMethod(obj, methodID, args...); + CheckForJavaException(); + return jf; } template jdouble CallDoubleMethod(jobject obj, jmethodID methodID, Args... args) { - return m_env->CallDoubleMethod(obj, methodID, args...); + jdouble jd = m_env->CallDoubleMethod(obj, methodID, args...); + CheckForJavaException(); + return jd; } template jobject NewObject(jclass clazz, jmethodID methodID, Args... args) { - return m_env->NewObject(clazz, methodID, args...); + jobject jo = m_env->NewObject(clazz, methodID, args...); + CheckForJavaException(); + return jo; + } static void Init(JavaVM *jvm); private: + void CheckForJavaException(); + JNIEnv *m_env; bool m_detach; diff --git a/src/jni/JniLocalRef.cpp b/src/jni/JniLocalRef.cpp index dd708461d..4009bb4e4 100644 --- a/src/jni/JniLocalRef.cpp +++ b/src/jni/JniLocalRef.cpp @@ -6,28 +6,28 @@ using namespace v8; using namespace tns; JniLocalRef::JniLocalRef() - : m_obj(nullptr) + : m_obj(nullptr), m_isWeak(false) { } -JniLocalRef::JniLocalRef(jobject obj) - : m_obj(obj) +JniLocalRef::JniLocalRef(jobject obj, bool isWeak) + : m_obj(obj), m_isWeak(isWeak) { } JniLocalRef::JniLocalRef(jclass obj) - : m_obj(obj) + : m_obj(obj), m_isWeak(false) { } - JniLocalRef::JniLocalRef(const JniLocalRef& rhs) { JEnv env; - m_obj = env.NewLocalRef(rhs.m_obj); + m_obj = rhs.m_isWeak ? rhs.m_obj : env.NewLocalRef(rhs.m_obj); + m_isWeak = rhs.m_isWeak; } @@ -42,14 +42,22 @@ JniLocalRef& JniLocalRef::operator=(const JniLocalRef& rhs) { if(this != &rhs) { - JEnv env; - if (m_obj != nullptr) - { - env.DeleteLocalRef(m_obj); - } - m_obj = (rhs.m_obj != nullptr) - ? env.NewLocalRef(rhs.m_obj) - : nullptr; + m_isWeak = rhs.m_isWeak; + if (m_isWeak) + { + m_obj = rhs.m_obj; + } + else + { + JEnv env; + if (m_obj != nullptr) + { + env.DeleteLocalRef(m_obj); + } + m_obj = (rhs.m_obj != nullptr) + ? env.NewLocalRef(rhs.m_obj) + : nullptr; + } } return *this; } @@ -145,7 +153,7 @@ JniLocalRef::operator jobjectArray() const JniLocalRef::~JniLocalRef() { - if (m_obj != nullptr) + if ((m_obj != nullptr) && !m_isWeak) { JEnv env; env.DeleteLocalRef(m_obj); diff --git a/src/jni/JniLocalRef.h b/src/jni/JniLocalRef.h index b161539b5..a0325db83 100644 --- a/src/jni/JniLocalRef.h +++ b/src/jni/JniLocalRef.h @@ -11,7 +11,7 @@ namespace tns public: JniLocalRef(); - JniLocalRef(jobject obj); + JniLocalRef(jobject obj, bool isWeak = false); JniLocalRef(jclass obj); @@ -56,6 +56,8 @@ namespace tns private: jobject m_obj; + + bool m_isWeak; }; } diff --git a/src/jni/JsDebugger.cpp b/src/jni/JsDebugger.cpp index dfbca4a56..3fa8636a3 100644 --- a/src/jni/JsDebugger.cpp +++ b/src/jni/JsDebugger.cpp @@ -1,6 +1,8 @@ #include "JsDebugger.h" #include "V8GlobalHelpers.h" #include "JniLocalRef.h" +#include "NativeScriptException.h" +#include "NativeScriptAssert.h" #include using namespace std; @@ -33,21 +35,6 @@ string JsDebugger::GetPackageName() return s_packageName; } -/* * - * private method that takes debug message as json from v8 - * after it gets the message the message handler passes it to enqueueMessage method in java - */ -void JsDebugger::MyMessageHandler(const v8::Debug::Message& message) -{ - auto json = message.GetJSON(); - auto str = ConvertToString(json); - - JEnv env; - JniLocalRef s(env.NewStringUTF(str.c_str())); - - env.CallStaticVoidMethod(s_JsDebuggerClass, s_EnqueueMessage, (jstring)s); -} - /* * * sets who will handle the messages when they start comming from v8 */ @@ -94,15 +81,21 @@ void JsDebugger::ProcessDebugMessages() v8::Debug::ProcessDebugMessages(); } -void JsDebugger::SendCommand(uint16_t *cmd, int length) -{ - auto isolate = s_isolate; +void JsDebugger::SendCommand(JNIEnv *_env, jobject obj, jbyteArray command, jint length) { + tns::JEnv env(_env); + auto buf = new jbyte[length]; - v8::Debug::SendCommand(isolate, cmd, length, nullptr); + env.GetByteArrayRegion(command, 0, length, buf); + + int len = length / sizeof(uint16_t); + SendCommandToV8(reinterpret_cast(buf), len); + + delete[] buf; } void JsDebugger::DebugBreakCallback(const v8::FunctionCallbackInfo& args) { + try { JEnv env; JniLocalRef packageName(env.NewStringUTF(s_packageName.c_str())); @@ -116,8 +109,38 @@ void JsDebugger::DebugBreakCallback(const v8::FunctionCallbackInfo& a env.CallStaticVoidMethod(s_JsDebuggerClass, s_EnableAgent, (jstring)packageName, port, jniFalse); DebugBreak(); + } catch (NativeScriptException& e) { + e.ReThrowToV8(); + } + catch (exception e) { + DEBUG_WRITE("Error: c++ exception: %s", e.what()); + } + catch (...) { + DEBUG_WRITE("Error: c++ exception!"); + } } +void JsDebugger::SendCommandToV8(uint16_t *cmd, int length) +{ + auto isolate = s_isolate; + + v8::Debug::SendCommand(isolate, cmd, length, nullptr); +} + +/* * + * private method that takes debug message as json from v8 + * after it gets the message the message handler passes it to enqueueMessage method in java + */ +void JsDebugger::MyMessageHandler(const v8::Debug::Message& message) +{ + auto json = message.GetJSON(); + auto str = ConvertToString(json); + + JEnv env; + JniLocalRef s(env.NewStringUTF(str.c_str())); + + env.CallStaticVoidMethod(s_JsDebuggerClass, s_EnqueueMessage, (jstring)s); +} v8::Isolate* JsDebugger::s_isolate = nullptr; string JsDebugger::s_packageName = ""; diff --git a/src/jni/JsDebugger.h b/src/jni/JsDebugger.h index 177e93343..1fcb93dde 100644 --- a/src/jni/JsDebugger.h +++ b/src/jni/JsDebugger.h @@ -23,7 +23,7 @@ namespace tns static std::string GetPackageName(); - static void SendCommand(uint16_t *cmd, int length); + static void SendCommand(JNIEnv *_env, jobject obj, jbyteArray command, jint length); static void DebugBreakCallback(const v8::FunctionCallbackInfo& args); @@ -31,6 +31,7 @@ namespace tns JsDebugger(); static void MyMessageHandler(const v8::Debug::Message& message); + static void SendCommandToV8(uint16_t *cmd, int length); static std::string s_packageName; static jclass s_JsDebuggerClass; diff --git a/src/jni/MetadataNode.cpp b/src/jni/MetadataNode.cpp index 74cc9e8ac..a68ad09fd 100644 --- a/src/jni/MetadataNode.cpp +++ b/src/jni/MetadataNode.cpp @@ -4,10 +4,10 @@ #include "Util.h" #include "V8GlobalHelpers.h" #include "V8StringConstants.h" -#include "ExceptionUtil.h" #include "SimpleProfiler.h" #include "JniLocalRef.h" #include "NativeScriptRuntime.h" +#include "NativeScriptException.h" #include #include #include @@ -192,9 +192,19 @@ Local MetadataNode::CreateJSWrapper(Isolate *isolate) void MetadataNode::ArrayLengthGetterCallack(Local property, const PropertyCallbackInfo& info) { + try { auto thiz = info.This(); auto length = NativeScriptRuntime::GetArrayLength(thiz); info.GetReturnValue().Set(Integer::New(info.GetIsolate(), length)); + } catch (NativeScriptException& e) { + e.ReThrowToV8(); + } + catch (exception e) { + DEBUG_WRITE("Error: c++ exception: %s", e.what()); + } + catch (...) { + DEBUG_WRITE("Error: c++ exception!"); + } } Local MetadataNode::CreateArrayWrapper(Isolate *isolate) @@ -239,24 +249,45 @@ void MetadataNode::SetClassAccessor(Local& ctorFunction) void MetadataNode::ClassAccessorGetterCallback(Local property, const PropertyCallbackInfo& info) { + try { auto thiz = info.This(); auto isolate = info.GetIsolate(); auto data = GetTypeMetadata(isolate, thiz.As()); auto value = NativeScriptRuntime::FindClass(data->name); info.GetReturnValue().Set(value); + } catch (NativeScriptException& e) { + e.ReThrowToV8(); + } + catch (exception e) { + DEBUG_WRITE("Error: c++ exception: %s", e.what()); + } + catch (...) { + DEBUG_WRITE("Error: c++ exception!"); + } } void MetadataNode::FieldAccessorGetterCallback(Local property, const PropertyCallbackInfo& info) { + try { auto thiz = info.This(); auto fieldCallbackData = reinterpret_cast(info.Data().As()->Value()); auto value = NativeScriptRuntime::GetJavaField(thiz, fieldCallbackData); info.GetReturnValue().Set(value); + } catch (NativeScriptException& e) { + e.ReThrowToV8(); + } + catch (exception e) { + DEBUG_WRITE("Error: c++ exception: %s", e.what()); + } + catch (...) { + DEBUG_WRITE("Error: c++ exception!"); + } } void MetadataNode::FieldAccessorSetterCallback(Local property,Local value, const PropertyCallbackInfo& info) { + try { DEBUG_WRITE("FieldAccessorSetterCallback"); auto thiz = info.This(); @@ -268,17 +299,27 @@ void MetadataNode::FieldAccessorSetterCallback(Local property,Localname << "\" which is a final field! Final fields can only be read."; string exceptionMessage = ss.str(); - ExceptionUtil::GetInstance()->ThrowExceptionToJs(exceptionMessage); + throw NativeScriptException(exceptionMessage); } else { NativeScriptRuntime::SetJavaField(thiz, value, fieldCallbackData); info.GetReturnValue().Set(value); } + } catch (NativeScriptException& e) { + e.ReThrowToV8(); + } + catch (exception e) { + DEBUG_WRITE("Error: c++ exception: %s", e.what()); + } + catch (...) { + DEBUG_WRITE("Error: c++ exception!"); + } } void MetadataNode::SuperAccessorGetterCallback(Local property, const PropertyCallbackInfo& info) { + try { auto thiz = info.This(); auto isolate = info.GetIsolate(); auto k = ConvertToV8String("supervalue"); @@ -303,6 +344,15 @@ void MetadataNode::SuperAccessorGetterCallback(Local property, const Pro } info.GetReturnValue().Set(superValue); + } catch (NativeScriptException& e) { + e.ReThrowToV8(); + } + catch (exception e) { + DEBUG_WRITE("Error: c++ exception: %s", e.what()); + } + catch (...) { + DEBUG_WRITE("Error: c++ exception!"); + } } Local MetadataNode::SetMembers(Isolate *isolate, Local& ctorFuncTemplate, Local& prototypeTemplate, vector& instanceMethodsCallbackData, const vector& baseInstanceMethodsCallbackData, MetadataTreeNode *treeNode) @@ -400,7 +450,7 @@ Local MetadataNode::SetMembersFromStaticMetadata(Isolate *isolate, Loc } auto extendFuncName = V8StringConstants::GetExtend(); - auto extendFuncTemplate = FunctionTemplate::New(isolate, ExtendCallMethodHandler, External::New(isolate, this)); + auto extendFuncTemplate = FunctionTemplate::New(isolate, ExtendCallMethodCallback, External::New(isolate, this)); ctorFunction->Set(extendFuncName, extendFuncTemplate->GetFunction()); //get candidates from static fields metadata @@ -496,6 +546,7 @@ Local MetadataNode::SetMembersFromRuntimeMetadata(Isolate *isolate, Lo void MetadataNode::InnerClassConstructorCallback(const v8::FunctionCallbackInfo& info) { + try { auto thiz = info.This(); auto isolate = info.GetIsolate(); auto data = reinterpret_cast(info.Data().As()->Value()); @@ -510,10 +561,20 @@ void MetadataNode::InnerClassConstructorCallback(const v8::FunctionCallbackInfo< string fullClassName = CreateFullClassName(className, extendName); bool success = NativeScriptRuntime::RegisterInstance(thiz, fullClassName, argWrapper, outerThis, false); + } catch (NativeScriptException& e) { + e.ReThrowToV8(); + } + catch (exception e) { + DEBUG_WRITE("Error: c++ exception: %s", e.what()); + } + catch (...) { + DEBUG_WRITE("Error: c++ exception!"); + } } void MetadataNode::InnerClassAccessorGetterCallback(Local property, const PropertyCallbackInfo& info) { + try { auto isolate = info.GetIsolate(); auto thiz = info.This(); auto node = reinterpret_cast(info.Data().As()->Value()); @@ -538,6 +599,15 @@ void MetadataNode::InnerClassAccessorGetterCallback(Local property, cons } info.GetReturnValue().Set(innerTypeCtorFunc); + } catch (NativeScriptException& e) { + e.ReThrowToV8(); + } + catch (exception e) { + DEBUG_WRITE("Error: c++ exception: %s", e.what()); + } + catch (...) { + DEBUG_WRITE("Error: c++ exception!"); + } } void MetadataNode::SetInnnerTypes(Isolate *isolate, Local& ctorFunction, MetadataTreeNode *treeNode) @@ -692,6 +762,7 @@ void MetadataNode::SetPackageMetadata(Isolate *isolate, Local value, Met void MetadataNode::ExtendedClassConstructorCallback(const v8::FunctionCallbackInfo& info) { + try { SET_PROFILER_FRAME(); assert(info.IsConstructCall()); @@ -715,11 +786,21 @@ void MetadataNode::ExtendedClassConstructorCallback(const v8::FunctionCallbackIn string fullClassName = extData->fullClassName; bool success = NativeScriptRuntime::RegisterInstance(thiz, fullClassName, argWrapper, implementationObject, false); + } catch (NativeScriptException& e) { + e.ReThrowToV8(); + } + catch (exception e) { + DEBUG_WRITE("Error: c++ exception: %s", e.what()); + } + catch (...) { + DEBUG_WRITE("Error: c++ exception!"); + } } void MetadataNode::InterfaceConstructorCallback(const v8::FunctionCallbackInfo& info) { + try { SET_PROFILER_FRAME(); auto isolate = info.GetIsolate(); @@ -739,8 +820,7 @@ void MetadataNode::InterfaceConstructorCallback(const v8::FunctionCallbackInfoIsObject()) { - isolate->ThrowException(ConvertToV8String("First argument must be implementation object")); - return; + throw NativeScriptException(string("First argument must be implementation object")); } implementationObject = info[0]->ToObject(); } @@ -748,13 +828,11 @@ void MetadataNode::InterfaceConstructorCallback(const v8::FunctionCallbackInfoIsString()) { - isolate->ThrowException(ConvertToV8String("First argument must be string")); - return; + throw NativeScriptException(string("First argument must be string")); } if (!info[1]->IsObject()) { - isolate->ThrowException(ConvertToV8String("Second argument must be implementation object")); - return; + throw NativeScriptException(string("Second argument must be implementation object")); } DEBUG_WRITE("InterfaceConstructorCallback: getting extend name"); @@ -763,8 +841,7 @@ void MetadataNode::InterfaceConstructorCallback(const v8::FunctionCallbackInfoThrowException(ConvertToV8String("Invalid number of arguments")); - return; + throw NativeScriptException(string("Invalid number of arguments")); } auto className = node->m_implType; @@ -784,10 +861,20 @@ void MetadataNode::InterfaceConstructorCallback(const v8::FunctionCallbackInfo()); auto success = NativeScriptRuntime::RegisterInstance(thiz, fullClassName, argWrapper, implementationObject, true); + } catch (NativeScriptException& e) { + e.ReThrowToV8(); + } + catch (exception e) { + DEBUG_WRITE("Error: c++ exception: %s", e.what()); + } + catch (...) { + DEBUG_WRITE("Error: c++ exception!"); + } } void MetadataNode::ClassConstructorCallback(const v8::FunctionCallbackInfo& info) { + try { SET_PROFILER_FRAME(); auto thiz = info.This(); @@ -803,10 +890,20 @@ void MetadataNode::ClassConstructorCallback(const v8::FunctionCallbackInfo& info) { + try { SET_PROFILER_FRAME(); auto e = info.Data().As(); @@ -868,24 +965,53 @@ void MetadataNode::MethodCallback(const v8::FunctionCallbackInfo& inf { NativeScriptRuntime::CallJavaMethod(thiz, *className, methodName, entry, first.isStatic, isSuper, info); } + } catch (NativeScriptException& e) { + e.ReThrowToV8(); + } + catch (exception e) { + DEBUG_WRITE("Error: c++ exception: %s", e.what()); + } + catch (...) { + DEBUG_WRITE("Error: c++ exception!"); + } } void MetadataNode::ArrayIndexedPropertyGetterCallback(uint32_t index, const PropertyCallbackInfo& info) { + try { auto node = GetNodeFromHandle(info.This()); auto element = NativeScriptRuntime::GetArrayElement(info.This(), index, node->m_name); info.GetReturnValue().Set(element); + } catch (NativeScriptException& e) { + e.ReThrowToV8(); + } + catch (exception e) { + DEBUG_WRITE("Error: c++ exception: %s", e.what()); + } + catch (...) { + DEBUG_WRITE("Error: c++ exception!"); + } } void MetadataNode::ArrayIndexedPropertySetterCallback(uint32_t index, Local value, const PropertyCallbackInfo& info) { - auto node = GetNodeFromHandle(info.This()); + try { + auto node = GetNodeFromHandle(info.This()); - NativeScriptRuntime::SetArrayElement(info.This(), index, node->m_name, value); + NativeScriptRuntime::SetArrayElement(info.This(), index, node->m_name, value); - info.GetReturnValue().Set(value); + info.GetReturnValue().Set(value); + } catch (NativeScriptException& e) { + e.ReThrowToV8(); + } + catch (exception e) { + DEBUG_WRITE("Error: c++ exception: %s", e.what()); + } + catch (...) { + DEBUG_WRITE("Error: c++ exception!"); + } } Local MetadataNode::GetImplementationObject(const Local& object) @@ -965,6 +1091,7 @@ Local MetadataNode::GetImplementationObject(const Local& object) void MetadataNode::PackageGetterCallback(Local property, const PropertyCallbackInfo& info) { + try { string propName = ConvertToString(property); if (propName.empty()) @@ -997,6 +1124,15 @@ void MetadataNode::PackageGetterCallback(Local property, const PropertyC } info.GetReturnValue().Set(cachedItem); + } catch (NativeScriptException& e) { + e.ReThrowToV8(); + } + catch (exception e) { + DEBUG_WRITE("Error: c++ exception: %s", e.what()); + } + catch (...) { + DEBUG_WRITE("Error: c++ exception!"); + } } @@ -1014,8 +1150,7 @@ bool MetadataNode::ValidateExtendArguments(const FunctionCallbackInfo& in ss << "Invalid extend() call. No name specified for extend at location: " << extendLocation.c_str(); string exceptionMessage = ss.str(); - ExceptionUtil::GetInstance()->ThrowExceptionToJs(exceptionMessage); - return false; + throw NativeScriptException(exceptionMessage); } @@ -1025,8 +1160,7 @@ bool MetadataNode::ValidateExtendArguments(const FunctionCallbackInfo& in ss << "Invalid extend() call. No implementation object specified at location: " << extendLocation.c_str(); string exceptionMessage = ss.str(); - ExceptionUtil::GetInstance()->ThrowExceptionToJs(exceptionMessage); - return false; + throw NativeScriptException(exceptionMessage); } implementationObject = info[0]->ToObject(); @@ -1039,8 +1173,7 @@ bool MetadataNode::ValidateExtendArguments(const FunctionCallbackInfo& in ss << "Invalid extend() call. No name for extend specified at location: " << extendLocation.c_str(); string exceptionMessage = ss.str(); - ExceptionUtil::GetInstance()->ThrowExceptionToJs(exceptionMessage); - return false; + throw NativeScriptException(exceptionMessage); } if (!info[1]->IsObject()) @@ -1049,8 +1182,7 @@ bool MetadataNode::ValidateExtendArguments(const FunctionCallbackInfo& in ss << "Invalid extend() call. Named extend should be called with second object parameter containing overridden methods at location: " << extendLocation.c_str(); string exceptionMessage = ss.str(); - ExceptionUtil::GetInstance()->ThrowExceptionToJs(exceptionMessage); - return false; + throw NativeScriptException(exceptionMessage); } DEBUG_WRITE("ExtendsCallMethodHandler: getting extend name"); @@ -1062,8 +1194,7 @@ bool MetadataNode::ValidateExtendArguments(const FunctionCallbackInfo& in ss << "The extend name \"" << ConvertToString(extendName) << "\" you provided contains invalid symbols. Try using the symbols [a-z, A-Z, 0-9, _]." << endl; string exceptionMessage = ss.str(); - ExceptionUtil::GetInstance()->ThrowExceptionToJs(exceptionMessage); - return false; + throw NativeScriptException(exceptionMessage); } implementationObject = info[1]->ToObject(); } @@ -1073,8 +1204,7 @@ bool MetadataNode::ValidateExtendArguments(const FunctionCallbackInfo& in ss << "Invalid extend() call at location: " << extendLocation.c_str(); string exceptionMessage = ss.str(); - ExceptionUtil::GetInstance()->ThrowExceptionToJs(exceptionMessage); - return false; + throw NativeScriptException(exceptionMessage); } return true; @@ -1106,13 +1236,13 @@ string MetadataNode::CreateFullClassName(const std::string& className, const std return fullClassName; } -void MetadataNode::ExtendCallMethodHandler(const v8::FunctionCallbackInfo& info) +void MetadataNode::ExtendCallMethodCallback(const v8::FunctionCallbackInfo& info) { + try { if (info.IsConstructCall()) { string exMsg("Cannot call 'extend' as constructor"); - ExceptionUtil::GetInstance()->ThrowExceptionToJs(exMsg); - return; + throw NativeScriptException(exMsg); } SET_PROFILER_FRAME(); @@ -1164,8 +1294,7 @@ void MetadataNode::ExtendCallMethodHandler(const v8::FunctionCallbackInfoThrowExceptionToJs(s.str()); - return; + throw NativeScriptException(s.str()); } auto baseClassCtorFunc = node->GetConstructorFunction(isolate); @@ -1192,6 +1321,15 @@ void MetadataNode::ExtendCallMethodHandler(const v8::FunctionCallbackInfo& name) diff --git a/src/jni/MetadataNode.h b/src/jni/MetadataNode.h index 784af8d7d..c7853fc50 100644 --- a/src/jni/MetadataNode.h +++ b/src/jni/MetadataNode.h @@ -202,7 +202,7 @@ namespace tns static void MethodCallback(const v8::FunctionCallbackInfo& info); static void InterfaceConstructorCallback(const v8::FunctionCallbackInfo& info); static void ClassConstructorCallback(const v8::FunctionCallbackInfo& info); - static void ExtendCallMethodHandler(const v8::FunctionCallbackInfo& info); + static void ExtendCallMethodCallback(const v8::FunctionCallbackInfo& info); static bool ValidateExtendArguments(const v8::FunctionCallbackInfo& info, std::string& extendLocation, v8::Local& extendName, v8::Local& implementationObject); static void ExtendedClassConstructorCallback(const v8::FunctionCallbackInfo& info); diff --git a/src/jni/MethodCache.cpp b/src/jni/MethodCache.cpp index fb04aa6dd..de5750244 100644 --- a/src/jni/MethodCache.cpp +++ b/src/jni/MethodCache.cpp @@ -1,7 +1,6 @@ #include "MethodCache.h" #include "JniLocalRef.h" #include "JsArgToArrayConverter.h" -#include "ExceptionUtil.h" #include "MetadataNode.h" #include "NativeScriptAssert.h" #include "Util.h" @@ -195,18 +194,13 @@ string MethodCache::ResolveJavaMethod(const FunctionCallbackInfo& args, c jstring signature = (jstring) env.CallStaticObjectMethod(PLATFORM_CLASS, RESOLVE_METHOD_OVERLOAD_METHOD_ID, (jstring) jsClassName, (jstring) jsMethodName, arrArgs); - bool exceptionOccurred = ExceptionUtil::GetInstance()->CheckForJavaException(env); - string resolvedSignature; - if (!exceptionOccurred) - { - const char* str = env.GetStringUTFChars(signature, nullptr); - resolvedSignature = string(str); - env.ReleaseStringUTFChars(signature, str); + const char* str = env.GetStringUTFChars(signature, nullptr); + resolvedSignature = string(str); + env.ReleaseStringUTFChars(signature, str); - env.DeleteLocalRef(signature); - } + env.DeleteLocalRef(signature); return resolvedSignature; } diff --git a/src/jni/Module.cpp b/src/jni/Module.cpp index b75499730..dd926a739 100644 --- a/src/jni/Module.cpp +++ b/src/jni/Module.cpp @@ -10,8 +10,8 @@ #include "ArgConverter.h" #include "V8GlobalHelpers.h" #include "NativeScriptAssert.h" -#include "ExceptionUtil.h" #include "Constants.h" +#include "NativeScriptException.h" #include #include @@ -100,74 +100,79 @@ Local Module::GetRequireFunction(Isolate *isolate, const string& dirNa void Module::RequireCallback(const v8::FunctionCallbackInfo& args) { - auto isolate = Isolate::GetCurrent(); - - if (args.Length() != 2) - { - isolate->ThrowException(ConvertToV8String("require should be called with two parameters")); - return; - } - if (!args[0]->IsString()) - { - isolate->ThrowException(ConvertToV8String("require's first parameter should be string")); - return; - } - if (!args[1]->IsString()) - { - isolate->ThrowException(ConvertToV8String("require's second parameter should be string")); - return; - } + try { + auto isolate = Isolate::GetCurrent(); - string moduleName = ConvertToString(args[0].As()); - string callingModuleDirName = ConvertToString(args[1].As()); + if (args.Length() != 2) + { + throw NativeScriptException(string("require should be called with two parameters")); + } + if (!args[0]->IsString()) + { + throw NativeScriptException(string("require's first parameter should be string")); + } + if (!args[1]->IsString()) + { + throw NativeScriptException(string("require's second parameter should be string")); + } - JEnv env; - JniLocalRef jsModulename(env.NewStringUTF(moduleName.c_str())); - JniLocalRef jsCallingModuleDirName(env.NewStringUTF(callingModuleDirName.c_str())); - JniLocalRef jsModulePath(env.CallStaticObjectMethod(MODULE_CLASS, GET_MODULE_PATH_METHOD_ID, (jstring) jsModulename, (jstring) jsCallingModuleDirName)); - - // cache the required modules by full path, not name only, since there might be some collisions with relative paths and names - string modulePath = ArgConverter::jstringToString((jstring) jsModulePath); - if(modulePath == ""){ - // module not found - stringstream ss; - ss << "Module \"" << moduleName << "\" not found"; - string exception = ss.str(); - ExceptionUtil::GetInstance()->ThrowExceptionToJs(exception); - return; - } - if (modulePath == "EXTERNAL_FILE_ERROR") - { - // module not found - stringstream ss; - ss << "Module \"" << moduleName << "\" is located on the external storage. Modules can be private application files ONLY"; - string exception = ss.str(); - ExceptionUtil::GetInstance()->ThrowExceptionToJs(exception); - return; - } + string moduleName = ConvertToString(args[0].As()); + string callingModuleDirName = ConvertToString(args[1].As()); + + JEnv env; + JniLocalRef jsModulename(env.NewStringUTF(moduleName.c_str())); + JniLocalRef jsCallingModuleDirName(env.NewStringUTF(callingModuleDirName.c_str())); + JniLocalRef jsModulePath(env.CallStaticObjectMethod(MODULE_CLASS, GET_MODULE_PATH_METHOD_ID, (jstring) jsModulename, (jstring) jsCallingModuleDirName)); + + // cache the required modules by full path, not name only, since there might be some collisions with relative paths and names + string modulePath = ArgConverter::jstringToString((jstring) jsModulePath); + if(modulePath == ""){ + // module not found + stringstream ss; + ss << "Module \"" << moduleName << "\" not found"; + string exception = ss.str(); + throw NativeScriptException(exception); + } + if (modulePath == "EXTERNAL_FILE_ERROR") + { + // module not found + stringstream ss; + ss << "Module \"" << moduleName << "\" is located on the external storage. Modules can be private application files ONLY"; + string exception = ss.str(); + throw NativeScriptException(exception); + } - auto it = s_loadedModules.find(modulePath); + auto it = s_loadedModules.find(modulePath); - bool hasError = false; + bool hasError = false; - Local moduleObj; + Local moduleObj; - if (it == s_loadedModules.end()) - { - moduleObj = CompileAndRun(modulePath, hasError); - } - else - { - moduleObj = Local::New(isolate, *it->second); - } + if (it == s_loadedModules.end()) + { + moduleObj = CompileAndRun(modulePath, hasError); + } + else + { + moduleObj = Local::New(isolate, *it->second); + } - if(!hasError) - { - auto exportsObj = moduleObj->Get(ConvertToV8String("exports")); + if(!hasError) + { + auto exportsObj = moduleObj->Get(ConvertToV8String("exports")); - assert(!exportsObj.IsEmpty()); + assert(!exportsObj.IsEmpty()); - args.GetReturnValue().Set(exportsObj); + args.GetReturnValue().Set(exportsObj); + } + } catch (NativeScriptException& e) { + e.ReThrowToV8(); + } + catch (exception e) { + DEBUG_WRITE("Error: c++ exception: %s", e.what()); + } + catch (...) { + DEBUG_WRITE("Error: c++ exception!"); } } @@ -217,13 +222,12 @@ Local Module::CompileAndRun(const string& modulePath, bool& hasError) DEBUG_WRITE("Compiled script (module %s)", modulePath.c_str()); - if (ExceptionUtil::GetInstance()->HandleTryCatch(tc, "Script " + modulePath + " contains compilation errors!")) - { - hasError = true; + if(tc.HasCaught()) { + throw NativeScriptException(tc, "Script " + modulePath + " contains compilation errors!"); } - else if (script.IsEmpty()) + + if (script.IsEmpty()) { - //think about more descriptive message -> [script_name] was empty DEBUG_WRITE("%s was empty", modulePath.c_str()); } else @@ -231,43 +235,28 @@ Local Module::CompileAndRun(const string& modulePath, bool& hasError) DEBUG_WRITE("Running script (module %s)", modulePath.c_str()); auto f = script->Run().As(); - if (ExceptionUtil::GetInstance()->HandleTryCatch(tc, "Error running script " + modulePath)) - { - hasError = true; + if(tc.HasCaught()) { + throw NativeScriptException(tc, "Error running script " + modulePath); } - else - { - auto fileName = ConvertToV8String(modulePath); - char pathcopy[1024]; - strcpy(pathcopy, modulePath.c_str()); - string strDirName(dirname(pathcopy)); - auto dirName = ConvertToV8String(strDirName); - auto require = GetRequireFunction(isolate, strDirName); - Local requireArgs[5] { moduleObj, exportsObj, require, fileName, dirName }; - - auto thiz = Object::New(isolate); - f->Call(thiz, sizeof(requireArgs) / sizeof(Local), requireArgs); - if(ExceptionUtil::GetInstance()->HandleTryCatch(tc, "Error calling module function ")) - { - hasError = true; - } - } - } - if(hasError) - { - s_loadedModules.erase(modulePath); - poModuleObj->Reset(); - delete poModuleObj; + auto fileName = ConvertToV8String(modulePath); + char pathcopy[1024]; + strcpy(pathcopy, modulePath.c_str()); + string strDirName(dirname(pathcopy)); + auto dirName = ConvertToV8String(strDirName); + auto require = GetRequireFunction(isolate, strDirName); + Local requireArgs[5] { moduleObj, exportsObj, require, fileName, dirName }; - // this handles recursive require calls - tc.ReThrow(); - } - else - { - result = moduleObj; + auto thiz = Object::New(isolate); + f->Call(thiz, sizeof(requireArgs) / sizeof(Local), requireArgs); + + if(tc.HasCaught()) { + throw NativeScriptException(tc, "Error calling module function "); + } } + result = moduleObj; + return result; } diff --git a/src/jni/NativePlatform.cpp b/src/jni/NativePlatform.cpp new file mode 100644 index 000000000..cf08a489a --- /dev/null +++ b/src/jni/NativePlatform.cpp @@ -0,0 +1,480 @@ +#include "NativeScriptRuntime.h" +#include "MetadataNode.h" +#include "JniLocalRef.h" +#include "JsArgConverter.h" +#include "JsArgToArrayConverter.h" +#include "ArgConverter.h" +#include "Util.h" +#include "V8GlobalHelpers.h" +#include "V8StringConstants.h" +#include "Constants.h" +#include "v8.h" +#include "libplatform/libplatform.h" +#include "Version.h" +#include "JEnv.h" +#include "WeakRef.h" +#include "Profiler.h" +#include "NativeScriptAssert.h" +#include "JsDebugger.h" +#include "SimpleProfiler.h" +#include "SimpleAllocator.h" +#include "File.h" +#include "JType.h" +#include "Module.h" +#include "NativeScriptException.h" +#include "NativePlatform.h" +#include +#include +#include +#include + +using namespace v8; +using namespace std; +using namespace tns; + +//TODO: Lubo: properly release this jni global ref on shutdown +JavaVM *g_jvm = nullptr; +Persistent *PrimaryContext = nullptr; +Context::Scope *context_scope = nullptr; +Isolate *g_isolate = nullptr; +ObjectManager *g_objectManager = nullptr; +bool tns::LogEnabled = true; +int AppJavaObjectID = -1; +int count = 0; +SimpleAllocator g_allocator; + +jobject ConvertJsValueToJavaObject(JEnv& env, const Local& value, int classReturnType); +void AppInitCallback(const v8::FunctionCallbackInfo& args); +void static PrepareExtendFunction(Isolate *isolate, jstring filesPath); +void static PrepareV8Runtime(Isolate *isolate, JEnv& env, jstring filesPath, jstring packageName); + +jint NativePlatform::JNI_ON_LOAD(JavaVM *vm, void *reserved) +{ + __android_log_print(ANDROID_LOG_INFO, "TNS.Native", "NativeScript Runtime Version %s, commit %s", NATIVE_SCRIPT_RUNTIME_VERSION, NATIVE_SCRIPT_RUNTIME_COMMIT_SHA); + DEBUG_WRITE("JNI_ONLoad"); + + g_jvm = vm; + + JEnv::Init(g_jvm); + + g_objectManager = new ObjectManager(); + + DEBUG_WRITE("JNI_ONLoad END"); + + return JNI_VERSION_1_6; +} + +void NativePlatform::InitNativeScript(JNIEnv *_env, jobject obj, jstring filesPath, jint appJavaObjectId, jboolean verboseLoggingEnabled, jstring packageName, jobjectArray args) +{ + AppJavaObjectID = appJavaObjectId; + tns::LogEnabled = verboseLoggingEnabled; + + JEnv env(_env); + + auto filesRoot = ArgConverter::jstringToString(filesPath); + Constants::APP_ROOT_FOLDER_PATH = filesRoot + "/app/"; + // read config options passed from Java + JniLocalRef v8Flags(env.GetObjectArrayElement(args, 0)); + Constants::V8_STARTUP_FLAGS = ArgConverter::jstringToString(v8Flags); + JniLocalRef cacheCode(env.GetObjectArrayElement(args, 1)); + Constants::V8_CACHE_COMPILED_CODE = (bool)cacheCode; + JniLocalRef snapshot(env.GetObjectArrayElement(args, 2)); + Constants::V8_HEAP_SNAPSHOT = (bool)snapshot; + + DEBUG_WRITE("Initializing Telerik NativeScript: app instance id:%d", appJavaObjectId); + + NativeScriptException::Init(g_jvm, g_objectManager); + PrepareV8Runtime(env, filesRoot, packageName); + +} + +void NativePlatform::RunModule(JNIEnv *_env, jobject obj, jstring scriptFile) +{ + JEnv env(_env); + auto isolate = g_isolate; + Isolate::Scope isolate_scope(isolate); + + HandleScope handleScope(isolate); + + string filePath = ArgConverter::jstringToString(scriptFile); + bool hasError = false; + + auto moduleObj = Module::CompileAndRun(filePath, hasError); +} + +jobject NativePlatform::RunScript(JNIEnv *_env, jobject obj, jstring scriptFile) +{ + JEnv env(_env); + jobject res = nullptr; + + auto isolate = g_isolate; + Isolate::Scope isolate_scope(isolate); + HandleScope handleScope(isolate); + auto context = isolate->GetCurrentContext(); + + auto filename = ArgConverter::jstringToString(scriptFile); + auto src = File::ReadText(filename); + auto source = ConvertToV8String(src); + + TryCatch tc; + + Local