diff --git a/mozilla/extensions/java/xpcom/nsJavaWrapper.cpp b/mozilla/extensions/java/xpcom/nsJavaWrapper.cpp index fb7e25f5deb..7a985ba3cee 100644 --- a/mozilla/extensions/java/xpcom/nsJavaWrapper.cpp +++ b/mozilla/extensions/java/xpcom/nsJavaWrapper.cpp @@ -334,26 +334,8 @@ SetupParams(JNIEnv *env, const jobject aParam, const nsXPTParamInfo &aParamInfo, env->GetObjectArrayElement((jobjectArray) aParam, 0); } - void* xpcom_obj; + nsISupports* xpcom_obj; if (java_obj) { - // Check if we already have a corresponding XPCOM object - jboolean isProxy = env->CallStaticBooleanMethod(xpcomJavaProxyClass, - isXPCOMJavaProxyMID, - java_obj); - if (env->ExceptionCheck()) { - rv = NS_ERROR_FAILURE; - break; - } - - void* inst; - if (isProxy) { - rv = GetXPCOMInstFromProxy(env, java_obj, &inst); - if (NS_FAILED(rv)) - break; - } else { - inst = gBindings->GetXPCOMObject(env, java_obj); - } - // Get IID for this param nsID iid; rv = GetIIDForMethodParam(aIInfo, aMethodInfo, aParamInfo, @@ -362,53 +344,57 @@ SetupParams(JNIEnv *env, const jobject aParam, const nsXPTParamInfo &aParamInfo, if (NS_FAILED(rv)) break; - PRBool isWeakRef = iid.Equals(NS_GET_IID(nsIWeakReference)); - - if (inst == nsnull && !isWeakRef) { - // If there is not corresponding XPCOM object, then that means that the - // parameter is non-generated class (that is, it is not one of our - // Java stubs that represent an exising XPCOM object). So we need to - // create an XPCOM stub, that can route any method calls to the class. - - // Get interface info for class - nsCOMPtr iim = XPTI_GetInterfaceInfoManager(); - nsCOMPtr iinfo; - rv = iim->GetInfoForIID(&iid, getter_AddRefs(iinfo)); - if (NS_FAILED(rv)) - break; - - // Create XPCOM stub - nsJavaXPTCStub* xpcomStub = new nsJavaXPTCStub(env, java_obj, iinfo); - if (!xpcomStub) { - rv = NS_ERROR_OUT_OF_MEMORY; - break; - } - inst = SetAsXPTCStub(xpcomStub); - gBindings->AddBinding(env, java_obj, inst); + // If the requested interface is nsIWeakReference, then we look for or + // create a stub for the nsISupports interface. Then we create a weak + // reference from that stub. + PRBool isWeakRef; + if (iid.Equals(NS_GET_IID(nsIWeakReference))) { + isWeakRef = PR_TRUE; + iid = NS_GET_IID(nsISupports); + } else { + isWeakRef = PR_FALSE; } + PRBool isXPTCStub; + rv = GetNewOrUsedXPCOMObject(env, java_obj, iid, &xpcom_obj, + &isXPTCStub); + if (NS_FAILED(rv)) + break; + + // If the function expects a weak reference, then we need to + // create it here. if (isWeakRef) { - // If the function expects an weak reference, then we need to - // create it here. - nsJavaXPTCStubWeakRef* weakref = - new nsJavaXPTCStubWeakRef(env, java_obj); - if (!weakref) { - rv = NS_ERROR_OUT_OF_MEMORY; - break; + if (isXPTCStub) { + nsJavaXPTCStub* stub = NS_STATIC_CAST(nsJavaXPTCStub*, + NS_STATIC_CAST(nsXPTCStubBase*, + xpcom_obj)); + nsJavaXPTCStubWeakRef* weakref; + weakref = new nsJavaXPTCStubWeakRef(env, java_obj, stub); + if (!weakref) { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + xpcom_obj = weakref; + NS_ADDREF(xpcom_obj); + aVariant.SetValIsAllocated(); + } else { // if is native XPCOM object + nsCOMPtr supportsweak = + do_QueryInterface(xpcom_obj); + if (supportsweak) { + nsWeakPtr weakref; + supportsweak->GetWeakReference(getter_AddRefs(weakref)); + xpcom_obj = weakref; + NS_ADDREF(xpcom_obj); + } else { + xpcom_obj = nsnull; + } } - NS_ADDREF(weakref); - xpcom_obj = (void*) weakref; + + } else if (isXPTCStub) { aVariant.SetValIsAllocated(); - } else if (IsXPTCStub(inst)) { - nsJavaXPTCStub* xpcomStub = GetXPTCStubAddr(inst); - NS_ADDREF(xpcomStub); - xpcom_obj = (void*) xpcomStub; - aVariant.SetValIsAllocated(); - - } else { - JavaXPCOMInstance* xpcomInst = (JavaXPCOMInstance*) inst; - xpcom_obj = (void*) xpcomInst->GetInstance(); + } else { // if is native XPCOM object + xpcom_obj->Release(); } } else { xpcom_obj = nsnull; @@ -682,7 +668,7 @@ FinalizeParams(JNIEnv *env, const jobject aParam, case nsXPTType::T_INTERFACE: case nsXPTType::T_INTERFACE_IS: { - void* xpcom_obj = aVariant.val.p; + nsISupports* xpcom_obj = NS_STATIC_CAST(nsISupports*, aVariant.val.p); if (aParamInfo.IsOut() && aParam) { // 'inout' & 'out' jobject java_obj = nsnull; @@ -694,9 +680,13 @@ FinalizeParams(JNIEnv *env, const jobject aParam, break; // Get matching Java object for given xpcom object - rv = gBindings->GetJavaObject(env, xpcom_obj, iid, PR_TRUE, &java_obj); + PRBool isNewProxy; + rv = GetNewOrUsedJavaObject(env, xpcom_obj, iid, &java_obj, + &isNewProxy); if (NS_FAILED(rv)) break; + if (isNewProxy) + NS_RELEASE(xpcom_obj); // Java proxy owns ref to object } // put new Java object into output array @@ -706,8 +696,7 @@ FinalizeParams(JNIEnv *env, const jobject aParam, // If VAL_IS_ALLOCD is set, that means that an XPCOM object was created // is SetupParams that now needs to be released. if (xpcom_obj && aVariant.IsValAllocated()) { - nsISupports* variant = NS_STATIC_CAST(nsISupports*, xpcom_obj); - NS_RELEASE(variant); + NS_RELEASE(xpcom_obj); } } break; @@ -877,7 +866,8 @@ SetRetval(JNIEnv *env, const nsXPTParamInfo &aParamInfo, case nsXPTType::T_INTERFACE: case nsXPTType::T_INTERFACE_IS: { - if (aVariant.val.p) { + nsISupports* xpcom_obj = NS_STATIC_CAST(nsISupports*, aVariant.val.p); + if (xpcom_obj) { nsID iid; rv = GetIIDForMethodParam(aIInfo, aMethodInfo, aParamInfo, aMethodIndex, aDispatchParams, PR_TRUE, iid); @@ -886,13 +876,15 @@ SetRetval(JNIEnv *env, const nsXPTParamInfo &aParamInfo, // Get matching Java object for given xpcom object jobject java_obj; - rv = gBindings->GetJavaObject(env, aVariant.val.p, iid, PR_TRUE, - &java_obj); + PRBool isNewProxy; + rv = GetNewOrUsedJavaObject(env, xpcom_obj, iid, &java_obj, + &isNewProxy); if (NS_FAILED(rv)) break; + if (isNewProxy) + xpcom_obj->Release(); // Java proxy owns ref to object // If returned object is an nsJavaXPTCStub, release it. - nsISupports* xpcom_obj = NS_STATIC_CAST(nsISupports*, aVariant.val.p); nsJavaXPTCStub* stub = nsnull; xpcom_obj->QueryInterface(NS_GET_IID(nsJavaXPTCStub), (void**) &stub); if (stub) { @@ -1079,7 +1071,7 @@ JAVAPROXY_NATIVE(callXPCOMMethod) (JNIEnv *env, jclass that, jobject aJavaProxy, #ifdef DEBUG_JAVAXPCOM const char* ifaceName; iinfo->GetNameShared(&ifaceName); - LOG(("=> Calling %s::%s()\n", ifaceName, methodInfo->GetName())); + LOG(("===> (XPCOM) %s::%s()\n", ifaceName, methodInfo->GetName())); #endif // Convert the Java params @@ -1199,6 +1191,7 @@ JAVAPROXY_NATIVE(callXPCOMMethod) (JNIEnv *env, jclass that, jobject aJavaProxy, ThrowException(env, invokeResult, message.get()); } + LOG(("<=== (XPCOM) %s::%s()\n", ifaceName, methodInfo->GetName())); return result; } @@ -1247,8 +1240,16 @@ CreateJavaProxy(JNIEnv* env, nsISupports* aXPCOMObject, const nsIID& aIID, } if (java_obj) { +#ifdef DEBUG_JAVAXPCOM + char* iid_str = aIID.ToString(); + LOG(("+ CreateJavaProxy (Java=%08x | XPCOM=%08x | IID=%s)\n", + env->CallIntMethod(java_obj, hashCodeMID), + (int) aXPCOMObject, iid_str)); + PR_Free(iid_str); +#endif + // Associate XPCOM object with Java proxy - rv = gBindings->AddBinding(env, java_obj, inst); + rv = gNativeToJavaProxyMap->Add(env, aXPCOMObject, aIID, java_obj); if (NS_SUCCEEDED(rv)) { *aResult = java_obj; return NS_OK; @@ -1278,6 +1279,17 @@ GetXPCOMInstFromProxy(JNIEnv* env, jobject aJavaObject, void** aResult) } *aResult = NS_REINTERPRET_CAST(void*, xpcom_obj); +#ifdef DEBUG_JAVAXPCOM + JavaXPCOMInstance* inst = NS_STATIC_CAST(JavaXPCOMInstance*, *aResult); + nsIID* iid; + inst->InterfaceInfo()->GetInterfaceIID(&iid); + char* iid_str = iid->ToString(); + LOG(("< GetXPCOMInstFromProxy (Java=%08x | XPCOM=%08x | IID=%s)\n", + env->CallIntMethod(aJavaObject, hashCodeMID), + (int) inst->GetInstance(), iid_str)); + PR_Free(iid_str); + nsMemory::Free(iid); +#endif return NS_OK; } @@ -1287,15 +1299,6 @@ GetXPCOMInstFromProxy(JNIEnv* env, jobject aJavaObject, void** aResult) extern "C" JX_EXPORT void JNICALL JAVAPROXY_NATIVE(finalizeProxy) (JNIEnv *env, jclass that, jobject aJavaProxy) { -#ifdef DEBUG_JAVAXPCOM - jstring string = nsnull; - string = (jstring) env->CallStaticObjectMethod(xpcomJavaProxyClass, - proxyToStringMID, aJavaProxy); - const char* javaObjectName = env->GetStringUTFChars(string, nsnull); - LOG(("*** Finalize(java_obj=%s)\n", javaObjectName)); - env->ReleaseStringUTFChars(string, javaObjectName); -#endif - // Due to Java's garbage collection, this finalize statement may get called // after FreeJavaGlobals(). So check to make sure that everything is still // initialized. @@ -1307,7 +1310,20 @@ JAVAPROXY_NATIVE(finalizeProxy) (JNIEnv *env, jclass that, jobject aJavaProxy) nsresult rv = GetXPCOMInstFromProxy(env, aJavaProxy, &xpcom_obj); if (NS_SUCCEEDED(rv)) { JavaXPCOMInstance* inst = NS_STATIC_CAST(JavaXPCOMInstance*, xpcom_obj); - gBindings->RemoveBinding(env, aJavaProxy, nsnull); + nsIID* iid; + rv = inst->InterfaceInfo()->GetInterfaceIID(&iid); + if (NS_SUCCEEDED(rv)) { + rv = gNativeToJavaProxyMap->Remove(env, inst->GetInstance(), *iid); +#ifdef DEBUG_JAVAXPCOM + char* iid_str = iid->ToString(); + LOG(("- Finalize (Java=%08x | XPCOM=%08x | IID=%s)\n", + env->CallIntMethod(aJavaProxy, hashCodeMID), + (int) inst->GetInstance(), iid_str)); + PR_Free(iid_str); +#endif + nsMemory::Free(iid); + } + NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to RemoveJavaProxy"); delete inst; } } diff --git a/mozilla/extensions/java/xpcom/nsJavaXPCOMBindingUtils.cpp b/mozilla/extensions/java/xpcom/nsJavaXPCOMBindingUtils.cpp index 6ebf759771b..40d8366d090 100644 --- a/mozilla/extensions/java/xpcom/nsJavaXPCOMBindingUtils.cpp +++ b/mozilla/extensions/java/xpcom/nsJavaXPCOMBindingUtils.cpp @@ -86,283 +86,12 @@ jmethodID getNameMID = nsnull; jmethodID proxyToStringMID = nsnull; #endif -nsJavaXPCOMBindings* gBindings = nsnull; +NativeToJavaProxyMap* gNativeToJavaProxyMap = nsnull; +JavaToXPTCStubMap* gJavaToXPTCStubMap = nsnull; + PRLock* gJavaXPCOMLock = nsnull; -/************************************** - * Java<->XPCOM binding stores - **************************************/ -class JavaXPCOMBindingEntry : public PLDHashEntryHdr -{ -public: - // mKey will either be a Java hash of the Java object, or the address of - // the XPCOM object, depending on which hash table this entry is used in. - const void* mKey; - jobject mJavaObject; - void* mXPCOMInstance; -}; - -PR_STATIC_CALLBACK(PRBool) -InitJavaXPCOMBindingEntry(PLDHashTable *table, PLDHashEntryHdr *entry, - const void *key) -{ - JavaXPCOMBindingEntry *e = - NS_CONST_CAST(JavaXPCOMBindingEntry *, - NS_STATIC_CAST(const JavaXPCOMBindingEntry *, entry)); - - e->mKey = key; - - return PR_TRUE; -} - -NS_IMETHODIMP -nsJavaXPCOMBindings::Init() -{ - static PLDHashTableOps java_to_xpcom_hash_ops = - { - PL_DHashAllocTable, - PL_DHashFreeTable, - PL_DHashGetKeyStub, - PL_DHashVoidPtrKeyStub, - PL_DHashMatchEntryStub, - PL_DHashMoveEntryStub, - PL_DHashClearEntryStub, - PL_DHashFinalizeStub, - InitJavaXPCOMBindingEntry - }; - - mJAVAtoXPCOMBindings = PL_NewDHashTable(&java_to_xpcom_hash_ops, nsnull, - sizeof(JavaXPCOMBindingEntry), 16); - if (!mJAVAtoXPCOMBindings) - return NS_ERROR_OUT_OF_MEMORY; - - static PLDHashTableOps xpcom_to_java_hash_ops = - { - PL_DHashAllocTable, - PL_DHashFreeTable, - PL_DHashGetKeyStub, - PL_DHashVoidPtrKeyStub, - PL_DHashMatchEntryStub, - PL_DHashMoveEntryStub, - PL_DHashClearEntryStub, - PL_DHashFinalizeStub, - InitJavaXPCOMBindingEntry - }; - - mXPCOMtoJAVABindings = PL_NewDHashTable(&xpcom_to_java_hash_ops, nsnull, - sizeof(JavaXPCOMBindingEntry), 16); - if (!mXPCOMtoJAVABindings) - return NS_ERROR_OUT_OF_MEMORY; - - return NS_OK; -} - -nsJavaXPCOMBindings::~nsJavaXPCOMBindings() -{ - if (mJAVAtoXPCOMBindings) - PL_DHashTableDestroy(mJAVAtoXPCOMBindings); - if (mXPCOMtoJAVABindings) - PL_DHashTableDestroy(mXPCOMtoJAVABindings); -} - -NS_IMETHODIMP -nsJavaXPCOMBindings::AddBinding(JNIEnv* env, jobject aJavaObject, - void* aXPCOMObject) -{ - // We use a Java hash of the Java object as a key since the JVM can return - // different "addresses" for the same Java object, but the hash code (the - // result of calling |hashCode()| on the Java object) will always be the same. - jint hash = env->CallIntMethod(aJavaObject, hashCodeMID); - jweak java_ref = env->NewWeakGlobalRef(aJavaObject); - if (!java_ref) - return NS_ERROR_OUT_OF_MEMORY; - - // Add a new entry into hash - JavaXPCOMBindingEntry *entry = - NS_STATIC_CAST(JavaXPCOMBindingEntry*, - PL_DHashTableOperate(mJAVAtoXPCOMBindings, - NS_INT32_TO_PTR(hash), - PL_DHASH_ADD)); - if (!entry) - return NS_ERROR_FAILURE; - - // Set entry fields - entry->mJavaObject = java_ref; - entry->mXPCOMInstance = aXPCOMObject; - - // We want the hash key to be the actual XPCOM object - void* xpcomObjKey = nsnull; - if (IsXPTCStub(aXPCOMObject)) - xpcomObjKey = GetXPTCStubAddr(aXPCOMObject); - else - xpcomObjKey = ((JavaXPCOMInstance*) aXPCOMObject)->GetInstance(); - - // Add a new entry into other hash table - entry = - NS_STATIC_CAST(JavaXPCOMBindingEntry*, - PL_DHashTableOperate(mXPCOMtoJAVABindings, xpcomObjKey, - PL_DHASH_ADD)); - if (!entry) - return NS_ERROR_FAILURE; - - entry->mJavaObject = java_ref; - entry->mXPCOMInstance = aXPCOMObject; - - LOG(("+ Adding Java<->XPCOM binding (Java=0x%08x | XPCOM=0x%08x) weakref=0x%08x\n", - hash, (int) xpcomObjKey, (PRUint32) java_ref)); - - return NS_OK; -} - -NS_IMETHODIMP -nsJavaXPCOMBindings::RemoveBinding(JNIEnv* env, jobject aJavaObject, - void* aXPCOMObject) -{ - // Given a Java or XPCOM object, find the associated object. - NS_PRECONDITION(aJavaObject != nsnull || aXPCOMObject != nsnull, - "Need either a Java or XPCOM object"); - - jint hash = 0; - void* xpcomObjKey = nsnull; - JavaXPCOMBindingEntry* entry = nsnull; - - if (aJavaObject) { - hash = env->CallIntMethod(aJavaObject, hashCodeMID); - JavaXPCOMBindingEntry* e = - NS_STATIC_CAST(JavaXPCOMBindingEntry*, - PL_DHashTableOperate(mJAVAtoXPCOMBindings, - NS_INT32_TO_PTR(hash), - PL_DHASH_LOOKUP)); - if (PL_DHASH_ENTRY_IS_BUSY(e)) - entry = e; - } else { - JavaXPCOMBindingEntry* e = - NS_STATIC_CAST(JavaXPCOMBindingEntry*, - PL_DHashTableOperate(mXPCOMtoJAVABindings, aXPCOMObject, - PL_DHASH_LOOKUP)); - if (PL_DHASH_ENTRY_IS_BUSY(e)) - entry = e; - } - if (!entry) { - NS_WARNING("Failed to find matching entry"); - return NS_ERROR_FAILURE; - } - - jobject jweakref = entry->mJavaObject; - void* xpcom_obj = entry->mXPCOMInstance; - - // Get keys. For Java, we use the hash key of the Java object. For XPCOM, - // we get the 'actual' object (either the nsJavaXPTCStub or the instance - // that is wrapped by JavaXPCOMInstance). - if (hash == 0) { - hash = env->CallIntMethod(jweakref, hashCodeMID); - } - if (aXPCOMObject) { - xpcomObjKey = aXPCOMObject; - } else { - if (IsXPTCStub(xpcom_obj)) - xpcomObjKey = GetXPTCStubAddr(xpcom_obj); - else - xpcomObjKey = ((JavaXPCOMInstance*) xpcom_obj)->GetInstance(); - } - - NS_ASSERTION(env->IsSameObject(jweakref, aJavaObject), - "Weakref does not point to expected Java object"); - NS_ASSERTION(!env->IsSameObject(jweakref, NULL), - "Weakref refers to garbage collected Java object. No longer valid"); - - // Remove both instances from stores - PL_DHashTableOperate(mJAVAtoXPCOMBindings, NS_INT32_TO_PTR(hash), - PL_DHASH_REMOVE); - PL_DHashTableOperate(mXPCOMtoJAVABindings, xpcomObjKey, PL_DHASH_REMOVE); - LOG(("- Removing Java<->XPCOM binding (Java=0x%08x | XPCOM=0x%08x) weakref=0x%08x\n", - hash, (int) xpcomObjKey, (PRUint32) jweakref)); - - env->DeleteWeakGlobalRef(NS_STATIC_CAST(jweak, jweakref)); - return NS_OK; -} - -void* -nsJavaXPCOMBindings::GetXPCOMObject(JNIEnv* env, jobject aJavaObject) -{ - jint hash = env->CallIntMethod(aJavaObject, hashCodeMID); - - JavaXPCOMBindingEntry *entry = - NS_STATIC_CAST(JavaXPCOMBindingEntry*, - PL_DHashTableOperate(mJAVAtoXPCOMBindings, - NS_INT32_TO_PTR(hash), - PL_DHASH_LOOKUP)); - - if (PL_DHASH_ENTRY_IS_BUSY(entry)) { -#ifdef DEBUG_JAVAXPCOM - void* xpcomObjKey = nsnull; - if (IsXPTCStub(entry->mXPCOMInstance)) - xpcomObjKey = GetXPTCStubAddr(entry->mXPCOMInstance); - else - xpcomObjKey = ((JavaXPCOMInstance*) entry->mXPCOMInstance)->GetInstance(); - LOG(("< Get Java<->XPCOM binding (Java=0x%08x | XPCOM=0x%08x)\n", - hash, (int) xpcomObjKey)); -#endif - return entry->mXPCOMInstance; - } - - return nsnull; -} - -NS_IMETHODIMP -nsJavaXPCOMBindings::GetJavaObject(JNIEnv* env, void* aXPCOMObject, - const nsIID& aIID, PRBool aDoReleaseObject, - jobject* aResult) -{ - NS_PRECONDITION(aResult != nsnull, "null ptr"); - if (!aResult) - return NS_ERROR_NULL_POINTER; - - *aResult = nsnull; - nsISupports* xpcom_obj = NS_STATIC_CAST(nsISupports*, aXPCOMObject); - nsresult rv; - - nsJavaXPTCStub* stub = nsnull; - xpcom_obj->QueryInterface(NS_GET_IID(nsJavaXPTCStub), (void**) &stub); - if (stub) { - // Get associated Java object directly from nsJavaXPTCStub - *aResult = stub->GetJavaObject(); - NS_ASSERTION(*aResult != nsnull, "nsJavaXPTCStub w/o matching Java object"); - NS_RELEASE(stub); - rv = NS_OK; - } else { - // Get associated Java object from hash table - JavaXPCOMBindingEntry *entry = - NS_STATIC_CAST(JavaXPCOMBindingEntry*, - PL_DHashTableOperate(mXPCOMtoJAVABindings, aXPCOMObject, - PL_DHASH_LOOKUP)); - - if (PL_DHASH_ENTRY_IS_BUSY(entry)) { - *aResult = entry->mJavaObject; - rv = NS_OK; - } - } - - if (*aResult == nsnull) { - // No Java object is associated with the given XPCOM object, so we create - // a Java proxy. - rv = CreateJavaProxy(env, xpcom_obj, aIID, aResult); - if (NS_SUCCEEDED(rv) && aDoReleaseObject) - NS_RELEASE(xpcom_obj); // Owning ref passed on - } - -#ifdef DEBUG_JAVAXPCOM - if (*aResult) { - LOG(("< Get Java<->XPCOM binding (Java=0x%08x | XPCOM=0x%08x)\n", - env->CallIntMethod(*aResult, hashCodeMID), (int) aXPCOMObject)); - } -#endif - - return rv; -} - - /****************************** * InitializeJavaGlobals ******************************/ @@ -504,9 +233,14 @@ InitializeJavaGlobals(JNIEnv *env) } #endif - gBindings = new nsJavaXPCOMBindings(); - if (NS_FAILED(gBindings->Init())) { - NS_WARNING("Problem creating JavaXPCOMBindings"); + gNativeToJavaProxyMap = new NativeToJavaProxyMap(); + if (NS_FAILED(gNativeToJavaProxyMap->Init())) { + NS_WARNING("Problem creating NativeToJavaProxyMap"); + goto init_error; + } + gJavaToXPTCStubMap = new JavaToXPTCStubMap(); + if (NS_FAILED(gJavaToXPTCStubMap->Init())) { + NS_WARNING("Problem creating JavaToXPTCStubMap"); goto init_error; } @@ -577,9 +311,13 @@ FreeJavaGlobals(JNIEnv* env) xpcomJavaProxyClass = nsnull; } - if (gBindings) { - delete gBindings; - gBindings = nsnull; + if (gNativeToJavaProxyMap) { + delete gNativeToJavaProxyMap; + gNativeToJavaProxyMap = nsnull; + } + if (gJavaToXPTCStubMap) { + delete gJavaToXPTCStubMap; + gJavaToXPTCStubMap = nsnull; } PR_Unlock(gJavaXPCOMLock); @@ -588,13 +326,252 @@ FreeJavaGlobals(JNIEnv* env) } +/************************************** + * Java<->XPCOM object mappings + **************************************/ + +static PLDHashTableOps hash_ops = +{ + PL_DHashAllocTable, + PL_DHashFreeTable, + PL_DHashGetKeyStub, + PL_DHashVoidPtrKeyStub, + PL_DHashMatchEntryStub, + PL_DHashMoveEntryStub, + PL_DHashClearEntryStub, + PL_DHashFinalizeStub +}; + +// NativeToJavaProxyMap: The common case is that each XPCOM object will have +// one Java proxy. But there are instances where there will be multiple Java +// proxies for a given XPCOM object, each representing a different interface. +// So we optimize the common case by using a hash table. Then, if there are +// multiple Java proxies, we cycle through the linked list, comparing IIDs. + +NativeToJavaProxyMap::~NativeToJavaProxyMap() +{ + PL_DHashTableDestroy(mHashTable); +} + +nsresult +NativeToJavaProxyMap::Init() +{ + mHashTable = PL_NewDHashTable(&hash_ops, nsnull, sizeof(Entry), 16); + if (!mHashTable) + return NS_ERROR_OUT_OF_MEMORY; + return NS_OK; +} + +nsresult +NativeToJavaProxyMap::Add(JNIEnv* env, nsISupports* aXPCOMObject, + const nsIID& aIID, jobject aProxy) +{ + Entry* e = NS_STATIC_CAST(Entry*, PL_DHashTableOperate(mHashTable, + aXPCOMObject, + PL_DHASH_ADD)); + if (!e) + return NS_ERROR_FAILURE; + + jweak ref = env->NewWeakGlobalRef(aProxy); + if (!ref) + return NS_ERROR_OUT_OF_MEMORY; + + // Add Java proxy ref to start of list + ProxyList* item = new ProxyList(ref, aIID, e->list); + e->key = aXPCOMObject; + e->list = item; + +#ifdef DEBUG_JAVAXPCOM + char* iid_str = aIID.ToString(); + LOG(("+ NativeToJavaProxyMap (Java=%08x | XPCOM=%08x | IID=%s)\n", + env->CallIntMethod(aProxy, hashCodeMID), (int) aXPCOMObject, iid_str)); + PR_Free(iid_str); +#endif + return NS_OK; +} + +nsresult +NativeToJavaProxyMap::Find(JNIEnv* env, nsISupports* aNativeObject, + const nsIID& aIID, jobject* aResult) +{ + NS_PRECONDITION(aResult != nsnull, "null ptr"); + if (!aResult) + return NS_ERROR_FAILURE; + + *aResult = nsnull; + Entry* e = NS_STATIC_CAST(Entry*, PL_DHashTableOperate(mHashTable, + aNativeObject, + PL_DHASH_LOOKUP)); + + if (PL_DHASH_ENTRY_IS_FREE(e)) + return NS_OK; + + ProxyList* item = e->list; + while (item != nsnull && *aResult == nsnull) { + if (item->iid.Equals(aIID)) { + jobject javaObject = env->NewLocalRef(item->javaObject); + if (javaObject) { + *aResult = javaObject; +#ifdef DEBUG_JAVAXPCOM + char* iid_str = aIID.ToString(); + LOG(("< NativeToJavaProxyMap (Java=%08x | XPCOM=%08x | IID=%s)\n", + env->CallIntMethod(*aResult, hashCodeMID), + (int) aNativeObject, iid_str)); + PR_Free(iid_str); +#endif + } + } + item = item->next; + } + + return NS_OK; +} + +nsresult +NativeToJavaProxyMap::Remove(JNIEnv* env, nsISupports* aNativeObject, + const nsIID& aIID) +{ + Entry* e = NS_STATIC_CAST(Entry*, PL_DHashTableOperate(mHashTable, + aNativeObject, + PL_DHASH_LOOKUP)); + + if (PL_DHASH_ENTRY_IS_FREE(e)) { + NS_WARNING("XPCOM object not found in hash table"); + return NS_ERROR_FAILURE; + } + + ProxyList* item = e->list; + ProxyList* last = e->list; + while (item != nsnull) { + if (item->iid.Equals(aIID)) { +#ifdef DEBUG_JAVAXPCOM + char* iid_str = aIID.ToString(); + LOG(("- NativeToJavaProxyMap (Java=%08x | XPCOM=%08x | IID=%s)\n", + env->CallIntMethod(item->javaObject, hashCodeMID), + (int) aNativeObject, iid_str)); + PR_Free(iid_str); +#endif + + env->DeleteWeakGlobalRef(item->javaObject); + if (item == e->list) { + e->list = item->next; + if (e->list == nsnull) + PL_DHashTableOperate(mHashTable, aNativeObject, PL_DHASH_REMOVE); + } else { + last->next = item->next; + } + + delete item; + return NS_OK; + } + + last = item; + item = item->next; + } + + NS_WARNING("Java proxy matching given IID not found"); + return NS_ERROR_FAILURE; +} + +JavaToXPTCStubMap::~JavaToXPTCStubMap() +{ + PL_DHashTableDestroy(mHashTable); +} + +nsresult +JavaToXPTCStubMap::Init() +{ + mHashTable = PL_NewDHashTable(&hash_ops, nsnull, sizeof(Entry), 16); + if (!mHashTable) + return NS_ERROR_OUT_OF_MEMORY; + return NS_OK; +} + +nsresult +JavaToXPTCStubMap::Add(JNIEnv* env, jobject aJavaObject, nsJavaXPTCStub* aProxy) +{ + jint hash = env->CallIntMethod(aJavaObject, hashCodeMID); + Entry* e = NS_STATIC_CAST(Entry*, PL_DHashTableOperate(mHashTable, + NS_INT32_TO_PTR(hash), + PL_DHASH_ADD)); + if (!e) + return NS_ERROR_FAILURE; + + NS_ASSERTION(e->key == nsnull, + "XPTCStub for given Java object already exists in hash table"); + e->key = hash; + e->xptcstub = aProxy; + +#ifdef DEBUG_JAVAXPCOM + nsIInterfaceInfo* iface_info; + aProxy->GetInterfaceInfo(&iface_info); + nsIID* iid; + iface_info->GetInterfaceIID(&iid); + char* iid_str = iid->ToString(); + LOG(("+ JavaToXPTCStubMap (Java=%08x | XPCOM=%08x | IID=%s)\n", + hash, (int) aProxy, iid_str)); + PR_Free(iid_str); + nsMemory::Free(iid); + NS_RELEASE(iface_info); +#endif + return NS_OK; +} + +nsresult +JavaToXPTCStubMap::Find(JNIEnv* env, jobject aJavaObject, const nsIID& aIID, + nsJavaXPTCStub** aResult) +{ + NS_PRECONDITION(aResult != nsnull, "null ptr"); + if (!aResult) + return NS_ERROR_FAILURE; + + *aResult = nsnull; + jint hash = env->CallIntMethod(aJavaObject, hashCodeMID); + Entry* e = NS_STATIC_CAST(Entry*, PL_DHashTableOperate(mHashTable, + NS_INT32_TO_PTR(hash), + PL_DHASH_LOOKUP)); + + if (PL_DHASH_ENTRY_IS_FREE(e)) + return NS_OK; + + nsresult rv = e->xptcstub->QueryInterface(aIID, (void**) aResult); + +#ifdef DEBUG_JAVAXPCOM + if (NS_SUCCEEDED(rv)) { + char* iid_str = aIID.ToString(); + LOG(("< JavaToXPTCStubMap (Java=%08x | XPCOM=%08x | IID=%s)\n", + hash, (int) *aResult, iid_str)); + PR_Free(iid_str); + } +#endif + + // NS_NOINTERFACE is not an error condition + if (rv == NS_NOINTERFACE) + rv = NS_OK; + return rv; +} + +nsresult +JavaToXPTCStubMap::Remove(JNIEnv* env, jobject aJavaObject) +{ + jint hash = env->CallIntMethod(aJavaObject, hashCodeMID); + PL_DHashTableOperate(mHashTable, NS_INT32_TO_PTR(hash), PL_DHASH_REMOVE); + +#ifdef DEBUG_JAVAXPCOM + LOG(("- JavaToXPTCStubMap (Java=%08x)\n", hash)); +#endif + + return NS_OK; +} + + /********************************************************** * JavaXPCOMInstance *********************************************************/ JavaXPCOMInstance::JavaXPCOMInstance(nsISupports* aInstance, nsIInterfaceInfo* aIInfo) - : mInstance(aInstance), - mIInfo(aIInfo) + : mInstance(aInstance) + , mIInfo(aIInfo) { NS_ADDREF(mInstance); NS_ADDREF(mIInfo); @@ -613,6 +590,124 @@ JavaXPCOMInstance::~JavaXPCOMInstance() } +/******************************* + * Helper functions + *******************************/ + +nsresult +GetNewOrUsedJavaObject(JNIEnv* env, nsISupports* aXPCOMObject, + const nsIID& aIID, jobject* aResult, PRBool* aIsNewProxy) +{ + NS_PRECONDITION(aResult != nsnull, "null ptr"); + if (!aResult) + return NS_ERROR_NULL_POINTER; + + if (aIsNewProxy) { + *aIsNewProxy = PR_FALSE; + } + + nsresult rv; + nsJavaXPTCStub* stub = nsnull; + aXPCOMObject->QueryInterface(NS_GET_IID(nsJavaXPTCStub), (void**) &stub); + if (stub) { + // Get Java object directly from nsJavaXPTCStub + *aResult = stub->GetJavaObject(); + NS_ASSERTION(*aResult != nsnull, "nsJavaXPTCStub w/o matching Java object"); + NS_RELEASE(stub); + return NS_OK; + } + + // Get associated Java object from hash table + rv = gNativeToJavaProxyMap->Find(env, aXPCOMObject, aIID, aResult); + if (NS_FAILED(rv)) + return rv; + if (*aResult) + return NS_OK; + + // No Java object is associated with the given XPCOM object, so we + // create a Java proxy. + if (aIsNewProxy) { + *aIsNewProxy = PR_TRUE; + } + return CreateJavaProxy(env, aXPCOMObject, aIID, aResult); +} + +nsresult +GetNewOrUsedXPCOMObject(JNIEnv* env, jobject aJavaObject, const nsIID& aIID, + nsISupports** aResult, PRBool* aIsXPTCStub) +{ + NS_PRECONDITION(aResult != nsnull && aIsXPTCStub != nsnull, "null ptr"); + if (!aResult || !aIsXPTCStub) + return NS_ERROR_NULL_POINTER; + + nsresult rv; + *aResult = nsnull; + + // Check if the given Java object is actually one of our Java proxies. If so, + // then we query the associated XPCOM object directly from the proxy. + // If Java object is not a proxy, then we try to find associated XPCOM object + // in the mapping table. + jboolean isProxy = env->CallStaticBooleanMethod(xpcomJavaProxyClass, + isXPCOMJavaProxyMID, + aJavaObject); + if (env->ExceptionCheck()) + return NS_ERROR_FAILURE; + + if (isProxy) { + void* inst; + rv = GetXPCOMInstFromProxy(env, aJavaObject, &inst); + if (NS_SUCCEEDED(rv)) { + *aResult = NS_STATIC_CAST(JavaXPCOMInstance*, inst)->GetInstance(); + NS_ADDREF(*aResult); + *aIsXPTCStub = PR_FALSE; + return NS_OK; + } + } + + *aIsXPTCStub = PR_TRUE; + + nsJavaXPTCStub* stub; + rv = gJavaToXPTCStubMap->Find(env, aJavaObject, aIID, &stub); + if (NS_FAILED(rv)) { + return rv; + } + if (stub) { + // stub is already AddRef'd + *aResult = NS_STATIC_CAST(nsISupports*, + NS_STATIC_CAST(nsXPTCStubBase*, stub)); + return NS_OK; + } + + // If there is no corresponding XPCOM object, then that means that the + // parameter is a non-generated class (that is, it is not one of our + // Java stubs that represent an exising XPCOM object). So we need to + // create an XPCOM stub, that can route any method calls to the class. + + // Get interface info for class + nsCOMPtr iim = XPTI_GetInterfaceInfoManager(); + nsCOMPtr iinfo; + rv = iim->GetInfoForIID(&aIID, getter_AddRefs(iinfo)); + if (NS_FAILED(rv)) + return rv; + + // Create XPCOM stub + stub = new nsJavaXPTCStub(env, aJavaObject, iinfo); + if (!stub) { + return NS_ERROR_OUT_OF_MEMORY; + } + rv = gJavaToXPTCStubMap->Add(env, aJavaObject, stub); + if (NS_FAILED(rv)) { + delete stub; + return rv; + } + + NS_ADDREF(stub); + *aResult = NS_STATIC_CAST(nsISupports*, + NS_STATIC_CAST(nsXPTCStubBase*, stub)); + + return NS_OK; +} + nsresult GetIIDForMethodParam(nsIInterfaceInfo *iinfo, const nsXPTMethodInfo *methodInfo, const nsXPTParamInfo ¶mInfo, PRUint16 methodIndex, diff --git a/mozilla/extensions/java/xpcom/nsJavaXPCOMBindingUtils.h b/mozilla/extensions/java/xpcom/nsJavaXPCOMBindingUtils.h index 74e2d9f52c1..e1a9fead3c6 100644 --- a/mozilla/extensions/java/xpcom/nsJavaXPCOMBindingUtils.h +++ b/mozilla/extensions/java/xpcom/nsJavaXPCOMBindingUtils.h @@ -43,9 +43,12 @@ #include "nsCOMPtr.h" #include "nsString.h" #include "pldhash.h" +#include "nsJavaXPTCStub.h" #include "nsAutoLock.h" //#define DEBUG_JAVAXPCOM +//#define DEBUG_JAVAXPCOM_REFCNT + #ifdef DEBUG_JAVAXPCOM #define LOG(x) printf x #else @@ -62,6 +65,7 @@ /********************* * Java JNI globals *********************/ + extern jclass booleanClass; extern jclass charClass; extern jclass byteClass; @@ -101,11 +105,24 @@ extern jmethodID getNameMID; extern jmethodID proxyToStringMID; #endif -class nsJavaXPCOMBindings; -extern nsJavaXPCOMBindings* gBindings; +class NativeToJavaProxyMap; +extern NativeToJavaProxyMap* gNativeToJavaProxyMap; +class JavaToXPTCStubMap; +extern JavaToXPTCStubMap* gJavaToXPTCStubMap; extern PRLock* gJavaXPCOMLock; + +/** + * Initialize global structures used by Javaconnect. + * @param env Java environment pointer + * @return PR_TRUE if Javaconnect is initialized; PR_FALSE if an error occurred + */ PRBool InitializeJavaGlobals(JNIEnv *env); + +/** + * Frees global structures that were allocated by InitializeJavaGlobals(). + * @param env Java environment pointer + */ void FreeJavaGlobals(JNIEnv* env); @@ -129,42 +146,125 @@ private: /************************************** - * Java<->XPCOM binding stores + * Java<->XPCOM object mappings **************************************/ -// This class is used to store the associations between existing Java object -// and XPCOM objects. -class nsJavaXPCOMBindings + +/** + * Maps native XPCOM objects to their associated Java proxy object. + */ +class NativeToJavaProxyMap { +protected: + struct ProxyList + { + ProxyList(const jobject aRef, const nsIID& aIID, ProxyList* aList) + : javaObject(aRef) + , iid(aIID) + , next(aList) + { } + + const jobject javaObject; + const nsIID iid; + ProxyList* next; + }; + + struct Entry : public PLDHashEntryHdr + { + nsISupports* key; + ProxyList* list; + }; + public: - nsJavaXPCOMBindings() - : mJAVAtoXPCOMBindings(nsnull) - , mXPCOMtoJAVABindings(nsnull) + NativeToJavaProxyMap() + : mHashTable(nsnull) { } - ~nsJavaXPCOMBindings(); - // Initializes internal structures. - NS_IMETHOD Init(); + ~NativeToJavaProxyMap(); - // Associates the given Java object with the given XPCOM object - NS_IMETHOD AddBinding(JNIEnv* env, jobject aJavaStub, void* aXPCOMObject); + nsresult Init(); - // Given either a Java object or XPCOM object, removes the association - // between the two. - NS_IMETHOD RemoveBinding(JNIEnv* env, jobject aJavaObject, void* aXPCOMObject); + nsresult Add(JNIEnv* env, nsISupports* aXPCOMObject, const nsIID& aIID, + jobject aProxy); - // Given a Java object, returns the associated XPCOM object. - void* GetXPCOMObject(JNIEnv* env, jobject aJavaObject); + nsresult Find(JNIEnv* env, nsISupports* aNativeObject, const nsIID& aIID, + jobject* aResult); - // Given an XPCOM object, returns the associated Java Object. If a Java - // object doesn't exist, then create a Java proxy for the XPCOM object. - NS_IMETHOD GetJavaObject(JNIEnv* env, void* aXPCOMObject, const nsIID& aIID, - PRBool aDoReleaseObject, jobject* aResult); -private: - PLDHashTable* mJAVAtoXPCOMBindings; - PLDHashTable* mXPCOMtoJAVABindings; + nsresult Remove(JNIEnv* env, nsISupports* aNativeObject, const nsIID& aIID); + +protected: + PLDHashTable* mHashTable; +}; + +/** + * Maps Java objects to their associated nsJavaXPTCStub. + */ +class JavaToXPTCStubMap +{ +protected: + struct Entry : public PLDHashEntryHdr + { + jint key; + nsJavaXPTCStub* xptcstub; + }; + +public: + JavaToXPTCStubMap() + : mHashTable(nsnull) + { } + + ~JavaToXPTCStubMap(); + + nsresult Init(); + + nsresult Add(JNIEnv* env, jobject aJavaObject, nsJavaXPTCStub* aProxy); + + nsresult Find(JNIEnv* env, jobject aJavaObject, const nsIID& aIID, + nsJavaXPTCStub** aResult); + + nsresult Remove(JNIEnv* env, jobject aJavaObject); + +protected: + PLDHashTable* mHashTable; }; +/******************************* + * Helper functions + *******************************/ + +/** + * Finds the associated Java object for the given XPCOM object and IID. If no + * such Java object exists, then it creates one. + * + * @param env Java environment pointer + * @param aXPCOMObject XPCOM object for which to find/create Java object + * @param aIID desired interface IID for Java object + * @param aResult on success, holds reference to Java object + * @param aIsNewProxy on success, holds PR_TRUE if aResult points to newlyXPTCStub; + * created Java proxy; PR_FALSE otherwise + * + * @return NS_OK if succeeded; all other return values are error codes. + */ +nsresult GetNewOrUsedJavaObject(JNIEnv* env, nsISupports* aXPCOMObject, + const nsIID& aIID, jobject* aResult, + PRBool* aIsNewProxy); + +/** + * Finds the associated XPCOM object for the given Java object and IID. If no + * such XPCOM object exists, then it creates one. + * + * @param env Java environment pointer + * @param aJavaObject Java object for which to find/create XPCOM object + * @param aIID desired interface IID for XPCOM object + * @param aResult on success, holds AddRef'd reference to XPCOM object + * @param aIsXPTCStub on success, holds PR_TRUE if aResult points to XPTCStub; + * PR_FALSE if aResult points to native XPCOM object + * + * @return NS_OK if succeeded; all other return values are error codes. + */ +nsresult GetNewOrUsedXPCOMObject(JNIEnv* env, jobject aJavaObject, + const nsIID& aIID, nsISupports** aResult, + PRBool* aIsXPTCStub); nsresult GetIIDForMethodParam(nsIInterfaceInfo *iinfo, const nsXPTMethodInfo *methodInfo, diff --git a/mozilla/extensions/java/xpcom/nsJavaXPTCStub.cpp b/mozilla/extensions/java/xpcom/nsJavaXPTCStub.cpp index 11dfebfa790..2d54e3ba05f 100644 --- a/mozilla/extensions/java/xpcom/nsJavaXPTCStub.cpp +++ b/mozilla/extensions/java/xpcom/nsJavaXPTCStub.cpp @@ -48,58 +48,42 @@ nsJavaXPTCStub::nsJavaXPTCStub(JNIEnv* aJavaEnv, jobject aJavaObject, nsIInterfaceInfo *aIInfo) : mJavaEnv(aJavaEnv) + , mJavaStrongRef(nsnull) , mIInfo(aIInfo) , mMaster(nsnull) + , mWeakRefCnt(0) { - mJavaObject = aJavaEnv->NewGlobalRef(aJavaObject); + mJavaWeakRef = aJavaEnv->NewWeakGlobalRef(aJavaObject); #ifdef DEBUG_JAVAXPCOM - jstring name; - const char* javaObjectName = nsnull; - jclass clazz = mJavaEnv->GetObjectClass(mJavaObject); - if (clazz) { - name = (jstring) mJavaEnv->CallObjectMethod(clazz, getNameMID); - if (name) - javaObjectName = mJavaEnv->GetStringUTFChars(name, nsnull); - } - - nsID* iid = nsnull; - char* iid_str = nsnull; - if (mIInfo) { - nsresult rv = mIInfo->GetInterfaceIID(&iid); - if (NS_SUCCEEDED(rv)) { - iid_str = iid->ToString(); - nsMemory::Free(iid); - } - } - - LOG(("+++ nsJavaXPTCStub(this=0x%08x java_obj=0x%08x %s iid=%s)\n", (int) this, - mJavaEnv->CallIntMethod(mJavaObject, hashCodeMID), - javaObjectName ? javaObjectName : "<-->", iid_str ? iid_str : "NULL")); - if (name) - mJavaEnv->ReleaseStringUTFChars(name, javaObjectName); - if (iid_str) - nsMemory::Free(iid_str); + nsIID* iid; + mIInfo->GetInterfaceIID(&iid); + char* iid_str = iid->ToString(); + LOG(("+ nsJavaXPTCStub (Java=%08x | XPCOM=%08x | IID=%s)\n", + aJavaEnv->CallIntMethod(aJavaObject, hashCodeMID), + (int) this, iid_str)); + PR_Free(iid_str); + nsMemory::Free(iid); #endif } nsJavaXPTCStub::~nsJavaXPTCStub() { -#ifdef DEBUG_JAVAXPCOM - jstring name; - const char* javaObjectName = nsnull; - jclass clazz = mJavaEnv->GetObjectClass(mJavaObject); - if (clazz) { - name = (jstring) mJavaEnv->CallObjectMethod(clazz, getNameMID); - if (name) - javaObjectName = mJavaEnv->GetStringUTFChars(name, nsnull); - } +} - LOG(("--- ~nsJavaXPTCStub(this=0x%08x java_obj=0x%08x %s)\n", (int) this, - mJavaEnv->CallIntMethod(mJavaObject, hashCodeMID), - javaObjectName ? javaObjectName : "<-->")); - if (name) - mJavaEnv->ReleaseStringUTFChars(name, javaObjectName); +void +nsJavaXPTCStub::Destroy() +{ +#ifdef DEBUG_JAVAXPCOM + nsIID* iid; + mIInfo->GetInterfaceIID(&iid); + char* iid_str = iid->ToString(); + jobject javaObject = mJavaEnv->NewLocalRef(mJavaWeakRef); + LOG(("- nsJavaXPTCStub (Java=%08x | XPCOM=%08x | IID=%s)\n", + mJavaEnv->CallIntMethod(javaObject, hashCodeMID), + (int) this, iid_str)); + PR_Free(iid_str); + nsMemory::Free(iid); #endif if (!mMaster) { @@ -108,18 +92,21 @@ nsJavaXPTCStub::~nsJavaXPTCStub() delete (nsJavaXPTCStub*) mChildren[i]; } - gBindings->RemoveBinding(mJavaEnv, mJavaObject, this); + gJavaToXPTCStubMap->Remove(mJavaEnv, mJavaStrongRef); } - mJavaEnv->DeleteGlobalRef(mJavaObject); + mJavaEnv->DeleteWeakGlobalRef(mJavaWeakRef); } NS_IMETHODIMP_(nsrefcnt) -nsJavaXPTCStub::AddRef() +nsJavaXPTCStub::AddRefInternal() { - // if this is a child - if (mMaster) - return mMaster->AddRef(); + // If this is the first AddRef call, we create a strong global ref to the + // Java object to keep it from being garbage collected. + if (mRefCnt == 0) { + mJavaStrongRef = mJavaEnv->NewGlobalRef(mJavaWeakRef); + NS_ASSERTION(mJavaStrongRef != nsnull, "Failed to acquire strong ref"); + } // if this is the master interface NS_PRECONDITION(PRInt32(mRefCnt) >= 0, "illegal refcnt"); @@ -130,24 +117,85 @@ nsJavaXPTCStub::AddRef() } NS_IMETHODIMP_(nsrefcnt) -nsJavaXPTCStub::Release() +nsJavaXPTCStub::AddRef() { - // if this is a child - if (mMaster) - return mMaster->Release(); +#ifdef DEBUG_JAVAXPCOM_REFCNT + nsIID* iid; + mIInfo->GetInterfaceIID(&iid); + char* iid_str = iid->ToString(); + int refcnt = PRInt32(mMaster ? mMaster->mRefCnt : mRefCnt) + 1; + LOG(("= nsJavaXPTCStub::AddRef (XPCOM=%08x | refcnt = %d | IID=%s)\n", + (int) this, refcnt, iid_str)); + PR_Free(iid_str); + nsMemory::Free(iid); +#endif + nsJavaXPTCStub* master = mMaster ? mMaster : this; + return master->AddRefInternal(); +} + +NS_IMETHODIMP_(nsrefcnt) +nsJavaXPTCStub::ReleaseInternal() +{ NS_PRECONDITION(0 != mRefCnt, "dup release"); NS_ASSERT_OWNINGTHREAD(nsJavaXPTCStub); --mRefCnt; NS_LOG_RELEASE(this, mRefCnt, "nsJavaXPTCStub"); if (mRefCnt == 0) { - mRefCnt = 1; /* stabilize */ - delete this; + // If we have a weak ref, we don't delete this object. + if (mWeakRefCnt == 0) { + mRefCnt = 1; /* stabilize */ + Destroy(); + + // delete strong ref; allows Java object to be garbage collected + mJavaEnv->DeleteGlobalRef(mJavaStrongRef); + delete this; + } else { + // delete strong ref; allows Java object to be garbage collected + mJavaEnv->DeleteGlobalRef(mJavaStrongRef); + } return 0; } return mRefCnt; } +NS_IMETHODIMP_(nsrefcnt) +nsJavaXPTCStub::Release() +{ +#ifdef DEBUG_JAVAXPCOM_REFCNT + nsIID* iid; + mIInfo->GetInterfaceIID(&iid); + char* iid_str = iid->ToString(); + int refcnt = PRInt32(mMaster ? mMaster->mRefCnt : mRefCnt) - 1; + LOG(("= nsJavaXPTCStub::Release (XPCOM=%08x | refcnt = %d | IID=%s)\n", + (int) this, refcnt, iid_str)); + PR_Free(iid_str); + nsMemory::Free(iid); +#endif + + nsJavaXPTCStub* master = mMaster ? mMaster : this; + return master->ReleaseInternal(); +} + +void +nsJavaXPTCStub::ReleaseWeakRef() +{ + // if this is a child + if (mMaster) + return mMaster->ReleaseWeakRef(); + + --mWeakRefCnt; + + // If there are no more associated weak refs, and no one else holds a strong + // ref to this object, then delete it. + if (mWeakRefCnt == 0 && mRefCnt == 0) { + NS_ASSERT_OWNINGTHREAD(nsJavaXPTCStub); + mRefCnt = 1; /* stabilize */ + Destroy(); + delete this; + } +} + NS_IMETHODIMP nsJavaXPTCStub::QueryInterface(const nsID &aIID, void **aInstancePtr) { @@ -191,15 +239,17 @@ nsJavaXPTCStub::QueryInterface(const nsID &aIID, void **aInstancePtr) // Query Java object LOG(("\tCalling Java object queryInterface\n")); + jobject javaObject = mJavaEnv->NewLocalRef(mJavaWeakRef); + jmethodID qiMID = 0; - jclass clazz = mJavaEnv->GetObjectClass(mJavaObject); + jclass clazz = mJavaEnv->GetObjectClass(javaObject); if (clazz) { char* sig = "(Ljava/lang/String;)Lorg/mozilla/xpcom/nsISupports;"; qiMID = mJavaEnv->GetMethodID(clazz, "queryInterface", sig); NS_ASSERTION(qiMID, "Failed to get queryInterface method ID"); } - if (qiMID == nsnull) { + if (qiMID == 0) { mJavaEnv->ExceptionClear(); return NS_NOINTERFACE; } @@ -217,7 +267,7 @@ nsJavaXPTCStub::QueryInterface(const nsID &aIID, void **aInstancePtr) PR_Free(iid_str); // call queryInterface method - jobject obj = mJavaEnv->CallObjectMethod(mJavaObject, qiMID, iid_jstr); + jobject obj = mJavaEnv->CallObjectMethod(javaObject, qiMID, iid_jstr); if (mJavaEnv->ExceptionCheck()) { mJavaEnv->ExceptionClear(); return NS_ERROR_FAILURE; @@ -316,10 +366,11 @@ nsJavaXPTCStub::CallMethod(PRUint16 aMethodIndex, #ifdef DEBUG_JAVAXPCOM const char* ifaceName; mIInfo->GetNameShared(&ifaceName); - LOG(("nsJavaXPTCStub::CallMethod [%s::%s]\n", ifaceName, aMethodInfo->GetName())); + LOG(("---> (Java) %s::%s()\n", ifaceName, aMethodInfo->GetName())); #endif nsresult rv = NS_OK; + jobject javaObject = mJavaEnv->NewLocalRef(mJavaWeakRef); nsCAutoString methodSig("("); @@ -375,7 +426,7 @@ nsJavaXPTCStub::CallMethod(PRUint16 aMethodIndex, methodName.SetCharAt(tolower(methodName[0]), 0); } - jclass clazz = mJavaEnv->GetObjectClass(mJavaObject); + jclass clazz = mJavaEnv->GetObjectClass(javaObject); if (clazz) mid = mJavaEnv->GetMethodID(clazz, methodName.get(), methodSig.get()); NS_ASSERTION(mid, "Failed to get requested method for Java object"); @@ -387,46 +438,46 @@ nsJavaXPTCStub::CallMethod(PRUint16 aMethodIndex, jvalue retval; if (NS_SUCCEEDED(rv)) { if (!retvalInfo) { - mJavaEnv->CallVoidMethodA(mJavaObject, mid, java_params); + mJavaEnv->CallVoidMethodA(javaObject, mid, java_params); } else { switch (retvalInfo->GetType().TagPart()) { case nsXPTType::T_I8: case nsXPTType::T_U8: - retval.b = mJavaEnv->CallByteMethodA(mJavaObject, mid, + retval.b = mJavaEnv->CallByteMethodA(javaObject, mid, java_params); break; case nsXPTType::T_I16: case nsXPTType::T_U16: - retval.s = mJavaEnv->CallShortMethodA(mJavaObject, mid, + retval.s = mJavaEnv->CallShortMethodA(javaObject, mid, java_params); break; case nsXPTType::T_I32: case nsXPTType::T_U32: - retval.i = mJavaEnv->CallIntMethodA(mJavaObject, mid, + retval.i = mJavaEnv->CallIntMethodA(javaObject, mid, java_params); break; case nsXPTType::T_FLOAT: - retval.f = mJavaEnv->CallFloatMethodA(mJavaObject, mid, + retval.f = mJavaEnv->CallFloatMethodA(javaObject, mid, java_params); break; case nsXPTType::T_DOUBLE: - retval.d = mJavaEnv->CallDoubleMethodA(mJavaObject, mid, + retval.d = mJavaEnv->CallDoubleMethodA(javaObject, mid, java_params); break; case nsXPTType::T_BOOL: - retval.z = mJavaEnv->CallBooleanMethodA(mJavaObject, mid, + retval.z = mJavaEnv->CallBooleanMethodA(javaObject, mid, java_params); break; case nsXPTType::T_CHAR: case nsXPTType::T_WCHAR: - retval.c = mJavaEnv->CallCharMethodA(mJavaObject, mid, + retval.c = mJavaEnv->CallCharMethodA(javaObject, mid, java_params); break; @@ -439,12 +490,12 @@ nsJavaXPTCStub::CallMethod(PRUint16 aMethodIndex, case nsXPTType::T_CSTRING: case nsXPTType::T_INTERFACE: case nsXPTType::T_INTERFACE_IS: - retval.l = mJavaEnv->CallObjectMethodA(mJavaObject, mid, + retval.l = mJavaEnv->CallObjectMethodA(javaObject, mid, java_params); break; case nsXPTType::T_VOID: - retval.i = mJavaEnv->CallIntMethodA(mJavaObject, mid, + retval.i = mJavaEnv->CallIntMethodA(javaObject, mid, java_params); break; @@ -505,6 +556,7 @@ nsJavaXPTCStub::CallMethod(PRUint16 aMethodIndex, if (java_params) delete [] java_params; + LOG(("<--- (Java) %s::%s()\n", ifaceName, aMethodInfo->GetName())); mJavaEnv->ExceptionClear(); return rv; } @@ -811,11 +863,11 @@ nsJavaXPTCStub::SetupJavaParams(const nsXPTParamInfo &aParamInfo, case nsXPTType::T_INTERFACE: case nsXPTType::T_INTERFACE_IS: { - void* xpcom_obj = nsnull; + nsISupports* xpcom_obj = nsnull; if (!aParamInfo.IsOut()) { // 'in' - xpcom_obj = aVariant.val.p; + xpcom_obj = NS_STATIC_CAST(nsISupports*, aVariant.val.p); } else if (aVariant.val.p) { // 'inout' & 'out' - void** variant = NS_STATIC_CAST(void**, aVariant.val.p); + nsISupports** variant = NS_STATIC_CAST(nsISupports**, aVariant.val.p); xpcom_obj = *variant; } @@ -828,8 +880,8 @@ nsJavaXPTCStub::SetupJavaParams(const nsXPTParamInfo &aParamInfo, break; // Get matching Java object for given xpcom object - rv = gBindings->GetJavaObject(mJavaEnv, xpcom_obj, iid, PR_FALSE, - &java_stub); + rv = GetNewOrUsedJavaObject(mJavaEnv, xpcom_obj, iid, &java_stub, + nsnull); if (NS_FAILED(rv)) break; } @@ -1349,25 +1401,6 @@ nsJavaXPTCStub::FinalizeJavaParams(const nsXPTParamInfo &aParamInfo, nsISupports** variant = NS_STATIC_CAST(nsISupports**, aVariant.val.p); if (java_obj) { - // Check if we already have a corresponding XPCOM object - jboolean isProxy; - isProxy = mJavaEnv->CallStaticBooleanMethod(xpcomJavaProxyClass, - isXPCOMJavaProxyMID, - java_obj); - if (mJavaEnv->ExceptionCheck()) { - rv = NS_ERROR_FAILURE; - break; - } - - void* inst; - if (isProxy) { - rv = GetXPCOMInstFromProxy(mJavaEnv, java_obj, &inst); - if (NS_FAILED(rv)) - break; - } else { - inst = gBindings->GetXPCOMObject(mJavaEnv, java_obj); - } - // Get IID for this param nsID iid; rv = GetIIDForMethodParam(mIInfo, aMethodInfo, aParamInfo, @@ -1376,55 +1409,63 @@ nsJavaXPTCStub::FinalizeJavaParams(const nsXPTParamInfo &aParamInfo, if (NS_FAILED(rv)) break; - PRBool isWeakRef = iid.Equals(NS_GET_IID(nsIWeakReference)); - - if (inst == nsnull && !isWeakRef) { - // Get interface info for class - nsCOMPtr iim = XPTI_GetInterfaceInfoManager(); - nsCOMPtr iinfo; - rv = iim->GetInfoForIID(&iid, getter_AddRefs(iinfo)); - if (NS_FAILED(rv)) - break; - - // Create XPCOM stub - nsJavaXPTCStub* xpcomStub; - xpcomStub = new nsJavaXPTCStub(mJavaEnv, java_obj, iinfo); - if (!xpcomStub) { - rv = NS_ERROR_OUT_OF_MEMORY; - break; - } - inst = SetAsXPTCStub(xpcomStub); - rv = gBindings->AddBinding(mJavaEnv, java_obj, inst); - if (NS_FAILED(rv)) - break; - } - - // Get appropriate XPCOM object - void* xpcom_obj; - if (isWeakRef) { - // If the function expects an weak reference, then we need to - // create it here. - nsJavaXPTCStubWeakRef* weakref; - weakref = new nsJavaXPTCStubWeakRef(mJavaEnv, java_obj); - if (!weakref) { - rv = NS_ERROR_OUT_OF_MEMORY; - break; - } - NS_ADDREF(weakref); - xpcom_obj = weakref; - } else if (IsXPTCStub(inst)) { - nsJavaXPTCStub* xpcomStub = GetXPTCStubAddr(inst); - NS_ADDREF(xpcomStub); - xpcom_obj = xpcomStub; + // If the requested interface is nsIWeakReference, then we look for or + // create a stub for the nsISupports interface. Then we create a weak + // reference from that stub. + PRBool isWeakRef; + if (iid.Equals(NS_GET_IID(nsIWeakReference))) { + isWeakRef = PR_TRUE; + iid = NS_GET_IID(nsISupports); } else { - JavaXPCOMInstance* xpcomInst = (JavaXPCOMInstance*) inst; - xpcom_obj = xpcomInst->GetInstance(); + isWeakRef = PR_FALSE; } + nsISupports* xpcom_obj; + PRBool isXPTCStub; + rv = GetNewOrUsedXPCOMObject(mJavaEnv, java_obj, iid, &xpcom_obj, + &isXPTCStub); + if (NS_FAILED(rv)) + break; + + // If the function expects a weak reference, then we need to + // create it here. + if (isWeakRef) { + if (isXPTCStub) { + nsJavaXPTCStub* stub = NS_STATIC_CAST(nsJavaXPTCStub*, + NS_STATIC_CAST(nsXPTCStubBase*, + xpcom_obj)); + nsJavaXPTCStubWeakRef* weakref; + weakref = new nsJavaXPTCStubWeakRef(mJavaEnv, java_obj, stub); + if (!weakref) { + rv = NS_ERROR_OUT_OF_MEMORY; + break; + } + xpcom_obj = weakref; + NS_ADDREF(xpcom_obj); + } else { // if is native XPCOM object + nsCOMPtr supportsweak = + do_QueryInterface(xpcom_obj); + if (supportsweak) { + nsWeakPtr weakref; + supportsweak->GetWeakReference(getter_AddRefs(weakref)); + xpcom_obj = weakref; + NS_ADDREF(xpcom_obj); + } else { + xpcom_obj = nsnull; + } + } + + } else if (!isXPTCStub) { // if is native XPCOM object + xpcom_obj->Release(); + } + +// } else if (isXPTCStub) { + // nothing to do + if (*variant && !aParamInfo.IsRetval()) { NS_RELEASE(*variant); } - *variant = (nsISupports*) xpcom_obj; + *variant = xpcom_obj; } else { // If were passed in an object, release it now, and set to null. if (*variant && !aParamInfo.IsRetval()) { @@ -1565,13 +1606,15 @@ nsJavaXPTCStub::GetWeakReference(nsIWeakReference** aInstancePtr) if (!aInstancePtr) return NS_ERROR_NULL_POINTER; + jobject javaObject = mJavaEnv->NewLocalRef(mJavaWeakRef); nsJavaXPTCStubWeakRef* weakref; - weakref = new nsJavaXPTCStubWeakRef(mJavaEnv, mJavaObject); + weakref = new nsJavaXPTCStubWeakRef(mJavaEnv, javaObject, this); if (!weakref) return NS_ERROR_OUT_OF_MEMORY; *aInstancePtr = weakref; NS_ADDREF(*aInstancePtr); + ++mWeakRefCnt; return NS_OK; } @@ -1579,5 +1622,18 @@ nsJavaXPTCStub::GetWeakReference(nsIWeakReference** aInstancePtr) jobject nsJavaXPTCStub::GetJavaObject() { - return mJavaObject; + jobject javaObject = mJavaEnv->NewLocalRef(mJavaWeakRef); + +#ifdef DEBUG_JAVAXPCOM + nsIID* iid; + mIInfo->GetInterfaceIID(&iid); + char* iid_str = iid->ToString(); + LOG(("< nsJavaXPTCStub (Java=%08x | XPCOM=%08x | IID=%s)\n", + mJavaEnv->CallIntMethod(javaObject, hashCodeMID), + (int) this, iid_str)); + PR_Free(iid_str); + nsMemory::Free(iid); +#endif + + return javaObject; } diff --git a/mozilla/extensions/java/xpcom/nsJavaXPTCStub.h b/mozilla/extensions/java/xpcom/nsJavaXPTCStub.h index b30d1a2ad1e..753b8aa02ca 100644 --- a/mozilla/extensions/java/xpcom/nsJavaXPTCStub.h +++ b/mozilla/extensions/java/xpcom/nsJavaXPTCStub.h @@ -53,6 +53,8 @@ class nsJavaXPTCStub : public nsXPTCStubBase, public nsSupportsWeakReference { + friend class nsJavaXPTCStubWeakRef; + public: NS_DECL_ISUPPORTS NS_DECL_NSISUPPORTSWEAKREFERENCE @@ -76,14 +78,23 @@ public: jobject GetJavaObject(); private: -// NS_HIDDEN ~JavaStub(); + NS_IMETHOD_(nsrefcnt) AddRefInternal(); + NS_IMETHOD_(nsrefcnt) ReleaseInternal(); + + // Deletes this object and its members. Called by ReleaseInternal() and + // ReleaseWeakRef(). + void Destroy(); + + // When a nsJavaXPTCStubWeakRef associated with this object is released, it + // calls this function to let this object know that there is one less weak + // ref. If there are no more weakrefs referencing this object, and no one + // holds a strong ref, then this function takes care of deleting the object. + void ReleaseWeakRef(); // returns a weak reference to a child supporting the specified interface -// NS_HIDDEN_(JavaStub *) FindStubSupportingIID(const nsID &aIID); nsJavaXPTCStub * FindStubSupportingIID(const nsID &aIID); // returns true if this stub supports the specified interface -// NS_HIDDEN_(PRBool) SupportsIID(const nsID &aIID); PRBool SupportsIID(const nsID &aIID); nsresult SetupJavaParams(const nsXPTParamInfo &aParamInfo, @@ -103,23 +114,14 @@ private: nsresult SetXPCOMRetval(); JNIEnv* mJavaEnv; - jobject mJavaObject; + jweak mJavaWeakRef; + jobject mJavaStrongRef; nsCOMPtr mIInfo; nsVoidArray mChildren; // weak references (cleared by the children) nsJavaXPTCStub *mMaster; // strong reference + + nsAutoRefCnt mWeakRefCnt; // count for number of associated weak refs }; -inline void* SetAsXPTCStub(nsJavaXPTCStub* ptr) - { NS_PRECONDITION(ptr, "null pointer"); - return (void*) (((unsigned long) ptr) | 0x1); } - -inline PRBool IsXPTCStub(void* ptr) - { NS_PRECONDITION(ptr, "null pointer"); - return ((unsigned long) ptr) & 0x1; } - -inline nsJavaXPTCStub* GetXPTCStubAddr(void* ptr) - { NS_PRECONDITION(ptr, "null pointer"); - return (nsJavaXPTCStub*) (((unsigned long) ptr) & ~0x1); } - #endif // _nsJavaXPTCStub_h_ diff --git a/mozilla/extensions/java/xpcom/nsJavaXPTCStubWeakRef.cpp b/mozilla/extensions/java/xpcom/nsJavaXPTCStubWeakRef.cpp index 1d33a6359a6..f3deb9714ca 100644 --- a/mozilla/extensions/java/xpcom/nsJavaXPTCStubWeakRef.cpp +++ b/mozilla/extensions/java/xpcom/nsJavaXPTCStubWeakRef.cpp @@ -42,15 +42,32 @@ #include "nsIInterfaceInfoManager.h" -nsJavaXPTCStubWeakRef::nsJavaXPTCStubWeakRef(JNIEnv* env, jobject aJavaObject) +/** + * How we handle XPCOM weak references to a Java object: + * + * If XPCOM requires or asks for a weak reference of a Java object, we first + * find (or create) an nsJavaXPTCStub for that Java object. That way, there is + * always an nsJavaXPTCStub for any nsJavaXPTCStubWeakRef. However, the + * XPTCStub may not always be 'valid'; that is, its refcount may be zero if + * is not currently referenced by any XPCOM class. + * When an XPCOM method queries the referent from the weak reference, the + * weak ref checks first whether the Java object is still valid. If so, we can + * immediately return an addref'd nsJavaXPTCStub. The XPTCStub takes care of + * finding an XPTCStub for the required IID. + */ + +nsJavaXPTCStubWeakRef::nsJavaXPTCStubWeakRef(JNIEnv* env, jobject aJavaObject, + nsJavaXPTCStub* aXPTCStub) + : mJavaEnv(env) + , mXPTCStub(aXPTCStub) { - mJavaEnv = env; mWeakRef = mJavaEnv->NewWeakGlobalRef(aJavaObject); } nsJavaXPTCStubWeakRef::~nsJavaXPTCStubWeakRef() { mJavaEnv->DeleteWeakGlobalRef(mWeakRef); + mXPTCStub->ReleaseWeakRef(); } NS_IMPL_ADDREF(nsJavaXPTCStubWeakRef) @@ -61,6 +78,8 @@ NS_IMPL_QUERY_INTERFACE1(nsJavaXPTCStubWeakRef, nsIWeakReference) NS_IMETHODIMP nsJavaXPTCStubWeakRef::QueryReferent(const nsIID& aIID, void** aInstancePtr) { + LOG(("nsJavaXPTCStubWeakRef::QueryReferent()\n")); + // Is weak ref still valid? // We create a strong local ref to make sure Java object isn't garbage // collected during this call. @@ -68,35 +87,7 @@ nsJavaXPTCStubWeakRef::QueryReferent(const nsIID& aIID, void** aInstancePtr) if (!javaObject) return NS_ERROR_NULL_POINTER; - // Java object has not been garbage collected. Do we have an - // associated nsJavaXPTCStub? - void* inst = gBindings->GetXPCOMObject(mJavaEnv, javaObject); - - if (!inst) { - // No XPTCStub exists, so create one - - // Get interface info for class - nsCOMPtr iim = XPTI_GetInterfaceInfoManager(); - nsCOMPtr iinfo; - nsresult rv = iim->GetInfoForIID(&aIID, getter_AddRefs(iinfo)); - if (NS_FAILED(rv)) - return rv; - - // Create XPCOM stub - nsJavaXPTCStub* xpcomStub = new nsJavaXPTCStub(mJavaEnv, javaObject, iinfo); - if (!xpcomStub) - return NS_ERROR_OUT_OF_MEMORY; - NS_ADDREF(xpcomStub); - gBindings->AddBinding(mJavaEnv, javaObject, SetAsXPTCStub(xpcomStub)); - - // return created stub - *aInstancePtr = (void*) xpcomStub; - return NS_OK; - } - NS_ASSERTION(IsXPTCStub(inst), "Found xpcom object was not an XPTCStub"); - - // We have an exising XPTCStub, so return QI result - nsJavaXPTCStub* xpcomStub = GetXPTCStubAddr(inst); - return xpcomStub->QueryInterface(aIID, aInstancePtr); + // Java object has not been garbage collected, so return QI from XPTCStub. + return mXPTCStub->QueryInterface(aIID, aInstancePtr); } diff --git a/mozilla/extensions/java/xpcom/nsJavaXPTCStubWeakRef.h b/mozilla/extensions/java/xpcom/nsJavaXPTCStubWeakRef.h index 28ebd4c1da6..3f51936180c 100644 --- a/mozilla/extensions/java/xpcom/nsJavaXPTCStubWeakRef.h +++ b/mozilla/extensions/java/xpcom/nsJavaXPTCStubWeakRef.h @@ -42,17 +42,24 @@ #include "nsIWeakReference.h" +class nsJavaXPTCStub; + +/** + * This class represents an XPCOM weak reference to a Java object. + */ class nsJavaXPTCStubWeakRef : public nsIWeakReference { public: - nsJavaXPTCStubWeakRef(JNIEnv* env, jobject aJavaObject); + nsJavaXPTCStubWeakRef(JNIEnv* env, jobject aJavaObject, + nsJavaXPTCStub* aXPTCStub); virtual ~nsJavaXPTCStubWeakRef(); NS_DECL_ISUPPORTS NS_DECL_NSIWEAKREFERENCE protected: - JNIEnv* mJavaEnv; - jweak mWeakRef; + JNIEnv* mJavaEnv; + jweak mWeakRef; + nsJavaXPTCStub* mXPTCStub; }; #endif // _nsJavaXPTCStubWeakRef_h_ diff --git a/mozilla/extensions/java/xpcom/tests/Foo.java b/mozilla/extensions/java/xpcom/tests/Foo.java index 7255d1821cf..8a197314a44 100644 --- a/mozilla/extensions/java/xpcom/tests/Foo.java +++ b/mozilla/extensions/java/xpcom/tests/Foo.java @@ -46,7 +46,8 @@ public class Foo implements IFoo { { mID = aID; ++gCount; - System.out.println("init: " + mID + " (" + this.hashCode() + "), " + + System.out.println("init: " + mID + " (" + + Integer.toHexString(this.hashCode()) + "), " + gCount +" total"); } @@ -65,7 +66,8 @@ public class Foo implements IFoo { protected void finalize() throws Throwable { --gCount; - System.out.println("destruct: " + mID + " (" + this.hashCode() + "), " + + System.out.println("destruct: " + mID + " (" + + Integer.toHexString(this.hashCode()) + "), " + gCount +" remain"); } } diff --git a/mozilla/extensions/java/xpcom/tests/Makefile.in b/mozilla/extensions/java/xpcom/tests/Makefile.in index d16a3b97bd0..95302de2877 100644 --- a/mozilla/extensions/java/xpcom/tests/Makefile.in +++ b/mozilla/extensions/java/xpcom/tests/Makefile.in @@ -54,6 +54,7 @@ JAVA_SRCS = \ TestArray.java \ TestProps.java \ TestQI.java \ + TestJavaProxy.java \ $(NULL) ifeq ($(OS_ARCH),WINNT) diff --git a/mozilla/extensions/java/xpcom/tests/TestArray.java b/mozilla/extensions/java/xpcom/tests/TestArray.java index 6664ced476a..384640845eb 100644 --- a/mozilla/extensions/java/xpcom/tests/TestArray.java +++ b/mozilla/extensions/java/xpcom/tests/TestArray.java @@ -211,7 +211,8 @@ public class TestArray { for (int index = 0; (index < count) && (index < aExpectedCount); index++) { IFoo foo = (IFoo) aArray.queryElementAt(index, IFoo.IFOO_IID); System.out.println(index + ": " + aElementIDs[index] + "=" + - foo.getId() + " (" + foo.hashCode() + ") " + + foo.getId() + " (" + + Integer.toHexString(foo.hashCode()) + ") " + assertEqual(foo.getId(), aElementIDs[index])); foo = null; } diff --git a/mozilla/extensions/java/xpcom/tests/TestJavaProxy.java b/mozilla/extensions/java/xpcom/tests/TestJavaProxy.java new file mode 100644 index 00000000000..4e07832bc95 --- /dev/null +++ b/mozilla/extensions/java/xpcom/tests/TestJavaProxy.java @@ -0,0 +1,76 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Java XPCOM Bindings. + * + * The Initial Developer of the Original Code is + * IBM Corporation. + * Portions created by the Initial Developer are Copyright (C) 2004 + * IBM Corporation. All Rights Reserved. + * + * Contributor(s): + * Javier Pedemonte (jhpedemonte@gmail.com) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +import org.mozilla.xpcom.*; +import java.io.File; + + +/** + * Tests that if calls to XPCOM functions return the same object, then + * the Javaconnect interface creates the proper Java proxies. + *

+ * The XPCOM call to nsISupports supp = entries.getNext() returns + * an object, for which we create an nsISupports Java proxy. Then, + * the XPCOM call to supp.queryInterface(nsIFile.NS_IFILE_IID) + * will return the same object (same address). Javaconnect needs to be smart + * enough to create a new nsIFile proxy, rather than reusing the + * nsISupports one that was previously created. + *

+ */ +public class TestJavaProxy { + public static void main(String [] args) throws Exception { + System.loadLibrary("javaxpcom"); + + String mozillaPath = System.getProperty("MOZILLA_FIVE_HOME"); + if (mozillaPath == null) { + throw new RuntimeException("MOZILLA_FIVE_HOME system property not set."); + } + + File localFile = new File(mozillaPath); + XPCOM.initXPCOM(localFile, null); + + nsILocalFile directory = XPCOM.newLocalFile("/usr", false); + nsISimpleEnumerator entries = (nsISimpleEnumerator) directory.getDirectoryEntries(); + while (entries.hasMoreElements()) { + nsISupports supp = entries.getNext(); + nsIFile file = (nsIFile) supp.queryInterface(nsIFile.NS_IFILE_IID); + System.out.println(file.getPath()); + } + + XPCOM.shutdownXPCOM(null); + } +}