From 334aeb529b4e88e85bdd7741a96b57d879c7069c Mon Sep 17 00:00:00 2001 From: "frankm%eng.sun.com" Date: Thu, 16 Sep 1999 18:50:27 +0000 Subject: [PATCH] Modularize code (somewhat), general cleanup. Proxy-related code has been moved to xpj_proxy.c, code used only for testing has been copied into xptest.cpp, and each "module" now has its own header (for internal use only). git-svn-id: svn://10.0.0.236/trunk@47798 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/java/xpcom/src/Makefile.in | 1 + mozilla/java/xpcom/src/xpj_ComUtilities.cpp | 92 +-- mozilla/java/xpcom/src/xpj_XPCMethod.cpp | 86 ++- mozilla/java/xpcom/src/xpj_dispatch.h | 95 +++ mozilla/java/xpcom/src/xpj_proxy.cpp | 235 ++++++++ mozilla/java/xpcom/src/xpj_proxy.h | 95 +++ mozilla/java/xpcom/src/xpj_utils.h | 68 +++ mozilla/java/xpcom/src/xpjava.cpp | 626 +++++++++----------- mozilla/java/xpcom/src/xpjava.h | 71 +-- mozilla/java/xpcom/test/Makefile.test | 8 +- mozilla/java/xpcom/test/xptest.cpp | 142 ++++- 11 files changed, 968 insertions(+), 551 deletions(-) create mode 100644 mozilla/java/xpcom/src/xpj_dispatch.h create mode 100644 mozilla/java/xpcom/src/xpj_proxy.cpp create mode 100644 mozilla/java/xpcom/src/xpj_proxy.h create mode 100644 mozilla/java/xpcom/src/xpj_utils.h diff --git a/mozilla/java/xpcom/src/Makefile.in b/mozilla/java/xpcom/src/Makefile.in index dbd2aeaa9bd..b394a56ae7f 100644 --- a/mozilla/java/xpcom/src/Makefile.in +++ b/mozilla/java/xpcom/src/Makefile.in @@ -31,6 +31,7 @@ LIBRARY_NAME = xpjava CPPSRCS = \ xpjava.cpp \ + xpj_proxy.cpp \ xpj_XPCMethod.cpp \ xpj_ComUtilities.cpp \ xpj_nsID.cpp \ diff --git a/mozilla/java/xpcom/src/xpj_ComUtilities.cpp b/mozilla/java/xpcom/src/xpj_ComUtilities.cpp index 72caa188607..0025a1073a7 100644 --- a/mozilla/java/xpcom/src/xpj_ComUtilities.cpp +++ b/mozilla/java/xpcom/src/xpj_ComUtilities.cpp @@ -36,39 +36,13 @@ extern "C" { #endif -/* Because not all platforms convert jlong to "long long" - * - * NOTE: this code was cut&pasted from xpj_XPCMethod.cpp, with tweaks. - * Normally I wouldn't do this, but my reasons are: - * - * 1. My alternatives were to put it in xpjava.h or xpjava.cpp - * I'd like to take stuff *out* of xpjava.h, and putting it - * in xpjava.cpp would preclude inlining. - * - * 2. How we map proxies to XPCOM objects is an implementation - * detail, which may change in the future (e.g. an index - * into a proxy table). Thus ToPtr/ToJLong is only of - * interest to those objects that stuff pointers into jlongs. - * - * 3. This allows adaptations to each implementation, for - * type safety (e.g. ToPtr returning nsISupports*). - * - * -- frankm, 99.09.09 - */ -static inline nsISupports* ToPtr(jlong l) { - int result; - jlong_L2I(result, l); - return (nsISupports *)result; -} - - JNIEXPORT jboolean JNICALL Java_org_mozilla_xpcom_XPComUtilities_initialize(JNIEnv *env, jclass cls) { - nsresult res = InitXPCOM(); + nsresult res = xpj_InitXPCOM(); if (NS_FAILED(res)) return JNI_FALSE; - return InitJavaCaches(env); + return xpjd_InitJavaCaches(env); // XXX: remove; do in dispatch } /* @@ -88,7 +62,10 @@ JNIEXPORT jobject JNICALL Java_org_mozilla_xpcom_XPComUtilities_CreateInstance nsISupports *delegate = NULL; if (jdelegate != NULL) { - delegate = This(env, jdelegate); + xpjp_QueryInterfaceToXPCOM(env, + jdelegate, + NS_GET_IID(nsISupports), + (void **)&delegate); } assert(classID != NULL && interfaceID != NULL); @@ -117,7 +94,7 @@ JNIEXPORT jobject JNICALL Java_org_mozilla_xpcom_XPComUtilities_CreateInstance // cerr << "Wrapping " << sample << " in new ComObject" << endl; // Wrap it in an ComObject - result = NewComObject(env, xpcobj, interfaceID); + result = xpjp_QueryInterfaceToJava(env, xpcobj, *interfaceID); return result; } @@ -171,7 +148,7 @@ JNIEXPORT void JNICALL Java_org_mozilla_xpcom_XPComUtilities_RegisterComponent JNIEXPORT void JNICALL Java_org_mozilla_xpcom_XPComUtilities_AddRef (JNIEnv *env, jclass cls, jlong ref) { - (ToPtr(ref))->AddRef(); + xpjp_SafeAddRefProxyID(ref); } /* @@ -182,7 +159,7 @@ JNIEXPORT void JNICALL Java_org_mozilla_xpcom_XPComUtilities_AddRef JNIEXPORT void JNICALL Java_org_mozilla_xpcom_XPComUtilities_Release (JNIEnv *env, jclass cls, jlong ref) { - (ToPtr(ref))->Release(); + xpjp_SafeReleaseProxyID(ref); } /* @@ -197,51 +174,20 @@ JNIEXPORT void JNICALL jlong ref, jint index, jobjectArray args) { - nsXPTCVariant variantArray[12]; - nsXPTCVariant *variantPtr = variantArray; - int paramcount; - nsID *nativeIID = ID_GetNative(env, iid); + nsIInterfaceInfo *info = nsnull; + nsISupports *target; - // PENDING: Get real IID - paramcount = - BuildParamsForOffset(nativeIID, index, &variantPtr); + // XXX: check for success + xpjd_GetInterfaceInfo(env, iid, &info); - if (paramcount < 0) { - // PENDING: throw an exception - } - else { - nsresult res; + // XXX: s.b. just |xpjp_UnwrapProxy(env, self);| + nsIID *nativeIID = ID_GetNative(env, iid); + xpjp_QueryInterfaceForProxyID(ref, *nativeIID, (void**)&target); - res = JArrayToVariant(env, paramcount, variantPtr, args); - if (NS_FAILED(res)) { - // PENDING: throw an exception - cerr << "Array and parameter list mismatch" << endl; - return; - } + xpjd_InvokeMethod(env, target, info, index, args); - nsISupports* true_this = ToPtr(ref); - - //true_this->AddRef(); - res = XPTC_InvokeByIndex(true_this, - (PRUint32)index, - (PRUint32)paramcount, - variantPtr); - - //true_this->Release(); - - if (NS_FAILED(res)) { - // PENDING: throw an exception - cerr << "Invocation failed, status: " << res << endl; - return; - } - - res = VariantToJArray(env, args, paramcount, variantPtr); - if (NS_FAILED(res)) { - // PENDING: throw an exception - cerr << "Array and parameter list mismatch" << endl; - return; - } - } + // XXX: remove when ref not QueryInterface'd + xpjp_SafeReleaseProxyID(ref); } #ifdef __cplusplus diff --git a/mozilla/java/xpcom/src/xpj_XPCMethod.cpp b/mozilla/java/xpcom/src/xpj_XPCMethod.cpp index 82817485774..d1901208e3f 100644 --- a/mozilla/java/xpcom/src/xpj_XPCMethod.cpp +++ b/mozilla/java/xpcom/src/xpj_XPCMethod.cpp @@ -39,7 +39,7 @@ static jfieldID XPCMethod_count_ID = NULL; jclass classXPCMethod = NULL; -#define USE_PARAM_TEMPLATE +#undef USE_PARAM_TEMPLATE #ifdef __cplusplus extern "C" { @@ -89,10 +89,18 @@ JNIEXPORT jint JNICALL const char *tmpstr; nsresult res; - // Get method info - tmpstr = env->GetStringUTFChars(methodName, NULL); - res = GetMethodInfoByName(iidPtr, tmpstr, PR_FALSE, &mi, &offset); + // Get interface info + nsIInterfaceInfo *info = nsnull; + res = (XPTI_GetInterfaceInfoManager())->GetInfoForIID(iidPtr, &info); + + if (NS_FAILED(res)) { + cerr << "Failed to find info for " << iidPtr->ToString() << endl; + return res; + } + + tmpstr = env->GetStringUTFChars(methodName, NULL); + res = xpj_GetMethodInfoByName(iidPtr, tmpstr, PR_FALSE, &mi, &offset); if (NS_FAILED(res)) { cerr << "Cannot find method for: " << (char *)tmpstr << endl; return -1; @@ -147,7 +155,7 @@ JNIEXPORT jint JNICALL env->SetLongField(self, XPCMethod_infoptr_ID, - ToJLong(mi)); + ToJLong(info)); env->SetIntField(self, XPCMethod_count_ID, @@ -155,8 +163,8 @@ JNIEXPORT jint JNICALL #ifdef USE_PARAM_TEMPLATE // Build parameter array - nsXPTCVariant *variantPtr = new nsXPTCVariant[mi->GetParamCount()]; - BuildParamsForMethodInfo(mi, variantPtr); + nsXPTCVariant *variantPtr = NULL; + xpjd_BuildParamsForOffset(info, offset, 0, &variantPtr); env->SetLongField(self, XPCMethod_frameptr_ID, @@ -181,7 +189,9 @@ JNIEXPORT void JNICALL jobject self, jlong peer) { nsXPTCVariant *variantPtr = (nsXPTCVariant *)ToPtr(peer); - delete [] variantPtr; + if (variantPtr != NULL) { + nsAllocator::Free(variantPtr); + } } /* @@ -199,9 +209,13 @@ JNIEXPORT jint JNICALL Java_org_mozilla_xpcom_XPCMethod_getParameterType return -1; } else { + jint offset = env->GetIntField(self, XPCMethod_offset_ID); jlong ptrval = env->GetLongField(self, XPCMethod_infoptr_ID); - const nsXPTMethodInfo *mi = - (const nsXPTMethodInfo *)ToPtr(ptrval); + + const nsXPTMethodInfo *mi; + nsIInterfaceInfo *info = (nsIInterfaceInfo *)ToPtr(ptrval); + + info->GetMethodInfo(offset, &mi); return mi->GetParam(index).GetType().TagPart(); } } @@ -232,14 +246,18 @@ JNIEXPORT void JNICALL Java_org_mozilla_xpcom_XPCMethod_invoke } jint offset = env->GetIntField(self, XPCMethod_offset_ID); - jint paramcount = env->GetIntField(self, XPCMethod_count_ID); - nsXPTCVariant variantArray[paramcount]; + jlong infoptr = env->GetLongField(self, XPCMethod_infoptr_ID); + nsIInterfaceInfo *info = + (nsIInterfaceInfo *)ToPtr(infoptr); #ifdef USE_PARAM_TEMPLATE - jlong ptrval = env->GetLongField(self, XPCMethod_frameptr_ID); + jint paramcount = env->GetIntField(self, XPCMethod_count_ID); + nsXPTCVariant *paramTemplate = - (nsXPTCVariant *)ToPtr(ptrval); + (nsXPTCVariant *)ToPtr(env->GetLongField(self, XPCMethod_frameptr_ID)); + + nsXPTCVariant variantArray[paramcount]; memcpy(variantArray, paramTemplate, paramcount * sizeof(nsXPTCVariant)); // Fix pointers @@ -249,42 +267,20 @@ JNIEXPORT void JNICALL Java_org_mozilla_xpcom_XPCMethod_invoke current->ptr = ¤t->val; } } -#else - jlong ptrval = env->GetLongField(self, XPCMethod_infoptr_ID); - const nsXPTMethodInfo *mi = - (const nsXPTMethodInfo *)ToPtr(ptrval); - BuildParamsForMethodInfo(mi, variantArray); #endif + nsIID* iid = nsnull; + nsISupports *true_target = nsnull; - res = JArrayToVariant(env, paramcount, variantArray, params); + // XXX: check for success + info->GetIID(&iid); - if (NS_FAILED(res)) { - // PENDING: throw an exception - cerr << "JArrayToVariant failed, status: " << res << endl; - return; - } + // XXX: check for success + xpjp_QueryInterfaceToXPCOM(env, target, *iid, (void**)&true_target); - nsISupports* true_target = This(env, target); - - res = XPTC_InvokeByIndex(true_target, - (PRUint32)offset, - (PRUint32)paramcount, - variantArray); - - if (NS_FAILED(res)) { - // PENDING: throw an exception - cerr << "Method failed, status: " << res << endl; - return; - } - - res = VariantToJArray(env, params, paramcount, variantArray); - - if (NS_FAILED(res)) { - // PENDING: throw an exception - cerr << "VariantToJArray failed, status: " << res << endl; - return; - } + xpjd_InvokeMethod(env, true_target, info, offset, params); + xpjp_SafeRelease(true_target); + nsAllocator::Free(iid); } #ifdef __cplusplus diff --git a/mozilla/java/xpcom/src/xpj_dispatch.h b/mozilla/java/xpcom/src/xpj_dispatch.h new file mode 100644 index 00000000000..00fe577b819 --- /dev/null +++ b/mozilla/java/xpcom/src/xpj_dispatch.h @@ -0,0 +1,95 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.0 (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. + * + * Contributors: + * Frank Mitchell (frank.mitchell@sun.com) + */ +#include +#include "nsISupports.h" +#include "xptcall.h" +#include "xptinfo.h" + +#ifdef __cplusplus +extern "C" { +#endif + + /** + * Initialize caches for often-used Java classes (all in java.lang). + * Will return JNI_FALSE if those classes, or their fields + * and methods, aren't found. + * @deprecated + */ + /* XXX: should be hidden in first call to xpjd_InvokeMethod */ +jboolean xpjd_InitJavaCaches(JNIEnv *env); + + /** + * Uncaches often-used Java classes (e.g. during unload). + */ + /* XXX: should be part of general unloading mechanism */ +void xpjd_FlushJavaCaches(JNIEnv *env); + + /** + * Convenience method to get the nsIInterfaceInfo for an + * interface denoted by the Java IID object `iid'. + * Will return JNI_FALSE if `iid' isn't a org.mozilla.xpcom.nsID + * or no info object exists. + */ +jboolean xpjd_GetInterfaceInfo(JNIEnv *env, + jobject iid, + nsIInterfaceInfo **info); + + /** + * Convenience method to get the nsIInterfaceInfo for an + * interface denoted by the C++ struct `iid'. + * Will return JNI_FALSE if `iid' isn't a org.mozilla.xpcom.nsID + * or no info object exists. + */ +jboolean xpjd_GetInterfaceInfoNative(REFNSIID iid, + nsIInterfaceInfo **info); + + /** + * Invoke a method on 'target' indicated by the 'methodIndex'-th + * method in `info', with arguments `args'. + * Throws a Java exception if `target' can't receive the method, + * `methodIndex' is out of bounds, `args' contains too few arguments, + * or any of the pointer arguments is NULL. + */ +void xpjd_InvokeMethod(JNIEnv *env, + nsISupports *target, + nsIInterfaceInfo *info, + jint methodIndex, + jobjectArray args); + +#if 0 /* not implemented yet */ + + /** + * Optimized version of `xpjd_InvokeMethod' to get attributes, or + * methods with only one in parameter and no outs or inouts. + */ +jobject xpjd_GetAttribute(JNIEnv *env, + nsISupports *target, + nsIInterfaceInfo *info, + jint getMethodIndex); + + /** + * Optimized version of `xpjd_InvokeMethod' to set attributes, or + * methods with only one out parameter and no ins or inouts. + */ +void xpjd_SetAttribute(JNIEnv *env, + nsISupports *target, + nsIInterfaceInfo *info, + jint setMethodIndex, + jobject value); + +#endif + +#ifdef __cplusplus +} +#endif diff --git a/mozilla/java/xpcom/src/xpj_proxy.cpp b/mozilla/java/xpcom/src/xpj_proxy.cpp new file mode 100644 index 00000000000..1d440a6b112 --- /dev/null +++ b/mozilla/java/xpcom/src/xpj_proxy.cpp @@ -0,0 +1,235 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.0 (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. + * + * Contributors: + * Frank Mitchell (frank.mitchell@sun.com) + */ +#include "xpjava.h" + +#define JAVA_XPCOBJECT_CLASS "org/mozilla/xpcom/ComObject" + +static jclass classComObject = NULL; +static jfieldID ComObject_objptr_ID = NULL; + +/* --------- SUPPORT FUNCTIONS ------------- */ + +/* Because not all platforms convert jlong to "long long" + * + * NOTE: this code was cut&pasted from xpj_XPCMethod.cpp, with tweaks. + * Normally I wouldn't do this, but my reasons are: + * + * 1. My alternatives were to put it in xpjava.h or xpjava.cpp + * I'd like to take stuff *out* of xpjava.h, and putting it + * in xpjava.cpp would preclude inlining. + * + * 2. How we map proxies to XPCOM objects is an implementation + * detail, which may change in the future (e.g. an index + * into a proxy table). Thus ToPtr/ToJLong is only of + * interest to those objects that stuff pointers into jlongs. + * + * 3. This allows adaptations to each implementation, for + * type safety (e.g. taking and returning nsISupports*). + * + * -- frankm, 99.09.09 + */ +static inline jlong ToJLong(nsISupports *p) { + jlong result; + jlong_I2L(result, (int)p); + return result; +} + +static inline nsISupports* ToPtr(jlong l) { + int result; + jlong_L2I(result, l); + return (nsISupports *)result; +} + +static inline jboolean xpjp_QueryInterface(nsISupports *object, + REFNSIID iid, + void **instance) { + assert(object != NULL && instance != NULL); + + if (NS_SUCCEEDED(object->QueryInterface(iid, instance))) { + return JNI_TRUE; + } + return JNI_FALSE; +} + +static jboolean xpjp_InitJavaCaches(JNIEnv *env) { + if (ComObject_objptr_ID == NULL) { + classComObject = env->FindClass(JAVA_XPCOBJECT_CLASS); + if (classComObject == NULL) return JNI_FALSE; + + classComObject = (jclass)env->NewGlobalRef(classComObject); + if (classComObject == NULL) return JNI_FALSE; + + ComObject_objptr_ID = env->GetFieldID(classComObject, "objptr", "J"); + if (ComObject_objptr_ID == NULL) return JNI_FALSE; + } + return JNI_TRUE; +} + + +static jclass xpjp_ClassForInterface(JNIEnv *env, REFNSIID iid) { +#if 0 + // Get info + jclass result = classComObject; // null? + nsIInterfaceInfo *info = nsnull; + char *interface_name; + char *name_space; + char *full_classname; + char *ch; + nsresult res; + + res = interfaceInfoManager->GetInfoForIID(&iid, &info); + + if (NS_FAILED(res)) { + cerr << "Failed to find info for " << iid.ToString() << endl; + goto end; + } + + // XXX: PENDING: find name_space somehow + name_space = "org.mozilla.xpcom"; + + res = info->GetName(&interface_name); + + if (NS_FAILED(res)) { + cerr << "Failed to find name for " << iid.ToString() << endl; + goto end; + } + + // Construct class name + full_classname = + (char*)nsAllocator::Alloc(strlen(interface_name) + strlen(name_space) + 2); + + strcpy(full_classname, name_space); + ch = full_classname; + while (ch != '\0') { + if (*ch == '.') { + *ch = '/'; + } + ch++; + } + strcat(full_classname, "/"); + strcat(full_classname, interface_name); + + cerr << "Looking for " << full_classname << endl; + + result = env->FindClass(full_classname); + // XXX: PENDING: If no such class found, make it + + // XXX: PENDING: Cache result + end: + // Cleanup + nsAllocator::Free(interface_name); + nsAllocator::Free(full_classname); + //nsAllocator::Free(name_space); + + return result; +#else + return classComObject; +#endif +} + +/* --------- PROXY API FUNCTIONS ------------- */ + +jobject xpjp_QueryInterfaceToJava(JNIEnv *env, + nsISupports *obj, + REFNSIID iid) { + if (!xpjp_InitJavaCaches(env)) { + return NULL; + } + + // XXX: Bad implementation; returns a new proxy every time + jobject result = 0; + jmethodID initID = 0; + jclass proxyClass = xpjp_ClassForInterface(env, iid); + jobject jiid = ID_NewJavaID(env, &iid); + + assert(proxyClass != 0); + + initID = env->GetMethodID(proxyClass, "", "(J)V"); + + if (initID != NULL) { + result = env->NewObject(proxyClass, initID, ToJLong(obj), jiid); + } + else { + initID = env->GetMethodID(proxyClass, "", "()V"); + + result = env->NewObject(proxyClass, initID); + env->SetLongField(result, ComObject_objptr_ID, ToJLong(obj)); + } + + return result; +} + +jboolean xpjp_QueryInterfaceToXPCOM(JNIEnv *env, + jobject proxy, + REFNSIID iid, + void **instance) { + nsISupports* xpcobj = xpjp_UnwrapProxy(env, proxy); + if (xpcobj != NULL) { + return xpjp_QueryInterface(xpcobj, iid, instance); + } + return PR_FALSE; +} + +nsISupports* xpjp_UnwrapProxy(JNIEnv *env, jobject proxy) { + if (!xpjp_InitJavaCaches(env)) { + return PR_FALSE; + } + return ToPtr(env->GetLongField(proxy, ComObject_objptr_ID)); +} + +void xpjp_SafeAddRef(nsISupports *object) { + /* XXX: NOT "SAFE" */ + NS_ADDREF(object); +} + +void xpjp_SafeRelease(nsISupports *object) { + /* XXX: NOT "SAFE" */ + NS_RELEASE(object); +} + +void xpjp_SafeAddRefProxy(JNIEnv *env, jobject proxy) { + nsISupports* xpcobj = xpjp_UnwrapProxy(env, proxy); + if (xpcobj != NULL) { + xpjp_SafeAddRef(xpcobj); + } +} + +void xpjp_SafeReleaseProxy(JNIEnv *env, jobject proxy) { + nsISupports* xpcobj = xpjp_UnwrapProxy(env, proxy); + if (xpcobj != NULL) { + xpjp_SafeRelease(xpcobj); + } +} + +/* deprecated */ +jboolean xpjp_QueryInterfaceForProxyID(jlong ref, + REFNSIID iid, + void **instance) { + nsISupports *xpcobj = ToPtr(ref); + + if (xpcobj != NULL) { + return xpjp_QueryInterface(xpcobj, iid, instance); + } + return PR_FALSE; +} + +/* deprecated */ +void xpjp_SafeReleaseProxyID(jlong ref) { + xpjp_SafeRelease(ToPtr(ref)); +} + +/* deprecated */ +void xpjp_SafeAddRefProxyID(jlong ref) { + xpjp_SafeAddRef(ToPtr(ref)); +} diff --git a/mozilla/java/xpcom/src/xpj_proxy.h b/mozilla/java/xpcom/src/xpj_proxy.h new file mode 100644 index 00000000000..a6863f1c306 --- /dev/null +++ b/mozilla/java/xpcom/src/xpj_proxy.h @@ -0,0 +1,95 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.0 (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. + * + * Contributors: + * Frank Mitchell (frank.mitchell@sun.com) + */ +#include +#include "nsISupports.h" +#include "xptcall.h" +#include "xptinfo.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + /** + * Returns a jobject implementing the interface indicated by `iid', + * or NULL if `ptr' does not implement that interface. + * The function wraps the XPCOM object in a Java proxy, unless it + * is itself a proxy to a Java object; in that case, it unwraps the + * proxy before testing. + * The refcount of `ptr' will be incremented if it is wrapped. + */ + /* XXX: should we skip actual QueryInterface if not a proxy? */ +jobject xpjp_QueryInterfaceToJava(JNIEnv *env, + nsISupports *ptr, + REFNSIID iid); + + /** + * Sets `instance' to an instance of the interface indicated by `iid'. + * If the Java object is a proxy, the function unwraps it and performs + * QueryInterface(); otherwise, it performs QueryInterface() on + * `object' and, if that succeeds, wraps it in a C++ proxy. + * The refcount of `object' will be incremented if it is unwrapped. + */ +jboolean xpjp_QueryInterfaceToXPCOM(JNIEnv *env, + jobject object, + REFNSIID iid, + void **instance); + + /** + * If `proxy' is a proxy to a nsISupports, returns the + * contained pointer and returns true; otherwise, return NULL. + * Used mainly for proxy implementation; others should + * use QueryInterfaceToXPCOM(). + * The refcount of the return value is unchanged. + */ +nsISupports* xpjp_UnwrapProxy(JNIEnv *env, jobject proxy); + + /** + * Perform ptr->AddRef() in a thread-safe manner. + */ +void xpjp_SafeAddRef(nsISupports *ptr); + + /** + * Perform ptr->Release() in a thread-safe manner. + */ +void xpjp_SafeRelease(nsISupports *ptr); + + /** + * Perform AddRef() on `proxy''s underlying object in a + * thread-safe manner. + * Has no effect if proxy is not a proxy to a ref-counted object. + */ +void xpjp_SafeAddRefProxy(JNIEnv *env, jobject proxy); + + /** + * Perform Release() on `proxy''s underlying object in a + * thread-safe manner. + * Has no effect if proxy is not a proxy to a ref-counted object. + */ +void xpjp_SafeReleaseProxy(JNIEnv *env, jobject proxy); + + + /* deprecated API */ + +jboolean xpjp_QueryInterfaceForProxyID(jlong ref, + REFNSIID iid, + void **instance); + +void xpjp_SafeAddRefProxyID(jlong ref); + +void xpjp_SafeReleaseProxyID(jlong ref); + +#ifdef __cplusplus +} +#endif diff --git a/mozilla/java/xpcom/src/xpj_utils.h b/mozilla/java/xpcom/src/xpj_utils.h new file mode 100644 index 00000000000..7af5ca4087d --- /dev/null +++ b/mozilla/java/xpcom/src/xpj_utils.h @@ -0,0 +1,68 @@ +/* + * The contents of this file are subject to the Mozilla Public License + * Version 1.0 (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. + * + * Contributors: + * Frank Mitchell (frank.mitchell@sun.com) + */ +#include + +#include "nsISupports.h" +#include "xptinfo.h" + +/* + * Macros defined in some, but not all, jni_md.h, for + * compilers that don't have 64 bit ints. + */ +#ifndef jlong_L2I +# define jlong_L2I(_i, _l) ((_i) = (_l)) +# define jlong_I2L(_l, _i) ((_l) = (_i)) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + + /** + * Start up XPCOM + * @deprecated + */ + /* XXX: should move into test directory */ +nsresult xpj_InitXPCOM(); + + /** + * Find the method info for method or attribute `methodname'. + * If an attribute, do not prefix with "get" or "set"; set + * `wantsSetter' to select the getter or setter. + * The contents of `indexPtr' are set to the method's index. + */ +nsresult xpj_GetMethodInfoByName(const nsID *iid, + const char *methodname, + PRBool wantSetter, + const nsXPTMethodInfo **miptr, + int *indexPtr); + +/* Defined in xpj_nsID.cpp */ + + /** Create a new Java wrapper for `id' */ +jobject ID_NewJavaID(JNIEnv *env, const nsID* id); + + /** Unwrap an nsID; returns the internal struct, *not a copy* */ +nsID* ID_GetNative(JNIEnv *env, jobject self); + + /** Copies `id' to a Java wrapper */ +void ID_SetNative(JNIEnv *env, jobject self, nsID* id); + + /** Compares two Java wrappers for an nsID */ +jboolean ID_IsEqual(JNIEnv *env, jobject self, jobject other); + +#ifdef __cplusplus +} +#endif + diff --git a/mozilla/java/xpcom/src/xpjava.cpp b/mozilla/java/xpcom/src/xpjava.cpp index 73c221cc8e2..7458cbb9ed8 100644 --- a/mozilla/java/xpcom/src/xpjava.cpp +++ b/mozilla/java/xpcom/src/xpjava.cpp @@ -42,8 +42,6 @@ #endif #endif -#define JAVA_XPCOBJECT_CLASS "org/mozilla/xpcom/ComObject" - /* Global references to frequently used classes and objects */ static jclass classString; @@ -55,7 +53,6 @@ static jclass classFloat; static jclass classDouble; static jclass classBoolean; static jclass classCharacter; -static jclass classComObject; /* Cached field and method IDs */ static jfieldID Byte_value_ID; @@ -67,8 +64,6 @@ static jfieldID Double_value_ID; static jfieldID Boolean_value_ID; static jfieldID Character_value_ID; -static jfieldID ComObject_objptr_ID; - static jmethodID Byte_init_ID; static jmethodID Short_init_ID; static jmethodID Integer_init_ID; @@ -81,137 +76,35 @@ static jmethodID Character_init_ID; /* Global references to frequently used XPCOM objects */ static nsIInterfaceInfoManager *interfaceInfoManager; -static NS_DEFINE_IID(kAllocatorCID, NS_ALLOCATOR_CID); +/* Flag to indicate caches filled */ +static jboolean cache_initialized = JNI_FALSE; -/* ---------- SUPPORT FUNCTIONS ------------ */ -nsISupports *This(JNIEnv *env, jobject self) { - jlong objptr = env->GetLongField(self, ComObject_objptr_ID); +/* ---------- GENERAL API FUNCTIONS ------------ */ - nsISupports *result = (nsISupports *)objptr; - - return result; -} - -jclass ClassForInterface(JNIEnv *env, const nsIID *iid) { -#if 0 - // Get info - jclass result = classComObject; // null? - nsIInterfaceInfo *info = nsnull; - char *interface_name; - char *name_space; - char *full_classname; - char *ch; +nsresult xpj_InitXPCOM() { nsresult res; - res = interfaceInfoManager->GetInfoForIID(iid, &info); - - if (NS_FAILED(res)) { - cerr << "Failed to find info for " << iid->ToString() << endl; - goto end; - } - - // XXX: PENDING: find name_space somehow - name_space = "org.mozilla.xpcom"; - - res = info->GetName(&interface_name); - - if (NS_FAILED(res)) { - cerr << "Failed to find name for " << iid->ToString() << endl; - goto end; - } - - // Construct class name - full_classname = - (char*)nsAllocator::Alloc(strlen(interface_name) + strlen(name_space) + 2); - - strcpy(full_classname, name_space); - ch = full_classname; - while (ch != '\0') { - if (*ch == '.') { - *ch = '/'; - } - ch++; - } - strcat(full_classname, "/"); - strcat(full_classname, interface_name); - - cerr << "Looking for " << full_classname << endl; - - result = env->FindClass(full_classname); - // XXX: PENDING: If no such class found, make it - - // XXX: PENDING: Cache result - end: - // Cleanup - nsAllocator::Free(interface_name); - nsAllocator::Free(full_classname); - //nsAllocator::Free(name_space); - - return result; -#else - return classComObject; +#ifdef DEBUG_frankm + cerr << "Initializing XPCOM" << endl; #endif + + // Autoregistration magic. Boogeda boogeda. + res = nsComponentManager::AutoRegister(nsIComponentManager::NS_Startup, + nsnull); + +#ifdef DEBUG_frankm + cerr << "XPCOM Initialized" << endl; +#endif + + return res; } -jobject NewComObject(JNIEnv *env, nsISupports *xpcobj, const nsIID *iid) { - jobject result = 0; - jmethodID initID = 0; - jclass proxyClass = ClassForInterface(env, iid); - jobject jiid = ID_NewJavaID(env, iid); - - assert(proxyClass != 0); - - initID = env->GetMethodID(proxyClass, "", "(J)V"); - - if (initID != NULL) { - result = env->NewObject(proxyClass, initID, (jlong)xpcobj, jiid); - } - else { - initID = env->GetMethodID(proxyClass, "", "()V"); - - result = env->NewObject(proxyClass, initID); - env->SetLongField(result, ComObject_objptr_ID, (jlong)xpcobj); - } - - return result; -} - -nsresult GetMethodInfo(const nsID *iid, jint offset, - const nsXPTMethodInfo **_retval) { - nsresult res; - - // Get info - nsIInterfaceInfo *info = nsnull; - - res = interfaceInfoManager->GetInfoForIID(iid, &info); - - if (NS_FAILED(res)) { - cerr << "Failed to find info for " << iid->ToString() << endl; - return res; - } - - // Find info for command - uint16 methodcount; - - info->GetMethodCount(&methodcount); - - if (offset < methodcount) { - info->GetMethodInfo(offset, _retval); - } - else { - cerr << "Offset " << offset << " out of range for IID " - << iid->ToString() << endl; - return NS_ERROR_FAILURE; - } - return NS_OK; -} - -nsresult GetMethodInfoByName(const nsID *iid, - const char *methodname, - PRBool wantSetter, - const nsXPTMethodInfo **miptr, - int *_retval) { +nsresult xpj_GetMethodInfoByName(const nsID *iid, + const char *methodname, + PRBool wantSetter, + const nsXPTMethodInfo **miptr, + int *_retval) { nsresult res; // Get info @@ -256,11 +149,44 @@ nsresult GetMethodInfoByName(const nsID *iid, return res; } -void BuildParamsForMethodInfo(const nsXPTMethodInfo *mi, - nsXPTCVariant variantArray[]) { +/* ---------- DISPATCH SUPPORT FUNCTIONS ------------ */ + +static +int xpjd_BuildParamsForOffset(nsIInterfaceInfo *info, + jint offset, + jint arraysize, + nsXPTCVariant **_retval) { + const nsXPTMethodInfo *mi; + nsresult res; + + // Find info for command + uint16 methodcount; + + info->GetMethodCount(&methodcount); + + if (offset < methodcount) { + info->GetMethodInfo(offset, &mi); + } + else { + cerr << "Offset " << offset << " should be < " << methodcount << endl; + return -1; + } + + if (NS_FAILED(res)) { + return -1; + } + + // Make sure the array is large enough, and alloc more if + // necessary. int paramcount = mi->GetParamCount(); - nsXPTCVariant *current = variantArray; + if (paramcount > arraysize || *_retval == NULL) { + *_retval = (nsXPTCVariant *) + nsAllocator::Alloc(sizeof(nsXPTCVariant) * paramcount); + } + + // Set flags, pointers, and types for array elements + nsXPTCVariant *current = *_retval; for (int i = 0; i < paramcount; i++) { nsXPTParamInfo param = mi->GetParam(i); @@ -292,140 +218,13 @@ void BuildParamsForMethodInfo(const nsXPTMethodInfo *mi, } current++; } + return paramcount; } -int BuildParamsForOffset(const nsID *iid, jint offset, - nsXPTCVariant **_retval) { - const nsXPTMethodInfo *mi; - - nsresult res = GetMethodInfo(iid, offset, &mi); - if (NS_FAILED(res)) { - return -1; - } - else { - int paramcount = mi->GetParamCount(); - - // Build result based on number and types of parameters - if (*_retval == NULL) { - *_retval = new nsXPTCVariant[paramcount]; - } - - BuildParamsForMethodInfo(mi, *_retval); - return paramcount; - } -} - -void PrintParams(const nsXPTCVariant params[], int paramcount) { - for (int i = 0; i < paramcount; i++) { - - cerr << i << ") "; - - switch(params[i].type) { - case nsXPTType::T_I8: - cerr << params[i].val.i8; - break; - case nsXPTType::T_I16: - cerr << params[i].val.i16; - break; - case nsXPTType::T_I32: - cerr << params[i].val.i32; - break; - case nsXPTType::T_I64: - cerr << params[i].val.i64; - break; - case nsXPTType::T_U8: - cerr << params[i].val.u8; - break; - case nsXPTType::T_U16: - cerr << params[i].val.u16; - break; - case nsXPTType::T_U32: - cerr << params[i].val.u32; - break; - case nsXPTType::T_U64: - cerr << params[i].val.u64; - break; - case nsXPTType::T_FLOAT: - cerr << params[i].val.f; - break; - case nsXPTType::T_DOUBLE: - cerr << params[i].val.d; - break; - case nsXPTType::T_BOOL: - cerr << (params[i].val.b ? "true" : "false"); - break; - case nsXPTType::T_CHAR: - cerr << "'" << params[i].val.c << "'"; - break; - case nsXPTType::T_WCHAR: - cerr << "'" << params[i].val.wc << "'"; - break; - case nsXPTType::T_CHAR_STR: - cerr << params[i].val.p << ' ' - << '"' << (char *)params[i].val.p << '"'; - break; - default: - // Ignore for now - break; - } - cerr << " : type " << (int)(params[i].type) - << ", ptr=" << params[i].ptr - << (params[i].IsPtrData() ? ", data" : "") - << (params[i].IsValOwned() ? ", owned" : "") - << (params[i].IsValInterface() ? ", interface" : "") - << endl; - } -} - -nsresult JArrayToVariant(JNIEnv *env, - int paramcount, - nsXPTCVariant *params, - const jobjectArray jarray) { - /* - * Match the array elements to the expected parameters; - * - * Match: - * T_BOOL : Boolean - * T_I8: Byte - * T_I16: Short - * T_I32: Integer - * T_I64: Long - * -- we may want to support widening casts - * T_U: T_I<2n> type (T_U64 not supported) - * -- we may allow T_I if actual value in range - * -- negative values are disallowed. - * T_FLOAT: Float - * T_DOUBLE: Double (or Float?) - * T_CHAR: Character if value is an ASCII value - * T_WCHAR: Character - * T_CHAR_STRING: String as UTF-8 chars - * T_WCHAR_STRING: String as Unicode chars - * T_BSTR: String as UTF-8 chars - * T_INTERFACE(_IS): XPCOM pointer for an ComObject, if nsID matches - */ - - nsXPTCVariant *current = params; - - for (jsize i = 0; i < paramcount; i++, current++) { - jobject elem = env->GetObjectArrayElement(jarray, i); - - if (elem == NULL) { - continue; - } - - if (JObjectToVariant(env, current, elem) == JNI_FALSE) { - // PENDING: throw an exception - cerr << "Argument " << i << " is not of the correct type" << endl; - } - } - return NS_OK; -} - - - -jboolean JObjectToVariant(JNIEnv *env, - nsXPTCVariant *current, - const jobject elem) { +static jboolean JObjectToVariant(JNIEnv *env, + nsXPTCVariant *current, + const jobject elem, + REFNSIID iid) { jboolean result = JNI_FALSE; /* * Match: @@ -548,7 +347,6 @@ jboolean JObjectToVariant(JNIEnv *env, tmpstr[jstrlen] = '\0'; current->val.p = tmpstr; - current->flags |= nsXPTCVariant::VAL_IS_OWNED; env->ReleaseStringChars(string, wstr); result = JNI_TRUE; @@ -562,7 +360,13 @@ jboolean JObjectToVariant(JNIEnv *env, break; case nsXPTType::T_INTERFACE: case nsXPTType::T_INTERFACE_IS: - // PENDING: unwrap the ComObject, or wrap Java object in stub + if (elem == NULL) { + current->val.p = NULL; + } + else { + xpjp_QueryInterfaceToXPCOM(env, elem, iid, &(current->val.p)); + } + current->flags |= nsXPTCVariant::VAL_IS_IFACE; break; case nsXPTType::T_BSTR: // Ignore for now @@ -573,51 +377,31 @@ jboolean JObjectToVariant(JNIEnv *env, return result; } -nsresult VariantToJArray(JNIEnv *env, - jobjectArray jarray, - int paramcount, - nsXPTCVariant *params) { +static nsresult JArrayToVariant(JNIEnv *env, + int paramcount, + nsXPTCVariant *params, + const jobjectArray jarray) { nsXPTCVariant *current = params; for (jsize i = 0; i < paramcount; i++, current++) { - jobject elem = NULL; // env->GetObjectArrayElement(jarray, i); - jboolean isequal = JNI_FALSE; - nsXPTCVariant currValue; + jobject elem = env->GetObjectArrayElement(jarray, i); + nsIID iid = NS_GET_IID(nsISupports); + // PENDING: get the iid of the object - if (!(current->flags & nsXPTCVariant::PTR_IS_DATA)) { + if (elem == NULL) { continue; } - if (elem != NULL) { - memcpy(&currValue, current, sizeof(nsXPTCVariant)); - if (JObjectToVariant(env, &currValue, elem) != JNI_FALSE) { - isequal = - (memcmp(&currValue, current, sizeof(nsXPTCVariant)) != 0); - } - } - - if (isequal) { - // PENDING: what about casting to more specific interfaces? - continue; - } - - elem = VariantToJObject(env, current); - - env->SetObjectArrayElement(jarray, i, elem); - - if (current->flags & nsXPTCVariant::VAL_IS_IFACE) { - ((nsISupports*)current->val.p)->Release(); - } - - if (current->flags & nsXPTCVariant::VAL_IS_OWNED) { - delete [] current->val.p; - current->val.p = 0; // for cleanliness sake + if (JObjectToVariant(env, current, elem, iid) == JNI_FALSE) { + // PENDING: throw an exception + cerr << "Argument " << i << " is not of the correct type" << endl; } } return NS_OK; } -extern jobject VariantToJObject(JNIEnv *env, const nsXPTCVariant *current) { + +static jobject VariantToJObject(JNIEnv *env, const nsXPTCVariant *current) { jobject result = NULL; // Integer code assumes that current->val.i# == current->val.u# @@ -717,64 +501,61 @@ extern jobject VariantToJObject(JNIEnv *env, const nsXPTCVariant *current) { return result; } -nsresult InitXPCOM() { - nsresult res; -#ifdef DEBUG_frankm - cerr << "Initializing XPCOM" << endl; -#endif +static nsresult VariantToJArray(JNIEnv *env, + jobjectArray jarray, + int paramcount, + nsXPTCVariant *params) { + nsXPTCVariant *current = params; - // Autoregistration magic. Boogeda boogeda. + for (jsize i = 0; i < paramcount; i++, current++) { + jobject elem = NULL; // env->GetObjectArrayElement(jarray, i); + jboolean isequal = JNI_FALSE; + nsXPTCVariant currValue; - nsComponentManager::AutoRegister(nsIComponentManager::NS_Startup, nsnull); + if (!(current->flags & nsXPTCVariant::PTR_IS_DATA)) { + continue; + } -#if 0 - // XXX Remove when allocator autoregisters - cerr << "Registering Allocator" << endl; + if (elem != NULL) { + nsIID iid = NS_GET_IID(nsISupports); + // PENDING: get the iid of the object - res = nsComponentManager::RegisterComponent(kAllocatorCID, - "nsAllocator", - "allocator", - XPCOM_DLL, - PR_TRUE, - PR_TRUE); + memcpy(&currValue, current, sizeof(nsXPTCVariant)); + if (JObjectToVariant(env, &currValue, elem, iid) != JNI_FALSE) { + isequal = + (memcmp(&currValue, current, sizeof(nsXPTCVariant)) != 0); + } + } - if (NS_FAILED(res)) { - cerr << "Failed to register allocator, res = " << res << endl; - return res; + if (isequal) { + // PENDING: what about casting to more specific interfaces? + continue; + } + + elem = VariantToJObject(env, current); + + env->SetObjectArrayElement(jarray, i, elem); + + if (current->flags & nsXPTCVariant::VAL_IS_IFACE) { + xpjp_SafeRelease((nsISupports*)current->val.p); + } + + if (current->flags & nsXPTCVariant::VAL_IS_OWNED) { + delete [] current->val.p; + current->val.p = 0; // for cleanliness sake + } } -#endif - - // Get InterfaceInfoManager - -#ifdef DEBUG_frankm - cerr << "Getting InterfaceInfoManager" << endl; -#endif - - interfaceInfoManager = XPTI_GetInterfaceInfoManager(); - - if (!interfaceInfoManager) { - cerr << "Failed to find InterfaceInfoManager" << endl; - return res; - } - -#ifdef DEBUG_frankm - cerr << "XPCOM Initialized" << endl; -#endif - - return res; + return NS_OK; } -jboolean InitJavaCaches(JNIEnv *env) { +/* ---------- DISPATCH API FUNCTIONS ------------ */ - // PENDING: move to ComObject, for better locality? - classComObject = env->FindClass(JAVA_XPCOBJECT_CLASS); - if (classComObject == NULL) return JNI_FALSE; - classComObject = (jclass)env->NewGlobalRef(classComObject); - if (classComObject == NULL) return JNI_FALSE; +jboolean xpjd_InitJavaCaches(JNIEnv *env) { - ComObject_objptr_ID = env->GetFieldID(classComObject, "objptr", "J"); - if (ComObject_objptr_ID == NULL) return JNI_FALSE; + if (cache_initialized) { + return JNI_TRUE; + } // For basic types @@ -871,6 +652,159 @@ jboolean InitJavaCaches(JNIEnv *env) { Character_value_ID = env->GetFieldID(classCharacter, "value", "C"); if (Character_value_ID == NULL) return JNI_FALSE; - return JNI_TRUE; + // Get InterfaceInfoManager + +#ifdef DEBUG_frankm + cerr << "Getting InterfaceInfoManager" << endl; +#endif + + interfaceInfoManager = XPTI_GetInterfaceInfoManager(); + + if (!interfaceInfoManager) { + // XXX: throw exception or something + cerr << "Failed to find InterfaceInfoManager" << endl; + return JNI_FALSE; + } + +#ifdef DEBUG_frankm + cerr << "InterfaceInfoManager found!" << endl; +#endif + + cache_initialized = JNI_TRUE; + + return cache_initialized; } +void xpjd_FlushJavaCaches(JNIEnv *env) { + + cache_initialized = JNI_FALSE; + + // For basic types + + env->DeleteGlobalRef(classString); + classString = NULL; + + env->DeleteGlobalRef(classByte); + classByte = NULL; + + env->DeleteGlobalRef(classShort); + classShort = NULL; + + env->DeleteGlobalRef(classInteger); + classInteger = NULL; + + env->DeleteGlobalRef(classLong); + classLong = NULL; + + env->DeleteGlobalRef(classFloat); + classFloat = NULL; + + env->DeleteGlobalRef(classDouble); + classDouble = NULL; + + env->DeleteGlobalRef(classBoolean); + classBoolean = NULL; + + env->DeleteGlobalRef(classCharacter); + classCharacter = NULL; + + Byte_init_ID = NULL; + Byte_value_ID = NULL; + Short_init_ID = NULL; + Short_value_ID = NULL; + Integer_init_ID = NULL; + Integer_value_ID = NULL; + Long_init_ID = NULL; + Long_value_ID = NULL; + Float_init_ID = NULL; + Float_value_ID = NULL; + Double_init_ID = NULL; + Double_value_ID = NULL; + Boolean_init_ID = NULL; + Boolean_value_ID = NULL; + Character_init_ID = NULL; + Character_value_ID = NULL; +} + +jboolean xpjd_GetInterfaceInfo(JNIEnv *env, + jobject iid, + nsIInterfaceInfo **info) { + nsID *nativeIID = ID_GetNative(env, iid); + + return xpjd_GetInterfaceInfoNative(*nativeIID, info); +} + +jboolean xpjd_GetInterfaceInfoNative(REFNSIID iid, + nsIInterfaceInfo **info) { + nsresult res; + + // Get info + *info = nsnull; + + res = interfaceInfoManager->GetInfoForIID(&iid, info); + + if (NS_FAILED(res)) { + cerr << "Failed to find info for " << iid.ToString() << endl; + return res; + } +} + +void xpjd_InvokeMethod(JNIEnv *env, + nsISupports *target, + nsIInterfaceInfo *info, + jint methodIndex, + jobjectArray jargs) { + + nsresult res = NS_OK; + nsXPTCVariant paramArray[32]; + nsXPTCVariant *params = paramArray; + int nparams = 0; + const int capacity = sizeof(paramArray)/sizeof(paramArray[0]); + + // XXX: check info != NULL, target != null, jargs != null, env != null + + // XXX: check bounds of methodIndex + + nparams = xpjd_BuildParamsForOffset(info, + methodIndex, + capacity, + ¶ms); + if (nparams < 0) { + // PENDING: throw an exception + cerr << "Couldn't initialize parameter array" << endl; + goto finally; + } + + res = JArrayToVariant(env, nparams, params, jargs); + if (NS_FAILED(res)) { + // PENDING: throw an exception + cerr << "Array and parameter list mismatch" << endl; + goto finally; + } + + //xpjp_SafeAddRef(target); + + res = XPTC_InvokeByIndex(target, methodIndex, nparams, params); + + //xpjp_SafeRelease(target); + + if (NS_FAILED(res)) { + // PENDING: throw an exception + cerr << "Invocation failed, status: " << res << endl; + goto finally; + } + + res = VariantToJArray(env, jargs, nparams, params); + if (NS_FAILED(res)) { + // PENDING: throw an exception + cerr << "Array and parameter list mismatch" << endl; + goto finally; + } + +finally: + if (params != paramArray) { + nsAllocator::Free(params); + } +} + + diff --git a/mozilla/java/xpcom/src/xpjava.h b/mozilla/java/xpcom/src/xpjava.h index 80d0870b820..eba120c77e4 100644 --- a/mozilla/java/xpcom/src/xpjava.h +++ b/mozilla/java/xpcom/src/xpjava.h @@ -11,72 +11,7 @@ * Contributors: * Frank Mitchell (frank.mitchell@sun.com) */ -#include -#include "nsISupports.h" -#include "xptcall.h" - -#ifdef __cplusplus -extern "C" { -#endif - -extern nsresult InitXPCOM(); - -extern jboolean InitJavaCaches(JNIEnv *env); - -extern nsISupports *This(JNIEnv *env, jobject self); - -extern nsID *This_IID(JNIEnv *env, jobject self); - -extern jobject NewComObject(JNIEnv *env, - nsISupports *xpcobj, const nsIID *iid); - -extern int BuildParamsForOffset(const nsID *iid, jint offset, - nsXPTCVariant **_retval); - -extern void BuildParamsForMethodInfo(const nsXPTMethodInfo *mi, - nsXPTCVariant variantArray[]); - -extern nsresult GetMethodInfo(const nsID *iid, jint offset, - const nsXPTMethodInfo **_retval); - -extern nsresult GetMethodInfoByName(const nsID *iid, - const char *methodname, - PRBool wantSetter, - const nsXPTMethodInfo **miptr, - int *_retval); - -extern void PrintParams(const nsXPTCVariant params[], int paramcount); - -extern nsresult JArrayToVariant(JNIEnv *env, - int paramcount, - nsXPTCVariant *params, - const jobjectArray jarray); - -extern jboolean JObjectToVariant(JNIEnv *env, - nsXPTCVariant *param, - const jobject obj); - -extern nsresult VariantToJArray(JNIEnv *env, - jobjectArray jarray, - int paramcount, - nsXPTCVariant *params); - -extern jobject VariantToJObject(JNIEnv *env, - const nsXPTCVariant *param); - - -/* Defined in nsID.cpp */ -extern jobject ID_NewJavaID(JNIEnv *env, const nsID* id); -extern nsID* ID_GetNative(JNIEnv *env, jobject self); -extern void ID_SetNative(JNIEnv *env, jobject self, nsID* id); -extern jboolean ID_IsEqual(JNIEnv *env, jobject self, jobject other); - -#ifndef jlong_L2I -# define jlong_L2I(_i, _l) ((_i) = (_l)) -# define jlong_I2L(_l, _i) ((_l) = (_i)) -#endif - -#ifdef __cplusplus -} -#endif +#include "xpj_dispatch.h" +#include "xpj_proxy.h" +#include "xpj_utils.h" diff --git a/mozilla/java/xpcom/test/Makefile.test b/mozilla/java/xpcom/test/Makefile.test index 4054098de99..ca63f8f3ba6 100644 --- a/mozilla/java/xpcom/test/Makefile.test +++ b/mozilla/java/xpcom/test/Makefile.test @@ -75,11 +75,13 @@ $(COMPDIR)/libxpjtest.so: libxpjtest.so # # C++ test program # -xptest: xptest.o ../src/libxpjava.so - $(CPP) -g -Wall -o xptest $(LIBS) -L ../src -lxpjava xptest.o +xptest: xptest.o + $(CPP) -g -Wall -o xptest $(LIBS) xptest.o -xptest.cpp: ../src/xpjava.h +# +# Java proxies +# $(PROXY_JAR): $(GENPROXY) $(COMPDIR)/xpjtest.xpt - mkdir $(PROXY_DIR) $(GENPROXY) -d $(PROXY_DIR) $(COMPDIR)/xpjtest.xpt diff --git a/mozilla/java/xpcom/test/xptest.cpp b/mozilla/java/xpcom/test/xptest.cpp index 7ad2070ba71..52686dd7327 100644 --- a/mozilla/java/xpcom/test/xptest.cpp +++ b/mozilla/java/xpcom/test/xptest.cpp @@ -29,31 +29,24 @@ #include "nsSpecialSystemDirectory.h" -#include "xpjava.h" -static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID); static NS_DEFINE_IID(kISampleIID, JSISAMPLE_IID); static NS_DEFINE_CID(kSampleCID, JS_SAMPLE_CID); -static NS_DEFINE_IID(kAllocatorCID, NS_ALLOCATOR_CID); - #ifdef XP_PC -#define XPCOM_DLL "xpcom.dll" #define SAMPLE_DLL "xpjtest.dll" #else #ifdef XP_MAC -#define XPCOM_DLL "XPCOM_DLL" #define SAMPLE_DLL "XPJTEST_DLL" #else -#define XPCOM_DLL "libxpcom.so" #define SAMPLE_DLL "libxpjtest.so" #endif #endif -void ParamsFromArgv(nsXPTCVariant *result, - const nsXPTMethodInfo *mi, - int argi, int argc, char **argv) { +static void ParamsFromArgv(nsXPTCVariant *result, + const nsXPTMethodInfo *mi, + int argi, int argc, char **argv) { uint8 paramcount = mi->GetParamCount(); memset(result, 0, sizeof(nsXPTCVariant) * paramcount); @@ -194,7 +187,126 @@ void ParamsFromArgv(nsXPTCVariant *result, } } } - return result; +} + + +static void xpjd_PrintParams(const nsXPTCVariant params[], int paramcount) { + for (int i = 0; i < paramcount; i++) { + + cerr << i << ") "; + + switch(params[i].type) { + case nsXPTType::T_I8: + cerr << params[i].val.i8; + break; + case nsXPTType::T_I16: + cerr << params[i].val.i16; + break; + case nsXPTType::T_I32: + cerr << params[i].val.i32; + break; + case nsXPTType::T_I64: + cerr << params[i].val.i64; + break; + case nsXPTType::T_U8: + cerr << params[i].val.u8; + break; + case nsXPTType::T_U16: + cerr << params[i].val.u16; + break; + case nsXPTType::T_U32: + cerr << params[i].val.u32; + break; + case nsXPTType::T_U64: + cerr << params[i].val.u64; + break; + case nsXPTType::T_FLOAT: + cerr << params[i].val.f; + break; + case nsXPTType::T_DOUBLE: + cerr << params[i].val.d; + break; + case nsXPTType::T_BOOL: + cerr << (params[i].val.b ? "true" : "false"); + break; + case nsXPTType::T_CHAR: + cerr << "'" << params[i].val.c << "'"; + break; + case nsXPTType::T_WCHAR: + cerr << "'" << params[i].val.wc << "'"; + break; + case nsXPTType::T_CHAR_STR: + cerr << params[i].val.p << ' ' + << '"' << (char *)params[i].val.p << '"'; + break; + default: + // Ignore for now + break; + } + cerr << " : type " << (int)(params[i].type) + << ", ptr=" << params[i].ptr + << (params[i].IsPtrData() ? ", data" : "") + << (params[i].IsValOwned() ? ", owned" : "") + << (params[i].IsValInterface() ? ", interface" : "") + << endl; + } +} + + +static nsresult GetMethodInfoByName(const nsID *iid, + const char *methodname, + PRBool wantSetter, + const nsXPTMethodInfo **miptr, + int *_retval) { + nsresult res; + nsIInterfaceInfoManager *iim; + nsIInterfaceInfo *info = nsnull; + + // Get info + iim = XPTI_GetInterfaceInfoManager(); + + if (!iim) { + cerr << "Failed to find InterfaceInfoManager" << endl; + return NS_ERROR_NOT_INITIALIZED; + } + + res = iim->GetInfoForIID(iid, &info); + + if (NS_FAILED(res)) { + cerr << "Failed to find info for " << iid->ToString() << endl; + return res; + } + + // Find info for command + uint16 methodcount; + + info->GetMethodCount(&methodcount); + + int i; + for (i = 0; i < methodcount; i++) { + const nsXPTMethodInfo *mi; + + info->GetMethodInfo(i, &mi); + // PENDING(frankm): match against name, get/set, *AND* param types + if (strcmp(methodname, mi->GetName()) == 0) { + PRBool setter = mi->IsSetter(); + PRBool getter = mi->IsGetter(); + if ((!getter && !setter) + || (setter && wantSetter) + || (getter && !wantSetter)) { + *miptr = mi; + *_retval = i; + break; + } + } + } + if (i >= methodcount) { + cerr << "Failed to find " << methodname << endl; + *miptr = NULL; + *_retval = -1; + return NS_ERROR_FAILURE; + } + return res; } @@ -217,7 +329,7 @@ int main(int argc, char **argv) } // Initialize XPCOM - InitXPCOM(); + nsComponentManager::AutoRegister(nsIComponentManager::NS_Startup, nsnull); // Create Instance res = nsComponentManager::CreateInstance(kSampleCID, @@ -275,7 +387,7 @@ int main(int argc, char **argv) cerr << "Arguments are: " << endl; - PrintParams(params, paramcount); + xpjd_PrintParams(params, paramcount); // Invoke command @@ -294,9 +406,7 @@ int main(int argc, char **argv) cerr << "Results are: " << endl; - PrintParams(params, paramcount); - - delete [] params; + xpjd_PrintParams(params, paramcount); // Release Instance NS_RELEASE(sample);