Back to index

lightning-sunbird  0.9+nobinonly
nsJavaXPTCStub.cpp
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is Java XPCOM Bindings.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * IBM Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 2005
00019  * IBM Corporation. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *   Javier Pedemonte (jhpedemonte@gmail.com)
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #include "nsJavaXPTCStub.h"
00039 #include "nsJavaWrapper.h"
00040 #include "nsJavaXPCOMBindingUtils.h"
00041 #include "prmem.h"
00042 #include "nsIInterfaceInfoManager.h"
00043 #include "nsString.h"
00044 #include "nsString.h"
00045 #include "nsCRT.h"
00046 #include "nsServiceManagerUtils.h"
00047 
00048 
00049 nsJavaXPTCStub::nsJavaXPTCStub(jobject aJavaObject, nsIInterfaceInfo *aIInfo)
00050   : mJavaStrongRef(nsnull)
00051   , mIInfo(aIInfo)
00052   , mMaster(nsnull)
00053   , mWeakRefCnt(0)
00054 {
00055   JNIEnv* env = GetJNIEnv();
00056   jobject weakref = env->NewObject(weakReferenceClass,
00057                                    weakReferenceConstructorMID, aJavaObject);
00058   mJavaWeakRef = env->NewGlobalRef(weakref);
00059   mJavaRefHashCode = env->CallStaticIntMethod(systemClass, hashCodeMID,
00060                                               aJavaObject);
00061 
00062 #ifdef DEBUG_JAVAXPCOM
00063   nsIID* iid;
00064   mIInfo->GetInterfaceIID(&iid);
00065   char* iid_str = iid->ToString();
00066   LOG(("+ nsJavaXPTCStub (Java=%08x | XPCOM=%08x | IID=%s)\n",
00067       (PRUint32) mJavaRefHashCode, (PRUint32) this, iid_str));
00068   PR_Free(iid_str);
00069   nsMemory::Free(iid);
00070 #endif
00071 }
00072 
00073 nsJavaXPTCStub::~nsJavaXPTCStub()
00074 {
00075 }
00076 
00077 NS_IMETHODIMP_(nsrefcnt)
00078 nsJavaXPTCStub::AddRefInternal()
00079 {
00080   // If this is the first AddRef call, we create a strong global ref to the
00081   // Java object to keep it from being garbage collected.
00082   if (mRefCnt == 0) {
00083     JNIEnv* env = GetJNIEnv();
00084     jobject referent = env->CallObjectMethod(mJavaWeakRef, getReferentMID);
00085     if (!env->IsSameObject(referent, NULL)) {
00086       mJavaStrongRef = env->NewGlobalRef(referent);
00087     }
00088     NS_ASSERTION(mJavaStrongRef != nsnull, "Failed to acquire strong ref");
00089   }
00090 
00091   // if this is the master interface
00092   NS_PRECONDITION(PRInt32(mRefCnt) >= 0, "illegal refcnt");
00093   NS_ASSERT_OWNINGTHREAD(nsJavaXPTCStub);
00094   ++mRefCnt;
00095   NS_LOG_ADDREF(this, mRefCnt, "nsJavaXPTCStub", sizeof(*this));
00096   return mRefCnt;
00097 }
00098 
00099 NS_IMETHODIMP_(nsrefcnt)
00100 nsJavaXPTCStub::AddRef()
00101 {
00102 #ifdef DEBUG_JAVAXPCOM_REFCNT
00103   nsIID* iid;
00104   mIInfo->GetInterfaceIID(&iid);
00105   char* iid_str = iid->ToString();
00106   int refcnt = PRInt32(mMaster ? mMaster->mRefCnt : mRefCnt) + 1;
00107   LOG(("= nsJavaXPTCStub::AddRef (XPCOM=%08x | refcnt = %d | IID=%s)\n",
00108        (int) this, refcnt, iid_str));
00109   PR_Free(iid_str);
00110   nsMemory::Free(iid);
00111 #endif
00112 
00113   nsJavaXPTCStub* master = mMaster ? mMaster : this;
00114   return master->AddRefInternal();
00115 }
00116 
00117 NS_IMETHODIMP_(nsrefcnt)
00118 nsJavaXPTCStub::ReleaseInternal()
00119 {
00120   NS_PRECONDITION(0 != mRefCnt, "dup release");
00121   NS_ASSERT_OWNINGTHREAD(nsJavaXPTCStub);
00122   --mRefCnt;
00123   NS_LOG_RELEASE(this, mRefCnt, "nsJavaXPTCStub");
00124   if (mRefCnt == 0) {
00125     // delete strong ref; allows Java object to be garbage collected
00126     DeleteStrongRef();
00127 
00128     // If we have a weak ref, we don't delete this object.
00129     if (mWeakRefCnt == 0) {
00130       mRefCnt = 1; /* stabilize */
00131       Destroy();
00132       delete this;
00133     }
00134     return 0;
00135   }
00136   return mRefCnt;
00137 }
00138 
00139 NS_IMETHODIMP_(nsrefcnt)
00140 nsJavaXPTCStub::Release()
00141 {
00142 #ifdef DEBUG_JAVAXPCOM_REFCNT
00143   nsIID* iid;
00144   mIInfo->GetInterfaceIID(&iid);
00145   char* iid_str = iid->ToString();
00146   int refcnt = PRInt32(mMaster ? mMaster->mRefCnt : mRefCnt) - 1;
00147   LOG(("= nsJavaXPTCStub::Release (XPCOM=%08x | refcnt = %d | IID=%s)\n",
00148        (int) this, refcnt, iid_str));
00149   PR_Free(iid_str);
00150   nsMemory::Free(iid);
00151 #endif
00152 
00153   nsJavaXPTCStub* master = mMaster ? mMaster : this;
00154   return master->ReleaseInternal();
00155 }
00156 
00157 void
00158 nsJavaXPTCStub::Destroy()
00159 {
00160   JNIEnv* env = GetJNIEnv();
00161 
00162 #ifdef DEBUG_JAVAXPCOM
00163   nsIID* iid;
00164   mIInfo->GetInterfaceIID(&iid);
00165   char* iid_str = iid->ToString();
00166   LOG(("- nsJavaXPTCStub (Java=%08x | XPCOM=%08x | IID=%s)\n",
00167       (PRUint32) mJavaRefHashCode, (PRUint32) this, iid_str));
00168   PR_Free(iid_str);
00169   nsMemory::Free(iid);
00170 #endif
00171 
00172   if (!mMaster) {
00173     // delete each child stub
00174     for (PRInt32 i = 0; i < mChildren.Count(); i++) {
00175       delete (nsJavaXPTCStub*) mChildren[i];
00176     }
00177 
00178     // Since we are destroying this stub, also remove the mapping.
00179     // It is possible for mJavaStrongRef to be NULL here.  That is why we
00180     // store the hash code value earlier.
00181     if (gJavaXPCOMInitialized) {
00182       gJavaToXPTCStubMap->Remove(mJavaRefHashCode);
00183     }
00184   }
00185 
00186   env->CallVoidMethod(mJavaWeakRef, clearReferentMID);
00187   env->DeleteGlobalRef(mJavaWeakRef);
00188 }
00189 
00190 void
00191 nsJavaXPTCStub::ReleaseWeakRef()
00192 {
00193   // if this is a child
00194   if (mMaster)
00195     mMaster->ReleaseWeakRef();
00196 
00197   --mWeakRefCnt;
00198 
00199   // If there are no more associated weak refs, and no one else holds a strong
00200   // ref to this object, then delete it.
00201   if (mWeakRefCnt == 0 && mRefCnt == 0) {
00202     NS_ASSERT_OWNINGTHREAD(nsJavaXPTCStub);
00203     mRefCnt = 1; /* stabilize */
00204     Destroy();
00205     delete this;
00206   }
00207 }
00208 
00209 void
00210 nsJavaXPTCStub::DeleteStrongRef()
00211 {
00212   if (mJavaStrongRef == nsnull)
00213     return;
00214 
00215   GetJNIEnv()->DeleteGlobalRef(mJavaStrongRef);
00216   mJavaStrongRef = nsnull;
00217 }
00218 
00219 NS_IMETHODIMP
00220 nsJavaXPTCStub::QueryInterface(const nsID &aIID, void **aInstancePtr)
00221 {
00222   nsresult rv;
00223 
00224   LOG(("JavaStub::QueryInterface()\n"));
00225   *aInstancePtr = nsnull;
00226   nsJavaXPTCStub *master = mMaster ? mMaster : this;
00227 
00228   // This helps us differentiate between the help classes.
00229   if (aIID.Equals(NS_GET_IID(nsJavaXPTCStub)))
00230   {
00231     *aInstancePtr = master;
00232     NS_ADDREF(this);
00233     return NS_OK;
00234   }
00235 
00236   // always return the master stub for nsISupports
00237   if (aIID.Equals(NS_GET_IID(nsISupports)))
00238   {
00239     *aInstancePtr = NS_STATIC_CAST(nsISupports*,
00240                                    NS_STATIC_CAST(nsXPTCStubBase*, master));
00241     NS_ADDREF(master);
00242     return NS_OK;
00243   }
00244 
00245   // All Java objects support weak references
00246   if (aIID.Equals(NS_GET_IID(nsISupportsWeakReference)))
00247   {
00248     *aInstancePtr = NS_STATIC_CAST(nsISupportsWeakReference*, master);
00249     NS_ADDREF(master);
00250     return NS_OK;
00251   }
00252 
00253   // does any existing stub support the requested IID?
00254   nsJavaXPTCStub *stub = master->FindStubSupportingIID(aIID);
00255   if (stub)
00256   {
00257     *aInstancePtr = stub;
00258     NS_ADDREF(stub);
00259     return NS_OK;
00260   }
00261 
00262   JNIEnv* env = GetJNIEnv();
00263 
00264   // Query Java object
00265   LOG(("\tCalling Java object queryInterface\n"));
00266   jobject javaObject = env->CallObjectMethod(mJavaWeakRef, getReferentMID);
00267 
00268   jmethodID qiMID = 0;
00269   jclass clazz = env->GetObjectClass(javaObject);
00270   if (clazz) {
00271     char* sig = "(Ljava/lang/String;)Lorg/mozilla/interfaces/nsISupports;";
00272     qiMID = env->GetMethodID(clazz, "queryInterface", sig);
00273     NS_ASSERTION(qiMID, "Failed to get queryInterface method ID");
00274   }
00275 
00276   if (qiMID == 0) {
00277     env->ExceptionClear();
00278     return NS_NOINTERFACE;
00279   }
00280 
00281   // construct IID string
00282   jstring iid_jstr = nsnull;
00283   char* iid_str = aIID.ToString();
00284   if (iid_str) {
00285     iid_jstr = env->NewStringUTF(iid_str);
00286   }
00287   if (!iid_str || !iid_jstr) {
00288     env->ExceptionClear();
00289     return NS_ERROR_OUT_OF_MEMORY;
00290   }
00291   PR_Free(iid_str);
00292 
00293   // call queryInterface method
00294   jobject obj = env->CallObjectMethod(javaObject, qiMID, iid_jstr);
00295   if (env->ExceptionCheck()) {
00296     env->ExceptionClear();
00297     return NS_ERROR_FAILURE;
00298   }
00299   if (!obj)
00300     return NS_NOINTERFACE;
00301 
00302   // Get interface info for new java object
00303   nsCOMPtr<nsIInterfaceInfoManager> iim = XPTI_GetInterfaceInfoManager();
00304 
00305   nsCOMPtr<nsIInterfaceInfo> iinfo;
00306   rv = iim->GetInfoForIID(&aIID, getter_AddRefs(iinfo));
00307   if (NS_FAILED(rv))
00308     return rv;
00309 
00310   stub = new nsJavaXPTCStub(obj, iinfo);
00311   if (!stub)
00312     return NS_ERROR_OUT_OF_MEMORY;
00313 
00314   // add stub to the master's list of children, so we can preserve
00315   // symmetry in future QI calls.  the master will delete each child
00316   // when it is destroyed.  the refcount of each child is bound to
00317   // the refcount of the master.  this is done to deal with code
00318   // like this:
00319   //
00320   //   nsCOMPtr<nsIBar> bar = ...;
00321   //   nsIFoo *foo;
00322   //   {
00323   //     nsCOMPtr<nsIFoo> temp = do_QueryInterface(bar);
00324   //     foo = temp;
00325   //   }
00326   //   foo->DoStuff();
00327   //
00328   // while this code is not valid XPCOM (since it is using |foo|
00329   // after having called Release on it), such code is unfortunately
00330   // very common in the mozilla codebase.  the assumption this code
00331   // is making is that so long as |bar| is alive, it should be valid
00332   // to access |foo| even if the code doesn't own a strong reference
00333   // to |foo|!  clearly wrong, but we need to support it anyways.
00334 
00335   stub->mMaster = master;
00336   master->mChildren.AppendElement(stub);
00337 
00338   *aInstancePtr = stub;
00339   NS_ADDREF(stub);
00340   return NS_OK;
00341 }
00342 
00343 PRBool
00344 nsJavaXPTCStub::SupportsIID(const nsID &iid)
00345 {
00346   PRBool match;
00347   nsCOMPtr<nsIInterfaceInfo> iter = mIInfo;
00348   do
00349   {
00350     if (NS_SUCCEEDED(iter->IsIID(&iid, &match)) && match)
00351       return PR_TRUE;
00352 
00353     nsCOMPtr<nsIInterfaceInfo> parent;
00354     iter->GetParent(getter_AddRefs(parent));
00355     iter = parent;
00356   }
00357   while (iter != nsnull);
00358 
00359   return PR_FALSE;
00360 }
00361 
00362 nsJavaXPTCStub *
00363 nsJavaXPTCStub::FindStubSupportingIID(const nsID &iid)
00364 {
00365   NS_ASSERTION(mMaster == nsnull, "this is not a master stub");
00366 
00367   if (SupportsIID(iid))
00368     return this;
00369 
00370   for (PRInt32 i = 0; i < mChildren.Count(); i++)
00371   {
00372     nsJavaXPTCStub *child = (nsJavaXPTCStub *) mChildren[i];
00373     if (child->SupportsIID(iid))
00374       return child;
00375   }
00376   return nsnull;
00377 }
00378 
00379 NS_IMETHODIMP
00380 nsJavaXPTCStub::GetInterfaceInfo(nsIInterfaceInfo **aInfo)
00381 {
00382   NS_ADDREF(*aInfo = mIInfo);
00383   return NS_OK;
00384 }
00385 
00386 NS_IMETHODIMP
00387 nsJavaXPTCStub::CallMethod(PRUint16 aMethodIndex,
00388                            const nsXPTMethodInfo *aMethodInfo,
00389                            nsXPTCMiniVariant *aParams)
00390 {
00391 #ifdef DEBUG_JAVAXPCOM
00392   const char* ifaceName;
00393   mIInfo->GetNameShared(&ifaceName);
00394   LOG(("---> (Java) %s::%s()\n", ifaceName, aMethodInfo->GetName()));
00395 #endif
00396 
00397   nsresult rv = NS_OK;
00398   JNIEnv* env = GetJNIEnv();
00399   jobject javaObject = env->CallObjectMethod(mJavaWeakRef, getReferentMID);
00400 
00401   nsCAutoString methodSig("(");
00402 
00403   // Create jvalue array to hold Java params
00404   PRUint8 paramCount = aMethodInfo->GetParamCount();
00405   jvalue* java_params = nsnull;
00406   const nsXPTParamInfo* retvalInfo = nsnull;
00407   if (paramCount) {
00408     java_params = new jvalue[paramCount];
00409     if (!java_params)
00410       return NS_ERROR_OUT_OF_MEMORY;
00411 
00412     for (PRUint8 i = 0; i < paramCount && NS_SUCCEEDED(rv); i++)
00413     {
00414       const nsXPTParamInfo &paramInfo = aMethodInfo->GetParam(i);
00415       if (!paramInfo.IsRetval()) {
00416         rv = SetupJavaParams(paramInfo, aMethodInfo, aMethodIndex, aParams,
00417                              aParams[i], java_params[i], methodSig);
00418       } else {
00419         retvalInfo = &paramInfo;
00420       }
00421     }
00422     NS_ASSERTION(NS_SUCCEEDED(rv), "SetupJavaParams failed");
00423   }
00424 
00425   // Finish method signature
00426   if (NS_SUCCEEDED(rv)) {
00427     methodSig.Append(')');
00428     if (retvalInfo) {
00429       nsCAutoString retvalSig;
00430       rv = GetRetvalSig(retvalInfo, aMethodInfo, aMethodIndex, aParams,
00431                         retvalSig);
00432       methodSig.Append(retvalSig);
00433     } else {
00434       methodSig.Append('V');
00435     }
00436     NS_ASSERTION(NS_SUCCEEDED(rv), "GetRetvalSig failed");
00437   }
00438 
00439   // Get Java method to call
00440   jmethodID mid = nsnull;
00441   if (NS_SUCCEEDED(rv)) {
00442     nsCAutoString methodName;
00443     if (aMethodInfo->IsGetter() || aMethodInfo->IsSetter()) {
00444       if (aMethodInfo->IsGetter())
00445         methodName.AppendLiteral("get");
00446       else
00447         methodName.AppendLiteral("set");
00448       methodName.AppendASCII(aMethodInfo->GetName());
00449       methodName.SetCharAt(toupper(methodName[3]), 3);
00450     } else {
00451       methodName.AppendASCII(aMethodInfo->GetName());
00452       methodName.SetCharAt(tolower(methodName[0]), 0);
00453     }
00454     // If it's a Java keyword, then prepend an underscore
00455     if (gJavaKeywords->GetEntry(methodName.get())) {
00456       methodName.Insert('_', 0);
00457     }
00458 
00459     jclass clazz = env->GetObjectClass(javaObject);
00460     if (clazz)
00461       mid = env->GetMethodID(clazz, methodName.get(), methodSig.get());
00462     NS_ASSERTION(mid, "Failed to get requested method for Java object");
00463     if (!mid)
00464       rv = NS_ERROR_FAILURE;
00465   }
00466 
00467   // Call method
00468   jvalue retval;
00469   if (NS_SUCCEEDED(rv)) {
00470     if (!retvalInfo) {
00471       env->CallVoidMethodA(javaObject, mid, java_params);
00472     } else {
00473       switch (retvalInfo->GetType().TagPart())
00474       {
00475         case nsXPTType::T_I8:
00476           retval.b = env->CallByteMethodA(javaObject, mid, java_params);
00477           break;
00478 
00479         case nsXPTType::T_I16:
00480         case nsXPTType::T_U8:
00481           retval.s = env->CallShortMethodA(javaObject, mid, java_params);
00482           break;
00483 
00484         case nsXPTType::T_I32:
00485         case nsXPTType::T_U16:
00486           retval.i = env->CallIntMethodA(javaObject, mid, java_params);
00487           break;
00488 
00489         case nsXPTType::T_I64:
00490         case nsXPTType::T_U32:
00491           retval.j = env->CallLongMethodA(javaObject, mid, java_params);
00492           break;
00493 
00494         case nsXPTType::T_FLOAT:
00495           retval.f = env->CallFloatMethodA(javaObject, mid, java_params);
00496           break;
00497 
00498         case nsXPTType::T_U64:
00499         case nsXPTType::T_DOUBLE:
00500           retval.d = env->CallDoubleMethodA(javaObject, mid, java_params);
00501           break;
00502 
00503         case nsXPTType::T_BOOL:
00504           retval.z = env->CallBooleanMethodA(javaObject, mid, java_params);
00505           break;
00506 
00507         case nsXPTType::T_CHAR:
00508         case nsXPTType::T_WCHAR:
00509           retval.c = env->CallCharMethodA(javaObject, mid, java_params);
00510           break;
00511 
00512         case nsXPTType::T_CHAR_STR:
00513         case nsXPTType::T_WCHAR_STR:
00514         case nsXPTType::T_IID:
00515         case nsXPTType::T_ASTRING:
00516         case nsXPTType::T_DOMSTRING:
00517         case nsXPTType::T_UTF8STRING:
00518         case nsXPTType::T_CSTRING:
00519         case nsXPTType::T_INTERFACE:
00520         case nsXPTType::T_INTERFACE_IS:
00521           retval.l = env->CallObjectMethodA(javaObject, mid, java_params);
00522           break;
00523 
00524         case nsXPTType::T_VOID:
00525           retval.j = env->CallLongMethodA(javaObject, mid, java_params);
00526           break;
00527 
00528         default:
00529           NS_WARNING("Unhandled retval type");
00530           break;
00531       }
00532     }
00533 
00534     // Check for exception from called Java function
00535     jthrowable exp = env->ExceptionOccurred();
00536     if (exp) {
00537       // If the exception is an instance of XPCOMException, then get the
00538       // nsresult from the exception instance.  Else, default to
00539       // NS_ERROR_FAILURE.
00540       if (env->IsInstanceOf(exp, xpcomExceptionClass)) {
00541         jfieldID fid;
00542         fid = env->GetFieldID(xpcomExceptionClass, "errorcode", "J");
00543         if (fid) {
00544           rv = env->GetLongField(exp, fid);
00545         } else {
00546           rv = NS_ERROR_FAILURE;
00547         }
00548         NS_ASSERTION(fid, "Couldn't get 'errorcode' field of XPCOMException");
00549       } else {
00550         rv = NS_ERROR_FAILURE;
00551       }
00552     }
00553   }
00554 
00555   // Handle any 'inout', 'out' and 'retval' params
00556   if (NS_SUCCEEDED(rv)) {
00557     for (PRUint8 i = 0; i < paramCount; i++)
00558     {
00559       const nsXPTParamInfo &paramInfo = aMethodInfo->GetParam(i);
00560       if (paramInfo.IsIn() && !paramInfo.IsOut() && !paramInfo.IsDipper()) // 'in'
00561         continue;
00562 
00563       // If param is null, then caller is not expecting an output value.
00564       if (aParams[i].val.p == nsnull)
00565         continue;
00566 
00567       if (!paramInfo.IsRetval()) {
00568         rv = FinalizeJavaParams(paramInfo, aMethodInfo, aMethodIndex, aParams,
00569                                 aParams[i], java_params[i]);
00570       } else {
00571         rv = FinalizeJavaParams(paramInfo, aMethodInfo, aMethodIndex, aParams,
00572                                 aParams[i], retval);
00573       }
00574     }
00575     NS_ASSERTION(NS_SUCCEEDED(rv), "FinalizeJavaParams/SetXPCOMRetval failed");
00576   }
00577 
00578   if (java_params)
00579     delete [] java_params;
00580 
00581 #ifdef DEBUG
00582   if (env->ExceptionCheck())
00583     env->ExceptionDescribe();
00584 #endif
00585   env->ExceptionClear();
00586 
00587   LOG(("<--- (Java) %s::%s()\n", ifaceName, aMethodInfo->GetName()));
00588   return rv;
00589 }
00590 
00594 nsresult
00595 nsJavaXPTCStub::SetupJavaParams(const nsXPTParamInfo &aParamInfo,
00596                 const nsXPTMethodInfo* aMethodInfo,
00597                 PRUint16 aMethodIndex,
00598                 nsXPTCMiniVariant* aDispatchParams,
00599                 nsXPTCMiniVariant &aVariant, jvalue &aJValue,
00600                 nsACString &aMethodSig)
00601 {
00602   nsresult rv = NS_OK;
00603   JNIEnv* env = GetJNIEnv();
00604   const nsXPTType &type = aParamInfo.GetType();
00605 
00606   PRUint8 tag = type.TagPart();
00607   switch (tag)
00608   {
00609     case nsXPTType::T_I8:
00610     {
00611       if (!aParamInfo.IsOut()) {  // 'in'
00612         aJValue.b = aVariant.val.i8;
00613         aMethodSig.Append('B');
00614       } else {  // 'inout' & 'out'
00615         if (aVariant.val.p) {
00616           jbyteArray array = env->NewByteArray(1);
00617           if (!array) {
00618             rv = NS_ERROR_OUT_OF_MEMORY;
00619             break;
00620           }
00621 
00622           env->SetByteArrayRegion(array, 0, 1, (jbyte*) aVariant.val.p);
00623           aJValue.l = array;
00624         } else {
00625           aJValue.l = nsnull;
00626         }
00627         aMethodSig.AppendLiteral("[B");
00628       }
00629     }
00630     break;
00631 
00632     case nsXPTType::T_I16:
00633     case nsXPTType::T_U8:
00634     {
00635       if (!aParamInfo.IsOut()) {  // 'in'
00636         aJValue.s = (tag == nsXPTType::T_I16) ? aVariant.val.i16 :
00637                                                 aVariant.val.u8;
00638         aMethodSig.Append('S');
00639       } else {  // 'inout' & 'out'
00640         if (aVariant.val.p) {
00641           jshortArray array = env->NewShortArray(1);
00642           if (!array) {
00643             rv = NS_ERROR_OUT_OF_MEMORY;
00644             break;
00645           }
00646 
00647           env->SetShortArrayRegion(array, 0, 1, (jshort*) aVariant.val.p);
00648           aJValue.l = array;
00649         } else {
00650           aJValue.l = nsnull;
00651         }
00652         aMethodSig.AppendLiteral("[S");
00653       }
00654     }
00655     break;
00656 
00657     case nsXPTType::T_I32:
00658     case nsXPTType::T_U16:
00659     {
00660       if (!aParamInfo.IsOut()) {  // 'in'
00661         aJValue.i = (tag == nsXPTType::T_I32) ? aVariant.val.i32 :
00662                                                 aVariant.val.u16;
00663         aMethodSig.Append('I');
00664       } else {  // 'inout' & 'out'
00665         if (aVariant.val.p) {
00666           jintArray array = env->NewIntArray(1);
00667           if (!array) {
00668             rv = NS_ERROR_OUT_OF_MEMORY;
00669             break;
00670           }
00671 
00672           env->SetIntArrayRegion(array, 0, 1, (jint*) aVariant.val.p);
00673           aJValue.l = array;
00674         } else {
00675           aJValue.l = nsnull;
00676         }
00677         aMethodSig.AppendLiteral("[I");
00678       }
00679     }
00680     break;
00681 
00682     case nsXPTType::T_I64:
00683     case nsXPTType::T_U32:
00684     {
00685       if (!aParamInfo.IsOut()) {  // 'in'
00686         aJValue.j = (tag == nsXPTType::T_I64) ? aVariant.val.i64 :
00687                                                 aVariant.val.u32;
00688         aMethodSig.Append('J');
00689       } else {  // 'inout' & 'out'
00690         if (aVariant.val.p) {
00691           jlongArray array = env->NewLongArray(1);
00692           if (!array) {
00693             rv = NS_ERROR_OUT_OF_MEMORY;
00694             break;
00695           }
00696 
00697           env->SetLongArrayRegion(array, 0, 1, (jlong*) aVariant.val.p);
00698           aJValue.l = array;
00699         } else {
00700           aJValue.l = nsnull;
00701         }
00702         aMethodSig.AppendLiteral("[J");
00703       }
00704     }
00705     break;
00706 
00707     case nsXPTType::T_FLOAT:
00708     {
00709       if (!aParamInfo.IsOut()) {  // 'in'
00710         aJValue.f = aVariant.val.f;
00711         aMethodSig.Append('F');
00712       } else {  // 'inout' & 'out'
00713         if (aVariant.val.p) {
00714           jfloatArray array = env->NewFloatArray(1);
00715           if (!array) {
00716             rv = NS_ERROR_OUT_OF_MEMORY;
00717             break;
00718           }
00719 
00720           env->SetFloatArrayRegion(array, 0, 1, (jfloat*) aVariant.val.p);
00721           aJValue.l = array;
00722         } else {
00723           aJValue.l = nsnull;
00724         }
00725         aMethodSig.AppendLiteral("[F");
00726       }
00727     }
00728     break;
00729 
00730     // XXX how do we handle unsigned 64-bit values?
00731     case nsXPTType::T_U64:
00732     case nsXPTType::T_DOUBLE:
00733     {
00734       if (!aParamInfo.IsOut()) {  // 'in'
00735         aJValue.d = (tag == nsXPTType::T_DOUBLE) ? aVariant.val.d :
00736                                                    aVariant.val.u64;
00737         aMethodSig.Append('D');
00738       } else {  // 'inout' & 'out'
00739         if (aVariant.val.p) {
00740           jdoubleArray array = env->NewDoubleArray(1);
00741           if (!array) {
00742             rv = NS_ERROR_OUT_OF_MEMORY;
00743             break;
00744           }
00745 
00746           env->SetDoubleArrayRegion(array, 0, 1, (jdouble*) aVariant.val.p);
00747           aJValue.l = array;
00748         } else {
00749           aJValue.l = nsnull;
00750         }
00751         aMethodSig.AppendLiteral("[D");
00752       }
00753     }
00754     break;
00755 
00756     case nsXPTType::T_BOOL:
00757     {
00758       if (!aParamInfo.IsOut()) {  // 'in'
00759         aJValue.z = aVariant.val.b;
00760         aMethodSig.Append('Z');
00761       } else {  // 'inout' & 'out'
00762         if (aVariant.val.p) {
00763           jbooleanArray array = env->NewBooleanArray(1);
00764           if (!array) {
00765             rv = NS_ERROR_OUT_OF_MEMORY;
00766             break;
00767           }
00768 
00769           env->SetBooleanArrayRegion(array, 0, 1, (jboolean*) aVariant.val.p);
00770           aJValue.l = array;
00771         } else {
00772           aJValue.l = nsnull;
00773         }
00774         aMethodSig.AppendLiteral("[Z");
00775       }
00776     }
00777     break;
00778 
00779     case nsXPTType::T_CHAR:
00780     case nsXPTType::T_WCHAR:
00781     {
00782       if (!aParamInfo.IsOut()) {  // 'in'
00783         if (tag == nsXPTType::T_CHAR)
00784           aJValue.c = aVariant.val.c;
00785         else
00786           aJValue.c = aVariant.val.wc;
00787         aMethodSig.Append('C');
00788       } else {  // 'inout' & 'out'
00789         if (aVariant.val.p) {
00790           jcharArray array = env->NewCharArray(1);
00791           if (!array) {
00792             rv = NS_ERROR_OUT_OF_MEMORY;
00793             break;
00794           }
00795 
00796           env->SetCharArrayRegion(array, 0, 1, (jchar*) aVariant.val.p);
00797           aJValue.l = array;
00798         } else {
00799           aJValue.l = nsnull;
00800         }
00801         aMethodSig.AppendLiteral("[C");
00802       }
00803     }
00804     break;
00805 
00806     case nsXPTType::T_CHAR_STR:
00807     case nsXPTType::T_WCHAR_STR:
00808     {
00809       void* ptr = nsnull;
00810       if (!aParamInfo.IsOut()) {  // 'in'
00811         ptr = aVariant.val.p;
00812       } else if (aVariant.val.p) {  // 'inout' & 'out'
00813         void** variant = NS_STATIC_CAST(void**, aVariant.val.p);
00814         ptr = *variant;
00815       }
00816 
00817       jobject str;
00818       if (ptr) {
00819         if (tag == nsXPTType::T_CHAR_STR) {
00820           str = env->NewStringUTF((const char*) ptr);
00821         } else {
00822           const PRUnichar* buf = (const PRUnichar*) ptr;
00823           str = env->NewString(buf, nsCRT::strlen(buf));
00824         }
00825         if (!str) {
00826           rv = NS_ERROR_OUT_OF_MEMORY;
00827           break;
00828         }
00829       } else {
00830         str = nsnull;
00831       }
00832 
00833       if (!aParamInfo.IsOut()) {  // 'in'
00834         aJValue.l = str;
00835         aMethodSig.AppendLiteral("Ljava/lang/String;");
00836       } else {  // 'inout' & 'out'
00837         if (aVariant.val.p) {
00838           aJValue.l = env->NewObjectArray(1, stringClass, str);
00839           if (aJValue.l == nsnull) {
00840             rv = NS_ERROR_OUT_OF_MEMORY;
00841             break;
00842           }
00843         } else {
00844           aJValue.l = nsnull;
00845         }
00846         aMethodSig.AppendLiteral("[Ljava/lang/String;");
00847       }
00848     }
00849     break;
00850 
00851     case nsXPTType::T_IID:
00852     {
00853       nsID* iid = nsnull;
00854       if (!aParamInfo.IsOut()) {  // 'in'
00855         iid = NS_STATIC_CAST(nsID*, aVariant.val.p);
00856       } else if (aVariant.val.p) {  // 'inout' & 'out'
00857         nsID** variant = NS_STATIC_CAST(nsID**, aVariant.val.p);
00858         iid = *variant;
00859       }
00860 
00861       jobject str = nsnull;
00862       if (iid) {
00863         char* iid_str = iid->ToString();
00864         if (iid_str) {
00865           str = env->NewStringUTF(iid_str);
00866         }
00867         if (!iid_str || !str) {
00868           rv = NS_ERROR_OUT_OF_MEMORY;
00869           break;
00870         }
00871         PR_Free(iid_str);
00872       }
00873 
00874       if (!aParamInfo.IsOut()) {  // 'in'
00875         aJValue.l = str;
00876         aMethodSig.AppendLiteral("Ljava/lang/String;");
00877       } else {  // 'inout' & 'out'
00878         if (aVariant.val.p) {
00879           aJValue.l = env->NewObjectArray(1, stringClass, str);
00880           if (aJValue.l == nsnull) {
00881             rv = NS_ERROR_OUT_OF_MEMORY;
00882             break;
00883           }
00884         } else {
00885           aJValue.l = nsnull;
00886         }
00887         aMethodSig.AppendLiteral("[Ljava/lang/String;");
00888       }
00889     }
00890     break;
00891 
00892     case nsXPTType::T_INTERFACE:
00893     case nsXPTType::T_INTERFACE_IS:
00894     {
00895       nsISupports* xpcom_obj = nsnull;
00896       if (!aParamInfo.IsOut()) {  // 'in'
00897         xpcom_obj = NS_STATIC_CAST(nsISupports*, aVariant.val.p);
00898       } else if (aVariant.val.p) {  // 'inout' & 'out'
00899         nsISupports** variant = NS_STATIC_CAST(nsISupports**, aVariant.val.p);
00900         xpcom_obj = *variant;
00901       }
00902 
00903       nsID iid;
00904       rv = GetIIDForMethodParam(mIInfo, aMethodInfo, aParamInfo,
00905                                 aParamInfo.GetType().TagPart(), aMethodIndex,
00906                                 aDispatchParams, PR_FALSE, iid);
00907       if (NS_FAILED(rv))
00908         break;
00909 
00910       // get name of interface
00911       char* iface_name = nsnull;
00912       nsCOMPtr<nsIInterfaceInfoManager> iim = XPTI_GetInterfaceInfoManager();
00913 
00914       rv = iim->GetNameForIID(&iid, &iface_name);
00915       if (NS_FAILED(rv) || !iface_name)
00916         break;
00917 
00918       jobject java_stub = nsnull;
00919       if (xpcom_obj) {
00920         // Get matching Java object for given xpcom object
00921         jobject objLoader = env->CallObjectMethod(mJavaWeakRef, getReferentMID);
00922         rv = GetNewOrUsedJavaObject(env, xpcom_obj, iid, objLoader, &java_stub);
00923         if (NS_FAILED(rv))
00924           break;
00925       }
00926 
00927       if (!aParamInfo.IsOut()) {  // 'in'
00928         aJValue.l = java_stub;
00929       } else {  // 'inout' & 'out'
00930         if (aVariant.val.p) {
00931           aJValue.l = env->NewObjectArray(1, nsISupportsClass, java_stub);
00932           if (aJValue.l == nsnull) {
00933             rv = NS_ERROR_OUT_OF_MEMORY;
00934             break;
00935           }
00936         } else {
00937           aJValue.l = nsnull;
00938         }
00939         aMethodSig.Append('[');
00940       }
00941 
00942       if (tag != nsXPTType::T_INTERFACE_IS) {
00943         aMethodSig.AppendLiteral("Lorg/mozilla/interfaces/");
00944         aMethodSig.AppendASCII(iface_name);
00945         aMethodSig.Append(';');
00946       } else {
00947         aMethodSig.AppendLiteral("Lorg/mozilla/interfaces/nsISupports;");
00948       }
00949 
00950       nsMemory::Free(iface_name);
00951     }
00952     break;
00953 
00954     case nsXPTType::T_ASTRING:
00955     case nsXPTType::T_DOMSTRING:
00956     {
00957       // This only handle 'in' or 'in dipper' params.  In XPIDL, the 'out'
00958       // descriptor is mapped to 'in dipper'.
00959       NS_PRECONDITION(aParamInfo.IsIn(), "unexpected param descriptor");
00960       if (!aParamInfo.IsIn()) {
00961         rv = NS_ERROR_UNEXPECTED;
00962         break;
00963       }
00964 
00965       nsString* str = NS_STATIC_CAST(nsString*, aVariant.val.p);
00966       if (!str) {
00967         rv = NS_ERROR_FAILURE;
00968         break;
00969       }
00970 
00971       jstring jstr = nsnull;
00972       if (!str->IsVoid()) {
00973         jstr = env->NewString(str->get(), str->Length());
00974         if (!jstr) {
00975           rv = NS_ERROR_OUT_OF_MEMORY;
00976           break;
00977         }
00978       }
00979 
00980       aJValue.l = jstr;
00981       aMethodSig.AppendLiteral("Ljava/lang/String;");
00982     }
00983     break;
00984 
00985     case nsXPTType::T_UTF8STRING:
00986     case nsXPTType::T_CSTRING:
00987     {
00988       // This only handle 'in' or 'in dipper' params.  In XPIDL, the 'out'
00989       // descriptor is mapped to 'in dipper'.
00990       NS_PRECONDITION(aParamInfo.IsIn(), "unexpected param descriptor");
00991       if (!aParamInfo.IsIn()) {
00992         rv = NS_ERROR_UNEXPECTED;
00993         break;
00994       }
00995 
00996       nsCString* str = NS_STATIC_CAST(nsCString*, aVariant.val.p);
00997       if (!str) {
00998         rv = NS_ERROR_FAILURE;
00999         break;
01000       }
01001 
01002       jstring jstr = nsnull;
01003       if (!str->IsVoid()) {
01004         jstr = env->NewStringUTF(str->get());
01005         if (!jstr) {
01006           rv = NS_ERROR_OUT_OF_MEMORY;
01007           break;
01008         }
01009       }
01010 
01011       aJValue.l = jstr;
01012       aMethodSig.AppendLiteral("Ljava/lang/String;");
01013     }
01014     break;
01015 
01016     // Pass the 'void*' address as a long
01017     case nsXPTType::T_VOID:
01018     {
01019       if (!aParamInfo.IsOut()) {  // 'in'
01020         aJValue.j = NS_REINTERPRET_CAST(jlong, aVariant.val.p);
01021         aMethodSig.Append('J');
01022       } else {  // 'inout' & 'out'
01023         if (aVariant.val.p) {
01024           jlongArray array = env->NewLongArray(1);
01025           if (!array) {
01026             rv = NS_ERROR_OUT_OF_MEMORY;
01027             break;
01028           }
01029 
01030           env->SetLongArrayRegion(array, 0, 1, (jlong*) aVariant.val.p);
01031           aJValue.l = array;
01032         } else {
01033           aJValue.l = nsnull;
01034         }
01035         aMethodSig.AppendLiteral("[J");
01036       }
01037     }
01038     break;
01039 
01040     case nsXPTType::T_ARRAY:
01041       NS_WARNING("array types are not yet supported");
01042       return NS_ERROR_NOT_IMPLEMENTED;
01043       break;
01044 
01045     case nsXPTType::T_PSTRING_SIZE_IS:
01046     case nsXPTType::T_PWSTRING_SIZE_IS:
01047     default:
01048       NS_WARNING("unexpected parameter type");
01049       return NS_ERROR_UNEXPECTED;
01050   }
01051 
01052   return rv;
01053 }
01054 
01055 nsresult
01056 nsJavaXPTCStub::GetRetvalSig(const nsXPTParamInfo* aParamInfo,
01057                              const nsXPTMethodInfo* aMethodInfo,
01058                              PRUint16 aMethodIndex,
01059                              nsXPTCMiniVariant* aDispatchParams,
01060                              nsACString &aRetvalSig)
01061 {
01062   PRUint8 type = aParamInfo->GetType().TagPart();
01063   switch (type)
01064   {
01065     case nsXPTType::T_I8:
01066       aRetvalSig.Append('B');
01067       break;
01068 
01069     case nsXPTType::T_I16:
01070     case nsXPTType::T_U8:
01071       aRetvalSig.Append('S');
01072       break;
01073 
01074     case nsXPTType::T_I32:
01075     case nsXPTType::T_U16:
01076       aRetvalSig.Append('I');
01077       break;
01078 
01079     case nsXPTType::T_I64:
01080     case nsXPTType::T_U32:
01081       aRetvalSig.Append('J');
01082       break;
01083 
01084     case nsXPTType::T_FLOAT:
01085       aRetvalSig.Append('F');
01086       break;
01087 
01088     case nsXPTType::T_U64:
01089     case nsXPTType::T_DOUBLE:
01090       aRetvalSig.Append('D');
01091       break;
01092 
01093     case nsXPTType::T_BOOL:
01094       aRetvalSig.Append('Z');
01095       break;
01096 
01097     case nsXPTType::T_CHAR:
01098     case nsXPTType::T_WCHAR:
01099       aRetvalSig.Append('C');
01100       break;
01101 
01102     case nsXPTType::T_CHAR_STR:
01103     case nsXPTType::T_WCHAR_STR:
01104     case nsXPTType::T_IID:
01105     case nsXPTType::T_ASTRING:
01106     case nsXPTType::T_DOMSTRING:
01107     case nsXPTType::T_UTF8STRING:
01108     case nsXPTType::T_CSTRING:
01109       aRetvalSig.AppendLiteral("Ljava/lang/String;");
01110       break;
01111 
01112     case nsXPTType::T_INTERFACE:
01113     {
01114       nsID iid;
01115       nsresult rv = GetIIDForMethodParam(mIInfo, aMethodInfo, *aParamInfo, type,
01116                                          aMethodIndex, aDispatchParams,
01117                                          PR_FALSE, iid);
01118       if (NS_FAILED(rv))
01119         break;
01120 
01121       // get name of interface
01122       char* iface_name = nsnull;
01123       nsCOMPtr<nsIInterfaceInfoManager> iim = XPTI_GetInterfaceInfoManager();
01124 
01125       rv = iim->GetNameForIID(&iid, &iface_name);
01126       if (NS_FAILED(rv) || !iface_name)
01127         break;
01128 
01129       aRetvalSig.AppendLiteral("Lorg/mozilla/interfaces/");
01130       aRetvalSig.AppendASCII(iface_name);
01131       aRetvalSig.Append(';');
01132       nsMemory::Free(iface_name);
01133       break;
01134     }
01135 
01136     case nsXPTType::T_INTERFACE_IS:
01137       aRetvalSig.AppendLiteral("Lorg/mozilla/interfaces/nsISupports;");
01138       break;
01139 
01140     case nsXPTType::T_VOID:
01141       aRetvalSig.Append('J');
01142       break;
01143 
01144     case nsXPTType::T_ARRAY:
01145       NS_WARNING("array types are not yet supported");
01146       return NS_ERROR_NOT_IMPLEMENTED;
01147       break;
01148 
01149     case nsXPTType::T_PSTRING_SIZE_IS:
01150     case nsXPTType::T_PWSTRING_SIZE_IS:
01151     default:
01152       NS_WARNING("unexpected parameter type");
01153       return NS_ERROR_UNEXPECTED;
01154   }
01155 
01156   return NS_OK;
01157 }
01158 
01162 nsresult
01163 nsJavaXPTCStub::FinalizeJavaParams(const nsXPTParamInfo &aParamInfo,
01164                                  const nsXPTMethodInfo* aMethodInfo,
01165                                  PRUint16 aMethodIndex,
01166                                  nsXPTCMiniVariant* aDispatchParams,
01167                                  nsXPTCMiniVariant &aVariant, jvalue &aJValue)
01168 {
01169   nsresult rv = NS_OK;
01170   JNIEnv* env = GetJNIEnv();
01171   const nsXPTType &type = aParamInfo.GetType();
01172 
01173   PRUint8 tag = type.TagPart();
01174   switch (tag)
01175   {
01176     case nsXPTType::T_I8:
01177     {
01178       jbyte value;
01179       if (aParamInfo.IsRetval()) {  // 'retval'
01180         value = aJValue.b;
01181       } else if (aJValue.l) {  // 'inout' & 'out'
01182         env->GetByteArrayRegion((jbyteArray) aJValue.l, 0, 1, &value);
01183       }
01184       if (aVariant.val.p)
01185         *((PRInt8 *) aVariant.val.p) = value;
01186     }
01187     break;
01188 
01189     case nsXPTType::T_U8:
01190     case nsXPTType::T_I16:
01191     {
01192       jshort value = 0;
01193       if (aParamInfo.IsRetval()) {  // 'retval'
01194         value = aJValue.s;
01195       } else if (aJValue.l) {  // 'inout' & 'out'
01196         env->GetShortArrayRegion((jshortArray) aJValue.l, 0, 1, &value);
01197       }
01198 
01199       if (aVariant.val.p) {
01200         if (tag == nsXPTType::T_U8)
01201           *((PRUint8 *) aVariant.val.p) = value;
01202         else
01203           *((PRInt16 *) aVariant.val.p) = value;
01204       }
01205     }
01206     break;
01207 
01208     case nsXPTType::T_U16:
01209     case nsXPTType::T_I32:
01210     {
01211       jint value = 0;
01212       if (aParamInfo.IsRetval()) {  // 'retval'
01213         value = aJValue.i;
01214       } else if (aJValue.l) {  // 'inout' & 'out'
01215         env->GetIntArrayRegion((jintArray) aJValue.l, 0, 1, &value);
01216       }
01217 
01218       if (aVariant.val.p) {
01219         if (tag == nsXPTType::T_U16)
01220           *((PRUint16 *) aVariant.val.p) = value;
01221         else
01222           *((PRInt32 *) aVariant.val.p) = value;
01223       }
01224     }
01225     break;
01226 
01227     case nsXPTType::T_U32:
01228     case nsXPTType::T_I64:
01229     {
01230       jlong value = 0;
01231       if (aParamInfo.IsRetval()) {  // 'retval'
01232         value = aJValue.j;
01233       } else if (aJValue.l) {  // 'inout' & 'out'
01234         env->GetLongArrayRegion((jlongArray) aJValue.l, 0, 1, &value);
01235       }
01236 
01237       if (aVariant.val.p) {
01238         if (tag == nsXPTType::T_U32)
01239           *((PRUint32 *) aVariant.val.p) = value;
01240         else
01241           *((PRInt64 *) aVariant.val.p) = value;
01242       }
01243     }
01244     break;
01245 
01246     case nsXPTType::T_FLOAT:
01247     {
01248       if (aParamInfo.IsRetval()) {  // 'retval'
01249         *((float *) aVariant.val.p) = aJValue.f;
01250       } else if (aJValue.l) {  // 'inout' & 'out'
01251         env->GetFloatArrayRegion((jfloatArray) aJValue.l, 0, 1,
01252                                  (jfloat*) aVariant.val.p);
01253       }
01254     }
01255     break;
01256 
01257     // XXX how do we handle 64-bit values?
01258     case nsXPTType::T_U64:
01259     case nsXPTType::T_DOUBLE:
01260     {
01261       jdouble value = 0;
01262       if (aParamInfo.IsRetval()) {  // 'retval'
01263         value = aJValue.d;
01264       } else if (aJValue.l) {  // 'inout' & 'out'
01265         env->GetDoubleArrayRegion((jdoubleArray) aJValue.l, 0, 1, &value);
01266       }
01267 
01268       if (aVariant.val.p) {
01269         if (tag == nsXPTType::T_DOUBLE)
01270           *((double *) aVariant.val.p) = value;
01271         else
01272           *((PRUint64 *) aVariant.val.p) = NS_STATIC_CAST(PRUint64, value);
01273       }
01274     }
01275     break;
01276 
01277     case nsXPTType::T_BOOL:
01278     {
01279       if (aParamInfo.IsRetval()) {  // 'retval'
01280         *((PRBool *) aVariant.val.p) = aJValue.z;
01281       } else if (aJValue.l) {  // 'inout' & 'out'
01282         env->GetBooleanArrayRegion((jbooleanArray) aJValue.l, 0, 1,
01283                                    (jboolean*) aVariant.val.p);
01284       }
01285     }
01286     break;
01287 
01288     case nsXPTType::T_CHAR:
01289     case nsXPTType::T_WCHAR:
01290     {
01291       if (aParamInfo.IsRetval()) {  // 'retval'
01292         if (type.TagPart() == nsXPTType::T_CHAR)
01293           *((char *) aVariant.val.p) = aJValue.c;
01294         else
01295           *((PRUnichar *) aVariant.val.p) = aJValue.c;
01296       } else if (aJValue.l) {  // 'inout' & 'out'
01297         jchar* array = env->GetCharArrayElements((jcharArray) aJValue.l,
01298                                                  nsnull);
01299         if (!array) {
01300           rv = NS_ERROR_OUT_OF_MEMORY;
01301           break;
01302         }
01303 
01304         if (type.TagPart() == nsXPTType::T_CHAR)
01305           *((char *) aVariant.val.p) = array[0];
01306         else
01307           *((PRUnichar *) aVariant.val.p) = array[0];
01308 
01309         env->ReleaseCharArrayElements((jcharArray) aJValue.l, array, JNI_ABORT);
01310       }
01311     }
01312     break;
01313 
01314     case nsXPTType::T_CHAR_STR:
01315     {
01316       jstring str = nsnull;
01317       if (aParamInfo.IsRetval()) {  // 'retval'
01318         str = (jstring) aJValue.l;
01319       } else {  // 'inout' & 'out'
01320         str = (jstring) env->GetObjectArrayElement((jobjectArray) aJValue.l, 0);
01321       }
01322 
01323       char** variant = NS_STATIC_CAST(char**, aVariant.val.p);
01324       if (str) {
01325         // Get string buffer
01326         const char* char_ptr = env->GetStringUTFChars(str, nsnull);
01327         if (!char_ptr) {
01328           rv = NS_ERROR_OUT_OF_MEMORY;
01329           break;
01330         }
01331 
01332         // If new string is different from one passed in, free old string
01333         // and replace with new string.
01334         if (aParamInfo.IsRetval() ||
01335             *variant == nsnull || strcmp(*variant, char_ptr) != 0)
01336         {
01337           if (!aParamInfo.IsRetval() && *variant)
01338             PR_Free(*variant);
01339 
01340           *variant = strdup(char_ptr);
01341           if (*variant == nsnull) {
01342             rv = NS_ERROR_OUT_OF_MEMORY;
01343             // don't 'break'; fall through to release chars
01344           }
01345         }
01346 
01347         // Release string buffer
01348         env->ReleaseStringUTFChars(str, char_ptr);
01349       } else {
01350         // If we were passed in a string, delete it now, and set to null.
01351         // (Only for 'inout' & 'out' params)
01352         if (*variant && !aParamInfo.IsRetval()) {
01353           PR_Free(*variant);
01354         }
01355         *variant = nsnull;
01356       }
01357     }
01358     break;
01359 
01360     case nsXPTType::T_WCHAR_STR:
01361     {
01362       jstring str = nsnull;
01363       if (aParamInfo.IsRetval()) {  // 'retval'
01364         str = (jstring) aJValue.l;
01365       } else {  // 'inout' & 'out'
01366         str = (jstring) env->GetObjectArrayElement((jobjectArray) aJValue.l, 0);
01367       }
01368 
01369       PRUnichar** variant = NS_STATIC_CAST(PRUnichar**, aVariant.val.p);
01370       if (str) {
01371         // Get string buffer
01372         const jchar* wchar_ptr = env->GetStringChars(str, nsnull);
01373         if (!wchar_ptr) {
01374           rv = NS_ERROR_OUT_OF_MEMORY;
01375           break;
01376         }
01377 
01378         // If new string is different from one passed in, free old string
01379         // and replace with new string.  We 
01380         if (aParamInfo.IsRetval() ||
01381             *variant == nsnull || nsCRT::strcmp(*variant, wchar_ptr) != 0)
01382         {
01383           if (!aParamInfo.IsRetval() && *variant)
01384             PR_Free(*variant);
01385 
01386           PRUint32 length = nsCRT::strlen(wchar_ptr);
01387           *variant = (PRUnichar*) PR_Malloc((length + 1) * sizeof(PRUnichar));
01388           if (*variant) {
01389             memcpy(*variant, wchar_ptr, length * sizeof(PRUnichar));
01390             (*variant)[length] = 0;
01391           } else {
01392             rv = NS_ERROR_OUT_OF_MEMORY;
01393             // don't 'break'; fall through to release chars
01394           }
01395         }
01396 
01397         // Release string buffer
01398         env->ReleaseStringChars(str, wchar_ptr);
01399       } else {
01400         // If we were passed in a string, delete it now, and set to null.
01401         // (Only for 'inout' & 'out' params)
01402         if (*variant && !aParamInfo.IsRetval()) {
01403           PR_Free(*variant);
01404         }
01405         *variant = nsnull;
01406       }
01407     }
01408     break;
01409 
01410     case nsXPTType::T_IID:
01411     {
01412       jstring str = nsnull;
01413       if (aParamInfo.IsRetval()) {  // 'retval'
01414         str = (jstring) aJValue.l;
01415       } else {  // 'inout' & 'out'
01416         str = (jstring) env->GetObjectArrayElement((jobjectArray) aJValue.l, 0);
01417       }
01418 
01419       nsID** variant = NS_STATIC_CAST(nsID**, aVariant.val.p);
01420       if (str) {
01421         // Get string buffer
01422         const char* char_ptr = env->GetStringUTFChars(str, nsnull);
01423         if (!char_ptr) {
01424           rv = NS_ERROR_OUT_OF_MEMORY;
01425           break;
01426         }
01427 
01428         if (!aParamInfo.IsRetval() && *variant) {
01429           // If we were given an nsID, set it to the new string
01430           nsID* oldIID = *variant;
01431           oldIID->Parse(char_ptr);
01432         } else {
01433           // If the argument that was passed in was null, then we need to
01434           // create a new nsID.
01435           nsID* newIID = new nsID;
01436           if (newIID) {
01437             newIID->Parse(char_ptr);
01438             *variant = newIID;
01439           } else {
01440             rv = NS_ERROR_OUT_OF_MEMORY;
01441             // don't 'break'; fall through to release chars
01442           }
01443         }
01444 
01445         // Release string buffer
01446         env->ReleaseStringUTFChars(str, char_ptr);
01447       } else {
01448         // If we were passed in an nsID, delete it now, and set to null.
01449         // (Free only 'inout' & 'out' params)
01450         if (*variant && !aParamInfo.IsRetval()) {
01451           delete *variant;
01452         }
01453         *variant = nsnull;
01454       }
01455     }
01456     break;
01457 
01458     case nsXPTType::T_INTERFACE:
01459     case nsXPTType::T_INTERFACE_IS:
01460     {
01461       jobject java_obj = nsnull;
01462       if (aParamInfo.IsRetval()) {  // 'retval'
01463         java_obj = aJValue.l;
01464       } else if (aJValue.l) {  // 'inout' & 'out'
01465         java_obj = env->GetObjectArrayElement((jobjectArray) aJValue.l, 0);
01466       }
01467 
01468       nsISupports* xpcom_obj = nsnull;
01469       if (java_obj) {
01470         // Get IID for this param
01471         nsID iid;
01472         rv = GetIIDForMethodParam(mIInfo, aMethodInfo, aParamInfo,
01473                                   aParamInfo.GetType().TagPart(), aMethodIndex,
01474                                   aDispatchParams, PR_FALSE, iid);
01475         if (NS_FAILED(rv))
01476           break;
01477 
01478         // If the requested interface is nsIWeakReference, then we look for or
01479         // create a stub for the nsISupports interface.  Then we create a weak
01480         // reference from that stub.
01481         PRBool isWeakRef;
01482         if (iid.Equals(NS_GET_IID(nsIWeakReference))) {
01483           isWeakRef = PR_TRUE;
01484           iid = NS_GET_IID(nsISupports);
01485         } else {
01486           isWeakRef = PR_FALSE;
01487         }
01488 
01489         rv = GetNewOrUsedXPCOMObject(env, java_obj, iid, &xpcom_obj);
01490         if (NS_FAILED(rv))
01491           break;
01492 
01493         // If the function expects a weak reference, then we need to
01494         // create it here.
01495         if (isWeakRef) {
01496           nsCOMPtr<nsISupportsWeakReference> supportsweak =
01497                                                  do_QueryInterface(xpcom_obj);
01498           if (supportsweak) {
01499             nsWeakPtr weakref;
01500             supportsweak->GetWeakReference(getter_AddRefs(weakref));
01501             NS_RELEASE(xpcom_obj);
01502             xpcom_obj = weakref;
01503             NS_ADDREF(xpcom_obj);
01504           } else {
01505             xpcom_obj = nsnull;
01506           }
01507         }
01508       }
01509 
01510       // For 'inout' params, if the resulting xpcom value is different than the
01511       // one passed in, then we must release the incoming xpcom value.
01512       nsISupports** variant = NS_STATIC_CAST(nsISupports**, aVariant.val.p);
01513       if (aParamInfo.IsIn() && *variant) {
01514         nsCOMPtr<nsISupports> in = do_QueryInterface(*variant);
01515         nsCOMPtr<nsISupports> out = do_QueryInterface(xpcom_obj);
01516         if (in != out) {
01517           NS_RELEASE(*variant);
01518         }
01519       }
01520 
01521       *variant = xpcom_obj;
01522     }
01523     break;
01524 
01525     case nsXPTType::T_ASTRING:
01526     case nsXPTType::T_DOMSTRING:
01527     {
01528       NS_PRECONDITION(aParamInfo.IsDipper(), "string argument is not dipper");
01529       if (!aParamInfo.IsDipper()) {
01530         rv = NS_ERROR_UNEXPECTED;
01531         break;
01532       }
01533 
01534       jstring jstr = (jstring) aJValue.l;
01535       nsString* variant = NS_STATIC_CAST(nsString*, aVariant.val.p);
01536       
01537       if (jstr) {
01538         // Get string buffer
01539         const jchar* wchar_ptr = env->GetStringChars(jstr, nsnull);
01540         if (!wchar_ptr) {
01541           rv = NS_ERROR_OUT_OF_MEMORY;
01542           break;
01543         }
01544 
01545         variant->Assign(wchar_ptr);
01546 
01547         // release String buffer
01548         env->ReleaseStringChars(jstr, wchar_ptr);
01549       } else {
01550         variant->SetIsVoid(PR_TRUE);
01551       }
01552     }
01553     break;
01554 
01555     case nsXPTType::T_UTF8STRING:
01556     case nsXPTType::T_CSTRING:
01557     {
01558       NS_PRECONDITION(aParamInfo.IsDipper(), "string argument is not dipper");
01559       if (!aParamInfo.IsDipper()) {
01560         rv = NS_ERROR_UNEXPECTED;
01561         break;
01562       }
01563 
01564       jstring jstr = (jstring) aJValue.l;
01565       nsCString* variant = NS_STATIC_CAST(nsCString*, aVariant.val.p);
01566       
01567       if (jstr) {
01568         // Get string buffer
01569         const char* char_ptr = env->GetStringUTFChars(jstr, nsnull);
01570         if (!char_ptr) {
01571           rv = NS_ERROR_OUT_OF_MEMORY;
01572           break;
01573         }
01574 
01575         variant->Assign(char_ptr);
01576 
01577         // release String buffer
01578         env->ReleaseStringUTFChars(jstr, char_ptr);
01579       } else {
01580         variant->SetIsVoid(PR_TRUE);
01581       }
01582     }
01583     break;
01584 
01585     case nsXPTType::T_VOID:
01586     {
01587       if (aParamInfo.IsRetval()) {  // 'retval'
01588         aVariant.val.p = NS_REINTERPRET_CAST(void*, aJValue.j);
01589       } else if (aJValue.l) {  // 'inout' & 'out'
01590         env->GetLongArrayRegion((jlongArray) aJValue.l, 0, 1,
01591                                 (jlong*) aVariant.val.p);
01592       }
01593     }
01594     break;
01595 
01596     default:
01597       NS_WARNING("unexpected parameter type");
01598       return NS_ERROR_UNEXPECTED;
01599   }
01600 
01601   return rv;
01602 }
01603 
01604 NS_IMETHODIMP
01605 nsJavaXPTCStub::GetWeakReference(nsIWeakReference** aInstancePtr)
01606 {
01607   if (mMaster)
01608     return mMaster->GetWeakReference(aInstancePtr);
01609 
01610   LOG(("==> nsJavaXPTCStub::GetWeakReference()\n"));
01611 
01612   if (!aInstancePtr)
01613     return NS_ERROR_NULL_POINTER;
01614 
01615   jobject javaObject = GetJNIEnv()->CallObjectMethod(mJavaWeakRef,
01616                                                      getReferentMID);
01617   nsJavaXPTCStubWeakRef* weakref;
01618   weakref = new nsJavaXPTCStubWeakRef(javaObject, this);
01619   if (!weakref)
01620     return NS_ERROR_OUT_OF_MEMORY;
01621 
01622   *aInstancePtr = weakref;
01623   NS_ADDREF(*aInstancePtr);
01624   ++mWeakRefCnt;
01625 
01626   return NS_OK;
01627 }
01628 
01629 jobject
01630 nsJavaXPTCStub::GetJavaObject()
01631 {
01632   JNIEnv* env = GetJNIEnv();
01633   jobject javaObject = env->CallObjectMethod(mJavaWeakRef, getReferentMID);
01634 
01635 #ifdef DEBUG_JAVAXPCOM
01636   nsIID* iid;
01637   mIInfo->GetInterfaceIID(&iid);
01638   char* iid_str = iid->ToString();
01639   LOG(("< nsJavaXPTCStub (Java=%08x | XPCOM=%08x | IID=%s)\n",
01640        (PRUint32) mJavaRefHashCode, (PRUint32) this, iid_str));
01641   PR_Free(iid_str);
01642   nsMemory::Free(iid);
01643 #endif
01644 
01645   return javaObject;
01646 }