JniLocalRef::JniLocalRef(const JniLocalRef& rhs) { JEnv env; m_obj = rhs.m_isWeak ? rhs.m_obj : env.NewLocalRef(rhs.m_obj); m_isWeak = rhs.m_isWeak; }
jobject NativeScriptRuntime::CreateJavaInstance(int objectID, const std::string& fullClassName, const ArgsWrapper& argWrapper, jclass javaClass, bool isInterface) { SET_PROFILER_FRAME(); jobject instance = nullptr; DEBUG_WRITE("CreateJavaInstance: %s", fullClassName.c_str()); JEnv env; auto& args = argWrapper.args; JsArgToArrayConverter argConverter(args, isInterface, argWrapper.outerThis); if (argConverter.IsValid()) { jobjectArray javaArgs = argConverter.ToJavaArray(); int ctorId = GetCachedConstructorId(env, args, fullClassName, javaArgs, javaClass); jobject obj = env.CallStaticObjectMethod(PlatformClass, CREATE_INSTANCE_METHOD_ID, javaArgs, (jint) objectID, ctorId); instance = obj; } else { JsArgToArrayConverter::Error err = argConverter.GetError(); throw NativeScriptException(err.msg); } return instance; }
void JsDebugger::DebugBreakCallback(const v8::FunctionCallbackInfo<v8::Value>& args) { if (s_jsDebugger == nullptr) { return; } try { JEnv env; env.CallStaticVoidMethod(s_JsDebuggerClass, s_EnableAgent); DebugBreak(); } catch (NativeScriptException& e) { e.ReThrowToV8(); } catch (std::exception e) { stringstream ss; ss << "Error: c++ exception: " << e.what() << endl; NativeScriptException nsEx(ss.str()); nsEx.ReThrowToV8(); } catch (...) { NativeScriptException nsEx(std::string("Error: c++ exception!")); nsEx.ReThrowToV8(); } }
int NativeScriptRuntime::GetCachedConstructorId(JEnv& env, const FunctionCallbackInfo<Value>& args, const string& fullClassName, jobjectArray javaArgs, jclass javaClass) { int ctorId = -1; string encodedCtorArgs = MethodCache::EncodeSignature(fullClassName, "<init>", args, false); auto itFound = s_constructorCache.find(encodedCtorArgs); if (itFound != s_constructorCache.end()) { ctorId = itFound->second; } else { jint id = env.CallStaticIntMethod(PlatformClass, CACHE_CONSTRUCTOR_METHOD_ID, javaClass, javaArgs); if (env.ExceptionCheck() == JNI_FALSE) { ctorId = id; s_constructorCache.insert(make_pair(encodedCtorArgs, ctorId)); } } DEBUG_WRITE("GetCachedConstructorId: encodedCtorArgs=%s, ctorId=%d", encodedCtorArgs.c_str(), ctorId); return ctorId; }
void ObjectManager::MakeRegularObjectsWeak(const set<int>& instances, DirectBuffer& inputBuff) { JEnv env; jboolean keepAsWeak = JNI_FALSE; for (auto javaObjectId : instances) { bool success = inputBuff.Write(javaObjectId); if (!success) { int length = inputBuff.Length(); env.CallStaticVoidMethod(PlatformClass, MAKE_INSTANCE_WEAK_BATCH_METHOD_ID, (jobject) inputBuff, length, keepAsWeak); inputBuff.Reset(); success = inputBuff.Write(javaObjectId); assert(success); } } int size = inputBuff.Size(); if (size > 0) { env.CallStaticVoidMethod(PlatformClass, MAKE_INSTANCE_WEAK_BATCH_METHOD_ID, (jobject) inputBuff, size, keepAsWeak); } inputBuff.Reset(); }
jclass NativeScriptRuntime::ResolveClass(const std::string& fullClassname, const Local<Object>& implementationObject) { auto itFound = s_classCache.find(fullClassname); jclass globalRefToGeneratedClass; if (itFound != s_classCache.end()) { globalRefToGeneratedClass = itFound->second; } else { JEnv env; //get needed arguments in order to load binding JniLocalRef javaFullClassName(env.NewStringUTF(fullClassname.c_str())); jobjectArray methodOverrides = GetMethodOverrides(env, implementationObject); //create or load generated binding (java class) JniLocalRef generatedClass(env.CallStaticObjectMethod(PlatformClass, RESOLVE_CLASS_METHOD_ID, (jstring)javaFullClassName, methodOverrides)); globalRefToGeneratedClass = reinterpret_cast<jclass>(env.NewGlobalRef(generatedClass)); s_classCache.insert(make_pair(fullClassname, globalRefToGeneratedClass)); } return globalRefToGeneratedClass; }
jobject ObjectManager::GetJavaObjectByIDImpl(uint32_t javaObjectID) { JEnv env; jobject object = env.CallStaticObjectMethod(PlatformClass, GET_JAVAOBJECT_BY_ID_METHOD_ID, javaObjectID); return object; }
void ObjectManager::MakeImplObjectsWeak(const vector<PersistentObjectIdPair>& instances, DirectBuffer& inputBuff) { JEnv env; jboolean keepAsWeak = JNI_TRUE; for (const auto& poIdPair : instances) { int javaObjectId = poIdPair.javaObjectId; bool success = inputBuff.Write(javaObjectId); if (!success) { int length = inputBuff.Length(); jboolean keepAsWeak = JNI_TRUE; env.CallStaticVoidMethod(PlatformClass, MAKE_INSTANCE_WEAK_BATCH_METHOD_ID, (jobject) inputBuff, length, keepAsWeak); inputBuff.Reset(); success = inputBuff.Write(javaObjectId); assert(success); } } int size = inputBuff.Size(); if (size > 0) { jboolean keepAsWeak = JNI_TRUE; env.CallStaticVoidMethod(PlatformClass, MAKE_INSTANCE_WEAK_BATCH_METHOD_ID, (jobject) inputBuff, size, keepAsWeak); } inputBuff.Reset(); }
bool NativeScriptRuntime::RegisterInstance(const Local<Object>& jsObject, const std::string& fullClassName, const ArgsWrapper& argWrapper, const Local<Object>& implementationObject, bool isInterface) { bool success; DEBUG_WRITE("RegisterInstance called for '%s'", fullClassName.c_str()); JEnv env; jclass generatedJavaClass = ResolveClass(fullClassName, implementationObject); int javaObjectID = objectManager->GenerateNewObjectID(); DEBUG_WRITE("RegisterInstance: Linking new instance"); objectManager->Link(jsObject, javaObjectID, nullptr); jobject instance = CreateJavaInstance(javaObjectID, fullClassName, argWrapper, generatedJavaClass, isInterface); JniLocalRef localInstance(instance); success = !localInstance.IsNull(); if (success) { DEBUG_WRITE("RegisterInstance: Updating linked instance with its real class"); jclass instanceClass = env.FindClass(fullClassName); objectManager->SetJavaClass(jsObject, instanceClass); } else { DEBUG_WRITE("RegisterInstance failed with null new instance"); } return success; }
string ObjectManager::GetClassName(jobject javaObject) { JEnv env; JniLocalRef objectClass(env.GetObjectClass(javaObject)); return GetClassName((jclass) objectClass); }
Local<Object> ObjectManager::CreateJSWrapper(jint javaObjectID, const string& typeName, jobject instance) { JEnv env; JniLocalRef clazz(env.GetObjectClass(instance)); return CreateJSWrapperHelper(javaObjectID, typeName, clazz); }
int ObjectManager::GetOrCreateObjectId(jobject object) { JEnv env; jint javaObjectID = env.CallStaticIntMethod(PlatformClass, GET_OR_CREATE_JAVA_OBJECT_ID_METHOD_ID, object); return javaObjectID; }
void NativeScriptRuntime::APP_FAIL(const char *message) { //ASSERT_FAIL(message); JEnv env; jstring msg = env.NewStringUTF(message); env.CallStaticVoidMethod(PlatformClass, APP_FAIL_METHOD_ID, msg); }
JniLocalRef::~JniLocalRef() { if ((m_obj != nullptr) && !m_isWeak) { JEnv env; env.DeleteLocalRef(m_obj); } }
void NativeScriptRuntime::RequireCallback(const v8::FunctionCallbackInfo<v8::Value>& args) { SET_PROFILER_FRAME(); ASSERT_MESSAGE(args.Length() == 2, "require should be called with two parameters"); ASSERT_MESSAGE(!args[0]->IsUndefined() && !args[0]->IsNull(), "require called with undefined moduleName parameter"); ASSERT_MESSAGE(!args[1]->IsUndefined() && !args[1]->IsNull(), "require called with undefined callingModulePath parameter"); ASSERT_MESSAGE(args[0]->IsString(), "require should be called with string parameter"); ASSERT_MESSAGE(args[1]->IsString(), "require should be called with string parameter"); string moduleName = ConvertToString(args[0].As<String>()); string callingModuleDirName = ConvertToString(args[1].As<String>()); JEnv env; JniLocalRef jsModulename(env.NewStringUTF(moduleName.c_str())); JniLocalRef jsCallingModuleDirName(env.NewStringUTF(callingModuleDirName.c_str())); JniLocalRef jsModulePath(env.CallStaticObjectMethod(RequireClass, GET_MODULE_PATH_METHOD_ID, (jstring) jsModulename, (jstring) jsCallingModuleDirName)); auto isolate = Isolate::GetCurrent(); // 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; } auto it = loadedModules.find(modulePath); Handle<Object> moduleObj; bool hasError = false; if (it == loadedModules.end()) { CompileAndRun(modulePath, hasError, moduleObj, false/*is bootstrap call*/); } else { moduleObj = Local<Object>::New(isolate, *((*it).second)); } if(!hasError){ args.GetReturnValue().Set(moduleObj); } }
int NativeScriptRuntime::GetArrayLength(const Local<Object>& arr) { JEnv env; auto javaArr = reinterpret_cast<jarray>(objectManager->GetJavaObjectByJsObject(arr)); auto length = env.GetArrayLength(javaArr); return length; }
jweak ObjectManager::NewWeakGlobalRefCallback(const int& javaObjectID, void *state) { ObjectManager *objManager = reinterpret_cast<ObjectManager*>(state); JniLocalRef obj(objManager->GetJavaObjectByIDImpl(javaObjectID)); JEnv env; jweak weakRef = env.NewWeakGlobalRef(obj); return weakRef; }
string ObjectManager::GetClassName(jclass clazz) { JEnv env; JniLocalRef javaCanonicalName(env.CallObjectMethod(clazz, GET_NAME_METHOD_ID)); string className = ArgConverter::jstringToString(javaCanonicalName); std::replace(className.begin(), className.end(), '.', '/'); return className; }
void Module::Init(Isolate *isolate) { JEnv env; MODULE_CLASS = env.FindClass("com/tns/Module"); assert(MODULE_CLASS != nullptr); RESOLVE_PATH_METHOD_ID = env.GetStaticMethodID(MODULE_CLASS, "resolvePath", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"); assert(RESOLVE_PATH_METHOD_ID != nullptr); string requireFactoryScript = "(function () { " " function require_factory(requireInternal, dirName) { " " return function require(modulePath) { " " if(global.__requireOverride) { " " var result = global.__requireOverride(modulePath, dirName); " " if(result) { " " return result; " " } " " } " " return requireInternal(modulePath, dirName); " " } " " } " " return require_factory; " "})()"; auto source = ConvertToV8String(requireFactoryScript); auto context = isolate->GetCurrentContext(); Local<Script> script; auto maybeScript = Script::Compile(context, source).ToLocal(&script); assert(!script.IsEmpty()); Local<Value> result; auto maybeResult = script->Run(context).ToLocal(&result); assert(!result.IsEmpty() && result->IsFunction()); auto requireFactoryFunction = result.As<Function>(); auto cache = GetCache(isolate); cache->RequireFactoryFunction = new Persistent<Function>(isolate, requireFactoryFunction); auto requireFuncTemplate = FunctionTemplate::New(isolate, RequireCallback); auto requireFunc = requireFuncTemplate->GetFunction(); cache->RequireFunction = new Persistent<Function>(isolate, requireFunc); auto global = isolate->GetCurrentContext()->Global(); auto globalRequire = GetRequireFunction(isolate, Constants::APP_ROOT_FOLDER_PATH); global->Set(ConvertToV8String("require"), globalRequire); }
void NativeScriptRuntime::DumpReferenceTablesMethodCallback(const v8::FunctionCallbackInfo<v8::Value>& args) { JEnv env; jclass vmDbgClass = env.FindClass("dalvik/system/VMDebug"); if (vmDbgClass != nullptr) { jmethodID mid = env.GetStaticMethodID(vmDbgClass, "dumpReferenceTables", "()V"); if (mid != 0) { env.CallStaticVoidMethod(vmDbgClass, mid); } } }
bool NativeScriptRuntime::RegisterInstance(const Handle<Object>& jsObject, const std::string& fullClassName, const ArgsWrapper& argWrapper, const Handle<Object>& implementationObject, bool isInterface) { bool success; DEBUG_WRITE("RegisterInstance called for '%s'", fullClassName.c_str()); if(fullClassName == "java/lang/Object_") { int a = 5; } JEnv env; // get class from implementation object if you can jclass generatedJavaClass = nullptr; bool classIsResolved = false; if (!implementationObject.IsEmpty()) { Local < Value > val = implementationObject->GetHiddenValue(ConvertToV8String(fullClassName)); if (!val.IsEmpty()) { void* voidPointerToVal = val.As<External>()->Value(); generatedJavaClass = reinterpret_cast<jclass>(voidPointerToVal); classIsResolved = true; } } if(!classIsResolved) { generatedJavaClass = ResolveClass(fullClassName, implementationObject); } int javaObjectID = objectManager->GenerateNewObjectID(); DEBUG_WRITE("RegisterInstance: Linking new instance"); objectManager->Link(jsObject, javaObjectID, nullptr); jobject instance = CreateJavaInstance(javaObjectID, fullClassName, argWrapper, generatedJavaClass, isInterface); JniLocalRef localInstance(instance); success = !localInstance.IsNull(); if (success) { DEBUG_WRITE("RegisterInstance: Updating linked instance with its real class"); jclass instanceClass = env.FindClass(fullClassName); objectManager->SetJavaClass(jsObject, instanceClass); } else { DEBUG_WRITE("RegisterInstance failed with null new instance"); } return success; }
ObjectManager::ObjectManager() : m_numberOfGC(0), m_currentObjectId(0), m_cache(NewWeakGlobalRefCallback, DeleteWeakGlobalRefCallback, 1000, this) { JEnv env; PlatformClass = env.FindClass("com/tns/Platform"); assert(PlatformClass != nullptr); GET_JAVAOBJECT_BY_ID_METHOD_ID = env.GetStaticMethodID(PlatformClass, "getJavaObjectByID", "(I)Ljava/lang/Object;"); assert(GET_JAVAOBJECT_BY_ID_METHOD_ID != nullptr); GET_OR_CREATE_JAVA_OBJECT_ID_METHOD_ID = env.GetStaticMethodID(PlatformClass, "getOrCreateJavaObjectID", "(Ljava/lang/Object;)I"); assert(GET_OR_CREATE_JAVA_OBJECT_ID_METHOD_ID != nullptr); MAKE_INSTANCE_WEAK_BATCH_METHOD_ID = env.GetStaticMethodID(PlatformClass, "makeInstanceWeak", "(Ljava/nio/ByteBuffer;IZ)V"); assert(MAKE_INSTANCE_WEAK_BATCH_METHOD_ID != nullptr); CHECK_WEAK_OBJECTS_ARE_ALIVE_METHOD_ID = env.GetStaticMethodID(PlatformClass, "checkWeakObjectAreAlive", "(Ljava/nio/ByteBuffer;Ljava/nio/ByteBuffer;I)V"); assert(CHECK_WEAK_OBJECTS_ARE_ALIVE_METHOD_ID != nullptr); JAVA_LANG_CLASS = env.FindClass("java/lang/Class"); assert(JAVA_LANG_CLASS != nullptr); GET_NAME_METHOD_ID = env.GetMethodID(JAVA_LANG_CLASS, "getName", "()Ljava/lang/String;"); assert(GET_NAME_METHOD_ID != nullptr); ObjectManager::instance = this; }
/* * * 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) { if (s_jsDebugger == nullptr) { return; } auto json = message.GetJSON(); auto str = ConvertToString(json); JEnv env; JniLocalRef s(env.NewStringUTF(str.c_str())); env.CallVoidMethod(s_jsDebugger, s_EnqueueMessage, (jstring) s); }
void ObjectManager::CheckWeakObjectsAreAlive(const vector<PersistentObjectIdPair>& instances, DirectBuffer& inputBuff, DirectBuffer& outputBuff) { JEnv env; for (const auto& poIdPair : instances) { int javaObjectId = poIdPair.javaObjectId; bool success = inputBuff.Write(javaObjectId); if (!success) { int length = inputBuff.Length(); env.CallStaticVoidMethod(PlatformClass, CHECK_WEAK_OBJECTS_ARE_ALIVE_METHOD_ID, (jobject) inputBuff, (jobject) outputBuff, length); // int *released = outputBuff.GetData(); for (int i = 0; i < length; i++) { bool isReleased = *released++ != 0; if (isReleased) { Persistent<Object> *po = instances[i].po; po->Reset(); } } // inputBuff.Reset(); success = inputBuff.Write(javaObjectId); assert(success); } } int size = inputBuff.Size(); if (size > 0) { env.CallStaticVoidMethod(PlatformClass, CHECK_WEAK_OBJECTS_ARE_ALIVE_METHOD_ID, (jobject) inputBuff, (jobject) outputBuff, size); int *released = outputBuff.GetData(); for (int i = 0; i < size; i++) { bool isReleased = *released++ != 0; if (isReleased) { Persistent<Object> *po = instances[i].po; po->Reset(); } } } }
void NativePlatform::AppInitCallback(const v8::FunctionCallbackInfo<v8::Value>& args) { try { auto isolate = Isolate::GetCurrent(); if (args.Length() != 1) { throw NativeScriptException(string("Application should be initialized with single parameter")); } if (!args[0]->IsObject()) { throw NativeScriptException(string("Application should be initialized with single object parameter containing overridden methods")); } // TODO: find another way to get "com/tns/NativeScriptApplication" metadata (move it to more appropriate place) auto node = MetadataNode::GetOrCreate("com/tns/NativeScriptApplication"); auto appInstance = node->CreateJSWrapper(isolate); DEBUG_WRITE("Application object created id: %d", appInstance->GetIdentityHash()); auto implementationObject = args[0]->ToObject(); implementationObject->SetHiddenValue(V8StringConstants::GetClassImplementationObject(), External::New(isolate, node)); DEBUG_WRITE("Application object implementation object is with id: %d", implementationObject->GetIdentityHash()); implementationObject->SetPrototype(appInstance->GetPrototype()); bool appSuccess = appInstance->SetPrototype(implementationObject); if (!appSuccess) { throw NativeScriptException(string("Application could not be initialized correctly")); } jweak applicationObject = g_objectManager->GetJavaObjectByID(AppJavaObjectID); JEnv env; jclass appClass = env.FindClass("com/tns/NativeScriptApplication"); g_objectManager->Link(appInstance, AppJavaObjectID, appClass); JniLocalRef applicationClass(env.GetObjectClass(applicationObject)); jmethodID setNativeScriptOverridesMethodId = env.GetMethodID((jclass)applicationClass, "setNativeScriptOverrides", "([Ljava/lang/String;)V"); jobjectArray methodOverrides = NativeScriptRuntime::GetMethodOverrides(env, implementationObject); env.CallVoidMethod(applicationObject, setNativeScriptOverridesMethodId, methodOverrides); } catch (NativeScriptException& e) { e.ReThrowToV8(); } catch (exception e) { DEBUG_WRITE("Error: c++ exception: %s", e.what()); } catch (...) { DEBUG_WRITE("Error: c++ exception!"); } }
jclass NativeScriptRuntime::ResolveClass(const std::string& fullClassname, const Handle<Object>& implementationObject) { JEnv env; //get needed arguments in order to load binding JniLocalRef javaFullClassName(env.NewStringUTF(fullClassname.c_str())); jobjectArray methodOverrides = GetMethodOverrides(env, implementationObject); //create or load generated binding (java class) JniLocalRef generatedClass(env.CallStaticObjectMethod(PlatformClass, RESOLVE_CLASS_METHOD_ID, (jstring)javaFullClassName, methodOverrides)); jclass globalRefToGeneratedClass = reinterpret_cast<jclass>(env.NewGlobalRef(generatedClass)); return globalRefToGeneratedClass; }
Local<Value> ArgConverter::jstringToV8String(jstring value) { if (value == nullptr) { return Null(Isolate::GetCurrent()); } JEnv env; auto chars = env.GetStringChars(value, NULL); auto length = env.GetStringLength(value); auto v8String = ConvertToV8String(chars, length); env.ReleaseStringChars(value, chars); return v8String; }
Local<Object> ObjectManager::CreateJSWrapperHelper(jint javaObjectID, const string& typeName, jclass clazz) { auto isolate = Isolate::GetCurrent(); auto className = (clazz != nullptr) ? GetClassName(clazz) : typeName; auto node = MetadataNode::GetOrCreate(className); auto jsWrapper = node->CreateJSWrapper(isolate); JEnv env; auto claz = env.FindClass(className); Link(jsWrapper, javaObjectID, claz); return jsWrapper; }
void NativeScriptRuntime::DisableVerboseLoggingMethodCallback(const v8::FunctionCallbackInfo<v8::Value>& args) { try { tns::LogEnabled = false; JEnv env; env.CallStaticVoidMethod(PlatformClass, DISABLE_VERBOSE_LOGGING_METHOD_ID); } catch (NativeScriptException& e) { e.ReThrowToV8(); } catch (exception e) { DEBUG_WRITE("Error: c++ exception: %s", e.what()); } catch (...) { DEBUG_WRITE("Error: c++ exception!"); } }
JsArgToArrayConverter::~JsArgToArrayConverter() { if (m_argsLen > 0) { JEnv env; int length = m_storedIndexes.size(); for (int i = 0; i < length; i++) { int index = m_storedIndexes[i]; env.DeleteLocalRef(m_argsAsObject[index]); } delete[] m_argsAsObject; } }