From 8335cd66fd2a94d7a32094cc6c401cc7c4c0d840 Mon Sep 17 00:00:00 2001 From: Eduardo Speroni Date: Mon, 1 Dec 2025 14:51:14 -0300 Subject: [PATCH 1/2] fix: improve reThrowToJava exception handling and runtime retrieval logic --- test-app/runtime/src/main/cpp/NativeScriptException.cpp | 9 +++------ test-app/runtime/src/main/cpp/Runtime.cpp | 6 +++--- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/test-app/runtime/src/main/cpp/NativeScriptException.cpp b/test-app/runtime/src/main/cpp/NativeScriptException.cpp index add4c553f..1a2e92303 100644 --- a/test-app/runtime/src/main/cpp/NativeScriptException.cpp +++ b/test-app/runtime/src/main/cpp/NativeScriptException.cpp @@ -75,8 +75,7 @@ void NativeScriptException::ReThrowToJava() { if (!m_javaException.IsNull()) { - auto objectManager = Runtime::GetObjectManager(isolate); - auto excClassName = objectManager->GetClassName((jobject) m_javaException); + auto excClassName = ObjectManager::GetClassName((jobject) m_javaException); if (excClassName == "com/tns/NativeScriptException") { ex = m_javaException; } else { @@ -103,8 +102,7 @@ void NativeScriptException::ReThrowToJava() { if (ex == nullptr) { ex = static_cast(env.NewObject(NATIVESCRIPTEXCEPTION_CLASS, NATIVESCRIPTEXCEPTION_JSVALUE_CTOR_ID, (jstring) msg, (jstring)stackTrace, reinterpret_cast(m_javascriptException))); } else { - auto objectManager = Runtime::GetObjectManager(isolate); - auto excClassName = objectManager->GetClassName(ex); + auto excClassName = ObjectManager::GetClassName(ex); if (excClassName != "com/tns/NativeScriptException") { ex = static_cast(env.NewObject(NATIVESCRIPTEXCEPTION_CLASS, NATIVESCRIPTEXCEPTION_THROWABLE_CTOR_ID, (jstring) msg, (jstring)stackTrace, ex)); } @@ -184,9 +182,8 @@ Local NativeScriptException::WrapJavaToJsException() { JEnv env; auto isolate = Isolate::GetCurrent(); - auto objectManager = Runtime::GetObjectManager(isolate); - string excClassName = objectManager->GetClassName((jobject) m_javaException); + string excClassName = ObjectManager::GetClassName((jobject) m_javaException); if (excClassName == "com/tns/NativeScriptException") { jfieldID fieldID = env.GetFieldID(env.GetObjectClass(m_javaException), "jsValueAddress", "J"); jlong addr = env.GetLongField(m_javaException, fieldID); diff --git a/test-app/runtime/src/main/cpp/Runtime.cpp b/test-app/runtime/src/main/cpp/Runtime.cpp index d972ba5d6..aa5142912 100644 --- a/test-app/runtime/src/main/cpp/Runtime.cpp +++ b/test-app/runtime/src/main/cpp/Runtime.cpp @@ -132,15 +132,15 @@ Runtime* Runtime::GetRuntime(int runtimeId) { } Runtime* Runtime::GetRuntime(v8::Isolate* isolate) { - auto runtime = s_isolate2RuntimesCache.at(isolate); + auto it = s_isolate2RuntimesCache.find(isolate); - if (runtime == nullptr) { + if (it == s_isolate2RuntimesCache.end()) { stringstream ss; ss << "Cannot find runtime for isolate: " << isolate; throw NativeScriptException(ss.str()); } - return runtime; + return it->second; } Runtime* Runtime::GetRuntimeFromIsolateData(v8::Isolate* isolate) { From e3d808dab131ec1c2f13114561fc3f3d2d32b942 Mon Sep 17 00:00:00 2001 From: Eduardo Speroni Date: Mon, 1 Dec 2025 15:28:41 -0300 Subject: [PATCH 2/2] fix: make some ObjectManager methods static --- .../runtime/src/main/cpp/ObjectManager.cpp | 838 ++++++++++-------- test-app/runtime/src/main/cpp/ObjectManager.h | 310 +++---- 2 files changed, 607 insertions(+), 541 deletions(-) diff --git a/test-app/runtime/src/main/cpp/ObjectManager.cpp b/test-app/runtime/src/main/cpp/ObjectManager.cpp index ba01fb8b6..18454156e 100644 --- a/test-app/runtime/src/main/cpp/ObjectManager.cpp +++ b/test-app/runtime/src/main/cpp/ObjectManager.cpp @@ -1,559 +1,615 @@ #include "ObjectManager.h" -#include "NativeScriptAssert.h" -#include "MetadataNode.h" + +#include +#include + #include "ArgConverter.h" +#include "ManualInstrumentation.h" +#include "MetadataNode.h" +#include "NativeScriptAssert.h" +#include "NativeScriptException.h" +#include "Runtime.h" #include "Util.h" #include "V8GlobalHelpers.h" #include "V8StringConstants.h" -#include "NativeScriptException.h" -#include "Runtime.h" #include "include/v8.h" -#include -#include -#include "ManualInstrumentation.h" using namespace v8; using namespace std; using namespace tns; -ObjectManager::ObjectManager(jobject javaRuntimeObject) : - m_javaRuntimeObject(javaRuntimeObject), - m_numberOfGC(0), - m_currentObjectId(0), - m_cache(NewWeakGlobalRefCallback, DeleteWeakGlobalRefCallback, ValidateWeakGlobalRefCallback, 1000, this) { - - JEnv env; - auto runtimeClass = env.FindClass("com/tns/Runtime"); - assert(runtimeClass != nullptr); - - GET_JAVAOBJECT_BY_ID_METHOD_ID = env.GetMethodID(runtimeClass, "getJavaObjectByID", - "(I)Ljava/lang/Object;"); - assert(GET_JAVAOBJECT_BY_ID_METHOD_ID != nullptr); - - GET_OR_CREATE_JAVA_OBJECT_ID_METHOD_ID = env.GetMethodID(runtimeClass, - "getOrCreateJavaObjectID", - "(Ljava/lang/Object;)I"); - assert(GET_OR_CREATE_JAVA_OBJECT_ID_METHOD_ID != nullptr); - - MAKE_INSTANCE_WEAK_BATCH_METHOD_ID = env.GetMethodID(runtimeClass, "makeInstanceWeak", - "(Ljava/nio/ByteBuffer;IZ)V"); - assert(MAKE_INSTANCE_WEAK_BATCH_METHOD_ID != nullptr); - - MAKE_INSTANCE_WEAK_AND_CHECK_IF_ALIVE_METHOD_ID = env.GetMethodID(runtimeClass, - "makeInstanceWeakAndCheckIfAlive", - "(I)Z"); - assert(MAKE_INSTANCE_WEAK_AND_CHECK_IF_ALIVE_METHOD_ID != nullptr); - - RELEASE_NATIVE_INSTANCE_METHOD_ID = env.GetMethodID(runtimeClass, "releaseNativeCounterpart", - "(I)V"); - assert(RELEASE_NATIVE_INSTANCE_METHOD_ID != nullptr); - - CHECK_WEAK_OBJECTS_ARE_ALIVE_METHOD_ID = env.GetMethodID(runtimeClass, - "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); - - auto useGlobalRefsMethodID = env.GetStaticMethodID(runtimeClass, "useGlobalRefs", "()Z"); - assert(useGlobalRefsMethodID != nullptr); - - auto useGlobalRefs = env.CallStaticBooleanMethod(runtimeClass, useGlobalRefsMethodID); - m_useGlobalRefs = useGlobalRefs == JNI_TRUE; - - auto getMarkingModeOrdinalMethodID = env.GetMethodID(runtimeClass, "getMarkingModeOrdinal", - "()I"); - jint markingMode = env.CallIntMethod(m_javaRuntimeObject, getMarkingModeOrdinalMethodID); - m_markingMode = static_cast(markingMode); -} - -void ObjectManager::SetInstanceIsolate(Isolate *isolate) { - m_isolate = isolate; -} - -void ObjectManager::Init(Isolate *isolate) { - auto jsWrapperFuncTemplate = FunctionTemplate::New(isolate, JSWrapperConstructorCallback); - jsWrapperFuncTemplate->InstanceTemplate()->SetInternalFieldCount( - static_cast(MetadataNodeKeys::END)); - auto context = isolate->GetCurrentContext(); - auto jsWrapperFunc = jsWrapperFuncTemplate->GetFunction(context).ToLocalChecked(); - m_poJsWrapperFunc = new Persistent(isolate, jsWrapperFunc); -} - - -JniLocalRef ObjectManager::GetJavaObjectByJsObject(const Local &object) { - JSInstanceInfo *jsInstanceInfo = GetJSInstanceInfo(object); - - if (jsInstanceInfo != nullptr) { - if (m_useGlobalRefs) { - JniLocalRef javaObject(GetJavaObjectByID(jsInstanceInfo->JavaObjectID), true); - return javaObject; - } else { - JEnv env; - JniLocalRef javaObject( - env.NewLocalRef(GetJavaObjectByID(jsInstanceInfo->JavaObjectID))); - return javaObject; - } +ObjectManager::ObjectManager(jobject javaRuntimeObject) + : m_javaRuntimeObject(javaRuntimeObject), + m_numberOfGC(0), + m_currentObjectId(0), + m_cache(NewWeakGlobalRefCallback, DeleteWeakGlobalRefCallback, + ValidateWeakGlobalRefCallback, 1000, this) { + JEnv env; + InitializeJNI(); + + auto runtimeClass = env.FindClass("com/tns/Runtime"); + assert(runtimeClass != nullptr); + + auto useGlobalRefsMethodID = + env.GetStaticMethodID(runtimeClass, "useGlobalRefs", "()Z"); + assert(useGlobalRefsMethodID != nullptr); + + auto useGlobalRefs = + env.CallStaticBooleanMethod(runtimeClass, useGlobalRefsMethodID); + m_useGlobalRefs = useGlobalRefs == JNI_TRUE; + + auto getMarkingModeOrdinalMethodID = + env.GetMethodID(runtimeClass, "getMarkingModeOrdinal", "()I"); + jint markingMode = + env.CallIntMethod(m_javaRuntimeObject, getMarkingModeOrdinalMethodID); + m_markingMode = static_cast(markingMode); +} + +void ObjectManager::InitializeJNI() { + if (GET_JAVAOBJECT_BY_ID_METHOD_ID != nullptr) { + return; + } + JEnv env; + auto runtimeClass = env.FindClass("com/tns/Runtime"); + assert(runtimeClass != nullptr); + GET_JAVAOBJECT_BY_ID_METHOD_ID = env.GetMethodID( + runtimeClass, "getJavaObjectByID", "(I)Ljava/lang/Object;"); + assert(GET_JAVAOBJECT_BY_ID_METHOD_ID != nullptr); + + GET_OR_CREATE_JAVA_OBJECT_ID_METHOD_ID = env.GetMethodID( + runtimeClass, "getOrCreateJavaObjectID", "(Ljava/lang/Object;)I"); + assert(GET_OR_CREATE_JAVA_OBJECT_ID_METHOD_ID != nullptr); + + MAKE_INSTANCE_WEAK_BATCH_METHOD_ID = env.GetMethodID( + runtimeClass, "makeInstanceWeak", "(Ljava/nio/ByteBuffer;IZ)V"); + assert(MAKE_INSTANCE_WEAK_BATCH_METHOD_ID != nullptr); + + MAKE_INSTANCE_WEAK_AND_CHECK_IF_ALIVE_METHOD_ID = + env.GetMethodID(runtimeClass, "makeInstanceWeakAndCheckIfAlive", "(I)Z"); + assert(MAKE_INSTANCE_WEAK_AND_CHECK_IF_ALIVE_METHOD_ID != nullptr); + + RELEASE_NATIVE_INSTANCE_METHOD_ID = + env.GetMethodID(runtimeClass, "releaseNativeCounterpart", "(I)V"); + assert(RELEASE_NATIVE_INSTANCE_METHOD_ID != nullptr); + + CHECK_WEAK_OBJECTS_ARE_ALIVE_METHOD_ID = + env.GetMethodID(runtimeClass, "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); +} + +void ObjectManager::SetInstanceIsolate(Isolate* isolate) { + m_isolate = isolate; +} + +void ObjectManager::Init(Isolate* isolate) { + auto jsWrapperFuncTemplate = + FunctionTemplate::New(isolate, JSWrapperConstructorCallback); + jsWrapperFuncTemplate->InstanceTemplate()->SetInternalFieldCount( + static_cast(MetadataNodeKeys::END)); + auto context = isolate->GetCurrentContext(); + auto jsWrapperFunc = + jsWrapperFuncTemplate->GetFunction(context).ToLocalChecked(); + m_poJsWrapperFunc = new Persistent(isolate, jsWrapperFunc); +} + +JniLocalRef ObjectManager::GetJavaObjectByJsObject( + const Local& object) { + JSInstanceInfo* jsInstanceInfo = GetJSInstanceInfo(object); + + if (jsInstanceInfo != nullptr) { + if (m_useGlobalRefs) { + JniLocalRef javaObject(GetJavaObjectByID(jsInstanceInfo->JavaObjectID), + true); + return javaObject; + } else { + JEnv env; + JniLocalRef javaObject( + env.NewLocalRef(GetJavaObjectByID(jsInstanceInfo->JavaObjectID))); + return javaObject; } + } - return JniLocalRef(); + return JniLocalRef(); } -ObjectManager::JSInstanceInfo *ObjectManager::GetJSInstanceInfo(const Local &object) { - JSInstanceInfo *jsInstanceInfo = nullptr; - if (IsJsRuntimeObject(object)) { - return GetJSInstanceInfoFromRuntimeObject(object); - } - return nullptr; +ObjectManager::JSInstanceInfo* ObjectManager::GetJSInstanceInfo( + const Local& object) { + JSInstanceInfo* jsInstanceInfo = nullptr; + if (IsJsRuntimeObject(object)) { + return GetJSInstanceInfoFromRuntimeObject(object); + } + return nullptr; } -ObjectManager::JSInstanceInfo * -ObjectManager::GetJSInstanceInfoFromRuntimeObject(const Local &object) { - HandleScope handleScope(m_isolate); +ObjectManager::JSInstanceInfo* +ObjectManager::GetJSInstanceInfoFromRuntimeObject(const Local& object) { + HandleScope handleScope(m_isolate); - const int jsInfoIdx = static_cast(MetadataNodeKeys::JsInfo); - auto jsInfo = object->GetInternalField(jsInfoIdx); - if (jsInfo->IsUndefined()) { - //Typescript object layout has an object instance as child of the actual registered instance. checking for that - auto prototypeObject = object->GetPrototype().As(); + const int jsInfoIdx = static_cast(MetadataNodeKeys::JsInfo); + auto jsInfo = object->GetInternalField(jsInfoIdx); + if (jsInfo->IsUndefined()) { + // Typescript object layout has an object instance as child of the actual + // registered instance. checking for that + auto prototypeObject = object->GetPrototype().As(); - if (!prototypeObject.IsEmpty() && prototypeObject->IsObject()) { - DEBUG_WRITE("GetJSInstanceInfo: need to check prototype :%d", - prototypeObject->GetIdentityHash()); - if (IsJsRuntimeObject(prototypeObject)) { - jsInfo = prototypeObject->GetInternalField(jsInfoIdx); - } - } + if (!prototypeObject.IsEmpty() && prototypeObject->IsObject()) { + DEBUG_WRITE("GetJSInstanceInfo: need to check prototype :%d", + prototypeObject->GetIdentityHash()); + if (IsJsRuntimeObject(prototypeObject)) { + jsInfo = prototypeObject->GetInternalField(jsInfoIdx); + } } + } - if (!jsInfo.IsEmpty() && jsInfo->IsExternal()) { - auto external = jsInfo.As(); - return static_cast(external->Value()); - } + if (!jsInfo.IsEmpty() && jsInfo->IsExternal()) { + auto external = jsInfo.As(); + return static_cast(external->Value()); + } - return nullptr; + return nullptr; } -bool ObjectManager::IsJsRuntimeObject(const v8::Local &object) { - int internalFieldCount = object->InternalFieldCount(); - const int count = static_cast(MetadataNodeKeys::END); - return internalFieldCount == count; +bool ObjectManager::IsJsRuntimeObject(const v8::Local& object) { + int internalFieldCount = object->InternalFieldCount(); + const int count = static_cast(MetadataNodeKeys::END); + return internalFieldCount == count; } jweak ObjectManager::GetJavaObjectByID(uint32_t javaObjectID) { - jweak obj = m_cache(javaObjectID); + jweak obj = m_cache(javaObjectID); - return obj; + return obj; } jobject ObjectManager::GetJavaObjectByIDImpl(uint32_t javaObjectID) { - JEnv env; - jobject object = env.CallObjectMethod(m_javaRuntimeObject, GET_JAVAOBJECT_BY_ID_METHOD_ID, - javaObjectID); - return object; + JEnv env; + jobject object = env.CallObjectMethod( + m_javaRuntimeObject, GET_JAVAOBJECT_BY_ID_METHOD_ID, javaObjectID); + return object; } void ObjectManager::UpdateCache(int objectID, jobject obj) { - m_cache.update(objectID, obj); + m_cache.update(objectID, obj); } -jclass ObjectManager::GetJavaClass(const Local &instance) { - DEBUG_WRITE("GetClass called"); +jclass ObjectManager::GetJavaClass(const Local& instance) { + DEBUG_WRITE("GetClass called"); - JSInstanceInfo *jsInfo = GetJSInstanceInfo(instance); - jclass clazz = jsInfo->ObjectClazz; + JSInstanceInfo* jsInfo = GetJSInstanceInfo(instance); + jclass clazz = jsInfo->ObjectClazz; - return clazz; + return clazz; } -void ObjectManager::SetJavaClass(const Local &instance, jclass clazz) { - JSInstanceInfo *jsInfo = GetJSInstanceInfo(instance); - jsInfo->ObjectClazz = clazz; +void ObjectManager::SetJavaClass(const Local& instance, jclass clazz) { + JSInstanceInfo* jsInfo = GetJSInstanceInfo(instance); + jsInfo->ObjectClazz = clazz; } int ObjectManager::GetOrCreateObjectId(jobject object) { - JEnv env; - jint javaObjectID = env.CallIntMethod(m_javaRuntimeObject, - GET_OR_CREATE_JAVA_OBJECT_ID_METHOD_ID, object); + JEnv env; + jint javaObjectID = env.CallIntMethod( + m_javaRuntimeObject, GET_OR_CREATE_JAVA_OBJECT_ID_METHOD_ID, object); - return javaObjectID; + return javaObjectID; } Local ObjectManager::GetJsObjectByJavaObject(int javaObjectID) { - auto isolate = m_isolate; - EscapableHandleScope handleScope(isolate); + auto isolate = m_isolate; + EscapableHandleScope handleScope(isolate); - auto it = m_idToObject.find(javaObjectID); - if (it == m_idToObject.end()) { - return handleScope.Escape(Local()); - } + auto it = m_idToObject.find(javaObjectID); + if (it == m_idToObject.end()) { + return handleScope.Escape(Local()); + } - Persistent *jsObject = it->second; + Persistent* jsObject = it->second; - auto localObject = Local::New(isolate, *jsObject); - return handleScope.Escape(localObject); + auto localObject = Local::New(isolate, *jsObject); + return handleScope.Escape(localObject); } - -Local ObjectManager::CreateJSWrapper(jint javaObjectID, const string &typeName) { - return CreateJSWrapperHelper(javaObjectID, typeName, nullptr); +Local ObjectManager::CreateJSWrapper(jint javaObjectID, + const string& typeName) { + return CreateJSWrapperHelper(javaObjectID, typeName, nullptr); } -Local -ObjectManager::CreateJSWrapper(jint javaObjectID, const string &typeName, jobject instance) { - JEnv env; - JniLocalRef clazz(env.GetObjectClass(instance)); +Local ObjectManager::CreateJSWrapper(jint javaObjectID, + const string& typeName, + jobject instance) { + JEnv env; + JniLocalRef clazz(env.GetObjectClass(instance)); - return CreateJSWrapperHelper(javaObjectID, typeName, clazz); + return CreateJSWrapperHelper(javaObjectID, typeName, clazz); } -Local -ObjectManager::CreateJSWrapperHelper(jint javaObjectID, const string &typeName, jclass clazz) { - auto isolate = m_isolate; +Local ObjectManager::CreateJSWrapperHelper(jint javaObjectID, + const string& typeName, + jclass clazz) { + auto isolate = m_isolate; - auto className = (clazz != nullptr) ? GetClassName(clazz) : typeName; + auto className = (clazz != nullptr) ? GetClassName(clazz) : typeName; - auto node = MetadataNode::GetOrCreate(className); + auto node = MetadataNode::GetOrCreate(className); - auto jsWrapper = node->CreateJSWrapper(isolate, this); + auto jsWrapper = node->CreateJSWrapper(isolate, this); - if (!jsWrapper.IsEmpty()) { - JEnv env; - auto claz = env.FindClass(className); - Link(jsWrapper, javaObjectID, claz); - } - return jsWrapper; + if (!jsWrapper.IsEmpty()) { + JEnv env; + auto claz = env.FindClass(className); + Link(jsWrapper, javaObjectID, claz); + } + return jsWrapper; } - /* * * Link the JavaScript object and it's java counterpart with an ID */ -void ObjectManager::Link(const Local &object, uint32_t javaObjectID, jclass clazz) { - if (!IsJsRuntimeObject(object)) { - string errMsg("Trying to link invalid 'this' to a Java object"); - throw NativeScriptException(errMsg); - } +void ObjectManager::Link(const Local& object, uint32_t javaObjectID, + jclass clazz) { + if (!IsJsRuntimeObject(object)) { + string errMsg("Trying to link invalid 'this' to a Java object"); + throw NativeScriptException(errMsg); + } - auto isolate = m_isolate; + auto isolate = m_isolate; - DEBUG_WRITE("Linking js object: %d and java instance id: %d", object->GetIdentityHash(), - javaObjectID); + DEBUG_WRITE("Linking js object: %d and java instance id: %d", + object->GetIdentityHash(), javaObjectID); - auto jsInstanceInfo = new JSInstanceInfo(false/*isJavaObjWeak*/, javaObjectID, clazz); + auto jsInstanceInfo = + new JSInstanceInfo(false /*isJavaObjWeak*/, javaObjectID, clazz); - auto objectHandle = new Persistent(isolate, object); - auto state = new ObjectWeakCallbackState(this, jsInstanceInfo, objectHandle); + auto objectHandle = new Persistent(isolate, object); + auto state = new ObjectWeakCallbackState(this, jsInstanceInfo, objectHandle); - // subscribe for JS GC event - if (m_markingMode == JavaScriptMarkingMode::None) { - objectHandle->SetWeak(state, JSObjectFinalizerStatic, WeakCallbackType::kFinalizer); - } else { - objectHandle->SetWeak(state, JSObjectWeakCallbackStatic, WeakCallbackType::kFinalizer); - } + // subscribe for JS GC event + if (m_markingMode == JavaScriptMarkingMode::None) { + objectHandle->SetWeak(state, JSObjectFinalizerStatic, + WeakCallbackType::kFinalizer); + } else { + objectHandle->SetWeak(state, JSObjectWeakCallbackStatic, + WeakCallbackType::kFinalizer); + } - auto jsInfoIdx = static_cast(MetadataNodeKeys::JsInfo); + auto jsInfoIdx = static_cast(MetadataNodeKeys::JsInfo); - auto jsInfo = External::New(isolate, jsInstanceInfo); + auto jsInfo = External::New(isolate, jsInstanceInfo); - //link - object->SetInternalField(jsInfoIdx, jsInfo); + // link + object->SetInternalField(jsInfoIdx, jsInfo); - m_idToObject.emplace(javaObjectID, objectHandle); + m_idToObject.emplace(javaObjectID, objectHandle); } -bool ObjectManager::CloneLink(const Local &src, const Local &dest) { - auto jsInfo = GetJSInstanceInfo(src); +bool ObjectManager::CloneLink(const Local& src, + const Local& dest) { + auto jsInfo = GetJSInstanceInfo(src); - auto success = jsInfo != nullptr; + auto success = jsInfo != nullptr; - if (success) { - auto jsInfoIdx = static_cast(MetadataNodeKeys::JsInfo); - auto jsInfo = src->GetInternalField(jsInfoIdx); - dest->SetInternalField(jsInfoIdx, jsInfo); - } + if (success) { + auto jsInfoIdx = static_cast(MetadataNodeKeys::JsInfo); + auto jsInfo = src->GetInternalField(jsInfoIdx); + dest->SetInternalField(jsInfoIdx, jsInfo); + } - return success; + return success; } string ObjectManager::GetClassName(jobject javaObject) { - JEnv env; - JniLocalRef objectClass(env.GetObjectClass(javaObject)); + InitializeJNI(); + JEnv env; + JniLocalRef objectClass(env.GetObjectClass(javaObject)); - return GetClassName((jclass) objectClass); + return GetClassName((jclass)objectClass); } string ObjectManager::GetClassName(jclass clazz) { - JEnv env; - JniLocalRef javaCanonicalName(env.CallObjectMethod(clazz, GET_NAME_METHOD_ID)); + InitializeJNI(); + JEnv env; + JniLocalRef javaCanonicalName( + env.CallObjectMethod(clazz, GET_NAME_METHOD_ID)); - string className = ArgConverter::jstringToString(javaCanonicalName); + string className = ArgConverter::jstringToString(javaCanonicalName); - std::replace(className.begin(), className.end(), '.', '/'); + std::replace(className.begin(), className.end(), '.', '/'); - return className; + return className; } -void -ObjectManager::JSObjectWeakCallbackStatic(const WeakCallbackInfo &data) { - ObjectWeakCallbackState *callbackState = data.GetParameter(); +void ObjectManager::JSObjectWeakCallbackStatic( + const WeakCallbackInfo& data) { + ObjectWeakCallbackState* callbackState = data.GetParameter(); - ObjectManager *thisPtr = callbackState->thisPtr; + ObjectManager* thisPtr = callbackState->thisPtr; - auto isolate = data.GetIsolate(); + auto isolate = data.GetIsolate(); - thisPtr->JSObjectWeakCallback(isolate, callbackState); + thisPtr->JSObjectWeakCallback(isolate, callbackState); } -void ObjectManager::JSObjectFinalizerStatic(const WeakCallbackInfo &data) { - ObjectWeakCallbackState *callbackState = data.GetParameter(); +void ObjectManager::JSObjectFinalizerStatic( + const WeakCallbackInfo& data) { + ObjectWeakCallbackState* callbackState = data.GetParameter(); - ObjectManager *thisPtr = callbackState->thisPtr; + ObjectManager* thisPtr = callbackState->thisPtr; - auto isolate = data.GetIsolate(); + auto isolate = data.GetIsolate(); - thisPtr->JSObjectFinalizer(isolate, callbackState); + thisPtr->JSObjectFinalizer(isolate, callbackState); } -void ObjectManager::JSObjectFinalizer(Isolate *isolate, ObjectWeakCallbackState *callbackState) { - HandleScope handleScope(m_isolate); - Persistent *po = callbackState->target; - auto jsInstanceInfo = GetJSInstanceInfoFromRuntimeObject(po->Get(m_isolate)); - - if (jsInstanceInfo == nullptr) { - po->Reset(); - delete po; - delete callbackState; - return; - } +void ObjectManager::JSObjectFinalizer(Isolate* isolate, + ObjectWeakCallbackState* callbackState) { + HandleScope handleScope(m_isolate); + Persistent* po = callbackState->target; + auto jsInstanceInfo = GetJSInstanceInfoFromRuntimeObject(po->Get(m_isolate)); - auto javaObjectID = jsInstanceInfo->JavaObjectID; - JEnv env; - jboolean isJavaInstanceAlive = env.CallBooleanMethod(m_javaRuntimeObject, - MAKE_INSTANCE_WEAK_AND_CHECK_IF_ALIVE_METHOD_ID, - javaObjectID); - if (isJavaInstanceAlive) { - // If the Java instance is alive, keep the JavaScript instance alive. - po->SetWeak(callbackState, JSObjectFinalizerStatic, WeakCallbackType::kFinalizer); - } else { - // If the Java instance is dead, this JavaScript instance can be let die. - delete jsInstanceInfo; - auto jsInfoIdx = static_cast(MetadataNodeKeys::JsInfo); - po->Get(m_isolate)->SetInternalField(jsInfoIdx, Undefined(m_isolate)); - po->Reset(); - m_idToObject.erase(javaObjectID); - delete po; - delete callbackState; - } + if (jsInstanceInfo == nullptr) { + po->Reset(); + delete po; + delete callbackState; + return; + } + + auto javaObjectID = jsInstanceInfo->JavaObjectID; + JEnv env; + jboolean isJavaInstanceAlive = env.CallBooleanMethod( + m_javaRuntimeObject, MAKE_INSTANCE_WEAK_AND_CHECK_IF_ALIVE_METHOD_ID, + javaObjectID); + if (isJavaInstanceAlive) { + // If the Java instance is alive, keep the JavaScript instance alive. + po->SetWeak(callbackState, JSObjectFinalizerStatic, + WeakCallbackType::kFinalizer); + } else { + // If the Java instance is dead, this JavaScript instance can be let die. + delete jsInstanceInfo; + auto jsInfoIdx = static_cast(MetadataNodeKeys::JsInfo); + po->Get(m_isolate)->SetInternalField(jsInfoIdx, Undefined(m_isolate)); + po->Reset(); + m_idToObject.erase(javaObjectID); + delete po; + delete callbackState; + } } - /* - * When JS GC happens change state of the java counterpart to mirror state of JS object and REVIVE the JS object unconditionally - * "Regular" js objects are pushed into the "regular objects" array - * "Callback" js objects (ones that have implementation object) are pushed into two "special objects" array: - * -ones called for the first time which are originally strong in java - * -ones called for the second or next time which are already weak in java too - * These objects are categorized by "regular" and "callback" and saved in different arrays for performance optimizations during GC + * When JS GC happens change state of the java counterpart to mirror state of JS + * object and REVIVE the JS object unconditionally "Regular" js objects are + * pushed into the "regular objects" array "Callback" js objects (ones that have + * implementation object) are pushed into two "special objects" array: -ones + * called for the first time which are originally strong in java -ones called + * for the second or next time which are already weak in java too These objects + * are categorized by "regular" and "callback" and saved in different arrays for + * performance optimizations during GC * */ -void ObjectManager::JSObjectWeakCallback(Isolate *isolate, ObjectWeakCallbackState *callbackState) { - HandleScope handleScope(isolate); - - Persistent *po = callbackState->target; - - auto itFound = m_visitedPOs.find(po); - - if (itFound == m_visitedPOs.end()) { - m_visitedPOs.insert(po); - - auto obj = Local::New(isolate, *po); - JSInstanceInfo *jsInstanceInfo = GetJSInstanceInfo(obj); - - if(jsInstanceInfo != nullptr){ - int javaObjectID = jsInstanceInfo->JavaObjectID; - - bool hasImplObj = HasImplObject(isolate, obj); - - DEBUG_WRITE("JSObjectWeakCallback objectId: %d, hasImplObj=%d", javaObjectID, hasImplObj); - - if (hasImplObj) { - if (jsInstanceInfo->IsJavaObjectWeak) { - m_implObjWeak.emplace_back(po, javaObjectID); - } else { - m_implObjStrong.emplace(javaObjectID, po); - jsInstanceInfo->IsJavaObjectWeak = true; - } - } else { - if(m_markedForGC.empty()){ - // Emulates the behavior in the OnGcStarted callback. Тhis is necessary as the hooking - // to the V8 GC is done only on the markSweepCompact phase. The JSObjectWeakCallback - // however is still triggered in other V8 GC phases (scavenger for example). This - // creates a problem that there is no 'top' on the m_markedForGC stack. - GarbageCollectionInfo gcInfo(++m_numberOfGC); - gcInfo.markedForGC.push_back(po); - m_markedForGC.push(gcInfo); - } else { - auto &topGCInfo = m_markedForGC.top(); - topGCInfo.markedForGC.push_back(po); - } - } +void ObjectManager::JSObjectWeakCallback( + Isolate* isolate, ObjectWeakCallbackState* callbackState) { + HandleScope handleScope(isolate); + + Persistent* po = callbackState->target; + + auto itFound = m_visitedPOs.find(po); + + if (itFound == m_visitedPOs.end()) { + m_visitedPOs.insert(po); + + auto obj = Local::New(isolate, *po); + JSInstanceInfo* jsInstanceInfo = GetJSInstanceInfo(obj); + + if (jsInstanceInfo != nullptr) { + int javaObjectID = jsInstanceInfo->JavaObjectID; + + bool hasImplObj = HasImplObject(isolate, obj); + + DEBUG_WRITE("JSObjectWeakCallback objectId: %d, hasImplObj=%d", + javaObjectID, hasImplObj); + + if (hasImplObj) { + if (jsInstanceInfo->IsJavaObjectWeak) { + m_implObjWeak.emplace_back(po, javaObjectID); + } else { + m_implObjStrong.emplace(javaObjectID, po); + jsInstanceInfo->IsJavaObjectWeak = true; } + } else { + if (m_markedForGC.empty()) { + // Emulates the behavior in the OnGcStarted callback. Тhis is + // necessary as the hooking to the V8 GC is done only on the + // markSweepCompact phase. The JSObjectWeakCallback however is still + // triggered in other V8 GC phases (scavenger for example). This + // creates a problem that there is no 'top' on the m_markedForGC + // stack. + GarbageCollectionInfo gcInfo(++m_numberOfGC); + gcInfo.markedForGC.push_back(po); + m_markedForGC.push(gcInfo); + } else { + auto& topGCInfo = m_markedForGC.top(); + topGCInfo.markedForGC.push_back(po); + } + } } + } - po->SetWeak(callbackState, JSObjectWeakCallbackStatic, WeakCallbackType::kFinalizer); + po->SetWeak(callbackState, JSObjectWeakCallbackStatic, + WeakCallbackType::kFinalizer); } int ObjectManager::GenerateNewObjectID() { - const int one = 1; - int oldValue = __sync_fetch_and_add(&m_currentObjectId, one); + const int one = 1; + int oldValue = __sync_fetch_and_add(&m_currentObjectId, one); - return oldValue; + return oldValue; } -void ObjectManager::ReleaseJSInstance(Persistent *po, JSInstanceInfo *jsInstanceInfo) { - int javaObjectID = jsInstanceInfo->JavaObjectID; +void ObjectManager::ReleaseJSInstance(Persistent* po, + JSInstanceInfo* jsInstanceInfo) { + int javaObjectID = jsInstanceInfo->JavaObjectID; - auto it = m_idToObject.find(javaObjectID); + auto it = m_idToObject.find(javaObjectID); - if (it == m_idToObject.end()) { - stringstream ss; - ss << "(InternalError): Js object with id: " << javaObjectID << " not found"; - throw NativeScriptException(ss.str()); - } + if (it == m_idToObject.end()) { + stringstream ss; + ss << "(InternalError): Js object with id: " << javaObjectID + << " not found"; + throw NativeScriptException(ss.str()); + } - assert(po == it->second); + assert(po == it->second); - m_idToObject.erase(it); - m_released.insert(po, javaObjectID); - po->Reset(); + m_idToObject.erase(it); + m_released.insert(po, javaObjectID); + po->Reset(); - delete po; - delete jsInstanceInfo; + delete po; + delete jsInstanceInfo; - DEBUG_WRITE("ReleaseJSObject instance disposed. id:%d", javaObjectID); + DEBUG_WRITE("ReleaseJSObject instance disposed. id:%d", javaObjectID); } /* - * The "regular" JS objects added on ObjectManager::JSObjectWeakCallback are dealt with(released) here. + * The "regular" JS objects added on ObjectManager::JSObjectWeakCallback are + * dealt with(released) here. * */ void ObjectManager::ReleaseRegularObjects() { - TNSPERF(); + TNSPERF(); - HandleScope handleScope(m_isolate); + HandleScope handleScope(m_isolate); - auto propName = String::NewFromUtf8(m_isolate, "t::gcNum", - NewStringType::kNormal).ToLocalChecked(); + auto propName = + String::NewFromUtf8(m_isolate, "t::gcNum", NewStringType::kNormal) + .ToLocalChecked(); - auto &topGCInfo = m_markedForGC.top(); - auto &marked = topGCInfo.markedForGC; - int numberOfGC = topGCInfo.numberOfGC; + auto& topGCInfo = m_markedForGC.top(); + auto& marked = topGCInfo.markedForGC; + int numberOfGC = topGCInfo.numberOfGC; - for (auto po : marked) { - if (m_released.contains(po)) { - continue; - } + for (auto po : marked) { + if (m_released.contains(po)) { + continue; + } - auto obj = Local::New(m_isolate, *po); + auto obj = Local::New(m_isolate, *po); - assert(!obj.IsEmpty()); + assert(!obj.IsEmpty()); - Local gcNum; - V8GetPrivateValue(m_isolate, obj, propName, gcNum); + Local gcNum; + V8GetPrivateValue(m_isolate, obj, propName, gcNum); - bool isReachableFromImplementationObject = false; + bool isReachableFromImplementationObject = false; - if (!gcNum.IsEmpty() && gcNum->IsNumber()) { - double objGcNum = gcNum.As()->Value(); + if (!gcNum.IsEmpty() && gcNum->IsNumber()) { + double objGcNum = gcNum.As()->Value(); - // done so we can release only java objects from this GC stack and pass all objects that will be released in parent GC stacks - isReachableFromImplementationObject = objGcNum >= numberOfGC; - } + // done so we can release only java objects from this GC stack and pass + // all objects that will be released in parent GC stacks + isReachableFromImplementationObject = objGcNum >= numberOfGC; + } - JSInstanceInfo *jsInstanceInfo = GetJSInstanceInfo(obj); + JSInstanceInfo* jsInstanceInfo = GetJSInstanceInfo(obj); - if (!isReachableFromImplementationObject) { - if (!jsInstanceInfo->IsJavaObjectWeak) { - jsInstanceInfo->IsJavaObjectWeak = true; + if (!isReachableFromImplementationObject) { + if (!jsInstanceInfo->IsJavaObjectWeak) { + jsInstanceInfo->IsJavaObjectWeak = true; - ReleaseJSInstance(po, jsInstanceInfo); - } - } + ReleaseJSInstance(po, jsInstanceInfo); + } } + } - marked.clear(); + marked.clear(); } -bool ObjectManager::HasImplObject(Isolate *isolate, const Local &obj) { - auto implObject = MetadataNode::GetImplementationObject(isolate, obj); +bool ObjectManager::HasImplObject(Isolate* isolate, const Local& obj) { + auto implObject = MetadataNode::GetImplementationObject(isolate, obj); - bool hasImplObj = !implObject.IsEmpty(); + bool hasImplObj = !implObject.IsEmpty(); - return hasImplObj; + return hasImplObj; } -jweak ObjectManager::NewWeakGlobalRefCallback(const int &javaObjectID, void *state) { - auto objManager = reinterpret_cast(state); +jweak ObjectManager::NewWeakGlobalRefCallback(const int& javaObjectID, + void* state) { + auto objManager = reinterpret_cast(state); - JniLocalRef obj(objManager->GetJavaObjectByIDImpl(javaObjectID)); + JniLocalRef obj(objManager->GetJavaObjectByIDImpl(javaObjectID)); - JEnv env; - jweak weakRef = env.NewWeakGlobalRef(obj); + JEnv env; + jweak weakRef = env.NewWeakGlobalRef(obj); - return weakRef; + return weakRef; } -void ObjectManager::DeleteWeakGlobalRefCallback(const jweak &object, void *state) { - JEnv env; - env.DeleteWeakGlobalRef(object); +void ObjectManager::DeleteWeakGlobalRefCallback(const jweak& object, + void* state) { + JEnv env; + env.DeleteWeakGlobalRef(object); } -bool ObjectManager::ValidateWeakGlobalRefCallback(const int &javaObjectID, const jweak &object, void *state) { - JEnv env; - return !env.isSameObject(object, NULL); +bool ObjectManager::ValidateWeakGlobalRefCallback(const int& javaObjectID, + const jweak& object, + void* state) { + JEnv env; + return !env.isSameObject(object, NULL); } -Local ObjectManager::GetEmptyObject(Isolate *isolate) { - auto emptyObjCtorFunc = Local::New(isolate, *m_poJsWrapperFunc); - auto context = Runtime::GetRuntime(isolate)->GetContext(); - auto val = emptyObjCtorFunc->CallAsConstructor(context, 0, nullptr); - if (val.IsEmpty()) { - return Local(); - } - auto localVal = val.ToLocalChecked(); - assert(localVal->IsObject()); - auto obj = localVal.As(); - return obj; +Local ObjectManager::GetEmptyObject(Isolate* isolate) { + auto emptyObjCtorFunc = Local::New(isolate, *m_poJsWrapperFunc); + auto context = Runtime::GetRuntime(isolate)->GetContext(); + auto val = emptyObjCtorFunc->CallAsConstructor(context, 0, nullptr); + if (val.IsEmpty()) { + return Local(); + } + auto localVal = val.ToLocalChecked(); + assert(localVal->IsObject()); + auto obj = localVal.As(); + return obj; } -void ObjectManager::JSWrapperConstructorCallback(const v8::FunctionCallbackInfo &info) { - assert(info.IsConstructCall()); +void ObjectManager::JSWrapperConstructorCallback( + const v8::FunctionCallbackInfo& info) { + assert(info.IsConstructCall()); } -void ObjectManager::ReleaseNativeCounterpart(v8::Local &object) { +void ObjectManager::ReleaseNativeCounterpart(v8::Local& object) { + if (!object->IsObject()) { + throw NativeScriptException("Argument is not an object!"); + } - if(!object->IsObject()){ - throw NativeScriptException("Argument is not an object!"); - } - - JSInstanceInfo *jsInstanceInfo = GetJSInstanceInfo(object); + JSInstanceInfo* jsInstanceInfo = GetJSInstanceInfo(object); - if(jsInstanceInfo == nullptr){ - throw NativeScriptException("Trying to release a non native object!"); - } + if (jsInstanceInfo == nullptr) { + throw NativeScriptException("Trying to release a non native object!"); + } - JEnv env; - env.CallVoidMethod(m_javaRuntimeObject, RELEASE_NATIVE_INSTANCE_METHOD_ID, - jsInstanceInfo->JavaObjectID); + JEnv env; + env.CallVoidMethod(m_javaRuntimeObject, RELEASE_NATIVE_INSTANCE_METHOD_ID, + jsInstanceInfo->JavaObjectID); - delete jsInstanceInfo; - auto jsInfoIdx = static_cast(MetadataNodeKeys::JsInfo); - object->SetInternalField(jsInfoIdx, Undefined(m_isolate)); + delete jsInstanceInfo; + auto jsInfoIdx = static_cast(MetadataNodeKeys::JsInfo); + object->SetInternalField(jsInfoIdx, Undefined(m_isolate)); } ObjectManager::JavaScriptMarkingMode ObjectManager::GetMarkingMode() { - return this->m_markingMode; -} \ No newline at end of file + return this->m_markingMode; +} + +jclass ObjectManager::JAVA_LANG_CLASS = nullptr; +jmethodID ObjectManager::GET_NAME_METHOD_ID = nullptr; +jmethodID ObjectManager::GET_JAVAOBJECT_BY_ID_METHOD_ID = nullptr; +jmethodID ObjectManager::GET_OR_CREATE_JAVA_OBJECT_ID_METHOD_ID = nullptr; +jmethodID ObjectManager::MAKE_INSTANCE_WEAK_BATCH_METHOD_ID = nullptr; +jmethodID ObjectManager::MAKE_INSTANCE_WEAK_AND_CHECK_IF_ALIVE_METHOD_ID = + nullptr; +jmethodID ObjectManager::RELEASE_NATIVE_INSTANCE_METHOD_ID = nullptr; +jmethodID ObjectManager::CHECK_WEAK_OBJECTS_ARE_ALIVE_METHOD_ID = nullptr; diff --git a/test-app/runtime/src/main/cpp/ObjectManager.h b/test-app/runtime/src/main/cpp/ObjectManager.h index a0ae80703..483307697 100644 --- a/test-app/runtime/src/main/cpp/ObjectManager.h +++ b/test-app/runtime/src/main/cpp/ObjectManager.h @@ -1,236 +1,246 @@ #ifndef OBJECTMANAGER_H_ #define OBJECTMANAGER_H_ -#include "v8.h" -#include "JEnv.h" -#include "JniLocalRef.h" -#include "ArgsWrapper.h" -#include "DirectBuffer.h" -#include "LRUCache.h" #include #include #include -#include #include +#include + +#include "ArgsWrapper.h" +#include "DirectBuffer.h" +#include "JEnv.h" +#include "JniLocalRef.h" +#include "LRUCache.h" +#include "v8.h" namespace tns { class ObjectManager { - public: - ObjectManager(jobject javaRuntimeObject); - - void Init(v8::Isolate* isolate); - - JniLocalRef GetJavaObjectByJsObject(const v8::Local& object); - - void UpdateCache(int objectID, jobject obj); + public: + ObjectManager(jobject javaRuntimeObject); - jclass GetJavaClass(const v8::Local& instance); + void Init(v8::Isolate* isolate); - void SetJavaClass(const v8::Local& instance, jclass clazz); - int GetOrCreateObjectId(jobject object); + JniLocalRef GetJavaObjectByJsObject(const v8::Local& object); - v8::Local GetJsObjectByJavaObject(int javaObjectID); + void UpdateCache(int objectID, jobject obj); - v8::Local CreateJSWrapper(jint javaObjectID, const std::string& typeName); + jclass GetJavaClass(const v8::Local& instance); - v8::Local CreateJSWrapper(jint javaObjectID, const std::string& typeName, jobject instance); + void SetJavaClass(const v8::Local& instance, jclass clazz); + int GetOrCreateObjectId(jobject object); - void Link(const v8::Local& object, uint32_t javaObjectID, jclass clazz); + v8::Local GetJsObjectByJavaObject(int javaObjectID); - void ReleaseNativeCounterpart(v8::Local& object); + v8::Local CreateJSWrapper(jint javaObjectID, + const std::string& typeName); - bool CloneLink(const v8::Local& src, const v8::Local& dest); + v8::Local CreateJSWrapper(jint javaObjectID, + const std::string& typeName, + jobject instance); - bool IsJsRuntimeObject(const v8::Local& object); + void Link(const v8::Local& object, uint32_t javaObjectID, + jclass clazz); - std::string GetClassName(jobject javaObject); + void ReleaseNativeCounterpart(v8::Local& object); - std::string GetClassName(jclass clazz); + bool CloneLink(const v8::Local& src, + const v8::Local& dest); - int GenerateNewObjectID(); + bool IsJsRuntimeObject(const v8::Local& object); - void SetInstanceIsolate(v8::Isolate* isolate); + static std::string GetClassName(jobject javaObject); - v8::Local GetEmptyObject(v8::Isolate* isolate); + static std::string GetClassName(jclass clazz); - enum class MetadataNodeKeys { - JsInfo, - CallSuper, - END - }; + int GenerateNewObjectID(); - /** - * Memory management modes. Keep the members in sync with the java/com/tns/MarkingMode. - */ - enum JavaScriptMarkingMode { - /** - * For JavaScript instances with implementation objects that were marked for collection, - * MarkReachableObjects will scan the whole graph of reachable objects and keep strong reference to - * the Java instances of implementation objects. - */ - Full, - /** - * Fully suppress the MarkReachableObjects. - */ - None - }; + void SetInstanceIsolate(v8::Isolate* isolate); - JavaScriptMarkingMode GetMarkingMode(); + v8::Local GetEmptyObject(v8::Isolate* isolate); - private: + enum class MetadataNodeKeys { JsInfo, CallSuper, END }; - struct JSInstanceInfo { - public: - JSInstanceInfo(bool isJavaObjectWeak, uint32_t javaObjectID, jclass claz) - :IsJavaObjectWeak(isJavaObjectWeak), JavaObjectID(javaObjectID), ObjectClazz(claz) { - } + /** + * Memory management modes. Keep the members in sync with the + * java/com/tns/MarkingMode. + */ + enum JavaScriptMarkingMode { + /** + * For JavaScript instances with implementation objects that were marked for + * collection, MarkReachableObjects will scan the whole graph of reachable + * objects and keep strong reference to the Java instances of implementation + * objects. + */ + Full, + /** + * Fully suppress the MarkReachableObjects. + */ + None + }; - bool IsJavaObjectWeak; - uint32_t JavaObjectID; - jclass ObjectClazz; - }; + JavaScriptMarkingMode GetMarkingMode(); - struct ObjectWeakCallbackState { - ObjectWeakCallbackState(ObjectManager* _thisPtr, JSInstanceInfo* _jsInfo, v8::Persistent* _target) - : - thisPtr(_thisPtr), jsInfo(_jsInfo), target(_target) { - } + private: + static void InitializeJNI(); + struct JSInstanceInfo { + public: + JSInstanceInfo(bool isJavaObjectWeak, uint32_t javaObjectID, jclass claz) + : IsJavaObjectWeak(isJavaObjectWeak), + JavaObjectID(javaObjectID), + ObjectClazz(claz) {} - ObjectManager* thisPtr; - JSInstanceInfo* jsInfo; - v8::Persistent* target; - }; + bool IsJavaObjectWeak; + uint32_t JavaObjectID; + jclass ObjectClazz; + }; - struct GarbageCollectionInfo { - GarbageCollectionInfo(int _numberOfGC) - : - numberOfGC(_numberOfGC) { - } - std::vector*> markedForGC; - int numberOfGC; - }; + struct ObjectWeakCallbackState { + ObjectWeakCallbackState(ObjectManager* _thisPtr, JSInstanceInfo* _jsInfo, + v8::Persistent* _target) + : thisPtr(_thisPtr), jsInfo(_jsInfo), target(_target) {} - class PersistentObjectIdSet { - public: - PersistentObjectIdSet() { - /* TODO: use functors */ - } + ObjectManager* thisPtr; + JSInstanceInfo* jsInfo; + v8::Persistent* target; + }; - void clear() { - m_POs.clear(); - m_IDs.clear(); - } + struct GarbageCollectionInfo { + GarbageCollectionInfo(int _numberOfGC) : numberOfGC(_numberOfGC) {} + std::vector*> markedForGC; + int numberOfGC; + }; - void insert(v8::Persistent* po, int javaObjectId) { - m_POs.insert(po); - m_IDs.insert(javaObjectId); - } + class PersistentObjectIdSet { + public: + PersistentObjectIdSet() { /* TODO: use functors */ } - bool contains(v8::Persistent* po) { - return m_POs.find(po) != m_POs.end(); - } + void clear() { + m_POs.clear(); + m_IDs.clear(); + } - std::set*> m_POs; - std::set m_IDs; - }; + void insert(v8::Persistent* po, int javaObjectId) { + m_POs.insert(po); + m_IDs.insert(javaObjectId); + } - struct PersistentObjectIdPair { - PersistentObjectIdPair(v8::Persistent* _po, int _javaObjectId) - : - po(_po), javaObjectId(_javaObjectId) { - } - v8::Persistent* po; - int javaObjectId; - }; + bool contains(v8::Persistent* po) { + return m_POs.find(po) != m_POs.end(); + } + std::set*> m_POs; + std::set m_IDs; + }; + struct PersistentObjectIdPair { + PersistentObjectIdPair(v8::Persistent* _po, int _javaObjectId) + : po(_po), javaObjectId(_javaObjectId) {} + v8::Persistent* po; + int javaObjectId; + }; - JSInstanceInfo* GetJSInstanceInfo(const v8::Local& object); + JSInstanceInfo* GetJSInstanceInfo(const v8::Local& object); - JSInstanceInfo* GetJSInstanceInfoFromRuntimeObject(const v8::Local& object); + JSInstanceInfo* GetJSInstanceInfoFromRuntimeObject( + const v8::Local& object); - void ReleaseJSInstance(v8::Persistent* po, JSInstanceInfo* jsInstanceInfo); + void ReleaseJSInstance(v8::Persistent* po, + JSInstanceInfo* jsInstanceInfo); - void ReleaseRegularObjects(); + void ReleaseRegularObjects(); - void MakeRegularObjectsWeak(const std::set& instances, DirectBuffer& inputBuff); + void MakeRegularObjectsWeak(const std::set& instances, + DirectBuffer& inputBuff); - void MakeImplObjectsWeak(const std::unordered_map*>& instances, DirectBuffer& inputBuff); + void MakeImplObjectsWeak( + const std::unordered_map*>& instances, + DirectBuffer& inputBuff); - void CheckWeakObjectsAreAlive(const std::vector& instances, DirectBuffer& inputBuff, DirectBuffer& outputBuff); + void CheckWeakObjectsAreAlive( + const std::vector& instances, + DirectBuffer& inputBuff, DirectBuffer& outputBuff); - v8::Local CreateJSWrapperHelper(jint javaObjectID, const std::string& typeName, jclass clazz); + v8::Local CreateJSWrapperHelper(jint javaObjectID, + const std::string& typeName, + jclass clazz); - static void JSObjectWeakCallbackStatic(const v8::WeakCallbackInfo& data); + static void JSObjectWeakCallbackStatic( + const v8::WeakCallbackInfo& data); - static void JSObjectFinalizerStatic(const v8::WeakCallbackInfo& data); + static void JSObjectFinalizerStatic( + const v8::WeakCallbackInfo& data); - void JSObjectWeakCallback(v8::Isolate* isolate, ObjectWeakCallbackState* callbackState); + void JSObjectWeakCallback(v8::Isolate* isolate, + ObjectWeakCallbackState* callbackState); - void JSObjectFinalizer(v8::Isolate* isolate, ObjectWeakCallbackState* callbackState); + void JSObjectFinalizer(v8::Isolate* isolate, + ObjectWeakCallbackState* callbackState); - bool HasImplObject(v8::Isolate* isolate, const v8::Local& obj); + bool HasImplObject(v8::Isolate* isolate, const v8::Local& obj); - jweak GetJavaObjectByID(uint32_t javaObjectID); + jweak GetJavaObjectByID(uint32_t javaObjectID); - jobject GetJavaObjectByIDImpl(uint32_t javaObjectID); + jobject GetJavaObjectByIDImpl(uint32_t javaObjectID); - static jweak NewWeakGlobalRefCallback(const int& javaObjectID, void* state); + static jweak NewWeakGlobalRefCallback(const int& javaObjectID, void* state); - static void DeleteWeakGlobalRefCallback(const jweak& object, void* state); + static void DeleteWeakGlobalRefCallback(const jweak& object, void* state); - static bool ValidateWeakGlobalRefCallback(const int &javaObjectID, const jweak &object, void *state); + static bool ValidateWeakGlobalRefCallback(const int& javaObjectID, + const jweak& object, void* state); - static void JSWrapperConstructorCallback(const v8::FunctionCallbackInfo& info); + static void JSWrapperConstructorCallback( + const v8::FunctionCallbackInfo& info); - jobject m_javaRuntimeObject; + jobject m_javaRuntimeObject; - int m_numberOfGC; + int m_numberOfGC; - v8::Isolate* m_isolate; + v8::Isolate* m_isolate; - std::stack m_markedForGC; + std::stack m_markedForGC; - std::unordered_map*> m_idToObject; + std::unordered_map*> m_idToObject; - PersistentObjectIdSet m_released; + PersistentObjectIdSet m_released; - std::set m_visited; + std::set m_visited; - LRUCache m_cache; + LRUCache m_cache; - std::set*> m_visitedPOs; - std::vector m_implObjWeak; - std::unordered_map*> m_implObjStrong; + std::set*> m_visitedPOs; + std::vector m_implObjWeak; + std::unordered_map*> m_implObjStrong; - volatile int m_currentObjectId; + volatile int m_currentObjectId; - DirectBuffer m_buff; + DirectBuffer m_buff; - DirectBuffer m_outBuff; + DirectBuffer m_outBuff; - bool m_useGlobalRefs; + bool m_useGlobalRefs; - JavaScriptMarkingMode m_markingMode; + JavaScriptMarkingMode m_markingMode; - jclass JAVA_LANG_CLASS; + static jclass JAVA_LANG_CLASS; - jmethodID GET_NAME_METHOD_ID; + static jmethodID GET_NAME_METHOD_ID; - jmethodID GET_JAVAOBJECT_BY_ID_METHOD_ID; + static jmethodID GET_JAVAOBJECT_BY_ID_METHOD_ID; - jmethodID GET_OR_CREATE_JAVA_OBJECT_ID_METHOD_ID; + static jmethodID GET_OR_CREATE_JAVA_OBJECT_ID_METHOD_ID; - jmethodID MAKE_INSTANCE_WEAK_BATCH_METHOD_ID; + static jmethodID MAKE_INSTANCE_WEAK_BATCH_METHOD_ID; - jmethodID MAKE_INSTANCE_WEAK_AND_CHECK_IF_ALIVE_METHOD_ID; + static jmethodID MAKE_INSTANCE_WEAK_AND_CHECK_IF_ALIVE_METHOD_ID; - jmethodID RELEASE_NATIVE_INSTANCE_METHOD_ID; + static jmethodID RELEASE_NATIVE_INSTANCE_METHOD_ID; - jmethodID CHECK_WEAK_OBJECTS_ARE_ALIVE_METHOD_ID; + static jmethodID CHECK_WEAK_OBJECTS_ARE_ALIVE_METHOD_ID; - v8::Persistent* m_poJsWrapperFunc; + v8::Persistent* m_poJsWrapperFunc; }; -} +} // namespace tns #endif /* OBJECTMANAGER_H_ */