• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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