diff options
author | Feng Qian <fqian@google.com> | 2009-04-29 11:05:23 -0700 |
---|---|---|
committer | Feng Qian <fqian@google.com> | 2009-04-29 11:05:23 -0700 |
commit | 7fa30a60f66c19c8e6fb91ef799bca4d8d6f57f2 (patch) | |
tree | 31d48cfcec68e2935ba4b869684d18eb0db2aaa4 /V8Binding/jni | |
parent | 1d46464ff4a2f0c744bdf3e04966bc3e692f3017 (diff) | |
download | external_webkit-7fa30a60f66c19c8e6fb91ef799bca4d8d6f57f2.zip external_webkit-7fa30a60f66c19c8e6fb91ef799bca4d8d6f57f2.tar.gz external_webkit-7fa30a60f66c19c8e6fb91ef799bca4d8d6f57f2.tar.bz2 |
Add first round JNI bindings.
Not compiling yet, and not enabled in the build script. Get it checked it, and
will merge the branch back to master and work there.
Diffstat (limited to 'V8Binding/jni')
-rw-r--r-- | V8Binding/jni/jni_class.cpp | 146 | ||||
-rw-r--r-- | V8Binding/jni/jni_class.h | 53 | ||||
-rw-r--r-- | V8Binding/jni/jni_instance.cpp | 228 | ||||
-rw-r--r-- | V8Binding/jni/jni_instance.h | 89 | ||||
-rw-r--r-- | V8Binding/jni/jni_npobject.cpp | 46 | ||||
-rw-r--r-- | V8Binding/jni/jni_npobject.h | 27 | ||||
-rw-r--r-- | V8Binding/jni/jni_runtime.cpp | 169 | ||||
-rw-r--r-- | V8Binding/jni/jni_runtime.h | 124 | ||||
-rw-r--r-- | V8Binding/jni/jni_utility.cpp | 474 | ||||
-rw-r--r-- | V8Binding/jni/jni_utility.h | 281 |
10 files changed, 1637 insertions, 0 deletions
diff --git a/V8Binding/jni/jni_class.cpp b/V8Binding/jni/jni_class.cpp new file mode 100644 index 0000000..4e3b5f9 --- /dev/null +++ b/V8Binding/jni/jni_class.cpp @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2003 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "jni_class.h" + +#if ENABLE(MAC_JAVA_BRIDGE) + +#include "JSDOMWindow.h" +#include <runtime/Identifier.h> +#include <runtime/JSLock.h> +#include "jni_utility.h" +#include "jni_runtime.h" + +using namespace JSC::Bindings; + +JavaClass::JavaClass(jobject anInstance) +{ + jobject aClass = callJNIMethod<jobject>(anInstance, "getClass", "()Ljava/lang/Class;"); + + if (!aClass) { + fprintf(stderr, "%s: unable to call getClass on instance %p\n", __PRETTY_FUNCTION__, anInstance); + return; + } + + jstring className = (jstring)callJNIMethod<jobject>(aClass, "getName", "()Ljava/lang/String;"); + const char *classNameC = getCharactersFromJString(className); + _name = strdup(classNameC); + releaseCharactersForJString(className, classNameC); + + int i; + JNIEnv *env = getJNIEnv(); + + // Get the fields + jarray fields = (jarray)callJNIMethod<jobject>(aClass, "getFields", "()[Ljava/lang/reflect/Field;"); + int numFields = env->GetArrayLength(fields); + for (i = 0; i < numFields; i++) { + jobject aJField = env->GetObjectArrayElement((jobjectArray)fields, i); + JavaField *aField = new JavaField(env, aJField); // deleted in the JavaClass destructor + { + JSLock lock(false); + _fields.set(aField->name(), aField); + } + env->DeleteLocalRef(aJField); + } + + // Get the methods + jarray methods = (jarray)callJNIMethod<jobject>(aClass, "getMethods", "()[Ljava/lang/reflect/Method;"); + int numMethods = env->GetArrayLength(methods); + for (i = 0; i < numMethods; i++) { + jobject aJMethod = env->GetObjectArrayElement((jobjectArray)methods, i); + JavaMethod *aMethod = new JavaMethod(env, aJMethod); // deleted in the JavaClass destructor + MethodList* methodList; + { + JSLock lock(false); + + methodList = _methods.get(aMethod->name()); + if (!methodList) { + methodList = new MethodList(); + _methods.set(aMethod->name(), methodList); + } + } + methodList->append(aMethod); + env->DeleteLocalRef(aJMethod); + } +#ifdef ANDROID_FIX + env->DeleteLocalRef(fields); + env->DeleteLocalRef(methods); + env->DeleteLocalRef(aClass); +#endif +} + +JavaClass::~JavaClass() { + free((void *)_name); + + JSLock lock(false); + + deleteAllValues(_fields); + _fields.clear(); + + MethodListMap::const_iterator end = _methods.end(); + for (MethodListMap::const_iterator it = _methods.begin(); it != end; ++it) { + const MethodList* methodList = it->second; + deleteAllValues(*methodList); + delete methodList; + } + _methods.clear(); +} + +MethodList JavaClass::methodsNamed(const Identifier& identifier, Instance*) const +{ + MethodList *methodList = _methods.get(identifier.ustring().rep()); + + if (methodList) + return *methodList; + return MethodList(); +} + +Field *JavaClass::fieldNamed(const Identifier& identifier, Instance*) const +{ + return _fields.get(identifier.ustring().rep()); +} + +bool JavaClass::isNumberClass() const +{ + return ((strcmp(_name, "java.lang.Byte") == 0 || + strcmp(_name, "java.lang.Short") == 0 || + strcmp(_name, "java.lang.Integer") == 0 || + strcmp(_name, "java.lang.Long") == 0 || + strcmp(_name, "java.lang.Float") == 0 || + strcmp(_name, "java.lang.Double") == 0) ); +} + +bool JavaClass::isBooleanClass() const +{ + return strcmp(_name, "java.lang.Boolean") == 0; +} + +bool JavaClass::isStringClass() const +{ + return strcmp(_name, "java.lang.String") == 0; +} + +#endif // ENABLE(MAC_JAVA_BRIDGE) diff --git a/V8Binding/jni/jni_class.h b/V8Binding/jni/jni_class.h new file mode 100644 index 0000000..2865be5 --- /dev/null +++ b/V8Binding/jni/jni_class.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2003 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef JNI_CLASS_H_ +#define JNI_CLASS_H_ + +#include <jni_runtime.h> +#include <wtf/HashMap.h> + +namespace JSC { + +namespace Bindings { + +typedef Vector<JavaMethod*> MethodList; +class JavaClass +public: + JavaClass (jobject anInstance); + ~JavaClass (); + + MethodList methodsNamed(NPIdentifier name, Instance* instance) const; + +private: + const char *_name; + MethodListMap _methods; +}; + +} // namespace Bindings + +} // namespace JSC + +#endif // JNI_CLASS_H_ diff --git a/V8Binding/jni/jni_instance.cpp b/V8Binding/jni/jni_instance.cpp new file mode 100644 index 0000000..887886e --- /dev/null +++ b/V8Binding/jni/jni_instance.cpp @@ -0,0 +1,228 @@ +/* + * Copyright (C) 2003, 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#include "jni_instance.h" +#include "jni_runtime.h" +#include "jni_utility.h" + +#include <assert.h> + +#ifdef NDEBUG +#define JS_LOG(formatAndArgs...) ((void)0) +#else +#define JS_LOG(formatAndArgs...) { \ + fprintf (stderr, "%s:%d -- %s: ", __FILE__, __LINE__, __FUNCTION__); \ + fprintf(stderr, formatAndArgs); \ +} +#endif + +using namespace JSC::Bindings; + +JavaInstance::JavaInstance (jobject instance) +{ + _instance = new JObjectWrapper (instance); +} + +JavaInstance::~JavaInstance () +{ +} + +#define NUM_LOCAL_REFS 64 + +bool JavaInstance::invokeMethod(NPIdentifier methodName, NPVariant* args, uint32_t count, NPVariant* resultValue) +{ + int i; + jvalue *jArgs; + Method *method = 0; + size_t numMethods = methodList.size(); + + // Try to find a good match for the overloaded method. The + // fundamental problem is that JavaScript doesn have the + // notion of method overloading and Java does. We could + // get a bit more sophisticated and attempt to does some + // type checking as we as checking the number of parameters. + Method *aMethod; + for (size_t methodIndex = 0; methodIndex < numMethods; methodIndex++) { + aMethod = methodList[methodIndex]; + if (aMethod->numParameters() == count) { + method = aMethod; + break; + } + } + if (method == 0) { + JS_LOG ("unable to find an appropiate method\n"); + return jsUndefined(); + } + + const JavaMethod *jMethod = static_cast<const JavaMethod*>(method); + + if (count > 0) { + jArgs = (jvalue *)malloc (count * sizeof(jvalue)); + } + else + jArgs = 0; + + for (i = 0; i < count; i++) { + JavaParameter* aParameter = jMethod->parameterAt(i); + jArgs[i] = convertNPVariantToJValue(args[i], aParameter->getJNIType(), aParameter->type()); + } + + jvalue result; + + // The following code can be conditionally removed once we have a Tiger update that + // contains the new Java plugin. It is needed for builds prior to Tiger. + { + jobject obj = _instance->_instance; + switch (jMethod->JNIReturnType()){ + case void_type: + callJNIMethodIDA<void>(obj, jMethod->methodID(obj), jArgs); + break; + case object_type: + result.l = callJNIMethodIDA<jobject>(obj, jMethod->methodID(obj), jArgs); + break; + case boolean_type: + result.z = callJNIMethodIDA<jboolean>(obj, jMethod->methodID(obj), jArgs); + break; + case byte_type: + result.b = callJNIMethodIDA<jbyte>(obj, jMethod->methodID(obj), jArgs); + break; + case char_type: + result.c = callJNIMethodIDA<jchar>(obj, jMethod->methodID(obj), jArgs); + break; + case short_type: + result.s = callJNIMethodIDA<jshort>(obj, jMethod->methodID(obj), jArgs); + break; + case int_type: + result.i = callJNIMethodIDA<jint>(obj, jMethod->methodID(obj), jArgs); + break; + + case long_type: + result.j = callJNIMethodIDA<jlong>(obj, jMethod->methodID(obj), jArgs); + break; + case float_type: + result.f = callJNIMethodIDA<jfloat>(obj, jMethod->methodID(obj), jArgs); + break; + case double_type: + result.d = callJNIMethodIDA<jdouble>(obj, jMethod->methodID(obj), jArgs); + break; + case invalid_type: + default: + break; + } + } + + switch (jMethod->JNIReturnType()){ + case void_type: { + VOID_TO_NPVARIANT(*resultValue); + } + break; + + case object_type: { + if (result.l != 0) { + OBJECT_TO_NPVARIANT(JavaObjectToNPObject(JavaInstance::create(result.l)), *resultValue); + } + else { + VOID_TO_NPVARIANT(*resultValue); + } + } + break; + + case boolean_type: { + BOOLEAN_TO_NPVARIANT(result.z, *resultValue); + } + break; + + case byte_type: { + INT32_TO_NPVARIANT(result.b, *resultValue); + } + break; + + case char_type: { + INT32_TO_NPVARIANT(result.c, *resultValue); + } + break; + + case short_type: { + INT32_TO_NPVARIANT(result.s, *resultValue); + } + break; + + case int_type: { + INT32_TO_NPVARIANT(result.i, *resultValue); + } + break; + + // TODO(fqian): check if cast to double is needed. + case long_type: { + DOUBLE_TO_NPVARIANT(result.j, *resultValue); + } + break; + + case float_type: { + DOUBLE_TO_NPVARIANT(result.f, *resultValue); + } + break; + + case double_type: { + DOUBLE_TO_NPVARIANT(result.d, *resultValue); + } + break; + + case invalid_type: + default: { + VOID_TO_NPVARIANT(*resultValue); + } + break; + } + + free (jArgs); + + return resultValue; +} + +JObjectWrapper::JObjectWrapper(jobject instance) +: _refCount(0) +{ + assert (instance != 0); + + // Cache the JNIEnv used to get the global ref for this java instanace. + // It'll be used to delete the reference. + _env = getJNIEnv(); + + _instance = _env->NewGlobalRef (instance); + + JS_LOG ("new global ref %p for %p\n", _instance, instance); + + if (_instance == NULL) { + fprintf (stderr, "%s: could not get GlobalRef for %p\n", __PRETTY_FUNCTION__, instance); + } +} + +JObjectWrapper::~JObjectWrapper() { + JS_LOG ("deleting global ref %p\n", _instance); + _env->DeleteGlobalRef (_instance); +} diff --git a/V8Binding/jni/jni_instance.h b/V8Binding/jni/jni_instance.h new file mode 100644 index 0000000..5fa4141 --- /dev/null +++ b/V8Binding/jni/jni_instance.h @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2003 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _JNI_INSTANCE_H_ +#define _JNI_INSTANCE_H_ + +#include <JavaVM/jni.h> + +namespace android { +class WeakJavaInstance; +} + +namespace JSC { + +namespace Bindings { + +class JObjectWrapper +{ +friend class RefPtr<JObjectWrapper>; +friend class JavaArray; +friend class JavaInstance; +friend class JavaMethod; +friend class android::WeakJavaInstance; + +protected: + JObjectWrapper(jobject instance); + ~JObjectWrapper(); + + void ref() { _refCount++; } + void deref() + { + if (--_refCount == 0) + delete this; + } + + jobject _instance; + +private: + JNIEnv *_env; + unsigned int _refCount; +}; + +class JavaInstance +{ +public: + static PassRefPtr<JavaInstance> create(jobject instance) + { + return adoptRef(new JavaInstance(instance)); + } + + ~JavaInstance(); + + NPVariant invokeMethod(NPIdentifier methodName, NPVariant* args, uint32_t argsCount); + + jobject javaInstance() const { return _instance->_instance; } + +private: + JavaInstance(jobject instance); + + RefPtr<JObjectWrapper> _instance; +}; + +} // namespace Bindings + +} // namespace JSC + +#endif // _JNI_INSTANCE_H_ diff --git a/V8Binding/jni/jni_npobject.cpp b/V8Binding/jni/jni_npobject.cpp new file mode 100644 index 0000000..daa26a8 --- /dev/null +++ b/V8Binding/jni/jni_npobject.cpp @@ -0,0 +1,46 @@ + +#include "jni_npobject.h" + +namespace V8 { namespace Binding { + +static NPClass JavaNPClass = { + NP_CLASS_STRUCT_VERSION, + 0, // allocate, + 0, // free, + 0, // invalidate + JavaNPObject_HasMethod, + JavaNPObject_Invoke, + 0, // invokeDefault, + JavaNPObject_HasProperty, + JavaNPobject_GetProperty, + JavaNPObject_SetProperty, + 0, // removeProperty + 0, // enumerate + 0 // construct +}; + +NPObject* JavaInstanceToNPObject(PassRefPtr<JavaInstance> instance) { + JavaNPObject* object = new JavaNPObject(instance); + return static_cast<NPObject*>(object); +} + +bool JavaNPObject_HasMethod(NPObject* obj, NPIdentifier name) { + // FIXME: for now, always pretend the object has the named method. + return true; +} + +bool JavaNPObject_Invoke(NPobject* obj, NPIdentifier methodName, const NPVariant* args, uint32_t argCount, NPVariant* result) { + +} + +bool JavaNPObject_HasProperty(NPObject* obj, NPIdentifier name) { +} + +bool JavaNPObject_GetProperty(NPObject* obj, NPIdentifier name, NPVariant* ressult) { +} + +bool JavaNPObject_SetProperty(NPObject* obj, NPIdentifier name, const NPVariant* value) { + +} + +} } // namespace V8::Binding diff --git a/V8Binding/jni/jni_npobject.h b/V8Binding/jni/jni_npobject.h new file mode 100644 index 0000000..99fe368 --- /dev/null +++ b/V8Binding/jni/jni_npobject.h @@ -0,0 +1,27 @@ +// A wrapper of a JNI value as an NPObject + + +#ifndef JNI_NPOBJECT_H_ +#define JNI_NPOBJECT_H_ + +#include "npapi.h" +#include <JavaVM/jni.h> + +namespace V8 { namespace V8Binding { + +struct JavaNPObject { + NPObject _object; + RefPtr<JavaInstance> _instance; +}; + +NPObject* JavaInstanceToNPObject(PassRefPtr<JavaInstance> instance); + +bool JavaNPObject_HasMethod(NPObject* obj, NPIdentifier name); +bool JavaNPObject_Invoke(NPobject* obj, NPIdentifier methodName, const NPVariant* args, uint32_t argCount, NPVariant* result); +bool JavaNPObject_HasProperty(NPObject* obj, NPIdentifier name); +bool JavaNPObject_GetProperty(NPObject* obj, NPIdentifier name, NPVariant* ressult); +bool JavaNPObject_SetProperty(NPObject* obj, NPIdentifier name, const NPVariant* value); + +} } + +#endif JNI_NPOBJECT_H_ diff --git a/V8Binding/jni/jni_runtime.cpp b/V8Binding/jni/jni_runtime.cpp new file mode 100644 index 0000000..1ff640a --- /dev/null +++ b/V8Binding/jni/jni_runtime.cpp @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2003 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#include "jni_runtime.h" +#include "jni_utility.h" + +#ifdef NDEBUG +#define JS_LOG(formatAndArgs...) ((void)0) +#else +#define JS_LOG(formatAndArgs...) { \ + fprintf (stderr, "%s:%d -- %s: ", __FILE__, __LINE__, __FUNCTION__); \ + fprintf(stderr, formatAndArgs); \ +} +#endif + +using namespace JSC::Bindings; + +JavaParameter::JavaParameter (JNIEnv *env, jstring type) +{ + _type = JavaString (env, type); + _JNIType = JNITypeFromClassName (_type.UTF8String()); +} + + +JavaMethod::JavaMethod (JNIEnv *env, jobject aMethod) +{ + // Get return type + jobject returnType = callJNIMethod<jobject>(aMethod, "getReturnType", "()Ljava/lang/Class;"); + jstring returnTypeName = (jstring)callJNIMethod<jobject>(returnType, "getName", "()Ljava/lang/String;"); + _returnType =JavaString (env, returnTypeName); + _JNIReturnType = JNITypeFromClassName (_returnType.UTF8String()); + env->DeleteLocalRef (returnType); + env->DeleteLocalRef (returnTypeName); + + // Get method name + jstring methodName = (jstring)callJNIMethod<jobject>(aMethod, "getName", "()Ljava/lang/String;"); + _name = JavaString (env, methodName); + env->DeleteLocalRef (methodName); + + // Get parameters + jarray jparameters = (jarray)callJNIMethod<jobject>(aMethod, "getParameterTypes", "()[Ljava/lang/Class;"); + _numParameters = env->GetArrayLength (jparameters); + _parameters = new JavaParameter[_numParameters]; + + int i; + for (i = 0; i < _numParameters; i++) { + jobject aParameter = env->GetObjectArrayElement ((jobjectArray)jparameters, i); + jstring parameterName = (jstring)callJNIMethod<jobject>(aParameter, "getName", "()Ljava/lang/String;"); + _parameters[i] = JavaParameter(env, parameterName); + env->DeleteLocalRef (aParameter); + env->DeleteLocalRef (parameterName); + } + env->DeleteLocalRef (jparameters); + + // Created lazily. + _signature = 0; + _methodID = 0; + + jclass modifierClass = env->FindClass("java/lang/reflect/Modifier"); + int modifiers = callJNIMethod<jint>(aMethod, "getModifiers", "()I"); + _isStatic = (bool)callJNIStaticMethod<jboolean>(modifierClass, "isStatic", "(I)Z", modifiers); +#ifdef ANDROID_FIX + env->DeleteLocalRef(modifierClass); +#endif +} + +JavaMethod::~JavaMethod() +{ + if (_signature) + free(_signature); + delete [] _parameters; +}; + +// JNI method signatures use '/' between components of a class name, but +// we get '.' between components from the reflection API. +static void appendClassName(UString& aString, const char* className) +{ + ASSERT(JSLock::lockCount() > 0); + + char *result, *cp = strdup(className); + + result = cp; + while (*cp) { + if (*cp == '.') + *cp = '/'; + cp++; + } + + aString.append(result); + + free (result); +} + +const char *JavaMethod::signature() const +{ + if (!_signature) { + JSLock lock(false); + + UString signatureBuilder("("); + for (int i = 0; i < _numParameters; i++) { + JavaParameter* aParameter = parameterAt(i); + JNIType _JNIType = aParameter->getJNIType(); + if (_JNIType == array_type) + appendClassName(signatureBuilder, aParameter->type()); + else { + signatureBuilder.append(signatureFromPrimitiveType(_JNIType)); + if (_JNIType == object_type) { + appendClassName(signatureBuilder, aParameter->type()); + signatureBuilder.append(";"); + } + } + } + signatureBuilder.append(")"); + + const char *returnType = _returnType.UTF8String(); + if (_JNIReturnType == array_type) { + appendClassName(signatureBuilder, returnType); + } else { + signatureBuilder.append(signatureFromPrimitiveType(_JNIReturnType)); + if (_JNIReturnType == object_type) { + appendClassName(signatureBuilder, returnType); + signatureBuilder.append(";"); + } + } + + _signature = strdup(signatureBuilder.ascii()); + } + + return _signature; +} + +JNIType JavaMethod::JNIReturnType() const +{ + return _JNIReturnType; +} + +jmethodID JavaMethod::methodID (jobject obj) const +{ + if (_methodID == 0) { + _methodID = getMethodID (obj, _name.UTF8String(), signature()); + } + return _methodID; +} + + diff --git a/V8Binding/jni/jni_runtime.h b/V8Binding/jni/jni_runtime.h new file mode 100644 index 0000000..932f26b --- /dev/null +++ b/V8Binding/jni/jni_runtime.h @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2003 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _JNI_RUNTIME_H_ +#define _JNI_RUNTIME_H_ + +#include "jni_utility.h" +#include "jni_instance.h" + +#include "CString.h" + +namespace JSC +{ + +namespace Bindings +{ + +class JavaString +{ +public: + JavaString() { } + + void _commonInit (JNIEnv *e, jstring s) + { + int size = e->GetStringLength(s); + const char* cs = getCharactersFromJStringInEnv(e, s); + { + _utf8String = WebCore::CString(cs, size); + } + releaseCharactersForJStringInEnv (e, s, cs); + } + + JavaString (JNIEnv *e, jstring s) { + _commonInit (e, s); + } + + JavaString (jstring s) { + _commonInit (getJNIEnv(), s); + } + + ~JavaString() { } + + int length() const { return _utf8String->length(); } + + const char* UTF8String() const { + return _utf8String.c_str(); + } + +private: + WebCore::CString _utf8String; +}; + +class JavaParameter +{ +public: + JavaParameter () : _JNIType(invalid_type) {}; + JavaParameter (JNIEnv *env, jstring type); + virtual ~JavaParameter() { } + + const char* type() const { return _type.UTF8String(); } + JNIType getJNIType() const { return _JNIType; } + +private: + JavaString _type; + JNIType _JNIType; +}; + + +class JavaMethod +{ +public: + JavaMethod(JNIEnv* env, jobject aMethod); + ~JavaMethod(); + + const char* name() const { return _name.UTF8String(); } + const char* returnType() const { return _returnType.UTF8String(); }; + JavaParameter* parameterAt(int i) const { return &_parameters[i]; }; + int numParameters() const { return _numParameters; }; + + const char *signature() const; + JNIType JNIReturnType() const; + + jmethodID methodID (jobject obj) const; + + bool isStatic() const { return _isStatic; } + +private: + JavaParameter* _parameters; + int _numParameters; + JavaString _name; + mutable char* _signature; + JavaString _returnType; + JNIType _JNIReturnType; + mutable jmethodID _methodID; + bool _isStatic; +}; + +} // namespace Bindings + +} // namespace JSC + +#endif // _JNI_RUNTIME_H_ diff --git a/V8Binding/jni/jni_utility.cpp b/V8Binding/jni/jni_utility.cpp new file mode 100644 index 0000000..d86dd7b --- /dev/null +++ b/V8Binding/jni/jni_utility.cpp @@ -0,0 +1,474 @@ +/* + * Copyright (C) 2003 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "jni_utility.h" +#include "jni_runtime.h" + +#include <dlfcn.h> + +namespace JSC { + +namespace Bindings { + +static jint KJS_GetCreatedJavaVMs(JavaVM** vmBuf, jsize bufLen, jsize* nVMs) +{ + static void* javaVMFramework = 0; + if (!javaVMFramework) + javaVMFramework = dlopen("/System/Library/Frameworks/JavaVM.framework/JavaVM", RTLD_LAZY); + if (!javaVMFramework) + return JNI_ERR; + + static jint(*functionPointer)(JavaVM**, jsize, jsize *) = 0; + if (!functionPointer) + functionPointer = (jint(*)(JavaVM**, jsize, jsize *))dlsym(javaVMFramework, "JNI_GetCreatedJavaVMs"); + if (!functionPointer) + return JNI_ERR; + return functionPointer(vmBuf, bufLen, nVMs); +} + +static JavaVM *jvm = 0; + +// Provide the ability for an outside component to specify the JavaVM to use +// If the jvm value is set, the getJavaVM function below will just return. +// In getJNIEnv(), if AttachCurrentThread is called to a VM that is already +// attached, the result is a no-op. +void setJavaVM(JavaVM *javaVM) +{ + jvm = javaVM; +} + +JavaVM *getJavaVM() +{ + if (jvm) + return jvm; + + JavaVM *jvmArray[1]; + jsize bufLen = 1; + jsize nJVMs = 0; + jint jniError = 0; + + // Assumes JVM is already running ..., one per process + jniError = KJS_GetCreatedJavaVMs(jvmArray, bufLen, &nJVMs); + if ( jniError == JNI_OK && nJVMs > 0 ) { + jvm = jvmArray[0]; + } + else + fprintf(stderr, "%s: JNI_GetCreatedJavaVMs failed, returned %ld\n", __PRETTY_FUNCTION__, (long)jniError); + + return jvm; +} + +JNIEnv* getJNIEnv() +{ + union { + JNIEnv* env; + void* dummy; + } u; + jint jniError = 0; + + jniError = (getJavaVM())->AttachCurrentThread(&u.dummy, NULL); + if (jniError == JNI_OK) + return u.env; + else + fprintf(stderr, "%s: AttachCurrentThread failed, returned %ld\n", __PRETTY_FUNCTION__, (long)jniError); + return NULL; +} + +jmethodID getMethodID (jobject obj, const char *name, const char *sig) +{ + JNIEnv *env = getJNIEnv(); + jmethodID mid = 0; + + if ( env != NULL) { + jclass cls = env->GetObjectClass(obj); + if ( cls != NULL ) { + mid = env->GetMethodID(cls, name, sig); + if (!mid) { + env->ExceptionClear(); + mid = env->GetStaticMethodID(cls, name, sig); + if (!mid) { + env->ExceptionClear(); + } + } + } + env->DeleteLocalRef(cls); + } + return mid; +} + +const char *getCharactersFromJString (jstring aJString) +{ + return getCharactersFromJStringInEnv (getJNIEnv(), aJString); +} + +void releaseCharactersForJString (jstring aJString, const char *s) +{ + releaseCharactersForJStringInEnv (getJNIEnv(), aJString, s); +} + +const char *getCharactersFromJStringInEnv (JNIEnv *env, jstring aJString) +{ + jboolean isCopy; + const char *s = env->GetStringUTFChars((jstring)aJString, &isCopy); + if (!s) { + env->ExceptionDescribe(); + env->ExceptionClear(); + fprintf (stderr, "\n"); + } + return s; +} + +void releaseCharactersForJStringInEnv (JNIEnv *env, jstring aJString, const char *s) +{ + env->ReleaseStringUTFChars (aJString, s); +} + +const jchar *getUCharactersFromJStringInEnv (JNIEnv *env, jstring aJString) +{ + jboolean isCopy; + const jchar *s = env->GetStringChars((jstring)aJString, &isCopy); + if (!s) { + env->ExceptionDescribe(); + env->ExceptionClear(); + fprintf (stderr, "\n"); + } + return s; +} + +void releaseUCharactersForJStringInEnv (JNIEnv *env, jstring aJString, const jchar *s) +{ + env->ReleaseStringChars (aJString, s); +} + +JNIType JNITypeFromClassName(const char *name) +{ + JNIType type; + + if (strcmp("byte",name) == 0) + type = byte_type; + else if (strcmp("short",name) == 0) + type = short_type; + else if (strcmp("int",name) == 0) + type = int_type; + else if (strcmp("long",name) == 0) + type = long_type; + else if (strcmp("float",name) == 0) + type = float_type; + else if (strcmp("double",name) == 0) + type = double_type; + else if (strcmp("char",name) == 0) + type = char_type; + else if (strcmp("boolean",name) == 0) + type = boolean_type; + else if (strcmp("void",name) == 0) + type = void_type; + else if ('[' == name[0]) + type = array_type; + else + type = object_type; + + return type; +} + +const char *signatureFromPrimitiveType(JNIType type) +{ + switch (type){ + case void_type: + return "V"; + + case array_type: + return "["; + + case object_type: + return "L"; + + case boolean_type: + return "Z"; + + case byte_type: + return "B"; + + case char_type: + return "C"; + + case short_type: + return "S"; + + case int_type: + return "I"; + + case long_type: + return "J"; + + case float_type: + return "F"; + + case double_type: + return "D"; + + case invalid_type: + default: + break; + } + return ""; +} + +JNIType JNITypeFromPrimitiveType(char type) +{ + switch (type){ + case 'V': + return void_type; + + case 'L': + return object_type; + + case '[': + return array_type; + + case 'Z': + return boolean_type; + + case 'B': + return byte_type; + + case 'C': + return char_type; + + case 'S': + return short_type; + + case 'I': + return int_type; + + case 'J': + return long_type; + + case 'F': + return float_type; + + case 'D': + return double_type; + + default: + break; + } + return invalid_type; +} + +jvalue getJNIField( jobject obj, JNIType type, const char *name, const char *signature) +{ + JavaVM *jvm = getJavaVM(); + JNIEnv *env = getJNIEnv(); + jvalue result; + + bzero (&result, sizeof(jvalue)); + if ( obj != NULL && jvm != NULL && env != NULL) { + jclass cls = env->GetObjectClass(obj); + if ( cls != NULL ) { + jfieldID field = env->GetFieldID(cls, name, signature); + if ( field != NULL ) { + switch (type) { + case array_type: + case object_type: + result.l = env->functions->GetObjectField(env, obj, field); + break; + case boolean_type: + result.z = env->functions->GetBooleanField(env, obj, field); + break; + case byte_type: + result.b = env->functions->GetByteField(env, obj, field); + break; + case char_type: + result.c = env->functions->GetCharField(env, obj, field); + break; + case short_type: + result.s = env->functions->GetShortField(env, obj, field); + break; + case int_type: + result.i = env->functions->GetIntField(env, obj, field); + break; + case long_type: + result.j = env->functions->GetLongField(env, obj, field); + break; + case float_type: + result.f = env->functions->GetFloatField(env, obj, field); + break; + case double_type: + result.d = env->functions->GetDoubleField(env, obj, field); + break; + default: + fprintf(stderr, "%s: invalid field type (%d)\n", __PRETTY_FUNCTION__, (int)type); + } + } + else + { + fprintf(stderr, "%s: Could not find field: %s\n", __PRETTY_FUNCTION__, name); + env->ExceptionDescribe(); + env->ExceptionClear(); + fprintf (stderr, "\n"); + } + + env->DeleteLocalRef(cls); + } + else { + fprintf(stderr, "%s: Could not find class for object\n", __PRETTY_FUNCTION__); + } + } + + return result; +} + + +jvalue convertNPVariantToJValue(NPVariant* value, JNIType _JNIType, const char* javaClassName) +{ + jvalue result; + NPVariantType type = value->type; + + switch (_JNIType){ + case array_type: + case object_type: { + result.l = (jobject)0; + + // First see if we have a Java instance. + if (type == NPVariantType_Object) { + NPObject* objectImp = NPVARIANT_TO_OBJECT(*value); + if (objectImp->_class == &JavaNPClass) { + JavaNPObject* imp = static_cast<JavaNPObject*>(objectImp); + JavaInstance *instance = imp->_instance; + if (instance) + result.l = instance->javaInstance(); + } + } + + // Now convert value to a string if the target type is a java.lang.string, and we're not + // converting from a Null. + if (result.l == 0 && strcmp(javaClassName, "java.lang.String") == 0) { +#ifdef CONVERT_NULL_TO_EMPTY_STRING + if (type == NPVariantType_Null) { + JNIEnv *env = getJNIEnv(); + jchar buf[2]; + jobject javaString = env->functions->NewString (env, buf, 0); + result.l = javaString; + } + else +#else + if (type == NPVariantType_String) { +#endif + NPString src = NPVARIANT_TO_STRING(*variant); + JNIEnv *env = getJNIEnv(); + jobject javaString = env->functions->NewStringUTF(env, src.UTF8Characters, src.UTF8Length); + result.l = javaString; + } + } else if (result.l == 0) + bzero (&result, sizeof(jvalue)); // Handle it the same as a void case + } + break; + + case boolean_type: { + if (type == NPVariantType_Boolean) + result.z = NPVARIANT_TO_BOOLEAN(*value); + else + bzero(&result, sizeof(jvalue)); // as void case + } + break; + + case byte_type: { + if (type == NPVariantType_Int32) + result.b = (byte)NPVARIANT_TO_INT32(*value); + else + bzero(&result, sizeof(jvalue)); + } + break; + + case char_type: { + if (type == NPVariantType_Int32) + result.c = (char)NPVARIANT_TO_INT32(*value); + else + bzero(&result, sizeof(jvalue)); + } + break; + + case short_type: { + if (type == NPVariantType_Int32) + result.s = (jshort)NPVARIANT_TO_INT32(*value); + else + bzero(&result, sizeof(jvalue)); + } + break; + + case int_type: { + if (type == NPVariantType_Int32) + result.i = (jint)NPVARIANT_TO_INT32(*value); + else + bzero(&result, sizeof(jvalue)); + } + break; + + case long_type: { + if (type == NPVariantType_Int32) + result.j = (jlong)NPVARIANT_TO_INT32(*value); + else if (type == NPVariantType_Double) + result.j = (jlong)NPVARIANT_TO_DOUBLE(*value); + else + bzero(&result, sizeof(jvalue)); + } + break; + + case float_type: { + if (type == NPVariantType_Int32) + result.j = (jfloat)NPVARIANT_TO_INT32(*value); + else if (type == NPVariantType_Double) + result.j = (jfloat)NPVARIANT_TO_DOUBLE(*value); + else + bzero(&result, sizeof(jvalue)); + } + break; + + case double_type: { + if (type == NPVariantType_Int32) + result.j = (jdouble)NPVARIANT_TO_INT32(*value); + else if (type == NPVariantType_Double) + result.j = (jdouble)NPVARIANT_TO_DOUBLE(*value); + else + bzero(&result, sizeof(jvalue)); + } + break; + + break; + + case invalid_type: + default: + case void_type: { + bzero (&result, sizeof(jvalue)); + } + break; + } + return result; +} + +} // end of namespace Bindings + +} // end of namespace JSC diff --git a/V8Binding/jni/jni_utility.h b/V8Binding/jni/jni_utility.h new file mode 100644 index 0000000..28b0763 --- /dev/null +++ b/V8Binding/jni/jni_utility.h @@ -0,0 +1,281 @@ +/* + * Copyright (C) 2003 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _JNI_UTILITY_H_ +#define _JNI_UTILITY_H_ + +#include <JavaVM/jni.h> + +// The order of these items can not be modified as they are tightly +// bound with the JVM on Mac OSX. If new types need to be added, they +// should be added to the end. It is used in jni_obc.mm when calling +// through to the JVM. Newly added items need to be made compatible +// in that file. +typedef enum { + invalid_type = 0, + void_type, + object_type, + boolean_type, + byte_type, + char_type, + short_type, + int_type, + long_type, + float_type, + double_type, + array_type +} JNIType; + +namespace JSC { + +namespace Bindings { + +class JavaParameter; + +const char *getCharactersFromJString(jstring aJString); +void releaseCharactersForJString(jstring aJString, const char *s); + +const char *getCharactersFromJStringInEnv(JNIEnv *env, jstring aJString); +void releaseCharactersForJStringInEnv(JNIEnv *env, jstring aJString, const char *s); +const jchar *getUCharactersFromJStringInEnv(JNIEnv *env, jstring aJString); +void releaseUCharactersForJStringInEnv(JNIEnv *env, jstring aJString, const jchar *s); + +JNIType JNITypeFromClassName(const char *name); +JNIType JNITypeFromPrimitiveType(char type); +const char *signatureFromPrimitiveType(JNIType type); + +jvalue convertNPVariantToJValue(NPVariant*, JNIType, const char* javaClassName); + +jvalue getJNIField(jobject obj, JNIType type, const char *name, const char *signature); + +jmethodID getMethodID(jobject obj, const char *name, const char *sig); +JNIEnv* getJNIEnv(); +JavaVM* getJavaVM(); +void setJavaVM(JavaVM*); + + +template <typename T> struct JNICaller; + +template<> struct JNICaller<void> { + static void callA(jobject obj, jmethodID mid, jvalue* args) + { + return getJNIEnv()->CallVoidMethodA(obj, mid, args); + } + static void callV(jobject obj, jmethodID mid, va_list args) + { + return getJNIEnv()->CallVoidMethodV(obj, mid, args); + } +}; + +template<> struct JNICaller<jobject> { + static jobject callA(jobject obj, jmethodID mid, jvalue* args) + { + return getJNIEnv()->CallObjectMethodA(obj, mid, args); + } + static jobject callV(jobject obj, jmethodID mid, va_list args) + { + return getJNIEnv()->CallObjectMethodV(obj, mid, args); + } +}; + +template<> struct JNICaller<jboolean> { + static jboolean callA(jobject obj, jmethodID mid, jvalue* args) + { + return getJNIEnv()->CallBooleanMethodA(obj, mid, args); + } + static jboolean callV(jobject obj, jmethodID mid, va_list args) + { + return getJNIEnv()->CallBooleanMethodV(obj, mid, args); + } + static jboolean callStaticV(jclass cls, jmethodID mid, va_list args) + { + return getJNIEnv()->CallStaticBooleanMethod(cls, mid, args); + } + +}; + +template<> struct JNICaller<jbyte> { + static jbyte callA(jobject obj, jmethodID mid, jvalue* args) + { + return getJNIEnv()->CallByteMethodA(obj, mid, args); + } + static jbyte callV(jobject obj, jmethodID mid, va_list args) + { + return getJNIEnv()->CallByteMethodV(obj, mid, args); + } +}; + +template<> struct JNICaller<jchar> { + static jchar callA(jobject obj, jmethodID mid, jvalue* args) + { + return getJNIEnv()->CallCharMethodA(obj, mid, args); + } + static jchar callV(jobject obj, jmethodID mid, va_list args) + { + return getJNIEnv()->CallCharMethodV(obj, mid, args); + } +}; + +template<> struct JNICaller<jshort> { + static jshort callA(jobject obj, jmethodID mid, jvalue* args) + { + return getJNIEnv()->CallShortMethodA(obj, mid, args); + } + static jshort callV(jobject obj, jmethodID mid, va_list args) + { + return getJNIEnv()->CallShortMethodV(obj, mid, args); + } +}; + +template<> struct JNICaller<jint> { + static jint callA(jobject obj, jmethodID mid, jvalue* args) + { + return getJNIEnv()->CallIntMethodA(obj, mid, args); + } + static jint callV(jobject obj, jmethodID mid, va_list args) + { + return getJNIEnv()->CallIntMethodV(obj, mid, args); + } +}; + +template<> struct JNICaller<jlong> { + static jlong callA(jobject obj, jmethodID mid, jvalue* args) + { + return getJNIEnv()->CallLongMethodA(obj, mid, args); + } + static jlong callV(jobject obj, jmethodID mid, va_list args) + { + return getJNIEnv()->CallLongMethodV(obj, mid, args); + } +}; + +template<> struct JNICaller<jfloat> { + static jfloat callA(jobject obj, jmethodID mid, jvalue* args) + { + return getJNIEnv()->CallFloatMethodA(obj, mid, args); + } + static jfloat callV(jobject obj, jmethodID mid, va_list args) + { + return getJNIEnv()->CallFloatMethodV(obj, mid, args); + } +}; + +template<> struct JNICaller<jdouble> { + static jdouble callA(jobject obj, jmethodID mid, jvalue* args) + { + return getJNIEnv()->CallDoubleMethodA(obj, mid, args); + } + static jdouble callV(jobject obj, jmethodID mid, va_list args) + { + return getJNIEnv()->CallDoubleMethodV(obj, mid, args); + } +}; + +template<typename T> T callJNIMethodIDA(jobject obj, jmethodID mid, jvalue *args) +{ + return JNICaller<T>::callA(obj, mid, args); +} + +template<typename T> +static T callJNIMethodV(jobject obj, const char *name, const char *sig, va_list args) +{ + JavaVM *jvm = getJavaVM(); + JNIEnv *env = getJNIEnv(); + + if ( obj != NULL && jvm != NULL && env != NULL) { + jclass cls = env->GetObjectClass(obj); + if ( cls != NULL ) { + jmethodID mid = env->GetMethodID(cls, name, sig); + if ( mid != NULL ) + { +#ifdef ANDROID_FIX // Avoids references to cls without popping the local frame. + env->DeleteLocalRef(cls); +#endif + return JNICaller<T>::callV(obj, mid, args); + } + else + { + fprintf(stderr, "%s: Could not find method: %s for %p\n", __PRETTY_FUNCTION__, name, obj); + env->ExceptionDescribe(); + env->ExceptionClear(); + fprintf (stderr, "\n"); + } + + env->DeleteLocalRef(cls); + } + else { + fprintf(stderr, "%s: Could not find class for %p\n", __PRETTY_FUNCTION__, obj); + } + } + + return 0; +} + +template<typename T> +T callJNIMethod(jobject obj, const char* methodName, const char* methodSignature, ...) +{ + va_list args; + va_start(args, methodSignature); + + T result= callJNIMethodV<T>(obj, methodName, methodSignature, args); + + va_end(args); + + return result; +} + +template<typename T> +T callJNIStaticMethod(jclass cls, const char* methodName, const char* methodSignature, ...) +{ + JavaVM *jvm = getJavaVM(); + JNIEnv *env = getJNIEnv(); + va_list args; + + va_start(args, methodSignature); + + T result = 0; + + if (cls != NULL && jvm != NULL && env != NULL) { + jmethodID mid = env->GetStaticMethodID(cls, methodName, methodSignature); + if (mid != NULL) + result = JNICaller<T>::callStaticV(cls, mid, args); + else { + fprintf(stderr, "%s: Could not find method: %s for %p\n", __PRETTY_FUNCTION__, methodName, cls); + env->ExceptionDescribe(); + env->ExceptionClear(); + fprintf (stderr, "\n"); + } + } + + va_end(args); + + return result; +} + +} // namespace Bindings + +} // namespace JSC + +#endif // _JNI_UTILITY_H_ |