1 /* 2 * Copyright (C) 2003, 2008, 2010 Apple Inc. All rights reserved. 3 * Copyright 2010, The Android Open Source Project 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY 15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #include "config.h" 28 #include "JavaInstanceV8.h" 29 30 #include "JNIBridge.h" 31 #include "JNIUtilityPrivate.h" 32 #include "JavaClassV8.h" 33 34 #include <assert.h> 35 #include <utils/Log.h> 36 37 #define LOG_TAG "v8binding" 38 39 // ANDROID 40 #include <cutils/log.h> 41 #define LOG_TAG JavaInstanceV8.cpp 42 // END ANDROID 43 44 using namespace JSC::Bindings; 45 46 JavaInstance::JavaInstance(jobject instance) 47 { 48 m_instance = new JObjectWrapper(instance); 49 m_class = 0; 50 } 51 52 JavaInstance::~JavaInstance() 53 { 54 m_instance = 0; 55 delete m_class; 56 } 57 58 JavaClass* JavaInstance::getClass() const 59 { 60 if (!m_class) 61 m_class = new JavaClass(javaInstance()); 62 return m_class; 63 } 64 65 bool JavaInstance::invokeMethod(const char* methodName, const NPVariant* args, int count, NPVariant* resultValue) 66 { 67 VOID_TO_NPVARIANT(*resultValue); 68 69 MethodList methodList = getClass()->methodsNamed(methodName); 70 71 size_t numMethods = methodList.size(); 72 73 // Try to find a good match for the overloaded method. The 74 // fundamental problem is that JavaScript doesn't have the 75 // notion of method overloading and Java does. We could 76 // get a bit more sophisticated and attempt to does some 77 // type checking as we as checking the number of parameters. 78 JavaMethod* aMethod; 79 JavaMethod* method = 0; 80 for (size_t methodIndex = 0; methodIndex < numMethods; methodIndex++) { 81 aMethod = methodList[methodIndex]; 82 if (aMethod->numParameters() == count) { 83 method = aMethod; 84 break; 85 } 86 } 87 if (!method) { 88 LOGW("unable to find an appropiate method\n"); 89 return false; 90 } 91 92 const JavaMethod* jMethod = static_cast<const JavaMethod*>(method); 93 94 jvalue* jArgs = 0; 95 if (count > 0) 96 jArgs = static_cast<jvalue*>(malloc(count * sizeof(jvalue))); 97 98 for (int i = 0; i < count; i++) { 99 JavaParameter* aParameter = jMethod->parameterAt(i); 100 jArgs[i] = convertNPVariantToJValue(args[i], aParameter->getJNIType(), aParameter->type()); 101 } 102 103 jvalue result; 104 105 // The following code can be conditionally removed once we have a Tiger update that 106 // contains the new Java plugin. It is needed for builds prior to Tiger. 107 { 108 jobject obj = javaInstance(); 109 switch (jMethod->JNIReturnType()) { 110 case void_type: 111 callJNIMethodIDA<void>(obj, jMethod->methodID(obj), jArgs); 112 break; 113 case object_type: 114 result.l = callJNIMethodIDA<jobject>(obj, jMethod->methodID(obj), jArgs); 115 break; 116 case boolean_type: 117 result.z = callJNIMethodIDA<jboolean>(obj, jMethod->methodID(obj), jArgs); 118 break; 119 case byte_type: 120 result.b = callJNIMethodIDA<jbyte>(obj, jMethod->methodID(obj), jArgs); 121 break; 122 case char_type: 123 result.c = callJNIMethodIDA<jchar>(obj, jMethod->methodID(obj), jArgs); 124 break; 125 case short_type: 126 result.s = callJNIMethodIDA<jshort>(obj, jMethod->methodID(obj), jArgs); 127 break; 128 case int_type: 129 result.i = callJNIMethodIDA<jint>(obj, jMethod->methodID(obj), jArgs); 130 break; 131 132 case long_type: 133 result.j = callJNIMethodIDA<jlong>(obj, jMethod->methodID(obj), jArgs); 134 break; 135 case float_type: 136 result.f = callJNIMethodIDA<jfloat>(obj, jMethod->methodID(obj), jArgs); 137 break; 138 case double_type: 139 result.d = callJNIMethodIDA<jdouble>(obj, jMethod->methodID(obj), jArgs); 140 break; 141 case invalid_type: 142 default: 143 break; 144 } 145 } 146 147 convertJValueToNPVariant(result, jMethod->JNIReturnType(), jMethod->returnType(), resultValue); 148 free(jArgs); 149 150 return true; 151 } 152 153 JObjectWrapper::JObjectWrapper(jobject instance) 154 : m_refCount(0) 155 { 156 assert(instance); 157 // ANDROID 158 if (!instance) 159 LOGE("Attempted to create JObjectWrapper for null object"); 160 // END ANDROID 161 162 // Cache the JNIEnv used to get the global ref for this java instanace. 163 // It'll be used to delete the reference. 164 m_env = getJNIEnv(); 165 166 m_instance = m_env->NewGlobalRef(instance); 167 168 LOGV("new global ref %p for %p\n", m_instance, instance); 169 170 if (!m_instance) 171 // ANDROID 172 LOGE("%s: could not get GlobalRef for %p\n", __PRETTY_FUNCTION__, instance); 173 // END ANDROID 174 } 175 176 JObjectWrapper::~JObjectWrapper() 177 { 178 LOGV("deleting global ref %p\n", m_instance); 179 m_env->DeleteGlobalRef(m_instance); 180 } 181