/* src/native/jni.c - implementation of the Java Native Interface functions
- Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel,
+ Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel,
C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
J. Wenninger, Institut f. Computersprachen - TU Wien
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA.
- Contact: cacao@cacaojvm.org
-
- Authors: Rainhard Grafl
- Roman Obermaisser
-
- Changes: Joseph Wenninger
- Martin Platter
- Christian Thalinger
- Edwin Steiner
-
- $Id: jni.c 5698 2006-10-05 17:28:13Z twisti $
+ $Id: jni.c 7723 2007-04-16 18:03:08Z michi $
*/
#include "vm/types.h"
-#include "mm/boehm.h"
+#include "mm/gc-common.h"
#include "mm/memory.h"
#include "native/jni.h"
#include "native/native.h"
-#include "native/include/gnu_classpath_Pointer.h"
+#if defined(ENABLE_JAVASE)
+# if defined(WITH_CLASSPATH_GNU)
+# include "native/include/gnu_classpath_Pointer.h"
-#if SIZEOF_VOID_P == 8
-# include "native/include/gnu_classpath_Pointer64.h"
-#else
-# include "native/include/gnu_classpath_Pointer32.h"
+# if SIZEOF_VOID_P == 8
+# include "native/include/gnu_classpath_Pointer64.h"
+# else
+# include "native/include/gnu_classpath_Pointer32.h"
+# endif
+# endif
#endif
#include "native/include/java_lang_Object.h"
#include "native/include/java_lang_Long.h"
#include "native/include/java_lang_Float.h"
#include "native/include/java_lang_Double.h"
+#include "native/include/java_lang_String.h"
#include "native/include/java_lang_Throwable.h"
-#include "native/include/java_lang_reflect_Method.h"
-#include "native/include/java_lang_reflect_Constructor.h"
-#include "native/include/java_lang_reflect_Field.h"
-#include "native/include/java_lang_Class.h" /* for java_lang_VMClass.h */
-#include "native/include/java_lang_VMClass.h"
-#include "native/include/java_lang_VMClassLoader.h"
-#include "native/include/java_nio_Buffer.h"
-#include "native/include/java_nio_DirectByteBufferImpl.h"
+#if defined(ENABLE_JAVASE)
+# include "native/include/java_lang_ClassLoader.h"
+
+# include "native/include/java_lang_reflect_Constructor.h"
+# include "native/include/java_lang_reflect_Field.h"
+# include "native/include/java_lang_reflect_Method.h"
+
+# include "native/include/java_nio_Buffer.h"
+# include "native/include/java_nio_DirectByteBufferImpl.h"
+#endif
#if defined(ENABLE_JVMTI)
# include "native/jvmti/cacaodbg.h"
#endif
+#include "native/vm/java_lang_Class.h"
+
+#if defined(ENABLE_JAVASE)
+# include "native/vm/java_lang_ClassLoader.h"
+#endif
+
#if defined(ENABLE_THREADS)
# include "threads/native/lock.h"
# include "threads/native/threads.h"
#else
# include "threads/none/lock.h"
+# include "threads/none/threads.h"
#endif
#include "toolbox/logging.h"
+
#include "vm/builtin.h"
#include "vm/exceptions.h"
#include "vm/global.h"
#include "vm/initialize.h"
-#include "vm/loader.h"
-#include "vm/options.h"
-#include "vm/resolve.h"
-#include "vm/statistics.h"
#include "vm/stringlocal.h"
+#include "vm/vm.h"
+
#include "vm/jit/asmpart.h"
#include "vm/jit/jit.h"
-#include "vm/statistics.h"
-#include "vm/vm.h"
+#include "vm/jit/stacktrace.h"
+
+#include "vmcore/loader.h"
+#include "vmcore/options.h"
+#include "vm/resolve.h"
+#include "vmcore/statistics.h"
/* global variables ***********************************************************/
#define HASHTABLE_GLOBAL_REF_SIZE 64 /* initial size of globalref-hash */
-static hashtable *hashtable_global_ref; /* hashtable for globalrefs */
+hashtable *hashtable_global_ref; /* hashtable for globalrefs */
/* direct buffer stuff ********************************************************/
+#if defined(ENABLE_JAVASE)
static classinfo *class_java_nio_Buffer;
static classinfo *class_java_nio_DirectByteBufferImpl;
static classinfo *class_java_nio_DirectByteBufferImpl_ReadWrite;
-#if SIZEOF_VOID_P == 8
+
+# if defined(WITH_CLASSPATH_GNU)
+# if SIZEOF_VOID_P == 8
static classinfo *class_gnu_classpath_Pointer64;
-#else
+# else
static classinfo *class_gnu_classpath_Pointer32;
-#endif
+# endif
+# endif
static methodinfo *dbbirw_init;
+#endif
/* local reference table ******************************************************/
hashtable_create(hashtable_global_ref, HASHTABLE_GLOBAL_REF_SIZE);
+#if defined(ENABLE_JAVASE)
/* direct buffer stuff */
if (!(class_java_nio_Buffer =
utf_new_char("(Ljava/lang/Object;Lgnu/classpath/Pointer;III)V"))))
return false;
-#if SIZEOF_VOID_P == 8
+# if defined(WITH_CLASSPATH_GNU)
+# if SIZEOF_VOID_P == 8
if (!(class_gnu_classpath_Pointer64 =
load_class_bootstrap(utf_new_char("gnu/classpath/Pointer64"))) ||
!link_class(class_gnu_classpath_Pointer64))
return false;
-#else
+# else
if (!(class_gnu_classpath_Pointer32 =
load_class_bootstrap(utf_new_char("gnu/classpath/Pointer32"))) ||
!link_class(class_gnu_classpath_Pointer32))
return false;
-#endif
+# endif
+# endif
+#endif /* defined(ENABLE_JAVASE) */
return true;
}
*******************************************************************************/
-static bool jni_init_localref_table(void)
+bool jni_init_localref_table(void)
{
localref_table *lrt;
+#if defined(ENABLE_GC_CACAO)
+ /* XXX this one will never get freed for the main thread;
+ call jni_free_localref_table() if you want to do it! */
+ lrt = NEW(localref_table);
+#else
lrt = GCNEW(localref_table);
+#endif
if (lrt == NULL)
return false;
}
+/* jni_init_localref_table *****************************************************
+
+ Frees the local references table of the current thread.
+
+*******************************************************************************/
+
+bool jni_free_localref_table(void)
+{
+ localref_table *lrt;
+
+#if defined(ENABLE_GC_CACAO)
+ lrt = LOCALREFTABLE;
+
+ assert(lrt);
+ assert(lrt->prev == NULL);
+
+ FREE(lrt, localref_table);
+
+ LOCALREFTABLE = NULL;
+#endif
+
+ return true;
+}
+
+
/* _Jv_jni_vmargs_from_objectarray *********************************************
XXX
java_objectheader *ro;
s4 argcount;
s4 paramcount;
+ java_objectheader *xptr;
- if (!m) {
+ if (m == NULL) {
exceptions_throw_nullpointerexception();
return NULL;
}
parameter is ignored. */
if (!(m->flags & ACC_STATIC) && o && (!builtin_instanceof(o, m->class))) {
- *exceptionptr =
- new_exception_message(string_java_lang_IllegalArgumentException,
- "Object parameter of wrong type in Java_java_lang_reflect_Method_invokeNative");
+ exceptions_throw_illegalargumentexception();
return NULL;
}
if (((params == NULL) && (paramcount != 0)) ||
(params && (params->header.size != paramcount)))
{
- *exceptionptr =
- new_exception(string_java_lang_IllegalArgumentException);
+ exceptions_throw_illegalargumentexception();
return NULL;
}
/* for instance methods we need an object */
if (!(m->flags & ACC_STATIC) && (o == NULL)) {
- *exceptionptr =
- new_exception_message(string_java_lang_NullPointerException,
- "Static mismatch in Java_java_lang_reflect_Method_invokeNative");
+ /* XXX not sure if that is the correct exception */
+ exceptions_throw_nullpointerexception();
return NULL;
}
if (o != NULL) {
/* for instance methods we must do a vftbl lookup */
resm = method_vftbl_lookup(o->vftbl, m);
-
- } else {
+ }
+ else {
/* for static methods, just for convenience */
resm = m;
}
vmargs = MNEW(vm_arg, argcount);
- if (!_Jv_jni_vmargs_from_objectarray(o, resm->parseddesc, vmargs, params))
+ if (!_Jv_jni_vmargs_from_objectarray(o, resm->parseddesc, vmargs, params)) {
+ MFREE(vmargs, vm_arg, argcount);
return NULL;
+ }
switch (resm->parseddesc->returntype.decltype) {
case TYPE_VOID:
MFREE(vmargs, vm_arg, argcount);
- if (*exceptionptr) {
- java_objectheader *cause;
-
- cause = *exceptionptr;
+ xptr = exceptions_get_exception();
+ if (xptr != NULL) {
/* clear exception pointer, we are calling JIT code again */
- *exceptionptr = NULL;
+ exceptions_clear_exception();
- *exceptionptr =
- new_exception_throwable(string_java_lang_reflect_InvocationTargetException,
- (java_lang_Throwable *) cause);
+ exceptions_throw_invocationtargetexception(xptr);
}
return ro;
jclass _Jv_JNI_DefineClass(JNIEnv *env, const char *name, jobject loader,
const jbyte *buf, jsize bufLen)
{
+#if defined(ENABLE_JAVASE)
java_lang_ClassLoader *cl;
java_lang_String *s;
java_bytearray *ba;
STATISTICS(jniinvokation());
cl = (java_lang_ClassLoader *) loader;
- s = javastring_new_from_utf_string(name);
+ s = (java_lang_String *) javastring_new_from_utf_string(name);
ba = (java_bytearray *) buf;
- c = (jclass) Java_java_lang_VMClassLoader_defineClass(env, NULL, cl, s, ba,
- 0, bufLen, NULL);
+ c = (jclass) _Jv_java_lang_ClassLoader_defineClass(cl, s, ba, 0, bufLen,
+ NULL);
return (jclass) _Jv_JNI_NewLocalRef(env, (jobject) c);
+#else
+ vm_abort("_Jv_JNI_DefineClass: not implemented in this configuration");
+
+ /* keep compiler happy */
+
+ return 0;
+#endif
}
jclass _Jv_JNI_FindClass(JNIEnv *env, const char *name)
{
+#if defined(ENABLE_JAVASE)
utf *u;
classinfo *cc;
classinfo *c;
return NULL;
return (jclass) _Jv_JNI_NewLocalRef(env, (jobject) c);
+#else
+ vm_abort("_Jv_JNI_FindClass: not implemented in this configuration");
+
+ /* keep compiler happy */
+
+ return NULL;
+#endif
}
jboolean _Jv_JNI_IsAssignableFrom(JNIEnv *env, jclass sub, jclass sup)
{
+ java_lang_Class *csup;
+ java_lang_Class *csub;
+
+ csup = (java_lang_Class *) sup;
+ csub = (java_lang_Class *) sub;
+
STATISTICS(jniinvokation());
- return Java_java_lang_VMClass_isAssignableFrom(env,
- NULL,
- (java_lang_Class *) sup,
- (java_lang_Class *) sub);
+ return _Jv_java_lang_Class_isAssignableFrom(csup, csub);
}
jint _Jv_JNI_Throw(JNIEnv *env, jthrowable obj)
{
+ java_objectheader *o;
+
STATISTICS(jniinvokation());
- *exceptionptr = (java_objectheader *) obj;
+ o = (java_objectheader *) obj;
+
+ exceptions_set_exception(o);
return JNI_OK;
}
jint _Jv_JNI_ThrowNew(JNIEnv* env, jclass clazz, const char *msg)
{
- classinfo *c;
- java_lang_Throwable *o;
- java_lang_String *s;
+ classinfo *c;
+ java_objectheader *o;
+ java_objectheader *s;
STATISTICS(jniinvokation());
c = (classinfo *) clazz;
- s = (java_lang_String *) javastring_new_from_utf_string(msg);
+ s = javastring_new_from_utf_string(msg);
/* instantiate exception object */
- o = (java_lang_Throwable *) native_new_and_init_string(c, s);
+ o = native_new_and_init_string(c, s);
if (o == NULL)
return -1;
- *exceptionptr = (java_objectheader *) o;
+ exceptions_set_exception(o);
return 0;
}
jthrowable _Jv_JNI_ExceptionOccurred(JNIEnv *env)
{
- java_objectheader *e;
+ java_objectheader *o;
STATISTICS(jniinvokation());
- e = *exceptionptr;
+ o = exceptions_get_exception();
- return _Jv_JNI_NewLocalRef(env, (jthrowable) e);
+ return _Jv_JNI_NewLocalRef(env, (jthrowable) o);
}
void _Jv_JNI_ExceptionDescribe(JNIEnv *env)
{
- java_objectheader *e;
+ java_objectheader *o;
methodinfo *m;
STATISTICS(jniinvokation());
- e = *exceptionptr;
+ o = exceptions_get_exception();
- if (e) {
+ if (o == NULL) {
/* clear exception, because we are calling jit code again */
- *exceptionptr = NULL;
+ exceptions_clear_exception();
/* get printStackTrace method from exception class */
- m = class_resolveclassmethod(e->vftbl->class,
+ m = class_resolveclassmethod(o->vftbl->class,
utf_printStackTrace,
utf_void__void,
NULL,
true);
- if (!m)
+ if (m == NULL)
/* XXX what should we do? */
return;
/* print the stacktrace */
- (void) vm_call_method(m, e);
+ (void) vm_call_method(m, o);
}
}
{
STATISTICS(jniinvokation());
- *exceptionptr = NULL;
+ exceptions_clear_exception();
}
{
STATISTICS(jniinvokation());
- throw_cacao_exception_exit(string_java_lang_InternalError, msg);
+ /* this seems to be the best way */
+
+ vm_abort(msg);
}
else
additionalrefs = 0;
+#if defined(ENABLE_GC_CACAO)
+ nlrt = MNEW(u1, sizeof(localref_table) + additionalrefs * SIZEOF_VOID_P);
+#else
nlrt = GCMNEW(u1, sizeof(localref_table) + additionalrefs * SIZEOF_VOID_P);
+#endif
if (nlrt == NULL)
return -1;
localref_table *lrt;
localref_table *plrt;
s4 localframes;
+ s4 additionalrefs;
STATISTICS(jniinvokation());
lrt->prev = NULL;
+#if defined(ENABLE_GC_CACAO)
+ /* for the exact GC local reference tables are not on the heap,
+ so we need to free them explicitly here. */
+
+ if (lrt->capacity > LOCALREFTABLE_CAPACITY)
+ additionalrefs = lrt->capacity - LOCALREFTABLE_CAPACITY;
+ else
+ additionalrefs = 0;
+
+ MFREE(lrt, u1, sizeof(localref_table) + additionalrefs * SIZEOF_VOID_P);
+#endif
+
/* set new local references table */
lrt = plrt;
{
localref_table *lrt;
- log_text("JNI-Call: EnsureLocalCapacity");
-
STATISTICS(jniinvokation());
/* get local reference table (thread specific) */
c = (classinfo *) clazz;
if ((c->flags & ACC_INTERFACE) || (c->flags & ACC_ABSTRACT)) {
- *exceptionptr =
- new_exception_utfmessage(string_java_lang_InstantiationException,
- c->name);
+ exceptions_throw_instantiationexception(c);
return NULL;
}
jboolean _Jv_JNI_IsInstanceOf(JNIEnv *env, jobject obj, jclass clazz)
{
+ java_lang_Class *c;
+ java_lang_Object *o;
+
STATISTICS(jniinvokation());
- return Java_java_lang_VMClass_isInstance(env,
- NULL,
- (java_lang_Class *) clazz,
- (java_lang_Object *) obj);
+ c = (java_lang_Class *) clazz;
+ o = (java_lang_Object *) obj;
+
+ return _Jv_java_lang_Class_isInstance(c, o);
}
jmethodID _Jv_JNI_FromReflectedMethod(JNIEnv *env, jobject method)
{
+#if defined(ENABLE_JAVASE)
methodinfo *mi;
classinfo *c;
s4 slot;
mi = &(c->methods[slot]);
return (jmethodID) mi;
+#else
+ vm_abort("_Jv_JNI_FromReflectedMethod: not implemented in this configuration");
+
+ /* keep compiler happy */
+
+ return NULL;
+#endif
}
jfieldID _Jv_JNI_FromReflectedField(JNIEnv* env, jobject field)
{
+#if defined(ENABLE_JAVASE)
java_lang_reflect_Field *rf;
classinfo *c;
fieldinfo *f;
f = &(c->fields[rf->slot]);
return (jfieldID) f;
+#else
+ vm_abort("_Jv_JNI_FromReflectedField: not implemented in this configuration");
+
+ /* keep compiler happy */
+
+ return NULL;
+#endif
}
jfieldID _Jv_JNI_GetFieldID(JNIEnv *env, jclass clazz, const char *name,
const char *sig)
{
+ classinfo *c;
fieldinfo *f;
utf *uname;
utf *udesc;
STATISTICS(jniinvokation());
+ c = (classinfo *) clazz;
+
uname = utf_new_char((char *) name);
udesc = utf_new_char((char *) sig);
f = class_findfield(clazz, uname, udesc);
- if (!f)
- *exceptionptr = new_exception(string_java_lang_NoSuchFieldError);
+ if (f == NULL)
+ exceptions_throw_nosuchfielderror(c, uname);
return (jfieldID) f;
}
jfieldID _Jv_JNI_GetStaticFieldID(JNIEnv *env, jclass clazz, const char *name,
const char *sig)
{
+ classinfo *c;
fieldinfo *f;
utf *uname;
utf *usig;
STATISTICS(jniinvokation());
+ c = (classinfo *) clazz;
+
uname = utf_new_char((char *) name);
usig = utf_new_char((char *) sig);
f = class_findfield(clazz, uname, usig);
if (f == NULL)
- *exceptionptr = new_exception(string_java_lang_NoSuchFieldError);
+ exceptions_throw_nosuchfielderror(c, uname);
return (jfieldID) f;
}
/* GetStringChars **************************************************************
Returns a pointer to the array of Unicode characters of the
- string. This pointer is valid until ReleaseStringchars() is called.
+ string. This pointer is valid until ReleaseStringChars() is called.
*******************************************************************************/
/* NewStringUTF ****************************************************************
- Constructs a new java.lang.String object from an array of UTF-8 characters.
+ Constructs a new java.lang.String object from an array of UTF-8
+ characters.
*******************************************************************************/
STATISTICS(jniinvokation());
- s = javastring_new(utf_new_char(bytes));
+ s = (java_lang_String *) javastring_safe_new_from_utf8(bytes);
return (jstring) _Jv_JNI_NewLocalRef(env, (jobject) s);
}
if (isCopy)
*isCopy = JNI_TRUE;
- u = javastring_toutf((java_lang_String *) string, false);
+ u = javastring_toutf((java_objectheader *) string, false);
if (u != NULL)
return u->text;
/* check if the class of value is a subclass of the element class
of the array */
- if (!builtin_canstore(oa, o)) {
- *exceptionptr = new_exception(string_java_lang_ArrayStoreException);
-
+ if (!builtin_canstore(oa, o))
return;
- }
oa->data[index] = val;
}
jboolean _Jv_JNI_ExceptionCheck(JNIEnv *env)
{
+ java_objectheader *o;
+
STATISTICS(jniinvokation());
- return *exceptionptr ? JNI_TRUE : JNI_FALSE;
+ o = exceptions_get_exception();
+
+ return (o != NULL) ? JNI_TRUE : JNI_FALSE;
}
jobject _Jv_JNI_NewDirectByteBuffer(JNIEnv *env, void *address, jlong capacity)
{
+#if defined(ENABLE_JAVASE)
java_objectheader *nbuf;
-#if SIZEOF_VOID_P == 8
+# if SIZEOF_VOID_P == 8
gnu_classpath_Pointer64 *paddress;
-#else
+# else
gnu_classpath_Pointer32 *paddress;
-#endif
+# endif
STATISTICS(jniinvokation());
/* alocate a gnu.classpath.Pointer{32,64} object */
-#if SIZEOF_VOID_P == 8
+# if SIZEOF_VOID_P == 8
if (!(paddress = (gnu_classpath_Pointer64 *)
builtin_new(class_gnu_classpath_Pointer64)))
-#else
+# else
if (!(paddress = (gnu_classpath_Pointer32 *)
builtin_new(class_gnu_classpath_Pointer32)))
-#endif
+# endif
return NULL;
/* fill gnu.classpath.Pointer{32,64} with address */
/* add local reference and return the value */
return _Jv_JNI_NewLocalRef(env, nbuf);
+#else
+ vm_abort("_Jv_JNI_NewDirectByteBuffer: not implemented in this configuration");
+
+ /* keep compiler happy */
+
+ return NULL;
+#endif
}
void *_Jv_JNI_GetDirectBufferAddress(JNIEnv *env, jobject buf)
{
+#if defined(ENABLE_JAVASE)
java_nio_DirectByteBufferImpl *nbuf;
-#if SIZEOF_VOID_P == 8
+# if SIZEOF_VOID_P == 8
gnu_classpath_Pointer64 *address;
-#else
+# else
gnu_classpath_Pointer32 *address;
-#endif
+# endif
STATISTICS(jniinvokation());
nbuf = (java_nio_DirectByteBufferImpl *) buf;
-#if SIZEOF_VOID_P == 8
+# if SIZEOF_VOID_P == 8
address = (gnu_classpath_Pointer64 *) nbuf->address;
-#else
+# else
address = (gnu_classpath_Pointer32 *) nbuf->address;
-#endif
+# endif
if (address == NULL)
return NULL;
return (void *) address->data;
+#else
+ vm_abort("_Jv_JNI_GetDirectBufferAddress: not implemented in this configuration");
+
+ /* keep compiler happy */
+
+ return NULL;
+#endif
}
jlong _Jv_JNI_GetDirectBufferCapacity(JNIEnv* env, jobject buf)
{
+#if defined(ENABLE_JAVASE)
java_nio_Buffer *nbuf;
STATISTICS(jniinvokation());
nbuf = (java_nio_Buffer *) buf;
return (jlong) nbuf->cap;
+#else
+ vm_abort("_Jv_JNI_GetDirectBufferCapacity: not implemented in this configuration");
+
+ /* keep compiler happy */
+
+ return 0;
+#endif
}
jint _Jv_JNI_DetachCurrentThread(JavaVM *vm)
{
+#if defined(ENABLE_THREADS)
threadobject *thread;
STATISTICS(jniinvokation());
if (thread == NULL)
return JNI_ERR;
+ if (!jni_free_localref_table())
+ return JNI_ERR;
+
if (!threads_detach_thread(thread))
return JNI_ERR;
+#endif
return JNI_OK;
}
jint JNI_CreateJavaVM(JavaVM **p_vm, void **p_env, void *vm_args)
{
- JavaVMInitArgs *_vm_args;
- _Jv_JNIEnv *env;
- _Jv_JavaVM *vm;
-
- /* get the arguments for the new JVM */
-
- _vm_args = (JavaVMInitArgs *) vm_args;
-
- /* get the VM and Env tables (must be set before vm_create) */
-
- env = NEW(_Jv_JNIEnv);
- env->env = &_Jv_JNINativeInterface;
-
- /* XXX Set the global variable. Maybe we should do that differently. */
-
- _Jv_env = env;
-
- /* create and fill a JavaVM structure */
-
- vm = NEW(_Jv_JavaVM);
- vm->functions = &_Jv_JNIInvokeInterface;
-
- /* XXX Set the global variable. Maybe we should do that differently. */
- /* XXX JVMTI Agents needs a JavaVM */
-
- _Jv_jvm = vm;
-
/* actually create the JVM */
- if (!vm_create(_vm_args))
- goto error;
-
- /* setup the local ref table (must be created after vm_create) */
-
- if (!jni_init_localref_table())
- goto error;
-
- /* now return the values */
-
- *p_vm = (JavaVM *) vm;
- *p_env = (void *) env;
+ if (!vm_createjvm(p_vm, p_env, vm_args))
+ return JNI_ERR;
return JNI_OK;
-
- error:
- /* release allocated memory */
-
- FREE(env, _Jv_JNIEnv);
- FREE(vm, _Jv_JavaVM);
-
- return JNI_ERR;
}