2 * Copyright (C) 2003 Apple Computer, Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 #include <jni_class.h>
26 #include <jni_instance.h>
27 #include <jni_runtime.h>
28 #include <jni_utility.h>
29 #include <runtime_object.h>
30 #include <runtime_root.h>
33 #define JS_LOG(formatAndArgs...) ((void)0)
35 #define JS_LOG(formatAndArgs...) { \
36 fprintf (stderr, "%s:%d -- %s: ", __FILE__, __LINE__, __FUNCTION__); \
37 fprintf(stderr, formatAndArgs); \
41 using namespace KJS::Bindings;
44 JavaInstance::JavaInstance (jobject instance, const RootObject *r)
46 _instance = new JObjectWrapper (instance);
51 JavaInstance::~JavaInstance ()
57 JavaInstance::JavaInstance (const JavaInstance &other) : Instance()
59 _instance = other._instance;
61 // Classes are kept around forever.
62 _class = other._class;
66 #define NUM_LOCAL_REFS 64
68 void JavaInstance::begin()
70 getJNIEnv()->PushLocalFrame (NUM_LOCAL_REFS);
73 void JavaInstance::end()
75 getJNIEnv()->PopLocalFrame (NULL);
78 Class *JavaInstance::getClass() const
81 _class = JavaClass::classForInstance (_instance->_instance);
85 KJS::Value JavaInstance::stringValue() const
87 jstring stringValue = (jstring)callJNIObjectMethod (_instance->_instance, "toString", "()Ljava/lang/String;");
88 JNIEnv *env = getJNIEnv();
89 const UChar *c = (const UChar *)getUCharactersFromJStringInEnv (env, stringValue);
90 UString u(c, (int)env->GetStringLength(stringValue));
92 releaseUCharactersForJStringInEnv (env, stringValue, (const jchar *)c);
96 KJS::Value JavaInstance::numberValue() const
98 jdouble doubleValue = callJNIDoubleMethod (_instance->_instance, "doubleValue", "()D");
99 KJS::Number v(doubleValue);
103 KJS::Value JavaInstance::booleanValue() const
105 jboolean booleanValue = callJNIBooleanMethod (_instance->_instance, "booleanValue", "()Z");
106 KJS::Boolean v(booleanValue);
110 Value JavaInstance::invokeMethod (KJS::ExecState *exec, const MethodList &methodList, const List &args)
112 int i, count = args.size();
116 unsigned int numMethods = methodList.length();
118 // Try to find a good match for the overloaded method. The
119 // fundamental problem is that JavaScript doesn have the
120 // notion of method overloading and Java does. We could
121 // get a bit more sophisticated and attempt to does some
122 // type checking as we as checking the number of parameters.
123 unsigned int methodIndex;
125 for (methodIndex = 0; methodIndex < numMethods; methodIndex++) {
126 aMethod = methodList.methodAt (methodIndex);
127 if (aMethod->numParameters() == count) {
133 JS_LOG ("unable to find an appropiate method\n");
137 const JavaMethod *jMethod = static_cast<const JavaMethod*>(method);
138 JS_LOG ("call %s %s on %p\n", method->name(), jMethod->signature(), _instance->_instance);
141 jArgs = (jvalue *)malloc (count * sizeof(jvalue));
146 for (i = 0; i < count; i++) {
147 JavaParameter *aParameter = static_cast<JavaParameter *>(jMethod->parameterAt(i));
148 jArgs[i] = convertValueToJValue (exec, args.at(i), aParameter->getJNIType(), aParameter->type());
154 // Try to use the JNI abstraction first, otherwise fall back to
155 // nornmal JNI. The JNI dispatch abstraction allows the Java plugin
156 // to dispatch the call on the appropriate internal VM thread.
157 const RootObject *execContext = executionContext();
158 bool handled = false;
159 if (execContext && execContext->nativeHandle()) {
160 jobject obj = _instance->_instance;
161 handled = dispatchJNICall (execContext->nativeHandle(), obj, jMethod->methodID(obj), jMethod->JNIReturnType(), jArgs, result);
164 // The following code can be conditionally removed once we have a Tiger update that
165 // contains the new Java plugin. It is needed for builds prior to Tiger.
167 jobject obj = _instance->_instance;
168 switch (jMethod->JNIReturnType()){
170 callJNIVoidMethodIDA (obj, jMethod->methodID(obj), jArgs);
175 result.l = callJNIObjectMethodIDA (obj, jMethod->methodID(obj), jArgs);
180 result.z = callJNIBooleanMethodIDA (obj, jMethod->methodID(obj), jArgs);
185 result.b = callJNIByteMethodIDA (obj, jMethod->methodID(obj), jArgs);
190 result.c = callJNICharMethodIDA (obj, jMethod->methodID(obj), jArgs);
195 result.s = callJNIShortMethodIDA (obj, jMethod->methodID(obj), jArgs);
200 result.i = callJNIIntMethodIDA (obj, jMethod->methodID(obj), jArgs);
205 result.j = callJNILongMethodIDA (obj, jMethod->methodID(obj), jArgs);
210 result.f = callJNIFloatMethodIDA (obj, jMethod->methodID(obj), jArgs);
215 result.d = callJNIDoubleMethodIDA (obj, jMethod->methodID(obj), jArgs);
226 switch (jMethod->JNIReturnType()){
228 resultValue = Undefined();
234 const char *arrayType = jMethod->returnType();
235 if (arrayType[0] == '[') {
236 resultValue = JavaArray::convertJObjectToArray (exec, result.l, arrayType, executionContext());
239 resultValue = Object(new RuntimeObjectImp(new JavaInstance (result.l, executionContext())));
243 resultValue = Undefined();
249 resultValue = KJS::Boolean(result.z);
254 resultValue = Number(result.b);
259 resultValue = Number(result.c);
264 resultValue = Number(result.s);
269 resultValue = Number(result.i);
274 resultValue = Number((long int)result.j);
279 resultValue = Number(result.f);
284 resultValue = Number(result.d);
290 resultValue = Undefined();
301 KJS::Value JavaInstance::defaultValue (KJS::Type hint) const
303 if (hint == StringType) {
304 return stringValue();
306 else if (hint == NumberType) {
307 return numberValue();
309 else if (hint == BooleanType) {
310 return booleanValue();
312 else if (hint == UnspecifiedType) {
313 JavaClass *aClass = static_cast<JavaClass*>(getClass());
314 if (aClass->isStringClass()) {
315 return stringValue();
317 else if (aClass->isNumberClass()) {
318 return numberValue();
320 else if (aClass->isBooleanClass()) {
321 return booleanValue();
328 KJS::Value JavaInstance::valueOf() const
330 return stringValue();
333 void JavaInstance::setExecutionContext (RootObject *r) { _root = r; }
334 const RootObject *JavaInstance::executionContext() const { return _root; }
336 JObjectWrapper::JObjectWrapper(jobject instance)
338 assert (instance != 0);
341 // Cache the JNIEnv used to get the global ref for this java instanace.
342 // It'll be used to delete the reference.
345 _instance = _env->NewGlobalRef (instance);
347 JS_LOG ("new global ref %p for %p\n", _instance, instance);
349 if (_instance == NULL) {
350 fprintf (stderr, "%s: could not get GlobalRef for %p\n", __PRETTY_FUNCTION__, instance);
354 JObjectWrapper::~JObjectWrapper() {
355 JS_LOG ("deleting global ref %p\n", _instance);
356 _env->DeleteGlobalRef (_instance);