Ejemplo n.º 1
0
   value CallMember(jobject inObject, value inArgs)
   {
      JNIEnv *env = GetEnv();

      jvalue jargs[MAX];
      if (!HaxeToJNIArgs(env,inArgs,jargs))
      {
         CleanStringArgs();
         ELOG("CallMember - bad argument list");
         return alloc_null();
      }
      value result = 0;

      switch(mReturn)
      {
         case jniVoid:
            result = alloc_null();
            env->CallVoidMethodA(inObject, mMethod, jargs);
            break;
         case jniObject:
            result = JObjectToHaxe(env->CallObjectMethodA(inObject,mMethod, jargs));
            break;
         case jniObjectString:
            result = JStringToHaxe(env,env->CallObjectMethodA(inObject, mMethod, jargs));
            break;
         case jniObjectArray:
            result = JArrayToHaxe(env->CallObjectMethodA(inObject, mMethod, jargs));
            break;
         case jniBoolean:
            result = alloc_bool(env->CallBooleanMethodA(inObject, mMethod, jargs));
            break;
         case jniByte:
            result = alloc_int(env->CallByteMethodA(inObject, mMethod, jargs));
            break;
         case jniChar:
            result = alloc_int(env->CallCharMethodA(inObject, mMethod, jargs));
            break;
         case jniShort:
            result = alloc_int(env->CallShortMethodA(inObject, mMethod, jargs));
            break;
         case jniInt:
            result = alloc_int(env->CallIntMethodA(mClass, mMethod, jargs));
            break;
         case jniLong:
            result = alloc_int(env->CallLongMethodA(inObject, mMethod, jargs));
            break;
         case jniFloat:
            result = alloc_float(env->CallFloatMethodA(inObject, mMethod, jargs));
            break;
         case jniDouble:
            result = alloc_float(env->CallDoubleMethodA(inObject, mMethod, jargs));
            break;
      }

      CleanStringArgs();
      return result;
   }
Ejemplo n.º 2
0
bool JavaClass::_call_method(JavaObject* p_instance,const StringName& p_method,const Variant** p_args,int p_argcount,Variant::CallError &r_error,Variant& ret) {

    Map<StringName,List<MethodInfo> >::Element *M=methods.find(p_method);
    if (!M)
        return false;

    JNIEnv *env = ThreadAndroid::get_env();

    MethodInfo *method=NULL;
    for (List<MethodInfo>::Element *E=M->get().front(); E; E=E->next()) {

        if (!p_instance && !E->get()._static) {
            r_error.error=Variant::CallError::CALL_ERROR_INSTANCE_IS_NULL;
            continue;
        }

        int pc = E->get().param_types.size();
        if (pc>p_argcount) {

            r_error.error=Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
            r_error.argument=pc;
            continue;
        }
        if (pc<p_argcount) {

            r_error.error=Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
            r_error.argument=pc;
            continue;
        }
        uint32_t *ptypes=E->get().param_types.ptr();
        bool valid=true;

        for(int i=0; i<pc; i++) {

            Variant::Type arg_expected=Variant::NIL;
            switch(ptypes[i]) {

            case ARG_TYPE_VOID: {
                //bug?
            } break;
            case ARG_TYPE_BOOLEAN: {
                if (p_args[i]->get_type()!=Variant::BOOL)
                    arg_expected=Variant::BOOL;
            }
            break;
            case ARG_NUMBER_CLASS_BIT|ARG_TYPE_BYTE:
            case ARG_NUMBER_CLASS_BIT|ARG_TYPE_CHAR:
            case ARG_NUMBER_CLASS_BIT|ARG_TYPE_SHORT:
            case ARG_NUMBER_CLASS_BIT|ARG_TYPE_INT:
            case ARG_NUMBER_CLASS_BIT|ARG_TYPE_LONG:
            case ARG_TYPE_BYTE:
            case ARG_TYPE_CHAR:
            case ARG_TYPE_SHORT:
            case ARG_TYPE_INT:
            case ARG_TYPE_LONG: {

                if (!p_args[i]->is_num())
                    arg_expected=Variant::INT;

            }
            break;
            case ARG_NUMBER_CLASS_BIT|ARG_TYPE_FLOAT:
            case ARG_NUMBER_CLASS_BIT|ARG_TYPE_DOUBLE:
            case ARG_TYPE_FLOAT:
            case ARG_TYPE_DOUBLE: {

                if (!p_args[i]->is_num())
                    arg_expected=Variant::REAL;

            }
            break;
            case ARG_TYPE_STRING: {

                if (p_args[i]->get_type()!=Variant::STRING)
                    arg_expected=Variant::STRING;

            }
            break;
            case ARG_TYPE_CLASS: {

                if (p_args[i]->get_type()!=Variant::OBJECT)
                    arg_expected=Variant::OBJECT;
                else {

                    Ref<Reference> ref = *p_args[i];
                    if (!ref.is_null()) {
                        if (ref->cast_to<JavaObject>() ) {

                            Ref<JavaObject> jo=ref;
                            //could be faster
                            jclass c = env->FindClass(E->get().param_sigs[i].operator String().utf8().get_data());
                            if (!c || !env->IsInstanceOf(jo->instance,c)) {

                                arg_expected=Variant::OBJECT;
                            } else {
                                //ok
                            }
                        } else {
                            arg_expected=Variant::OBJECT;
                        }

                    }
                }

            }
            break;
            default: {

                if (p_args[i]->get_type()!=Variant::ARRAY)
                    arg_expected=Variant::ARRAY;

            }
            break;

            }

            if (arg_expected!=Variant::NIL) {
                r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
                r_error.argument=i;
                r_error.expected=arg_expected;
                valid=false;
                break;

            }

        }
        if (!valid)
            continue;


        method=&E->get();
        break;

    }

    if (!method)
        return true; //no version convinces



    r_error.error=Variant::CallError::CALL_OK;

    jvalue *argv=NULL;

    if (method->param_types.size()) {

        argv=(jvalue*)alloca( sizeof(jvalue)*method->param_types.size() );
    }

    List<jobject> to_free;
    for(int i=0; i<method->param_types.size(); i++) {

        switch(method->param_types[i]) {
        case ARG_TYPE_VOID:  {
            //can't happen
            argv[i].l=NULL; //I hope this works
        }
        break;

        case ARG_TYPE_BOOLEAN: {
            argv[i].z=*p_args[i];
        }
        break;
        case ARG_TYPE_BYTE: {
            argv[i].b=*p_args[i];
        }
        break;
        case ARG_TYPE_CHAR: {
            argv[i].c=*p_args[i];
        }
        break;
        case ARG_TYPE_SHORT: {
            argv[i].s=*p_args[i];
        }
        break;
        case ARG_TYPE_INT: {
            argv[i].i=*p_args[i];
        }
        break;
        case ARG_TYPE_LONG: {
            argv[i].j=*p_args[i];
        }
        break;
        case ARG_TYPE_FLOAT: {
            argv[i].f=*p_args[i];
        }
        break;
        case ARG_TYPE_DOUBLE: {
            argv[i].d=*p_args[i];
        }
        break;
        case ARG_NUMBER_CLASS_BIT|ARG_TYPE_BOOLEAN: {
            jclass bclass = env->FindClass("java/lang/Boolean");
            jmethodID ctor = env->GetMethodID(bclass, "<init>", "(Z)V");
            jvalue val;
            val.z = (bool)(*p_args[i]);
            jobject obj = env->NewObjectA(bclass, ctor, &val);
            argv[i].l = obj;
            to_free.push_back(obj);
        }
        break;
        case ARG_NUMBER_CLASS_BIT|ARG_TYPE_BYTE: {
            jclass bclass = env->FindClass("java/lang/Byte");
            jmethodID ctor = env->GetMethodID(bclass, "<init>", "(B)V");
            jvalue val;
            val.b = (int)(*p_args[i]);
            jobject obj = env->NewObjectA(bclass, ctor, &val);
            argv[i].l = obj;
            to_free.push_back(obj);
        }
        break;
        case ARG_NUMBER_CLASS_BIT|ARG_TYPE_CHAR: {
            jclass bclass = env->FindClass("java/lang/Character");
            jmethodID ctor = env->GetMethodID(bclass, "<init>", "(C)V");
            jvalue val;
            val.c = (int)(*p_args[i]);
            jobject obj = env->NewObjectA(bclass, ctor, &val);
            argv[i].l = obj;
            to_free.push_back(obj);
        }
        break;
        case ARG_NUMBER_CLASS_BIT|ARG_TYPE_SHORT: {
            jclass bclass = env->FindClass("java/lang/Short");
            jmethodID ctor = env->GetMethodID(bclass, "<init>", "(S)V");
            jvalue val;
            val.s = (int)(*p_args[i]);
            jobject obj = env->NewObjectA(bclass, ctor, &val);
            argv[i].l = obj;
            to_free.push_back(obj);
        }
        break;
        case ARG_NUMBER_CLASS_BIT|ARG_TYPE_INT: {
            jclass bclass = env->FindClass("java/lang/Integer");
            jmethodID ctor = env->GetMethodID(bclass, "<init>", "(I)V");
            jvalue val;
            val.i = (int)(*p_args[i]);
            jobject obj = env->NewObjectA(bclass, ctor, &val);
            argv[i].l = obj;
            to_free.push_back(obj);
        }
        break;
        case ARG_NUMBER_CLASS_BIT|ARG_TYPE_LONG: {
            jclass bclass = env->FindClass("java/lang/Long");
            jmethodID ctor = env->GetMethodID(bclass, "<init>", "(J)V");
            jvalue val;
            val.j = (int64_t)(*p_args[i]);
            jobject obj = env->NewObjectA(bclass, ctor, &val);
            argv[i].l = obj;
            to_free.push_back(obj);
        }
        break;
        case ARG_NUMBER_CLASS_BIT|ARG_TYPE_FLOAT: {
            jclass bclass = env->FindClass("java/lang/Float");
            jmethodID ctor = env->GetMethodID(bclass, "<init>", "(F)V");
            jvalue val;
            val.f = (float)(*p_args[i]);
            jobject obj = env->NewObjectA(bclass, ctor, &val);
            argv[i].l = obj;
            to_free.push_back(obj);
        }
        break;
        case ARG_NUMBER_CLASS_BIT|ARG_TYPE_DOUBLE: {
            jclass bclass = env->FindClass("java/lang/Double");
            jmethodID ctor = env->GetMethodID(bclass, "<init>", "(D)V");
            jvalue val;
            val.d = (double)(*p_args[i]);
            jobject obj = env->NewObjectA(bclass, ctor, &val);
            argv[i].l = obj;
            to_free.push_back(obj);
        }
        break;
        case ARG_TYPE_STRING: {
            String s = *p_args[i];
            jstring jStr = env->NewStringUTF(s.utf8().get_data());
            argv[i].l=jStr;
            to_free.push_back(jStr);
        }
        break;
        case ARG_TYPE_CLASS: {

            Ref<JavaObject> jo=*p_args[i];
            if (jo.is_valid()) {

                argv[i].l=jo->instance;
            } else {
                argv[i].l=NULL; //I hope this works
            }

        }
        break;
        case ARG_ARRAY_BIT|ARG_TYPE_BOOLEAN: {

            Array arr = *p_args[i];
            jbooleanArray a = env->NewBooleanArray(arr.size());
            for(int j=0; j<arr.size(); j++) {
                jboolean val = arr[j];
                env->SetBooleanArrayRegion(a,j,1,&val);
            }
            argv[i].l=a;
            to_free.push_back(a);

        }
        break;
        case ARG_ARRAY_BIT|ARG_TYPE_BYTE: {

            Array arr = *p_args[i];
            jbyteArray a = env->NewByteArray(arr.size());
            for(int j=0; j<arr.size(); j++) {
                jbyte val = arr[j];
                env->SetByteArrayRegion(a,j,1,&val);
            }
            argv[i].l=a;
            to_free.push_back(a);


        }
        break;
        case ARG_ARRAY_BIT|ARG_TYPE_CHAR: {

            Array arr = *p_args[i];
            jcharArray a = env->NewCharArray(arr.size());
            for(int j=0; j<arr.size(); j++) {
                jchar val = arr[j];
                env->SetCharArrayRegion(a,j,1,&val);
            }
            argv[i].l=a;
            to_free.push_back(a);

        }
        break;
        case ARG_ARRAY_BIT|ARG_TYPE_SHORT: {

            Array arr = *p_args[i];
            jshortArray a = env->NewShortArray(arr.size());
            for(int j=0; j<arr.size(); j++) {
                jshort val = arr[j];
                env->SetShortArrayRegion(a,j,1,&val);
            }
            argv[i].l=a;
            to_free.push_back(a);

        }
        break;
        case ARG_ARRAY_BIT|ARG_TYPE_INT: {

            Array arr = *p_args[i];
            jintArray a = env->NewIntArray(arr.size());
            for(int j=0; j<arr.size(); j++) {
                jint val = arr[j];
                env->SetIntArrayRegion(a,j,1,&val);
            }
            argv[i].l=a;
            to_free.push_back(a);
        }
        break;
        case ARG_ARRAY_BIT|ARG_TYPE_LONG: {
            Array arr = *p_args[i];
            jlongArray a = env->NewLongArray(arr.size());
            for(int j=0; j<arr.size(); j++) {
                jlong val = arr[j];
                env->SetLongArrayRegion(a,j,1,&val);
            }
            argv[i].l=a;
            to_free.push_back(a);

        }
        break;
        case ARG_ARRAY_BIT|ARG_TYPE_FLOAT: {

            Array arr = *p_args[i];
            jfloatArray a = env->NewFloatArray(arr.size());
            for(int j=0; j<arr.size(); j++) {
                jfloat val = arr[j];
                env->SetFloatArrayRegion(a,j,1,&val);
            }
            argv[i].l=a;
            to_free.push_back(a);


        }
        break;
        case ARG_ARRAY_BIT|ARG_TYPE_DOUBLE: {

            Array arr = *p_args[i];
            jdoubleArray a = env->NewDoubleArray(arr.size());
            for(int j=0; j<arr.size(); j++) {
                jdouble val = arr[j];
                env->SetDoubleArrayRegion(a,j,1,&val);
            }
            argv[i].l=a;
            to_free.push_back(a);

        }
        break;
        case ARG_ARRAY_BIT|ARG_TYPE_STRING: {

            Array arr = *p_args[i];
            jobjectArray a = env->NewObjectArray(arr.size(),env->FindClass("java/lang/String"),NULL);
            for(int j=0; j<arr.size(); j++) {

                String s = arr[j];
                jstring jStr = env->NewStringUTF(s.utf8().get_data());
                env->SetObjectArrayElement(a,j,jStr);
                to_free.push_back(jStr);
            }

            argv[i].l=a;
            to_free.push_back(a);
        }
        break;
        case ARG_ARRAY_BIT|ARG_TYPE_CLASS: {

            argv[i].l=NULL;
        }
        break;
        }
    }

    r_error.error=Variant::CallError::CALL_OK;
    bool success=true;

    switch(method->return_type) {


    case ARG_TYPE_VOID: {
        if (method->_static) {
            env->CallStaticVoidMethodA(_class,method->method,argv);
        } else {
            env->CallVoidMethodA(p_instance->instance,method->method,argv);
        }
        ret=Variant();

    }
    break;
    case ARG_TYPE_BOOLEAN: {
        if (method->_static) {
            ret=env->CallStaticBooleanMethodA(_class,method->method,argv);
        } else {
            ret=env->CallBooleanMethodA(p_instance->instance,method->method,argv);
        }
    }
    break;
    case ARG_TYPE_BYTE: {
        if (method->_static) {
            ret=env->CallStaticByteMethodA(_class,method->method,argv);
        } else {
            ret=env->CallByteMethodA(p_instance->instance,method->method,argv);
        }
    }
    break;
    case ARG_TYPE_CHAR: {

        if (method->_static) {
            ret=env->CallStaticCharMethodA(_class,method->method,argv);
        } else {
            ret=env->CallCharMethodA(p_instance->instance,method->method,argv);
        }
    }
    break;
    case ARG_TYPE_SHORT: {

        if (method->_static) {
            ret=env->CallStaticShortMethodA(_class,method->method,argv);
        } else {
            ret=env->CallShortMethodA(p_instance->instance,method->method,argv);
        }

    }
    break;
    case ARG_TYPE_INT: {

        if (method->_static) {
            ret=env->CallStaticIntMethodA(_class,method->method,argv);
        } else {
            ret=env->CallIntMethodA(p_instance->instance,method->method,argv);
        }

    }
    break;
    case ARG_TYPE_LONG: {

        if (method->_static) {
            ret=env->CallStaticLongMethodA(_class,method->method,argv);
        } else {
            ret=env->CallLongMethodA(p_instance->instance,method->method,argv);
        }

    }
    break;
    case ARG_TYPE_FLOAT: {

        if (method->_static) {
            ret=env->CallStaticFloatMethodA(_class,method->method,argv);
        } else {
            ret=env->CallFloatMethodA(p_instance->instance,method->method,argv);
        }

    }
    break;
    case ARG_TYPE_DOUBLE: {

        if (method->_static) {
            ret=env->CallStaticDoubleMethodA(_class,method->method,argv);
        } else {
            ret=env->CallDoubleMethodA(p_instance->instance,method->method,argv);
        }

    }
    break;
    default: {

        jobject obj;
        if (method->_static) {
            obj=env->CallStaticObjectMethodA(_class,method->method,argv);
        } else {
            obj=env->CallObjectMethodA(p_instance->instance,method->method,argv);
        }

        if (!obj) {
            ret=Variant();
        } else {

            if (!_convert_object_to_variant(env, obj, ret,method->return_type)) {
                ret=Variant();
                r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
                success=false;
            }
            env->DeleteLocalRef(obj);
        }

    }
    break;

    }

    for(List<jobject>::Element *E=to_free.front(); E; E=E->next()) {
        env->DeleteLocalRef(E->get());
    }

    return success;
}
Ejemplo n.º 3
0
NS_IMETHODIMP
nsJavaXPTCStub::CallMethod(PRUint16 aMethodIndex,
                           const XPTMethodDescriptor *aMethodInfo,
                           nsXPTCMiniVariant *aParams)
{
#ifdef DEBUG_JAVAXPCOM
  const char* ifaceName;
  mIInfo->GetNameShared(&ifaceName);
  LOG(("---> (Java) %s::%s()\n", ifaceName, aMethodInfo->name));
#endif

  nsresult rv = NS_OK;
  JNIEnv* env = GetJNIEnv();
  jobject javaObject = env->CallObjectMethod(mJavaWeakRef, getReferentMID);

  nsCAutoString methodSig("(");

  // Create jvalue array to hold Java params
  PRUint8 paramCount = aMethodInfo->num_args;
  jvalue* java_params = nsnull;
  const nsXPTParamInfo* retvalInfo = nsnull;
  if (paramCount) {
    java_params = new jvalue[paramCount];
    if (!java_params)
      return NS_ERROR_OUT_OF_MEMORY;

    for (PRUint8 i = 0; i < paramCount && NS_SUCCEEDED(rv); i++)
    {
      const nsXPTParamInfo &paramInfo = aMethodInfo->params[i];
      if (!paramInfo.IsRetval()) {
        rv = SetupJavaParams(paramInfo, aMethodInfo, aMethodIndex, aParams,
                             aParams[i], java_params[i], methodSig);
      } else {
        retvalInfo = &paramInfo;
      }
    }
    NS_ASSERTION(NS_SUCCEEDED(rv), "SetupJavaParams failed");
  }

  // Finish method signature
  if (NS_SUCCEEDED(rv)) {
    methodSig.Append(')');
    if (retvalInfo) {
      nsCAutoString retvalSig;
      rv = GetRetvalSig(retvalInfo, aMethodInfo, aMethodIndex, aParams,
                        retvalSig);
      methodSig.Append(retvalSig);
    } else {
      methodSig.Append('V');
    }
    NS_ASSERTION(NS_SUCCEEDED(rv), "GetRetvalSig failed");
  }

  // Get Java method to call
  jmethodID mid = nsnull;
  if (NS_SUCCEEDED(rv)) {
    nsCAutoString methodName;
    if (XPT_MD_IS_GETTER(aMethodInfo->flags) ||
        XPT_MD_IS_SETTER(aMethodInfo->flags)) {
      if (XPT_MD_IS_GETTER(aMethodInfo->flags))
        methodName.AppendLiteral("get");
      else
        methodName.AppendLiteral("set");
      methodName.AppendASCII(aMethodInfo->name);
      methodName.SetCharAt(toupper(methodName[3]), 3);
    } else {
      methodName.AppendASCII(aMethodInfo->name);
      methodName.SetCharAt(tolower(methodName[0]), 0);
    }
    // If it's a Java keyword, then prepend an underscore
    if (gJavaKeywords->GetEntry(methodName.get())) {
      methodName.Insert('_', 0);
    }

    jclass clazz = env->GetObjectClass(javaObject);
    if (clazz)
      mid = env->GetMethodID(clazz, methodName.get(), methodSig.get());
    NS_ASSERTION(mid, "Failed to get requested method for Java object");
    if (!mid)
      rv = NS_ERROR_FAILURE;
  }

  // Call method
  jvalue retval;
  if (NS_SUCCEEDED(rv)) {
    if (!retvalInfo) {
      env->CallVoidMethodA(javaObject, mid, java_params);
    } else {
      switch (retvalInfo->GetType().TagPart())
      {
        case nsXPTType::T_I8:
          retval.b = env->CallByteMethodA(javaObject, mid, java_params);
          break;

        case nsXPTType::T_I16:
        case nsXPTType::T_U8:
          retval.s = env->CallShortMethodA(javaObject, mid, java_params);
          break;

        case nsXPTType::T_I32:
        case nsXPTType::T_U16:
          retval.i = env->CallIntMethodA(javaObject, mid, java_params);
          break;

        case nsXPTType::T_I64:
        case nsXPTType::T_U32:
          retval.j = env->CallLongMethodA(javaObject, mid, java_params);
          break;

        case nsXPTType::T_FLOAT:
          retval.f = env->CallFloatMethodA(javaObject, mid, java_params);
          break;

        case nsXPTType::T_U64:
        case nsXPTType::T_DOUBLE:
          retval.d = env->CallDoubleMethodA(javaObject, mid, java_params);
          break;

        case nsXPTType::T_BOOL:
          retval.z = env->CallBooleanMethodA(javaObject, mid, java_params);
          break;

        case nsXPTType::T_CHAR:
        case nsXPTType::T_WCHAR:
          retval.c = env->CallCharMethodA(javaObject, mid, java_params);
          break;

        case nsXPTType::T_CHAR_STR:
        case nsXPTType::T_WCHAR_STR:
        case nsXPTType::T_IID:
        case nsXPTType::T_ASTRING:
        case nsXPTType::T_DOMSTRING:
        case nsXPTType::T_UTF8STRING:
        case nsXPTType::T_CSTRING:
        case nsXPTType::T_INTERFACE:
        case nsXPTType::T_INTERFACE_IS:
          retval.l = env->CallObjectMethodA(javaObject, mid, java_params);
          break;

        case nsXPTType::T_VOID:
          retval.j = env->CallLongMethodA(javaObject, mid, java_params);
          break;

        default:
          NS_WARNING("Unhandled retval type");
          break;
      }
    }

    // Check for exception from called Java function
    jthrowable exp = env->ExceptionOccurred();
    if (exp) {
      // If the exception is an instance of XPCOMException, then get the
      // nsresult from the exception instance.  Else, default to
      // NS_ERROR_FAILURE.
      if (env->IsInstanceOf(exp, xpcomExceptionClass)) {
        jfieldID fid;
        fid = env->GetFieldID(xpcomExceptionClass, "errorcode", "J");
        if (fid) {
          rv = env->GetLongField(exp, fid);
        } else {
          rv = NS_ERROR_FAILURE;
        }
        NS_ASSERTION(fid, "Couldn't get 'errorcode' field of XPCOMException");
      } else {
        rv = NS_ERROR_FAILURE;
      }
    }
  }

  // Handle any 'inout', 'out' and 'retval' params
  if (NS_SUCCEEDED(rv)) {
    for (PRUint8 i = 0; i < paramCount; i++)
    {
      const nsXPTParamInfo &paramInfo = aMethodInfo->params[i];
      if (paramInfo.IsIn() && !paramInfo.IsOut() && !paramInfo.IsDipper()) // 'in'
        continue;

      // If param is null, then caller is not expecting an output value.
      if (aParams[i].val.p == nsnull)
        continue;

      if (!paramInfo.IsRetval()) {
        rv = FinalizeJavaParams(paramInfo, aMethodInfo, aMethodIndex, aParams,
                                aParams[i], java_params[i]);
      } else {
        rv = FinalizeJavaParams(paramInfo, aMethodInfo, aMethodIndex, aParams,
                                aParams[i], retval);
      }
    }
    NS_ASSERTION(NS_SUCCEEDED(rv), "FinalizeJavaParams/SetXPCOMRetval failed");
  }

  if (java_params)
    delete [] java_params;

#ifdef DEBUG
  if (env->ExceptionCheck())
    env->ExceptionDescribe();
#endif
  env->ExceptionClear();

  LOG(("<--- (Java) %s::%s()\n", ifaceName, aMethodInfo->name));
  return rv;
}