1 /*
2 * Copyright (C) 2003, 2008 Apple Inc. All rights reserved.
3 * Copyright 2009, 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 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. 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 APPLE COMPUTER, INC. ``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 APPLE COMPUTER, INC. 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 #define LOG_TAG "v8binding"
28
29 #include "config.h"
30
31 #include "jni_class.h"
32 #include "jni_instance.h"
33 #include "jni_runtime.h"
34 #include "jni_utility.h"
35
36 #include <assert.h>
37 #include <utils/Log.h>
38
39 using namespace JSC::Bindings;
40
JavaInstance(jobject instance)41 JavaInstance::JavaInstance (jobject instance)
42 {
43 _instance = new JObjectWrapper(instance);
44 _class = 0;
45 _refCount = 0;
46 }
47
~JavaInstance()48 JavaInstance::~JavaInstance ()
49 {
50 _instance = 0;
51 delete _class;
52 }
53
getClass() const54 JavaClass* JavaInstance::getClass() const
55 {
56 if (_class == 0) {
57 jobject local_ref = getLocalRef();
58 _class = new JavaClass(local_ref);
59 getJNIEnv()->DeleteLocalRef(local_ref);
60 }
61 return _class;
62 }
63
invokeMethod(const char * methodName,const NPVariant * args,uint32_t count,NPVariant * resultValue)64 bool JavaInstance::invokeMethod(const char* methodName, const NPVariant* args, uint32_t count, NPVariant* resultValue)
65 {
66 int i;
67 jvalue *jArgs;
68 JavaMethod *method = 0;
69
70 VOID_TO_NPVARIANT(*resultValue);
71
72 MethodList methodList = getClass()->methodsNamed(methodName);
73
74 size_t numMethods = methodList.size();
75
76 // Try to find a good match for the overloaded method. The
77 // fundamental problem is that JavaScript doesn have the
78 // notion of method overloading and Java does. We could
79 // get a bit more sophisticated and attempt to does some
80 // type checking as we as checking the number of parameters.
81 JavaMethod *aMethod;
82 for (size_t methodIndex = 0; methodIndex < numMethods; methodIndex++) {
83 aMethod = methodList[methodIndex];
84 if (aMethod->numParameters() == count) {
85 method = aMethod;
86 break;
87 }
88 }
89 if (method == 0) {
90 LOGW("unable to find an appropiate method\n");
91 return false;
92 }
93
94 const JavaMethod *jMethod = static_cast<const JavaMethod*>(method);
95
96 if (count > 0) {
97 jArgs = (jvalue *)malloc (count * sizeof(jvalue));
98 }
99 else
100 jArgs = 0;
101
102 for (i = 0; i < count; i++) {
103 JavaParameter* aParameter = jMethod->parameterAt(i);
104 jArgs[i] = convertNPVariantToJValue(args[i], aParameter->getJNIType(), aParameter->type());
105 }
106
107 jvalue result;
108
109 // The following code can be conditionally removed once we have a Tiger update that
110 // contains the new Java plugin. It is needed for builds prior to Tiger.
111 {
112 jobject obj = getLocalRef();
113 switch (jMethod->JNIReturnType()){
114 case void_type:
115 callJNIMethodIDA<void>(obj, jMethod->methodID(obj), jArgs);
116 break;
117 case object_type:
118 result.l = callJNIMethodIDA<jobject>(obj, jMethod->methodID(obj), jArgs);
119 break;
120 case boolean_type:
121 result.z = callJNIMethodIDA<jboolean>(obj, jMethod->methodID(obj), jArgs);
122 break;
123 case byte_type:
124 result.b = callJNIMethodIDA<jbyte>(obj, jMethod->methodID(obj), jArgs);
125 break;
126 case char_type:
127 result.c = callJNIMethodIDA<jchar>(obj, jMethod->methodID(obj), jArgs);
128 break;
129 case short_type:
130 result.s = callJNIMethodIDA<jshort>(obj, jMethod->methodID(obj), jArgs);
131 break;
132 case int_type:
133 result.i = callJNIMethodIDA<jint>(obj, jMethod->methodID(obj), jArgs);
134 break;
135
136 case long_type:
137 result.j = callJNIMethodIDA<jlong>(obj, jMethod->methodID(obj), jArgs);
138 break;
139 case float_type:
140 result.f = callJNIMethodIDA<jfloat>(obj, jMethod->methodID(obj), jArgs);
141 break;
142 case double_type:
143 result.d = callJNIMethodIDA<jdouble>(obj, jMethod->methodID(obj), jArgs);
144 break;
145 case invalid_type:
146 default:
147 break;
148 }
149 getJNIEnv()->DeleteLocalRef(obj);
150 }
151
152 convertJValueToNPVariant(result, jMethod->JNIReturnType(), jMethod->returnType(), resultValue);
153 free (jArgs);
154
155 return true;
156 }
157
JObjectWrapper(jobject instance)158 JObjectWrapper::JObjectWrapper(jobject instance)
159 : _refCount(0)
160 {
161 assert (instance != 0);
162
163 // Cache the JNIEnv used to get the global ref for this java instanace.
164 // It'll be used to delete the reference.
165 _env = getJNIEnv();
166
167 jclass localClsRef = _env->FindClass("java/lang/ref/WeakReference");
168 jmethodID weakRefInit = _env->GetMethodID(localClsRef, "<init>",
169 "(Ljava/lang/Object;)V");
170 mWeakRefGet = _env->GetMethodID(localClsRef, "get",
171 "()Ljava/lang/Object;");
172
173 jobject weakRef = _env->NewObject(localClsRef, weakRefInit, instance);
174
175 _instance = _env->NewGlobalRef(weakRef);
176
177 LOGV("new global ref %p for %p\n", _instance, instance);
178
179 if (_instance == NULL) {
180 fprintf (stderr, "%s: could not get GlobalRef for %p\n", __PRETTY_FUNCTION__, instance);
181 }
182
183 _env->DeleteLocalRef(weakRef);
184 _env->DeleteLocalRef(localClsRef);
185 }
186
~JObjectWrapper()187 JObjectWrapper::~JObjectWrapper() {
188 LOGV("deleting global ref %p\n", _instance);
189 _env->DeleteGlobalRef(_instance);
190 }
191
getLocalRef() const192 jobject JObjectWrapper::getLocalRef() const {
193 jobject real = _env->CallObjectMethod(_instance, mWeakRefGet);
194 if (!real)
195 LOGE("The real object has been deleted");
196 return _env->NewLocalRef(real);
197 }
198