* src/vm/vm.c, src/vm/vm.h: Moved to .cpp.
[cacao.git] / src / native / jni.c
index 162aebcb0d872f897b051029d9a7b1cae5d5297f..592a16350d690640a5ce3ffacf2b6db34c2b22d5 100644 (file)
@@ -1,9 +1,7 @@
 /* src/native/jni.c - implementation of the Java Native Interface functions
 
-   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
+   Copyright (C) 1996-2005, 2006, 2007, 2008
+   CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
 
    This file is part of CACAO.
 
@@ -22,8 +20,6 @@
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301, USA.
 
-   $Id: jni.c 8299 2007-08-13 08:41:18Z michi $
-
 */
 
 
 
 #include "vm/types.h"
 
-#include "mm/gc-common.h"
+#include "mm/gc.hpp"
 #include "mm/memory.h"
+
 #include "native/jni.h"
 #include "native/llni.h"
+#include "native/localref.h"
 #include "native/native.h"
 
 #if defined(ENABLE_JAVASE)
-# if defined(WITH_CLASSPATH_GNU)
+# if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
 #  include "native/include/gnu_classpath_Pointer.h"
 
 #  if SIZEOF_VOID_P == 8
 #endif
 
 #include "native/include/java_lang_Object.h"
-#include "native/include/java_lang_Byte.h"
-#include "native/include/java_lang_Character.h"
-#include "native/include/java_lang_Short.h"
-#include "native/include/java_lang_Integer.h"
-#include "native/include/java_lang_Boolean.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"
 
 #if defined(ENABLE_JAVASE)
-# if defined(WITH_CLASSPATH_SUN)
+
+# if defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
 #  include "native/include/java_nio_ByteBuffer.h"       /* required by j.l.CL */
 # endif
 
+/* java_lang_ClassLoader is used in java_lang_Class and vice versa, so
+   we pre-define it here to prevent a compiler warning for Sun
+   configurations. */
+
+struct java_lang_ClassLoader;
+
+# include "native/include/java_lang_Class.h"
 # include "native/include/java_lang_ClassLoader.h"
 
 # include "native/include/java_lang_reflect_Constructor.h"
 
 # include "native/include/java_nio_Buffer.h"
 
-# if defined(WITH_CLASSPATH_GNU)
+# if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
+#  include "native/include/java_lang_reflect_VMConstructor.h"
+#  include "native/include/java_lang_reflect_VMField.h"
+#  include "native/include/java_lang_reflect_VMMethod.h"
+
 #  include "native/include/java_nio_DirectByteBufferImpl.h"
 # endif
+#elif defined(ENABLE_JAVAME_CLDC1_1)
+# include "native/include/java_lang_Class.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"
 # include "native/vm/reflect.h"
 #endif
 
 #include "threads/lock-common.h"
-#include "threads/threads-common.h"
+#include "threads/thread.h"
 
 #include "toolbox/logging.h"
 
+#include "vm/array.h"
 #include "vm/builtin.h"
 #include "vm/exceptions.h"
 #include "vm/global.h"
 #include "vm/initialize.h"
-#include "vm/primitive.h"
+#include "vm/primitive.hpp"
 #include "vm/resolve.h"
 #include "vm/stringlocal.h"
-#include "vm/vm.h"
+#include "vm/vm.hpp"
 
+#include "vm/jit/argument.h"
 #include "vm/jit/asmpart.h"
 #include "vm/jit/jit.h"
 #include "vm/jit/stacktrace.h"
 /* debug **********************************************************************/
 
 #if !defined(NDEBUG)
-# define TRACEJNICALLS(format, ...) \
-    do { \
-        if (opt_TraceJNICalls) { \
-            log_println((format), __VA_ARGS__); \
-        } \
+
+# define TRACEJNICALLS(x)                                              \
+    do {                                                                               \
+        if (opt_TraceJNICalls) {                               \
+            log_println x;                                             \
+        }                                                                              \
+    } while (0)
+
+# define TRACEJNICALLSENTER(x)                                                                 \
+    do {                                                                                                               \
+        if (opt_TraceJNICalls) {                                                               \
+                       log_start();                                                                            \
+            log_print x;                                                                               \
+        }                                                                                                              \
     } while (0)
+
+# define TRACEJNICALLSEXIT(x)                                                                  \
+    do {                                                                                                               \
+        if (opt_TraceJNICalls) {                                                               \
+                       log_print x;                                                                            \
+                       log_finish();                                                                           \
+        }                                                                                                              \
+    } while (0)
+
 #else
-# define TRACEJNICALLS(format, ...)
+
+# define TRACEJNICALLS(x)
+# define TRACEJNICALLSENTER(x)
+# define TRACEJNICALLSEXIT(x)
+
 #endif
 
 
@@ -146,34 +171,34 @@ static hashtable *hashtable_global_ref; /* hashtable for globalrefs           */
 
 #if defined(ENABLE_JAVASE)
 static classinfo *class_java_nio_Buffer;
+
+# if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
+
 static classinfo *class_java_nio_DirectByteBufferImpl;
 static classinfo *class_java_nio_DirectByteBufferImpl_ReadWrite;
 
-# if defined(WITH_CLASSPATH_GNU)
 #  if SIZEOF_VOID_P == 8
 static classinfo *class_gnu_classpath_Pointer64;
 #  else
 static classinfo *class_gnu_classpath_Pointer32;
 #  endif
-# endif
 
 static methodinfo *dbbirw_init;
-#endif
 
+# elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
 
-/* accessing instance fields macros *******************************************/
+static classinfo *class_sun_nio_ch_DirectBuffer;
+static classinfo *class_java_nio_DirectByteBuffer;
 
-#define SET_FIELD(o,type,f,value) \
-    *((type *) (((intptr_t) (o)) + ((intptr_t) ((fieldinfo *) (f))->offset))) = (type) (value)
+static methodinfo *dbb_init;
 
-#define GET_FIELD(o,type,f) \
-    *((type *) (((intptr_t) (o)) + ((intptr_t) ((fieldinfo *) (f))->offset)))
+# endif
+#endif
 
 
 /* some forward declarations **************************************************/
 
-jobject _Jv_JNI_NewLocalRef(JNIEnv *env, jobject ref);
-jint _Jv_JNI_EnsureLocalCapacity(JNIEnv* env, jint capacity);
+jobject jni_NewLocalRef(JNIEnv *env, jobject ref);
 
 
 /* jni_init ********************************************************************
@@ -184,6 +209,8 @@ jint _Jv_JNI_EnsureLocalCapacity(JNIEnv* env, jint capacity);
 
 bool jni_init(void)
 {
+       TRACESUBSYSTEMINITIALIZATION("jni_init");
+
        /* create global ref hashtable */
 
        hashtable_global_ref = NEW(hashtable);
@@ -192,14 +219,15 @@ bool jni_init(void)
 
 
 #if defined(ENABLE_JAVASE)
-       /* direct buffer stuff */
+       /* Direct buffer stuff. */
 
        if (!(class_java_nio_Buffer =
                  load_class_bootstrap(utf_new_char("java/nio/Buffer"))) ||
                !link_class(class_java_nio_Buffer))
                return false;
 
-# if defined(WITH_CLASSPATH_GNU)
+# if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
+
        if (!(class_java_nio_DirectByteBufferImpl =
                  load_class_bootstrap(utf_new_char("java/nio/DirectByteBufferImpl"))) ||
                !link_class(class_java_nio_DirectByteBufferImpl))
@@ -227,35 +255,61 @@ bool jni_init(void)
                !link_class(class_gnu_classpath_Pointer32))
                return false;
 #  endif
+
+# elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
+
+       if (!(class_sun_nio_ch_DirectBuffer =
+                 load_class_bootstrap(utf_new_char("sun/nio/ch/DirectBuffer"))))
+               vm_abort("jni_init: loading sun/nio/ch/DirectBuffer failed");
+
+       if (!link_class(class_sun_nio_ch_DirectBuffer))
+               vm_abort("jni_init: linking sun/nio/ch/DirectBuffer failed");
+
+       if (!(class_java_nio_DirectByteBuffer =
+                 load_class_bootstrap(utf_new_char("java/nio/DirectByteBuffer"))))
+               vm_abort("jni_init: loading java/nio/DirectByteBuffer failed");
+
+       if (!link_class(class_java_nio_DirectByteBuffer))
+               vm_abort("jni_init: linking java/nio/DirectByteBuffer failed");
+
+       if (!(dbb_init =
+                 class_resolvemethod(class_java_nio_DirectByteBuffer,
+                                                         utf_init,
+                                                         utf_new_char("(JI)V"))))
+               vm_abort("jni_init: resolving java/nio/DirectByteBuffer.init(JI)V failed");
+
 # endif
+
 #endif /* defined(ENABLE_JAVASE) */
 
        return true;
 }
 
 
-/* jni_init_localref_table *****************************************************
+/* jni_version_check ***********************************************************
 
-   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;
+   Check if the given JNI version is supported.
 
-       assert(lrt);
-       assert(lrt->prev == NULL);
+   IN:
+       version....JNI version to check
 
-       FREE(lrt, localref_table);
+   RETURN VALUE:
+       true.......supported
+       false......not supported
 
-       LOCALREFTABLE = NULL;
-#endif
+*******************************************************************************/
 
-       return true;
+bool jni_version_check(int version)
+{
+       switch (version) {
+       case JNI_VERSION_1_1:
+       case JNI_VERSION_1_2:
+       case JNI_VERSION_1_4:
+       case JNI_VERSION_1_6:
+               return true;
+       default:
+               return false;
+       }
 }
 
 
@@ -774,158 +828,6 @@ static void _Jv_jni_CallVoidMethodA(java_handle_t *o, vftbl_t *vftbl,
 }
 
 
-/* _Jv_jni_invokeNative ********************************************************
-
-   Invoke a method on the given object with the given arguments.
-
-   For instance methods OBJ must be != NULL and the method is looked up
-   in the vftbl of the object.
-
-   For static methods, OBJ is ignored.
-
-*******************************************************************************/
-
-java_handle_t *_Jv_jni_invokeNative(methodinfo *m, java_handle_t *o,
-                                                                       java_objectarray *params)
-{
-       methodinfo    *resm;
-       java_handle_t *ro;
-       s4             argcount;
-       s4             paramcount;
-       java_handle_t *xptr;
-       int32_t        dumpsize;
-       uint64_t      *array;
-       imm_union          value;
-
-       if (m == NULL) {
-               exceptions_throw_nullpointerexception();
-               return NULL;
-       }
-
-       argcount = m->parseddesc->paramcount;
-       paramcount = argcount;
-
-       /* if method is non-static, remove the `this' pointer */
-
-       if (!(m->flags & ACC_STATIC))
-               paramcount--;
-
-       /* For instance methods the object has to be an instance of the
-          class the method belongs to. For static methods the obj
-          parameter is ignored. */
-
-       if (!(m->flags & ACC_STATIC) && o && (!builtin_instanceof(o, m->class))) {
-               exceptions_throw_illegalargumentexception();
-               return NULL;
-       }
-
-       /* check if we got the right number of arguments */
-
-       if (((params == NULL) && (paramcount != 0)) ||
-               (params && (params->header.size != paramcount))) 
-       {
-               exceptions_throw_illegalargumentexception();
-               return NULL;
-       }
-
-       /* for instance methods we need an object */
-
-       if (!(m->flags & ACC_STATIC) && (o == NULL)) {
-               /* XXX not sure if that is the correct exception */
-               exceptions_throw_nullpointerexception();
-               return NULL;
-       }
-
-       /* for static methods, zero object to make subsequent code simpler */
-       if (m->flags & ACC_STATIC)
-               o = NULL;
-
-       if (o != NULL) {
-               /* for instance methods we must do a vftbl lookup */
-               resm = method_vftbl_lookup(o->vftbl, m);
-       }
-       else {
-               /* for static methods, just for convenience */
-               resm = m;
-       }
-
-       /* mark start of dump memory area */
-
-       dumpsize = dump_size();
-
-       /* Fill the argument array from a object-array. */
-
-       array = vm_array_from_objectarray(resm, o, params);
-
-       /* The array can be NULL if we don't have any arguments to pass
-          and the architecture does not have any argument registers
-          (e.g. i386).  In that case we additionally check for an
-          exception thrown. */
-
-       if ((array == NULL) && (exceptions_get_exception() != NULL)) {
-               /* release dump area */
-
-               dump_release(dumpsize);
-
-               return NULL;
-       }
-
-       switch (resm->parseddesc->returntype.decltype) {
-       case TYPE_VOID:
-               (void) vm_call_array(resm, array);
-               ro = NULL;
-               break;
-
-       case PRIMITIVETYPE_BOOLEAN:
-       case PRIMITIVETYPE_BYTE:
-       case PRIMITIVETYPE_CHAR:
-       case PRIMITIVETYPE_SHORT:
-       case PRIMITIVETYPE_INT:
-               value.i = vm_call_int_array(resm, array);
-               ro = primitive_box(resm->parseddesc->returntype.decltype, value);
-               break;
-
-       case PRIMITIVETYPE_LONG:
-               value.l = vm_call_long_array(resm, array);
-               ro = primitive_box(resm->parseddesc->returntype.decltype, value);
-               break;
-
-       case PRIMITIVETYPE_FLOAT:
-               value.f = vm_call_float_array(resm, array);
-               ro = primitive_box(resm->parseddesc->returntype.decltype, value);
-               break;
-
-       case PRIMITIVETYPE_DOUBLE:
-               value.d = vm_call_double_array(resm, array);
-               ro = primitive_box(resm->parseddesc->returntype.decltype, value);
-               break;
-
-       case TYPE_ADR:
-               ro = vm_call_array(resm, array);
-               break;
-
-       default:
-               vm_abort("_Jv_jni_invokeNative: invalid return type %d", resm->parseddesc->returntype.decltype);
-       }
-
-       xptr = exceptions_get_exception();
-
-       if (xptr != NULL) {
-               /* clear exception pointer, we are calling JIT code again */
-
-               exceptions_clear_exception();
-
-               exceptions_throw_invocationtargetexception(xptr);
-       }
-
-       /* release dump area */
-
-       dump_release(dumpsize);
-
-       return ro;
-}
-
-
 /* GetVersion ******************************************************************
 
    Returns the major version number in the higher 16 bits and the
@@ -935,11 +837,11 @@ java_handle_t *_Jv_jni_invokeNative(methodinfo *m, java_handle_t *o,
 
 jint _Jv_JNI_GetVersion(JNIEnv *env)
 {
-       STATISTICS(jniinvokation());
+       TRACEJNICALLS(("_Jv_JNI_GetVersion(env=%p)", env));
 
-       /* we support JNI 1.4 */
+       /* We support JNI 1.6. */
 
-       return JNI_VERSION_1_4;
+       return JNI_VERSION_1_6;
 }
 
 
@@ -957,18 +859,21 @@ jclass _Jv_JNI_DefineClass(JNIEnv *env, const char *name, jobject loader,
                                                   const jbyte *buf, jsize bufLen)
 {
 #if defined(ENABLE_JAVASE)
-       utf         *u;
-       classloader *cl;
-       classinfo   *c;
+       utf             *u;
+       classloader_t   *cl;
+       classinfo       *c;
+       java_lang_Class *co;
 
-       TRACEJNICALLS("_Jv_JNI_DefineClass(env=%p, name=%s, loader=%p, buf=%p, bufLen=%d", env, name, loader, buf, bufLen);
+       TRACEJNICALLS(("_Jv_JNI_DefineClass(env=%p, name=%s, loader=%p, buf=%p, bufLen=%d)", env, name, loader, buf, bufLen));
 
        u  = utf_new_char(name);
-       cl = (classloader *) loader;
+       cl = loader_hashtable_classloader_add((java_handle_t *) loader);
 
-       c = class_define(u, cl, bufLen, (const uint8_t *) buf);
+       c = class_define(u, cl, bufLen, (uint8_t *) buf, NULL);
 
-       return (jclass) _Jv_JNI_NewLocalRef(env, (jobject) c);
+       co = LLNI_classinfo_wrap(c);
+
+       return (jclass) jni_NewLocalRef(env, (jobject) co);
 #else
        vm_abort("_Jv_JNI_DefineClass: not implemented in this configuration");
 
@@ -987,17 +892,26 @@ jclass _Jv_JNI_DefineClass(JNIEnv *env, const char *name, jobject loader,
 
 *******************************************************************************/
 
-jclass _Jv_JNI_FindClass(JNIEnv *env, const char *name)
+jclass jni_FindClass(JNIEnv *env, const char *name)
 {
 #if defined(ENABLE_JAVASE)
-       utf       *u;
-       classinfo *cc;
-       classinfo *c;
 
-       STATISTICS(jniinvokation());
+       utf             *u;
+       classinfo       *cc;
+       classinfo       *c;
+       java_lang_Class *co;
+
+       TRACEJNICALLS(("jni_FindClass(env=%p, name=%s)", env, name));
+
+       /* FIXME If name is NULL we have a problem here. */
 
        u = utf_new_char_classname((char *) name);
 
+       if ((u == NULL) /*|| (int)strlen(name) > symbolOopDesc::max_length() */) {
+               exceptions_throw_noclassdeffounderror(u);
+               return NULL;
+       }
+
        /* Check stacktrace for classloader, if one found use it,
           otherwise use the system classloader. */
 
@@ -1012,22 +926,47 @@ jclass _Jv_JNI_FindClass(JNIEnv *env, const char *name)
           its associated class loader. In that case, the result of
           ClassLoader.getBaseClassLoader is used." */
 
-       cc = stacktrace_getCurrentClass();
+       cc = stacktrace_get_current_class();
 
        if (cc == NULL)
                c = load_class_from_sysloader(u);
        else
                c = load_class_from_classloader(u, cc->classloader);
 
-       if (c == NULL)
+       if (c == NULL) {
+               resolve_handle_pending_exception(true);
+               return NULL;
+       }
+
+       if (!link_class(c))
+               return NULL;
+
+       co = LLNI_classinfo_wrap(c);
+
+       return (jclass) jni_NewLocalRef(env, (jobject) co);
+
+#elif defined(ENABLE_JAVAME_CLDC1_1)
+
+       utf       *u;
+       classinfo *c;
+
+       TRACEJNICALLS(("jni_FindClass(env=%p, name=%s)", env, name));
+
+       u = utf_new_char_classname((char *) name);
+       c = load_class_bootstrap(u);
+
+       if (c == NULL) {
+               resolve_handle_pending_exception(true);
                return NULL;
+       }
 
        if (!link_class(c))
                return NULL;
 
-       return (jclass) _Jv_JNI_NewLocalRef(env, (jobject) c);
+       return (jclass) jni_NewLocalRef(env, (jobject) c);
+       
 #else
-       vm_abort("_Jv_JNI_FindClass: not implemented in this configuration");
+       vm_abort("jni_FindClass: not implemented in this configuration");
 
        /* keep compiler happy */
 
@@ -1046,19 +985,22 @@ jclass _Jv_JNI_FindClass(JNIEnv *env, const char *name)
  
 jclass _Jv_JNI_GetSuperclass(JNIEnv *env, jclass sub)
 {
-       classinfo *c;
-       classinfo *super;
+       classinfo       *c;
+       classinfo       *super;
+       java_lang_Class *co;
 
-       TRACEJNICALLS("_Jv_JNI_GetSuperclass(env=%p, sub=%p)", env, sub);
+       TRACEJNICALLS(("_Jv_JNI_GetSuperclass(env=%p, sub=%p)", env, sub));
 
-       c = (classinfo *) sub;
+       c = LLNI_classinfo_unwrap(sub);
 
        if (c == NULL)
                return NULL;
 
        super = class_get_superclass(c);
 
-       return (jclass) _Jv_JNI_NewLocalRef(env, (jobject) super);
+       co = LLNI_classinfo_wrap(super);
+
+       return (jclass) jni_NewLocalRef(env, (jobject) co);
 }
   
  
@@ -1070,15 +1012,15 @@ jclass _Jv_JNI_GetSuperclass(JNIEnv *env, jclass sub)
 
 jboolean _Jv_JNI_IsAssignableFrom(JNIEnv *env, jclass sub, jclass sup)
 {
-       java_lang_Class *csup;
-       java_lang_Class *csub;
+       classinfo *to;
+       classinfo *from;
 
-       csup = (java_lang_Class *) sup;
-       csub = (java_lang_Class *) sub;
+       TRACEJNICALLS(("_Jv_JNI_IsAssignableFrom(env=%p, sub=%p, sup=%p)", env, sub, sup));
 
-       STATISTICS(jniinvokation());
+       to   = (classinfo *) sup;
+       from = (classinfo *) sub;
 
-       return _Jv_java_lang_Class_isAssignableFrom(csup, csub);
+       return class_is_assignable_from(to, from);
 }
 
 
@@ -1118,7 +1060,7 @@ jint _Jv_JNI_ThrowNew(JNIEnv* env, jclass clazz, const char *msg)
 
        STATISTICS(jniinvokation());
 
-       c = (classinfo *) clazz;
+       c = LLNI_classinfo_unwrap(clazz);
        if (msg == NULL)
                msg = "";
        s = javastring_new_from_utf_string(msg);
@@ -1148,11 +1090,11 @@ jthrowable _Jv_JNI_ExceptionOccurred(JNIEnv *env)
 {
        java_handle_t *o;
 
-       STATISTICS(jniinvokation());
+       TRACEJNICALLS(("_Jv_JNI_ExceptionOccurred(env=%p)", env));
 
        o = exceptions_get_exception();
 
-       return _Jv_JNI_NewLocalRef(env, (jthrowable) o);
+       return jni_NewLocalRef(env, (jthrowable) o);
 }
 
 
@@ -1164,36 +1106,11 @@ jthrowable _Jv_JNI_ExceptionOccurred(JNIEnv *env)
 
 *******************************************************************************/
 
-void _Jv_JNI_ExceptionDescribe(JNIEnv *env)
+void jni_ExceptionDescribe(JNIEnv *env)
 {
-       java_handle_t *o;
-       methodinfo    *m;
-
-       STATISTICS(jniinvokation());
-
-       o = exceptions_get_exception();
-
-       if (o == NULL) {
-               /* clear exception, because we are calling jit code again */
-
-               exceptions_clear_exception();
-
-               /* get printStackTrace method from exception class */
-
-               m = class_resolveclassmethod(o->vftbl->class,
-                                                                        utf_printStackTrace,
-                                                                        utf_void__void,
-                                                                        NULL,
-                                                                        true);
+       TRACEJNICALLS(("jni_ExceptionDescribe(env=%p)", env));
 
-               if (m == NULL)
-                       /* XXX what should we do? */
-                       return;
-
-               /* print the stacktrace */
-
-               (void) vm_call_method(m, o);
-       }
+       exceptions_print_stacktrace();
 }
 
 
@@ -1204,9 +1121,9 @@ void _Jv_JNI_ExceptionDescribe(JNIEnv *env)
 
 *******************************************************************************/
 
-void _Jv_JNI_ExceptionClear(JNIEnv *env)
+void jni_ExceptionClear(JNIEnv *env)
 {
-       STATISTICS(jniinvokation());
+       TRACEJNICALLS(("jni_ExceptionClear(env=%p)", env));
 
        exceptions_clear_exception();
 }
@@ -1236,9 +1153,9 @@ void _Jv_JNI_FatalError(JNIEnv *env, const char *msg)
 
 *******************************************************************************/
 
-jint _Jv_JNI_PushLocalFrame(JNIEnv* env, jint capacity)
+jint jni_PushLocalFrame(JNIEnv* env, jint capacity)
 {
-       STATISTICS(jniinvokation());
+       TRACEJNICALLS(("jni_PushLocalFrame(env=%p, capacity=%d)", env, capacity));
 
        if (capacity <= 0)
                return -1;
@@ -1260,9 +1177,9 @@ jint _Jv_JNI_PushLocalFrame(JNIEnv* env, jint capacity)
 
 *******************************************************************************/
 
-jobject _Jv_JNI_PopLocalFrame(JNIEnv* env, jobject result)
+jobject jni_PopLocalFrame(JNIEnv* env, jobject result)
 {
-       STATISTICS(jniinvokation());
+       TRACEJNICALLS(("jni_PopLocalFrame(env=%p, result=%p)", env, result));
 
        /* release all current local frames */
 
@@ -1270,7 +1187,7 @@ jobject _Jv_JNI_PopLocalFrame(JNIEnv* env, jobject result)
 
        /* add local reference and return the value */
 
-       return _Jv_JNI_NewLocalRef(env, result);
+       return jni_NewLocalRef(env, result);
 }
 
 
@@ -1280,41 +1197,20 @@ jobject _Jv_JNI_PopLocalFrame(JNIEnv* env, jobject result)
 
 *******************************************************************************/
 
-void _Jv_JNI_DeleteLocalRef(JNIEnv *env, jobject localRef)
+void jni_DeleteLocalRef(JNIEnv *env, jobject localRef)
 {
-       java_handle_t  *o;
-       localref_table *lrt;
-       s4              i;
+       java_handle_t *o;
 
-       STATISTICS(jniinvokation());
+       TRACEJNICALLS(("jni_DeleteLocalRef(env=%p, ref=%p)", env, localRef));
 
        o = (java_handle_t *) localRef;
 
-       /* get local reference table (thread specific) */
-
-       lrt = LOCALREFTABLE;
-
-       /* go through all local frames */
-
-       for (; lrt != NULL; lrt = lrt->prev) {
-
-               /* and try to remove the reference */
-
-               for (i = 0; i < lrt->capacity; i++) {
-                       if (lrt->refs[i] == o) {
-                               lrt->refs[i] = NULL;
-                               lrt->used--;
-
-                               return;
-                       }
-               }
-       }
+       if (o == NULL)
+               return;
 
-       /* this should not happen */
+       /* delete the reference */
 
-/*     if (opt_checkjni) */
-/*     FatalError(env, "Bad global or local ref passed to JNI"); */
-       log_text("JNI-DeleteLocalRef: Local ref passed to JNI not found");
+       localref_del(o);
 }
 
 
@@ -1326,12 +1222,25 @@ void _Jv_JNI_DeleteLocalRef(JNIEnv *env, jobject localRef)
 
 jboolean _Jv_JNI_IsSameObject(JNIEnv *env, jobject ref1, jobject ref2)
 {
+       java_handle_t *o1;
+       java_handle_t *o2;
+       jboolean       result;
+
        STATISTICS(jniinvokation());
 
-       if (ref1 == ref2)
-               return JNI_TRUE;
+       o1 = (java_handle_t *) ref1;
+       o2 = (java_handle_t *) ref2;
+
+       LLNI_CRITICAL_START;
+
+       if (LLNI_UNWRAP(o1) == LLNI_UNWRAP(o2))
+               result = JNI_TRUE;
        else
-               return JNI_FALSE;
+               result = JNI_FALSE;
+
+       LLNI_CRITICAL_END;
+
+       return result;
 }
 
 
@@ -1341,51 +1250,23 @@ jboolean _Jv_JNI_IsSameObject(JNIEnv *env, jobject ref1, jobject ref2)
 
 *******************************************************************************/
 
-jobject _Jv_JNI_NewLocalRef(JNIEnv *env, jobject ref)
+jobject jni_NewLocalRef(JNIEnv *env, jobject ref)
 {
-       localref_table *lrt;
-       s4              i;
-
-       STATISTICS(jniinvokation());
-
-       if (ref == NULL)
-               return NULL;
-
-       /* get local reference table (thread specific) */
-
-       lrt = LOCALREFTABLE;
+       java_handle_t *o;
+       java_handle_t *localref;
 
-       /* Check if we have space for the requested reference?  No,
-          allocate a new frame.  This is actually not what the spec says,
-          but for compatibility reasons... */
+       TRACEJNICALLS(("jni_NewLocalRef(env=%p, ref=%p)", env, ref));
 
-       if (lrt->used == lrt->capacity) {
-               if (_Jv_JNI_EnsureLocalCapacity(env, 16) != 0)
-                       return NULL;
+       o = (java_handle_t *) ref;
 
-               /* get the new local reference table */
-
-               lrt = LOCALREFTABLE;
-       }
+       if (o == NULL)
+               return NULL;
 
        /* insert the reference */
 
-       for (i = 0; i < lrt->capacity; i++) {
-               if (lrt->refs[i] == NULL) {
-                       lrt->refs[i] = (java_handle_t *) ref;
-                       lrt->used++;
-
-                       return ref;
-               }
-       }
-
-       /* should not happen, just to be sure */
-
-       assert(0);
-
-       /* keep compiler happy */
+       localref = localref_add(LLNI_DIRECT(o));
 
-       return NULL;
+       return (jobject) localref;
 }
 
 
@@ -1396,11 +1277,11 @@ jobject _Jv_JNI_NewLocalRef(JNIEnv *env, jobject ref)
 
 *******************************************************************************/
 
-jint _Jv_JNI_EnsureLocalCapacity(JNIEnv* env, jint capacity)
+jint jni_EnsureLocalCapacity(JNIEnv* env, jint capacity)
 {
        localref_table *lrt;
 
-       STATISTICS(jniinvokation());
+       TRACEJNICALLS(("jni_EnsureLocalCapacity(env=%p, capacity=%d)", env, capacity));
 
        /* get local reference table (thread specific) */
 
@@ -1409,7 +1290,7 @@ jint _Jv_JNI_EnsureLocalCapacity(JNIEnv* env, jint capacity)
        /* check if capacity elements are available in the local references table */
 
        if ((lrt->used + capacity) > lrt->capacity)
-               return _Jv_JNI_PushLocalFrame(env, capacity);
+               return jni_PushLocalFrame(env, capacity);
 
        return 0;
 }
@@ -1429,7 +1310,7 @@ jobject _Jv_JNI_AllocObject(JNIEnv *env, jclass clazz)
 
        STATISTICS(jniinvokation());
 
-       c = (classinfo *) clazz;
+       c = LLNI_classinfo_unwrap(clazz);
 
        if ((c->flags & ACC_INTERFACE) || (c->flags & ACC_ABSTRACT)) {
                exceptions_throw_instantiationexception(c);
@@ -1438,7 +1319,7 @@ jobject _Jv_JNI_AllocObject(JNIEnv *env, jclass clazz)
                
        o = builtin_new(c);
 
-       return _Jv_JNI_NewLocalRef(env, (jobject) o);
+       return jni_NewLocalRef(env, (jobject) o);
 }
 
 
@@ -1451,16 +1332,16 @@ jobject _Jv_JNI_AllocObject(JNIEnv *env, jclass clazz)
 
 *******************************************************************************/
 
-jobject _Jv_JNI_NewObject(JNIEnv *env, jclass clazz, jmethodID methodID, ...)
+jobject jni_NewObject(JNIEnv *env, jclass clazz, jmethodID methodID, ...)
 {
        java_handle_t *o;
        classinfo     *c;
        methodinfo    *m;
        va_list        ap;
 
-       STATISTICS(jniinvokation());
+       TRACEJNICALLSENTER(("jni_NewObject(env=%p, clazz=%p, methodID=%p, ...)", env, clazz, methodID));
 
-       c = (classinfo *) clazz;
+       c = LLNI_classinfo_unwrap(clazz);
        m = (methodinfo *) methodID;
 
        /* create object */
@@ -1473,10 +1354,12 @@ jobject _Jv_JNI_NewObject(JNIEnv *env, jclass clazz, jmethodID methodID, ...)
        /* call constructor */
 
        va_start(ap, methodID);
-       _Jv_jni_CallVoidMethod(o, o->vftbl, m, ap);
+       _Jv_jni_CallVoidMethod(o, LLNI_vftbl_direct(o), m, ap);
        va_end(ap);
 
-       return _Jv_JNI_NewLocalRef(env, (jobject) o);
+       TRACEJNICALLSEXIT(("->%p", o));
+
+       return jni_NewLocalRef(env, (jobject) o);
 }
 
 
@@ -1499,7 +1382,7 @@ jobject _Jv_JNI_NewObjectV(JNIEnv* env, jclass clazz, jmethodID methodID,
 
        STATISTICS(jniinvokation());
 
-       c = (classinfo *) clazz;
+       c = LLNI_classinfo_unwrap(clazz);
        m = (methodinfo *) methodID;
 
        /* create object */
@@ -1511,9 +1394,9 @@ jobject _Jv_JNI_NewObjectV(JNIEnv* env, jclass clazz, jmethodID methodID,
 
        /* call constructor */
 
-       _Jv_jni_CallVoidMethod(o, o->vftbl, m, args);
+       _Jv_jni_CallVoidMethod(o, LLNI_vftbl_direct(o), m, args);
 
-       return _Jv_JNI_NewLocalRef(env, (jobject) o);
+       return jni_NewLocalRef(env, (jobject) o);
 }
 
 
@@ -1536,7 +1419,7 @@ jobject _Jv_JNI_NewObjectA(JNIEnv* env, jclass clazz, jmethodID methodID,
 
        STATISTICS(jniinvokation());
 
-       c = (classinfo *) clazz;
+       c = LLNI_classinfo_unwrap(clazz);
        m = (methodinfo *) methodID;
 
        /* create object */
@@ -1548,9 +1431,9 @@ jobject _Jv_JNI_NewObjectA(JNIEnv* env, jclass clazz, jmethodID methodID,
 
        /* call constructor */
 
-       _Jv_jni_CallVoidMethodA(o, o->vftbl, m, args);
+       _Jv_jni_CallVoidMethodA(o, LLNI_vftbl_direct(o), m, args);
 
-       return _Jv_JNI_NewLocalRef(env, (jobject) o);
+       return jni_NewLocalRef(env, (jobject) o);
 }
 
 
@@ -1562,19 +1445,22 @@ jobject _Jv_JNI_NewObjectA(JNIEnv* env, jclass clazz, jmethodID methodID,
 
 jclass _Jv_JNI_GetObjectClass(JNIEnv *env, jobject obj)
 {
-       java_handle_t *o;
-       classinfo     *c;
+       java_handle_t   *o;
+       classinfo       *c;
+       java_lang_Class *co;
 
        STATISTICS(jniinvokation());
 
        o = (java_handle_t *) obj;
 
-       if ((o == NULL) || (o->vftbl == NULL))
+       if ((o == NULL) || (LLNI_vftbl_direct(o) == NULL))
                return NULL;
 
-       c = o->vftbl->class;
+       LLNI_class_get(o, c);
+
+       co = LLNI_classinfo_wrap(c);
 
-       return (jclass) _Jv_JNI_NewLocalRef(env, (jobject) c);
+       return (jclass) jni_NewLocalRef(env, (jobject) co);
 }
 
 
@@ -1586,15 +1472,16 @@ jclass _Jv_JNI_GetObjectClass(JNIEnv *env, jobject obj)
 
 jboolean _Jv_JNI_IsInstanceOf(JNIEnv *env, jobject obj, jclass clazz)
 {
-       java_lang_Class  *c;
-       java_lang_Object *o;
+       classinfo     *c;
+       java_handle_t *h;
 
-       STATISTICS(jniinvokation());
+       TRACEJNICALLS(("_Jv_JNI_IsInstanceOf(env=%p, obj=%p, clazz=%p)", env, obj, clazz));
 
-       c = (java_lang_Class *) clazz;
-       o = (java_lang_Object *) obj;
+       /* XXX Is this correct? */
+       c = LLNI_classinfo_unwrap(clazz);
+       h = (java_handle_t *) obj;
 
-       return _Jv_java_lang_Class_isInstance(c, o);
+       return class_is_instance(c, h);
 }
 
 
@@ -1607,45 +1494,74 @@ jboolean _Jv_JNI_IsInstanceOf(JNIEnv *env, jobject obj, jclass clazz)
   
 *******************************************************************************/
   
-jmethodID _Jv_JNI_FromReflectedMethod(JNIEnv *env, jobject method)
+jmethodID jni_FromReflectedMethod(JNIEnv *env, jobject method)
 {
 #if defined(ENABLE_JAVASE)
-       java_handle_t *o;
-       classinfo     *c;
-       methodinfo    *m;
-       s4             slot;
+       java_handle_t                   *o;
+       java_lang_reflect_Method        *rm;
+       java_lang_reflect_Constructor   *rc;
+       classinfo                       *c;
+       methodinfo                      *m;
+       int32_t                          slot;
+
+#if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
+       java_lang_reflect_VMMethod      *rvmm;
+       java_lang_reflect_VMConstructor *rvmc;
+#endif
 
-       STATISTICS(jniinvokation());
+       TRACEJNICALLS(("jni_FromReflectedMethod(env=%p, method=%p)", env, method));
 
        o = (java_handle_t *) method;
 
        if (o == NULL)
                return NULL;
-       
-       if (builtin_instanceof(o, class_java_lang_reflect_Method)) {
-               java_lang_reflect_Method *rm;
 
-               rm   = (java_lang_reflect_Method *) method;
-               LLNI_field_get_cls(rm, clazz, c);
-               LLNI_field_get_val(rm, slot , slot);
-       }
-       else if (builtin_instanceof(o, class_java_lang_reflect_Constructor)) {
-               java_lang_reflect_Constructor *rc;
+       if (o->vftbl->clazz == class_java_lang_reflect_Constructor) {
+               rc = (java_lang_reflect_Constructor *) method;
+
+#if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
+
+               LLNI_field_get_ref(rc,   cons , rvmc);
+               LLNI_field_get_cls(rvmc, clazz, c);
+               LLNI_field_get_val(rvmc, slot , slot);
+
+#elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
 
-               rc   = (java_lang_reflect_Constructor *) method;
                LLNI_field_get_cls(rc, clazz, c);
                LLNI_field_get_val(rc, slot , slot);
+
+#else
+# error unknown configuration
+#endif
+       }
+       else {
+               assert(o->vftbl->clazz == class_java_lang_reflect_Method);
+
+               rm = (java_lang_reflect_Method *) method;
+
+#if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
+
+               LLNI_field_get_ref(rm,   m ,    rvmm);
+               LLNI_field_get_cls(rvmm, clazz, c);
+               LLNI_field_get_val(rvmm, slot , slot);
+
+#elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
+
+               LLNI_field_get_cls(rm, clazz, c);
+               LLNI_field_get_val(rm, slot , slot);
+
+#else
+# error unknown configuration
+#endif
        }
-       else
-               return NULL;
 
        m = &(c->methods[slot]);
 
        return (jmethodID) m;
 #else
-       vm_abort("_Jv_JNI_FromReflectedMethod: not implemented in this configuration");
+       vm_abort("jni_FromReflectedMethod: Not implemented in this configuration.");
 
-       /* keep compiler happy */
+       /* Keep compiler happy. */
 
        return NULL;
 #endif
@@ -1658,30 +1574,47 @@ jmethodID _Jv_JNI_FromReflectedMethod(JNIEnv *env, jobject method)
 
 *******************************************************************************/
  
-jfieldID _Jv_JNI_FromReflectedField(JNIEnv* env, jobject field)
+jfieldID jni_FromReflectedField(JNIEnv* env, jobject field)
 {
 #if defined(ENABLE_JAVASE)
-       java_lang_reflect_Field *rf;
-       classinfo               *c;
-       fieldinfo               *f;
-       int32_t                  slot;
+       java_lang_reflect_Field   *rf;
+       classinfo                 *c;
+       fieldinfo                 *f;
+       int32_t                    slot;
 
-       STATISTICS(jniinvokation());
+#if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
+       java_lang_reflect_VMField *rvmf;
+#endif
+
+       TRACEJNICALLS(("jni_FromReflectedField(env=%p, field=%p)", env, field));
 
        rf = (java_lang_reflect_Field *) field;
 
        if (rf == NULL)
                return NULL;
 
+#if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
+
+       LLNI_field_get_ref(rf,   f,     rvmf);
+       LLNI_field_get_cls(rvmf, clazz, c);
+       LLNI_field_get_val(rvmf, slot , slot);
+
+#elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
+
        LLNI_field_get_cls(rf, clazz, c);
        LLNI_field_get_val(rf, slot , slot);
+
+#else
+# error unknown configuration
+#endif
+
        f = &(c->fields[slot]);
 
        return (jfieldID) f;
 #else
-       vm_abort("_Jv_JNI_FromReflectedField: not implemented in this configuration");
+       vm_abort("jni_FromReflectedField: Not implemented in this configuration.");
 
-       /* keep compiler happy */
+       /* Keep compiler happy. */
 
        return NULL;
 #endif
@@ -1704,7 +1637,7 @@ jobject _Jv_JNI_ToReflectedMethod(JNIEnv* env, jclass cls, jmethodID methodID,
        java_lang_reflect_Constructor *rc;
        java_lang_reflect_Method      *rm;
 
-       STATISTICS(jniinvokation());
+       TRACEJNICALLS(("_Jv_JNI_ToReflectedMethod(env=%p, cls=%p, methodID=%p, isStatic=%d)", env, cls, methodID, isStatic));
 
        m = (methodinfo *) methodID;
 
@@ -1773,7 +1706,7 @@ jmethodID _Jv_JNI_GetMethodID(JNIEnv* env, jclass clazz, const char *name,
 
        STATISTICS(jniinvokation());
 
-       c = (classinfo *) clazz;
+       c = LLNI_classinfo_unwrap(clazz);
 
        if (c == NULL)
                return NULL;
@@ -1814,7 +1747,7 @@ type _Jv_JNI_Call##name##Method(JNIEnv *env, jobject obj,   \
        m = (methodinfo *) methodID;                            \
                                                             \
        va_start(ap, methodID);                                 \
-       ret = _Jv_jni_Call##intern##Method(o, o->vftbl, m, ap); \
+       ret = _Jv_jni_Call##intern##Method(o, LLNI_vftbl_direct(o), m, ap); \
        va_end(ap);                                             \
                                                             \
        return ret;                                             \
@@ -1841,7 +1774,7 @@ type _Jv_JNI_Call##name##MethodV(JNIEnv *env, jobject obj,         \
        o = (java_handle_t *) obj;                                     \
        m = (methodinfo *) methodID;                                   \
                                                                    \
-       ret = _Jv_jni_Call##intern##Method(o, o->vftbl, m, args);      \
+       ret = _Jv_jni_Call##intern##Method(o, LLNI_vftbl_direct(o), m, args);      \
                                                                    \
        return ret;                                                    \
 }
@@ -1868,7 +1801,7 @@ type _Jv_JNI_Call##name##MethodA(JNIEnv *env, jobject obj,     \
        o = (java_handle_t *) obj;                                 \
        m = (methodinfo *) methodID;                               \
                                                                \
-       ret = _Jv_jni_Call##intern##MethodA(o, o->vftbl, m, args); \
+       ret = _Jv_jni_Call##intern##MethodA(o, LLNI_vftbl_direct(o), m, args); \
                                                                \
        return ret;                                                \
 }
@@ -1895,10 +1828,10 @@ jobject _Jv_JNI_CallObjectMethod(JNIEnv *env, jobject obj, jmethodID methodID,
        m = (methodinfo *) methodID;
 
        va_start(ap, methodID);
-       ret = _Jv_jni_CallObjectMethod(o, o->vftbl, m, ap);
+       ret = _Jv_jni_CallObjectMethod(o, LLNI_vftbl_direct(o), m, ap);
        va_end(ap);
 
-       return _Jv_JNI_NewLocalRef(env, (jobject) ret);
+       return jni_NewLocalRef(env, (jobject) ret);
 }
 
 
@@ -1912,9 +1845,9 @@ jobject _Jv_JNI_CallObjectMethodV(JNIEnv *env, jobject obj, jmethodID methodID,
        o = (java_handle_t *) obj;
        m = (methodinfo *) methodID;
 
-       ret = _Jv_jni_CallObjectMethod(o, o->vftbl, m, args);
+       ret = _Jv_jni_CallObjectMethod(o, LLNI_vftbl_direct(o), m, args);
 
-       return _Jv_JNI_NewLocalRef(env, (jobject) ret);
+       return jni_NewLocalRef(env, (jobject) ret);
 }
 
 
@@ -1928,9 +1861,9 @@ jobject _Jv_JNI_CallObjectMethodA(JNIEnv *env, jobject obj, jmethodID methodID,
        o = (java_handle_t *) obj;
        m = (methodinfo *) methodID;
 
-       ret = _Jv_jni_CallObjectMethodA(o, o->vftbl, m, args);
+       ret = _Jv_jni_CallObjectMethodA(o, LLNI_vftbl_direct(o), m, args);
 
-       return _Jv_JNI_NewLocalRef(env, (jobject) ret);
+       return jni_NewLocalRef(env, (jobject) ret);
 }
 
 
@@ -1945,7 +1878,7 @@ void _Jv_JNI_CallVoidMethod(JNIEnv *env, jobject obj, jmethodID methodID, ...)
        m = (methodinfo *) methodID;
 
        va_start(ap, methodID);
-       _Jv_jni_CallVoidMethod(o, o->vftbl, m, ap);
+       _Jv_jni_CallVoidMethod(o, LLNI_vftbl_direct(o), m, ap);
        va_end(ap);
 }
 
@@ -1959,7 +1892,7 @@ void _Jv_JNI_CallVoidMethodV(JNIEnv *env, jobject obj, jmethodID methodID,
        o = (java_handle_t *) obj;
        m = (methodinfo *) methodID;
 
-       _Jv_jni_CallVoidMethod(o, o->vftbl, m, args);
+       _Jv_jni_CallVoidMethod(o, LLNI_vftbl_direct(o), m, args);
 }
 
 
@@ -1972,7 +1905,7 @@ void _Jv_JNI_CallVoidMethodA(JNIEnv *env, jobject obj, jmethodID methodID,
        o = (java_handle_t *) obj;
        m = (methodinfo *) methodID;
 
-       _Jv_jni_CallVoidMethodA(o, o->vftbl, m, args);
+       _Jv_jni_CallVoidMethodA(o, LLNI_vftbl_direct(o), m, args);
 }
 
 
@@ -1989,7 +1922,7 @@ type _Jv_JNI_CallNonvirtual##name##Method(JNIEnv *env, jobject obj,         \
        type           ret;                                                     \
                                                                             \
        o = (java_handle_t *) obj;                                              \
-       c = (classinfo *) clazz;                                                \
+       c = LLNI_classinfo_unwrap(clazz);                                       \
        m = (methodinfo *) methodID;                                            \
                                                                             \
        va_start(ap, methodID);                                                 \
@@ -2020,7 +1953,7 @@ type _Jv_JNI_CallNonvirtual##name##MethodV(JNIEnv *env, jobject obj,         \
        type           ret;                                                      \
                                                                              \
        o = (java_handle_t *) obj;                                               \
-       c = (classinfo *) clazz;                                                 \
+       c = LLNI_classinfo_unwrap(clazz);                                        \
        m = (methodinfo *) methodID;                                             \
                                                                              \
        ret = _Jv_jni_CallIntMethod(o, c->vftbl, m, args);                       \
@@ -2068,14 +2001,14 @@ jobject _Jv_JNI_CallNonvirtualObjectMethod(JNIEnv *env, jobject obj,
        va_list        ap;
 
        o = (java_handle_t *) obj;
-       c = (classinfo *) clazz;
+       c = LLNI_classinfo_unwrap(clazz);
        m = (methodinfo *) methodID;
 
        va_start(ap, methodID);
        r = _Jv_jni_CallObjectMethod(o, c->vftbl, m, ap);
        va_end(ap);
 
-       return _Jv_JNI_NewLocalRef(env, (jobject) r);
+       return jni_NewLocalRef(env, (jobject) r);
 }
 
 
@@ -2089,12 +2022,12 @@ jobject _Jv_JNI_CallNonvirtualObjectMethodV(JNIEnv *env, jobject obj,
        java_handle_t *r;
 
        o = (java_handle_t *) obj;
-       c = (classinfo *) clazz;
+       c = LLNI_classinfo_unwrap(clazz);
        m = (methodinfo *) methodID;
 
        r = _Jv_jni_CallObjectMethod(o, c->vftbl, m, args);
 
-       return _Jv_JNI_NewLocalRef(env, (jobject) r);
+       return jni_NewLocalRef(env, (jobject) r);
 }
 
 
@@ -2104,7 +2037,7 @@ jobject _Jv_JNI_CallNonvirtualObjectMethodA(JNIEnv *env, jobject obj,
 {
        log_text("JNI-Call: CallNonvirtualObjectMethodA: IMPLEMENT ME!");
 
-       return _Jv_JNI_NewLocalRef(env, NULL);
+       return jni_NewLocalRef(env, NULL);
 }
 
 
@@ -2117,7 +2050,7 @@ void _Jv_JNI_CallNonvirtualVoidMethod(JNIEnv *env, jobject obj, jclass clazz,
        va_list        ap;
 
        o = (java_handle_t *) obj;
-       c = (classinfo *) clazz;
+       c = LLNI_classinfo_unwrap(clazz);
        m = (methodinfo *) methodID;
 
        va_start(ap, methodID);
@@ -2134,7 +2067,7 @@ void _Jv_JNI_CallNonvirtualVoidMethodV(JNIEnv *env, jobject obj, jclass clazz,
        methodinfo    *m;
 
        o = (java_handle_t *) obj;
-       c = (classinfo *) clazz;
+       c = LLNI_classinfo_unwrap(clazz);
        m = (methodinfo *) methodID;
 
        _Jv_jni_CallVoidMethod(o, c->vftbl, m, args);
@@ -2149,7 +2082,7 @@ void _Jv_JNI_CallNonvirtualVoidMethodA(JNIEnv *env, jobject obj, jclass clazz,
        methodinfo    *m;
 
        o = (java_handle_t *) obj;
-       c = (classinfo *) clazz;
+       c = LLNI_classinfo_unwrap(clazz);
        m = (methodinfo *) methodID;
 
        _Jv_jni_CallVoidMethodA(o, c->vftbl, m, args);
@@ -2177,7 +2110,7 @@ jfieldID _Jv_JNI_GetFieldID(JNIEnv *env, jclass clazz, const char *name,
 
        STATISTICS(jniinvokation());
 
-       c = (classinfo *) clazz;
+       c = LLNI_classinfo_unwrap(clazz);
 
        /* XXX NPE check? */
 
@@ -2201,14 +2134,21 @@ jfieldID _Jv_JNI_GetFieldID(JNIEnv *env, jclass clazz, const char *name,
 
 *******************************************************************************/
 
+#define GET_FIELD(o,type,f) \
+    *((type *) (((intptr_t) (o)) + ((intptr_t) ((fieldinfo *) (f))->offset)))
+
 #define JNI_GET_FIELD(name, type, intern)                                 \
 type _Jv_JNI_Get##name##Field(JNIEnv *env, jobject obj, jfieldID fieldID) \
 {                                                                         \
        intern ret;                                                           \
                                                                           \
-       STATISTICS(jniinvokation());                                          \
+       TRACEJNICALLS(("_Jv_JNI_Get" STR(name) "Field(env=%p, obj=%p, fieldId=%p)", env, obj, fieldID)); \
                                                                           \
-       ret = GET_FIELD(obj, intern, fieldID);                                \
+       LLNI_CRITICAL_START;                                                  \
+                                                                          \
+       ret = GET_FIELD(LLNI_DIRECT((java_handle_t *) obj), intern, fieldID); \
+                                                                          \
+       LLNI_CRITICAL_END;                                                    \
                                                                           \
        return (type) ret;                                                    \
 }
@@ -2227,12 +2167,15 @@ jobject _Jv_JNI_GetObjectField(JNIEnv *env, jobject obj, jfieldID fieldID)
 {
        java_handle_t *o;
 
-       STATISTICS(jniinvokation());
+       TRACEJNICALLS(("_Jv_JNI_GetObjectField(env=%p, obj=%p, fieldId=%p)", env, obj, fieldID));
+
+       LLNI_CRITICAL_START;
 
-#warning this needs to be fixed
-       o = GET_FIELD(obj, java_handle_t*, fieldID);
+       o = LLNI_WRAP(GET_FIELD(LLNI_DIRECT((java_handle_t *) obj), java_object_t*, fieldID));
 
-       return _Jv_JNI_NewLocalRef(env, (jobject) o);
+       LLNI_CRITICAL_END;
+
+       return jni_NewLocalRef(env, (jobject) o);
 }
 
 
@@ -2244,13 +2187,20 @@ jobject _Jv_JNI_GetObjectField(JNIEnv *env, jobject obj, jfieldID fieldID)
 
 *******************************************************************************/
 
-#define JNI_SET_FIELD(name, type, intern)                                 \
-void _Jv_JNI_Set##name##Field(JNIEnv *env, jobject obj, jfieldID fieldID, \
-                                                         type value)                                 \
-{                                                                         \
-       STATISTICS(jniinvokation());                                          \
-                                                                          \
-       SET_FIELD(obj, intern, fieldID, value);                               \
+#define SET_FIELD(o,type,f,value) \
+    *((type *) (((intptr_t) (o)) + ((intptr_t) ((fieldinfo *) (f))->offset))) = (type) (value)
+
+#define JNI_SET_FIELD(name, type, intern)                                  \
+void _Jv_JNI_Set##name##Field(JNIEnv *env, jobject obj, jfieldID fieldID,  \
+                                                         type value)                                  \
+{                                                                          \
+       TRACEJNICALLS(("_Jv_JNI_Set" STR(name) "Field(env=%p, obj=%p, fieldId=%p, value=%p)", env, obj, fieldID, value)); \
+                                                                           \
+       LLNI_CRITICAL_START;                                                   \
+                                                                           \
+       SET_FIELD(LLNI_DIRECT((java_handle_t *) obj), intern, fieldID, value); \
+                                                                              \
+       LLNI_CRITICAL_START;                                                   \
 }
 
 JNI_SET_FIELD(Boolean, jboolean, s4)
@@ -2266,10 +2216,13 @@ JNI_SET_FIELD(Double,  jdouble,  double)
 void _Jv_JNI_SetObjectField(JNIEnv *env, jobject obj, jfieldID fieldID,
                                                        jobject value)
 {
-       STATISTICS(jniinvokation());
+       TRACEJNICALLS(("_Jv_JNI_SetObjectField(env=%p, obj=%p, fieldId=%p, value=%p)", env, obj, fieldID, value));
 
-#warning this needs to be fixed
-       SET_FIELD(obj, java_handle_t*, fieldID, value);
+       LLNI_CRITICAL_START;
+
+       SET_FIELD(obj, java_handle_t*, fieldID, LLNI_UNWRAP((java_handle_t*) value));
+
+       LLNI_CRITICAL_END;
 }
 
 
@@ -2293,11 +2246,11 @@ jmethodID _Jv_JNI_GetStaticMethodID(JNIEnv *env, jclass clazz, const char *name,
        utf        *udesc;
        methodinfo *m;
 
-       STATISTICS(jniinvokation());
+       TRACEJNICALLS(("_Jv_JNI_GetStaticMethodID(env=%p, clazz=%p, name=%s, sig=%s)", env, clazz, name, sig));
 
-       c = (classinfo *) clazz;
+       c = LLNI_classinfo_unwrap(clazz);
 
-       if (!c)
+       if (c == NULL)
                return NULL;
 
        if (!(c->state & CLASS_INITIALIZED))
@@ -2403,13 +2356,15 @@ jobject _Jv_JNI_CallStaticObjectMethod(JNIEnv *env, jclass clazz,
        java_handle_t *o;
        va_list        ap;
 
+       TRACEJNICALLS(("_Jv_JNI_CallStaticObjectMethod(env=%p, clazz=%p, methodID=%p, ...)", env, clazz, methodID));
+
        m = (methodinfo *) methodID;
 
        va_start(ap, methodID);
        o = _Jv_jni_CallObjectMethod(NULL, NULL, m, ap);
        va_end(ap);
 
-       return _Jv_JNI_NewLocalRef(env, (jobject) o);
+       return jni_NewLocalRef(env, (jobject) o);
 }
 
 
@@ -2419,11 +2374,13 @@ jobject _Jv_JNI_CallStaticObjectMethodV(JNIEnv *env, jclass clazz,
        methodinfo    *m;
        java_handle_t *o;
 
+       TRACEJNICALLS(("_Jv_JNI_CallStaticObjectMethodV(env=%p, clazz=%p, methodID=%p, args=%p)", env, clazz, methodID, args));
+
        m = (methodinfo *) methodID;
 
        o = _Jv_jni_CallObjectMethod(NULL, NULL, m, args);
 
-       return _Jv_JNI_NewLocalRef(env, (jobject) o);
+       return jni_NewLocalRef(env, (jobject) o);
 }
 
 
@@ -2433,11 +2390,13 @@ jobject _Jv_JNI_CallStaticObjectMethodA(JNIEnv *env, jclass clazz,
        methodinfo    *m;
        java_handle_t *o;
 
+       TRACEJNICALLS(("_Jv_JNI_CallStaticObjectMethodA(env=%p, clazz=%p, methodID=%p, args=%p)", env, clazz, methodID, args));
+
        m = (methodinfo *) methodID;
 
        o = _Jv_jni_CallObjectMethodA(NULL, NULL, m, args);
 
-       return _Jv_JNI_NewLocalRef(env, (jobject) o);
+       return jni_NewLocalRef(env, (jobject) o);
 }
 
 
@@ -2447,6 +2406,8 @@ void _Jv_JNI_CallStaticVoidMethod(JNIEnv *env, jclass clazz,
        methodinfo *m;
        va_list     ap;
 
+       TRACEJNICALLS(("_Jv_JNI_CallStaticVoidMethod(env=%p, clazz=%p, methodID=%p, ...)", env, clazz, methodID));
+
        m = (methodinfo *) methodID;
 
        va_start(ap, methodID);
@@ -2460,6 +2421,8 @@ void _Jv_JNI_CallStaticVoidMethodV(JNIEnv *env, jclass clazz,
 {
        methodinfo *m;
 
+       TRACEJNICALLS(("_Jv_JNI_CallStaticVoidMethodV(env=%p, clazz=%p, methodID=%p, args=%p)", env, clazz, methodID, args));
+
        m = (methodinfo *) methodID;
 
        _Jv_jni_CallVoidMethod(NULL, NULL, m, args);
@@ -2471,6 +2434,8 @@ void _Jv_JNI_CallStaticVoidMethodA(JNIEnv *env, jclass clazz,
 {
        methodinfo *m;
 
+       TRACEJNICALLS(("_Jv_JNI_CallStaticVoidMethodA(env=%p, clazz=%p, methodID=%p, args=%p)", env, clazz, methodID, args));
+
        m = (methodinfo *) methodID;
 
        _Jv_jni_CallVoidMethodA(NULL, NULL, m, args);
@@ -2498,7 +2463,7 @@ jfieldID _Jv_JNI_GetStaticFieldID(JNIEnv *env, jclass clazz, const char *name,
 
        STATISTICS(jniinvokation());
 
-       c = (classinfo *) clazz;
+       c = LLNI_classinfo_unwrap(clazz);
 
        uname = utf_new_char((char *) name);
        usig  = utf_new_char((char *) sig);
@@ -2528,7 +2493,7 @@ type _Jv_JNI_GetStatic##name##Field(JNIEnv *env, jclass clazz, \
                                                                \
        STATISTICS(jniinvokation());                               \
                                                                \
-       c = (classinfo *) clazz;                                   \
+       c = LLNI_classinfo_unwrap(clazz);                          \
        f = (fieldinfo *) fieldID;                                 \
                                                                \
        if (!(c->state & CLASS_INITIALIZED))                       \
@@ -2551,19 +2516,22 @@ JNI_GET_STATIC_FIELD(Double,  jdouble,  d)
 jobject _Jv_JNI_GetStaticObjectField(JNIEnv *env, jclass clazz,
                                                                         jfieldID fieldID)
 {
-       classinfo *c;
-       fieldinfo *f;
+       classinfo     *c;
+       fieldinfo     *f;
+       java_handle_t *h;
 
        STATISTICS(jniinvokation());
 
-       c = (classinfo *) clazz;
+       c = LLNI_classinfo_unwrap(clazz);
        f = (fieldinfo *) fieldID;
 
        if (!(c->state & CLASS_INITIALIZED))
                if (!initialize_class(c))
                        return NULL;
 
-       return _Jv_JNI_NewLocalRef(env, f->value->a);
+       h = LLNI_WRAP(f->value->a);
+
+       return jni_NewLocalRef(env, (jobject) h);
 }
 
 
@@ -2584,7 +2552,7 @@ void _Jv_JNI_SetStatic##name##Field(JNIEnv *env, jclass clazz, \
                                                                \
        STATISTICS(jniinvokation());                               \
                                                                \
-       c = (classinfo *) clazz;                                   \
+       c = LLNI_classinfo_unwrap(clazz);                          \
        f = (fieldinfo *) fieldID;                                 \
                                                                \
        if (!(c->state & CLASS_INITIALIZED))                       \
@@ -2612,14 +2580,14 @@ void _Jv_JNI_SetStaticObjectField(JNIEnv *env, jclass clazz, jfieldID fieldID,
 
        STATISTICS(jniinvokation());
 
-       c = (classinfo *) clazz;
+       c = LLNI_classinfo_unwrap(clazz);
        f = (fieldinfo *) fieldID;
 
        if (!(c->state & CLASS_INITIALIZED))
                if (!initialize_class(c))
                        return;
 
-       f->value->a = value;
+       f->value->a = LLNI_UNWRAP((java_handle_t *) value);
 }
 
 
@@ -2634,9 +2602,9 @@ void _Jv_JNI_SetStaticObjectField(JNIEnv *env, jclass clazz, jfieldID fieldID,
 
 jstring _Jv_JNI_NewString(JNIEnv *env, const jchar *buf, jsize len)
 {
-       java_lang_String *s;
-       java_chararray   *a;
-       u4                i;
+       java_lang_String        *s;
+       java_handle_chararray_t *a;
+       u4                       i;
 
        STATISTICS(jniinvokation());
        
@@ -2649,13 +2617,13 @@ jstring _Jv_JNI_NewString(JNIEnv *env, const jchar *buf, jsize len)
 
        /* copy text */
        for (i = 0; i < len; i++)
-               a->data[i] = buf[i];
+               LLNI_array_direct(a, i) = buf[i];
 
        LLNI_field_set_ref(s, value , a);
        LLNI_field_set_val(s, offset, 0);
        LLNI_field_set_val(s, count , len);
 
-       return (jstring) _Jv_JNI_NewLocalRef(env, (jobject) s);
+       return (jstring) jni_NewLocalRef(env, (jobject) s);
 }
 
 
@@ -2673,7 +2641,7 @@ jsize _Jv_JNI_GetStringLength(JNIEnv *env, jstring str)
        java_lang_String *s;
        jsize             len;
 
-       TRACEJNICALLS("_Jv_JNI_GetStringLength(env=%p, str=%p)", env, str);
+       TRACEJNICALLS(("_Jv_JNI_GetStringLength(env=%p, str=%p)", env, str));
 
        s = (java_lang_String *) str;
 
@@ -2687,10 +2655,12 @@ jsize _Jv_JNI_GetStringLength(JNIEnv *env, jstring str)
        
 u2 *javastring_tou2(jstring so) 
 {
-       java_lang_String *s;
-       java_chararray   *a;
-       u2               *stringbuffer;
-       u4                i;
+       java_lang_String        *s;
+       java_handle_chararray_t *a;
+       u2                      *stringbuffer;
+       u4                       i;
+       int32_t                  count;
+       int32_t                  offset;
 
        STATISTICS(jniinvokation());
        
@@ -2704,14 +2674,17 @@ u2 *javastring_tou2(jstring so)
        if (!a)
                return NULL;
 
+       LLNI_field_get_val(s, count, count);
+       LLNI_field_get_val(s, offset, offset);
+
        /* allocate memory */
 
-       stringbuffer = MNEW(u2, LLNI_field_direct(s, count) + 1);
+       stringbuffer = MNEW(u2, count + 1);
 
        /* copy text */
 
-       for (i = 0; i < LLNI_field_direct(s, count); i++)
-               stringbuffer[i] = a->data[LLNI_field_direct(s, offset) + i];
+       for (i = 0; i < count; i++)
+               stringbuffer[i] = LLNI_array_direct(a, offset + i);
        
        /* terminate string */
 
@@ -2784,11 +2757,11 @@ jstring _Jv_JNI_NewStringUTF(JNIEnv *env, const char *bytes)
 {
        java_lang_String *s;
 
-       TRACEJNICALLS("_Jv_JNI_NewStringUTF(env=%p, bytes=%s)", env, bytes);
+       TRACEJNICALLS(("_Jv_JNI_NewStringUTF(env=%p, bytes=%s)", env, bytes));
 
        s = (java_lang_String *) javastring_safe_new_from_utf8(bytes);
 
-    return (jstring) _Jv_JNI_NewLocalRef(env, (jobject) s);
+    return (jstring) jni_NewLocalRef(env, (jobject) s);
 }
 
 
@@ -2796,14 +2769,14 @@ jstring _Jv_JNI_NewStringUTF(JNIEnv *env, const char *bytes)
 
 jsize _Jv_JNI_GetStringUTFLength(JNIEnv *env, jstring string)
 {   
-    java_lang_String *s;
+       java_lang_String *s;
        s4                length;
 
-       TRACEJNICALLS("_Jv_JNI_GetStringUTFLength(env=%p, string=%p)", env, string);
+       TRACEJNICALLS(("_Jv_JNI_GetStringUTFLength(env=%p, string=%p)", env, string));
 
        s = (java_lang_String *) string;
 
-    length = u2_utflength(LLNI_field_direct(s, value)->data, LLNI_field_direct(s, count));
+       length = u2_utflength(LLNI_field_direct(s, value)->data, LLNI_field_direct(s, count));
 
        return length;
 }
@@ -2867,13 +2840,16 @@ void _Jv_JNI_ReleaseStringUTFChars(JNIEnv *env, jstring string, const char *utf)
 
 jsize _Jv_JNI_GetArrayLength(JNIEnv *env, jarray array)
 {
-       java_arrayheader *a;
+       java_handle_t *a;
+       jsize          size;
 
-       STATISTICS(jniinvokation());
+       TRACEJNICALLS(("_Jv_JNI_GetArrayLength(env=%p, array=%p)", env, array));
 
-       a = (java_arrayheader *) array;
+       a = (java_handle_t *) array;
 
-       return a->size;
+       size = LLNI_array_size(a);
+
+       return size;
 }
 
 
@@ -2887,14 +2863,14 @@ jsize _Jv_JNI_GetArrayLength(JNIEnv *env, jarray array)
 jobjectArray _Jv_JNI_NewObjectArray(JNIEnv *env, jsize length,
                                                                        jclass elementClass, jobject initialElement)
 {
-       classinfo         *c;
-       java_handle_t     *o;
-       java_objectarray  *oa;
-       s4                 i;
+       classinfo                 *c;
+       java_handle_t             *o;
+       java_handle_objectarray_t *oa;
+       s4                         i;
 
        STATISTICS(jniinvokation());
 
-       c = (classinfo *) elementClass;
+       c = LLNI_classinfo_unwrap(elementClass);
        o = (java_handle_t *) initialElement;
 
        if (length < 0) {
@@ -2910,45 +2886,45 @@ jobjectArray _Jv_JNI_NewObjectArray(JNIEnv *env, jsize length,
        /* set all elements to initialElement */
 
        for (i = 0; i < length; i++)
-               oa->data[i] = o;
+               array_objectarray_element_set(oa, i, o);
 
-       return (jobjectArray) _Jv_JNI_NewLocalRef(env, (jobject) oa);
+       return (jobjectArray) jni_NewLocalRef(env, (jobject) oa);
 }
 
 
 jobject _Jv_JNI_GetObjectArrayElement(JNIEnv *env, jobjectArray array,
                                                                          jsize index)
 {
-       java_objectarray *oa;
-       java_handle_t    *o;
+       java_handle_objectarray_t *oa;
+       java_handle_t             *o;
 
        STATISTICS(jniinvokation());
 
-       oa = (java_objectarray *) array;
+       oa = (java_handle_objectarray_t *) array;
 
-       if (index >= oa->header.size) {
+       if (index >= LLNI_array_size(oa)) {
                exceptions_throw_arrayindexoutofboundsexception();
                return NULL;
        }
 
-       o = oa->data[index];
+       o = array_objectarray_element_get(oa, index);
 
-       return _Jv_JNI_NewLocalRef(env, (jobject) o);
+       return jni_NewLocalRef(env, (jobject) o);
 }
 
 
 void _Jv_JNI_SetObjectArrayElement(JNIEnv *env, jobjectArray array,
                                                                   jsize index, jobject val)
 {
-       java_objectarray *oa;
-       java_handle_t    *o;
+       java_handle_objectarray_t *oa;
+       java_handle_t             *o;
 
        STATISTICS(jniinvokation());
 
-       oa = (java_objectarray *) array;
+       oa = (java_handle_objectarray_t *) array;
        o  = (java_handle_t *) val;
 
-       if (index >= oa->header.size) {
+       if (index >= LLNI_array_size(oa)) {
                exceptions_throw_arrayindexoutofboundsexception();
                return;
        }
@@ -2959,14 +2935,14 @@ void _Jv_JNI_SetObjectArrayElement(JNIEnv *env, jobjectArray array,
        if (!builtin_canstore(oa, o))
                return;
 
-       oa->data[index] = o;
+       array_objectarray_element_set(oa, index, o);
 }
 
 
 #define JNI_NEW_ARRAY(name, type, intern)                \
 type _Jv_JNI_New##name##Array(JNIEnv *env, jsize len)    \
 {                                                        \
-       java_##intern##array *a;                             \
+       java_handle_##intern##array_t *a;                    \
                                                          \
        STATISTICS(jniinvokation());                         \
                                                          \
@@ -2977,13 +2953,13 @@ type _Jv_JNI_New##name##Array(JNIEnv *env, jsize len)    \
                                                          \
        a = builtin_newarray_##intern(len);                  \
                                                          \
-       return (type) _Jv_JNI_NewLocalRef(env, (jobject) a); \
+       return (type) jni_NewLocalRef(env, (jobject) a); \
 }
 
 JNI_NEW_ARRAY(Boolean, jbooleanArray, boolean)
 JNI_NEW_ARRAY(Byte,    jbyteArray,    byte)
 JNI_NEW_ARRAY(Char,    jcharArray,    char)
-JNI_NEW_ARRAY(Short,   jshortArray,   byte)
+JNI_NEW_ARRAY(Short,   jshortArray,   short)
 JNI_NEW_ARRAY(Int,     jintArray,     int)
 JNI_NEW_ARRAY(Long,    jlongArray,    long)
 JNI_NEW_ARRAY(Float,   jfloatArray,   float)
@@ -3000,16 +2976,16 @@ JNI_NEW_ARRAY(Double,  jdoubleArray,  double)
 type *_Jv_JNI_Get##name##ArrayElements(JNIEnv *env, type##Array array, \
                                                                                 jboolean *isCopy)             \
 {                                                                      \
-       java_##intern##array *a;                                           \
+       java_handle_##intern##array_t *a;                                  \
                                                                        \
-       STATISTICS(jniinvokation());                                       \
+       TRACEJNICALLS(("_Jv_JNI_Get" STR(name) "ArrayElements(env=%p, array=%p, isCopy=%d)", env, array, isCopy)); \
                                                                        \
-       a = (java_##intern##array *) array;                                \
+       a = (java_handle_##intern##array_t *) array;                       \
                                                                        \
        if (isCopy)                                                        \
                *isCopy = JNI_FALSE;                                           \
                                                                        \
-       return a->data;                                                    \
+       return (type *) LLNI_array_data(a);                                \
 }
 
 JNI_GET_ARRAY_ELEMENTS(Boolean, jboolean, boolean)
@@ -3033,30 +3009,30 @@ JNI_GET_ARRAY_ELEMENTS(Double,  jdouble,  double)
 
 *******************************************************************************/
 
-#define JNI_RELEASE_ARRAY_ELEMENTS(name, type, intern, intern2)           \
-void _Jv_JNI_Release##name##ArrayElements(JNIEnv *env, type##Array array, \
-                                                                                 type *elems, jint mode)         \
-{                                                                         \
-       java_##intern##array *a;                                              \
-                                                                          \
-       STATISTICS(jniinvokation());                                          \
-                                                                          \
-       a = (java_##intern##array *) array;                                   \
-                                                                          \
-       if (elems != a->data) {                                               \
-               switch (mode) {                                                   \
-               case JNI_COMMIT:                                                  \
-                       MCOPY(a->data, elems, intern2, a->header.size);               \
-                       break;                                                        \
-               case 0:                                                           \
-                       MCOPY(a->data, elems, intern2, a->header.size);               \
-                       /* XXX TWISTI how should it be freed? */                      \
-                       break;                                                        \
-               case JNI_ABORT:                                                   \
-                       /* XXX TWISTI how should it be freed? */                      \
-                       break;                                                        \
-               }                                                                 \
-       }                                                                     \
+#define JNI_RELEASE_ARRAY_ELEMENTS(name, type, intern, intern2)            \
+void _Jv_JNI_Release##name##ArrayElements(JNIEnv *env, type##Array array,  \
+                                                                                 type *elems, jint mode)          \
+{                                                                          \
+       java_handle_##intern##array_t *a;                                      \
+                                                                           \
+       STATISTICS(jniinvokation());                                           \
+                                                                           \
+       a = (java_handle_##intern##array_t *) array;                           \
+                                                                           \
+       if (elems != (type *) LLNI_array_data(a)) {                            \
+               switch (mode) {                                                    \
+               case JNI_COMMIT:                                                   \
+                       MCOPY(LLNI_array_data(a), elems, intern2, LLNI_array_size(a)); \
+                       break;                                                         \
+               case 0:                                                            \
+                       MCOPY(LLNI_array_data(a), elems, intern2, LLNI_array_size(a)); \
+                       /* XXX TWISTI how should it be freed? */                       \
+                       break;                                                         \
+               case JNI_ABORT:                                                    \
+                       /* XXX TWISTI how should it be freed? */                       \
+                       break;                                                         \
+               }                                                                  \
+       }                                                                      \
 }
 
 JNI_RELEASE_ARRAY_ELEMENTS(Boolean, jboolean, boolean, u1)
@@ -3076,20 +3052,20 @@ JNI_RELEASE_ARRAY_ELEMENTS(Double,  jdouble,  double,  double)
 
 *******************************************************************************/
 
-#define JNI_GET_ARRAY_REGION(name, type, intern, intern2)              \
-void _Jv_JNI_Get##name##ArrayRegion(JNIEnv *env, type##Array array,    \
-                                                                       jsize start, jsize len, type *buf) \
-{                                                                      \
-       java_##intern##array *a;                                           \
-                                                                       \
-       STATISTICS(jniinvokation());                                       \
-                                                                       \
-       a = (java_##intern##array *) array;                                \
-                                                                       \
-       if ((start < 0) || (len < 0) || (start + len > a->header.size))    \
-               exceptions_throw_arrayindexoutofboundsexception();             \
-       else                                                               \
-               MCOPY(buf, &a->data[start], intern2, len);                     \
+#define JNI_GET_ARRAY_REGION(name, type, intern, intern2)               \
+void _Jv_JNI_Get##name##ArrayRegion(JNIEnv *env, type##Array array,     \
+                                                                       jsize start, jsize len, type *buf)  \
+{                                                                       \
+       java_handle_##intern##array_t *a;                                   \
+                                                                        \
+       TRACEJNICALLS(("_Jv_JNI_Get" STR(name) "ArrayRegion(env=%p, array=%p, start=%d, len=%d, buf=%p)", env, array, start, len, buf)); \
+                                                                        \
+       a = (java_handle_##intern##array_t *) array;                        \
+                                                                        \
+       if ((start < 0) || (len < 0) || (start + len > LLNI_array_size(a))) \
+               exceptions_throw_arrayindexoutofboundsexception();              \
+       else                                                                \
+               MCOPY(buf, &LLNI_array_direct(a, start), intern2, len);         \
 }
 
 JNI_GET_ARRAY_REGION(Boolean, jboolean, boolean, u1)
@@ -3113,16 +3089,16 @@ JNI_GET_ARRAY_REGION(Double,  jdouble,  double,  double)
 void _Jv_JNI_Set##name##ArrayRegion(JNIEnv *env, type##Array array,          \
                                                                        jsize start, jsize len, const type *buf) \
 {                                                                            \
-       java_##intern##array *a;                                                 \
+       java_handle_##intern##array_t *a;                                        \
                                                                              \
        STATISTICS(jniinvokation());                                             \
                                                                              \
-       a = (java_##intern##array *) array;                                      \
+       a = (java_handle_##intern##array_t *) array;                             \
                                                                              \
-       if ((start < 0) || (len < 0) || (start + len > a->header.size))          \
+       if ((start < 0) || (len < 0) || (start + len > LLNI_array_size(a)))      \
                exceptions_throw_arrayindexoutofboundsexception();                   \
        else                                                                     \
-               MCOPY(&a->data[start], buf, intern2, len);                           \
+               MCOPY(&LLNI_array_direct(a, start), buf, intern2, len);              \
 }
 
 JNI_SET_ARRAY_REGION(Boolean, jboolean, boolean, u1)
@@ -3154,7 +3130,7 @@ jint _Jv_JNI_RegisterNatives(JNIEnv *env, jclass clazz,
 
        STATISTICS(jniinvokation());
 
-       c = (classinfo *) clazz;
+       c = LLNI_classinfo_unwrap(clazz);
 
        /* XXX: if implemented this needs a call to jvmti_NativeMethodBind
        if (jvmti) jvmti_NativeMethodBind(method, address,  new_address_ptr);
@@ -3253,7 +3229,7 @@ jint _Jv_JNI_GetJavaVM(JNIEnv *env, JavaVM **vm)
 {
        STATISTICS(jniinvokation());
 
-    *vm = (JavaVM *) _Jv_jvm;
+    *vm = VM_get_javavm();
 
        return 0;
 }
@@ -3271,8 +3247,8 @@ jint _Jv_JNI_GetJavaVM(JNIEnv *env, JavaVM **vm)
 void _Jv_JNI_GetStringRegion(JNIEnv* env, jstring str, jsize start, jsize len,
                                                         jchar *buf)
 {
-       java_lang_String *s;
-       java_chararray   *ca;
+       java_lang_String        *s;
+       java_handle_chararray_t *ca;
 
        STATISTICS(jniinvokation());
 
@@ -3285,7 +3261,7 @@ void _Jv_JNI_GetStringRegion(JNIEnv* env, jstring str, jsize start, jsize len,
                return;
        }
 
-       MCOPY(buf, &ca->data[start], u2, len);
+       MCOPY(buf, &LLNI_array_direct(ca, start), u2, len);
 }
 
 
@@ -3302,23 +3278,26 @@ void _Jv_JNI_GetStringRegion(JNIEnv* env, jstring str, jsize start, jsize len,
 void _Jv_JNI_GetStringUTFRegion(JNIEnv* env, jstring str, jsize start,
                                                                jsize len, char *buf)
 {
-       java_lang_String *s;
-       java_chararray   *ca;
-       s4                i;
+       java_lang_String        *s;
+       java_handle_chararray_t *ca;
+       s4                       i;
+       int32_t                  count;
+       int32_t                  offset;
 
-       TRACEJNICALLS("_Jv_JNI_GetStringUTFRegion(env=%p, str=%p, start=%d, len=%d, buf=%p)", env, str, start, len, buf);
+       TRACEJNICALLS(("_Jv_JNI_GetStringUTFRegion(env=%p, str=%p, start=%d, len=%d, buf=%p)", env, str, start, len, buf));
 
        s  = (java_lang_String *) str;
        LLNI_field_get_ref(s, value, ca);
+       LLNI_field_get_val(s, count, count);
+       LLNI_field_get_val(s, offset, offset);
 
-       if ((start < 0) || (len < 0) || (start > LLNI_field_direct(s, count)) ||
-               (start + len > LLNI_field_direct(s, count))) {
+       if ((start < 0) || (len < 0) || (start > count) || (start + len > count)) {
                exceptions_throw_stringindexoutofboundsexception();
                return;
        }
 
        for (i = 0; i < len; i++)
-               buf[i] = ca->data[LLNI_field_direct(s, offset) + start + i];
+               buf[i] = LLNI_array_direct(ca, offset + start + i);
 
        buf[i] = '\0';
 }
@@ -3328,21 +3307,37 @@ void _Jv_JNI_GetStringUTFRegion(JNIEnv* env, jstring str, jsize start,
 
    Obtain a direct pointer to array elements.
 
+   ATTENTION: Critical section keeps open when this function returns!
+   See ReleasePrimitiveArrayCritical.
+
 *******************************************************************************/
 
-void *_Jv_JNI_GetPrimitiveArrayCritical(JNIEnv *env, jarray array,
-                                                                               jboolean *isCopy)
+void* jni_GetPrimitiveArrayCritical(JNIEnv *env, jarray array, jboolean *isCopy)
 {
-       java_bytearray *ba;
-       jbyte          *bp;
+       java_handle_t*   h;
+       java_array_t*    a;
+       arraydescriptor* ad;
+       void*            data;
+
+       TRACEJNICALLS(("jni_GetPrimitiveArrayCritical(env=%p, array=%p, isCopy=%d)", env, array, isCopy));
+
+       if (isCopy != NULL) {
+               *isCopy = JNI_FALSE;
+       }
+
+       LLNI_CRITICAL_START;
+
+       h  = (java_handle_t*) array;
+       a  = (java_array_t*) LLNI_UNWRAP(h);
+       ad = a->objheader.vftbl->arraydesc;
 
-       ba = (java_bytearray *) array;
+       /* Sanity check. */
 
-       /* do the same as Kaffe does */
+       assert(ad != NULL);
 
-       bp = _Jv_JNI_GetByteArrayElements(env, (jbyteArray) ba, isCopy);
+       data = (void*) (((intptr_t) a) + ad->dataoffset);
 
-       return (void *) bp;
+       return data;
 }
 
 
@@ -3350,17 +3345,16 @@ void *_Jv_JNI_GetPrimitiveArrayCritical(JNIEnv *env, jarray array,
 
    No specific documentation.
 
+   ATTENTION: This function closes the critical section opened in
+   GetPrimitiveArrayCritical!
+
 *******************************************************************************/
 
-void _Jv_JNI_ReleasePrimitiveArrayCritical(JNIEnv *env, jarray array,
-                                                                                  void *carray, jint mode)
+void jni_ReleasePrimitiveArrayCritical(JNIEnv *env, jarray array, void *carray, jint mode)
 {
-       STATISTICS(jniinvokation());
+       TRACEJNICALLS(("jni_ReleasePrimitiveArrayCritical(env=%p, array=%p, carray=%p, mode=%d)", env, array, carray, mode));
 
-       /* do the same as Kaffe does */
-
-       _Jv_JNI_ReleaseByteArrayElements(env, (jbyteArray) array, (jbyte *) carray,
-                                                                        mode);
+       LLNI_CRITICAL_END;
 }
 
 
@@ -3391,9 +3385,7 @@ void _Jv_JNI_ReleaseStringCritical(JNIEnv *env, jstring string,
 
 jweak _Jv_JNI_NewWeakGlobalRef(JNIEnv* env, jobject obj)
 {
-       STATISTICS(jniinvokation());
-
-       log_text("JNI-Call: NewWeakGlobalRef: IMPLEMENT ME!");
+       TRACEJNICALLS(("_Jv_JNI_NewWeakGlobalRef(env=%p, obj=%p): IMPLEMENT ME!", env, obj));
 
        return obj;
 }
@@ -3401,9 +3393,7 @@ jweak _Jv_JNI_NewWeakGlobalRef(JNIEnv* env, jobject obj)
 
 void _Jv_JNI_DeleteWeakGlobalRef(JNIEnv* env, jweak ref)
 {
-       STATISTICS(jniinvokation());
-
-       log_text("JNI-Call: DeleteWeakGlobalRef: IMPLEMENT ME");
+       TRACEJNICALLS(("_Jv_JNI_DeleteWeakGlobalRef(env=%p, ref=%p): IMPLEMENT ME", env, ref));
 }
 
 
@@ -3414,67 +3404,79 @@ void _Jv_JNI_DeleteWeakGlobalRef(JNIEnv* env, jweak ref)
 
 *******************************************************************************/
     
-jobject _Jv_JNI_NewGlobalRef(JNIEnv* env, jobject obj)
+jobject jni_NewGlobalRef(JNIEnv* env, jobject obj)
 {
        hashtable_global_ref_entry *gre;
        u4   key;                           /* hashkey                            */
        u4   slot;                          /* slot in hashtable                  */
        java_handle_t *o;
 
-       STATISTICS(jniinvokation());
+       TRACEJNICALLS(("jni_NewGlobalRef(env=%p, obj=%p)", env, obj));
 
        o = (java_handle_t *) obj;
 
        LOCK_MONITOR_ENTER(hashtable_global_ref->header);
 
+       LLNI_CRITICAL_START;
+
        /* normally addresses are aligned to 4, 8 or 16 bytes */
 
-       key  = ((u4) (ptrint) obj) >> 4;           /* align to 16-byte boundaries */
+       key  = heap_hashcode(LLNI_DIRECT(o)) >> 4; /* align to 16-byte boundaries */
        slot = key & (hashtable_global_ref->size - 1);
        gre  = hashtable_global_ref->ptr[slot];
        
        /* search external hash chain for the entry */
 
        while (gre) {
-               if (gre->o == o) {
+               if (gre->o == LLNI_DIRECT(o)) {
                        /* global object found, increment the reference */
 
                        gre->refs++;
 
-                       LOCK_MONITOR_EXIT(hashtable_global_ref->header);
-
-                       return obj;
+                       break;
                }
 
                gre = gre->hashlink;                /* next element in external chain */
        }
 
+       LLNI_CRITICAL_END;
+
        /* global ref not found, create a new one */
 
-       gre = NEW(hashtable_global_ref_entry);
+       if (gre == NULL) {
+               gre = GCNEW_UNCOLLECTABLE(hashtable_global_ref_entry, 1);
 
 #if defined(ENABLE_GC_CACAO)
-       /* register global ref with the GC */
+               /* register global ref with the GC */
 
-       gc_reference_register(&(gre->o));
+               gc_reference_register(&(gre->o), GC_REFTYPE_JNI_GLOBALREF);
 #endif
 
-       gre->o    = o;
-       gre->refs = 1;
+               LLNI_CRITICAL_START;
+
+               gre->o    = LLNI_DIRECT(o);
+               gre->refs = 1;
+
+               LLNI_CRITICAL_END;
 
-       /* insert entry into hashtable */
+               /* insert entry into hashtable */
 
-       gre->hashlink = hashtable_global_ref->ptr[slot];
+               gre->hashlink = hashtable_global_ref->ptr[slot];
 
-       hashtable_global_ref->ptr[slot] = gre;
+               hashtable_global_ref->ptr[slot] = gre;
 
-       /* update number of hashtable-entries */
+               /* update number of hashtable-entries */
 
-       hashtable_global_ref->entries++;
+               hashtable_global_ref->entries++;
+       }
 
        LOCK_MONITOR_EXIT(hashtable_global_ref->header);
 
+#if defined(ENABLE_HANDLES)
+       return gre;
+#else
        return obj;
+#endif
 }
 
 
@@ -3484,7 +3486,7 @@ jobject _Jv_JNI_NewGlobalRef(JNIEnv* env, jobject obj)
 
 *******************************************************************************/
 
-void _Jv_JNI_DeleteGlobalRef(JNIEnv* env, jobject globalRef)
+void jni_DeleteGlobalRef(JNIEnv* env, jobject globalRef)
 {
        hashtable_global_ref_entry *gre;
        hashtable_global_ref_entry *prevgre;
@@ -3492,15 +3494,17 @@ void _Jv_JNI_DeleteGlobalRef(JNIEnv* env, jobject globalRef)
        u4   slot;                          /* slot in hashtable                  */
        java_handle_t              *o;
 
-       STATISTICS(jniinvokation());
+       TRACEJNICALLS(("jni_DeleteGlobalRef(env=%p, globalRef=%p)", env, globalRef));
 
        o = (java_handle_t *) globalRef;
 
        LOCK_MONITOR_ENTER(hashtable_global_ref->header);
 
+       LLNI_CRITICAL_START;
+
        /* normally addresses are aligned to 4, 8 or 16 bytes */
 
-       key  = ((u4) (ptrint) globalRef) >> 4;     /* align to 16-byte boundaries */
+       key  = heap_hashcode(LLNI_DIRECT(o)) >> 4; /* align to 16-byte boundaries */
        slot = key & (hashtable_global_ref->size - 1);
        gre  = hashtable_global_ref->ptr[slot];
 
@@ -3511,7 +3515,7 @@ void _Jv_JNI_DeleteGlobalRef(JNIEnv* env, jobject globalRef)
        /* search external hash chain for the entry */
 
        while (gre) {
-               if (gre->o == o) {
+               if (gre->o == LLNI_DIRECT(o)) {
                        /* global object found, decrement the reference count */
 
                        gre->refs--;
@@ -3532,9 +3536,11 @@ void _Jv_JNI_DeleteGlobalRef(JNIEnv* env, jobject globalRef)
                                gc_reference_unregister(&(gre->o));
 #endif
 
-                               FREE(gre, hashtable_global_ref_entry);
+                               GCFREE(gre);
                        }
 
+                       LLNI_CRITICAL_END;
+
                        LOCK_MONITOR_EXIT(hashtable_global_ref->header);
 
                        return;
@@ -3544,7 +3550,9 @@ void _Jv_JNI_DeleteGlobalRef(JNIEnv* env, jobject globalRef)
                gre     = gre->hashlink;            /* next element in external chain */
        }
 
-       log_println("JNI-DeleteGlobalRef: global reference not found");
+       log_println("jni_DeleteGlobalRef: Global reference not found.");
+
+       LLNI_CRITICAL_END;
 
        LOCK_MONITOR_EXIT(hashtable_global_ref->header);
 }
@@ -3579,9 +3587,10 @@ jboolean _Jv_JNI_ExceptionCheck(JNIEnv *env)
 
 *******************************************************************************/
 
-jobject _Jv_JNI_NewDirectByteBuffer(JNIEnv *env, void *address, jlong capacity)
+jobject jni_NewDirectByteBuffer(JNIEnv *env, void *address, jlong capacity)
 {
-#if defined(ENABLE_JAVASE) && defined(WITH_CLASSPATH_GNU)
+#if defined(ENABLE_JAVASE)
+# if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
        java_handle_t           *nbuf;
 
 # if SIZEOF_VOID_P == 8
@@ -3590,7 +3599,7 @@ jobject _Jv_JNI_NewDirectByteBuffer(JNIEnv *env, void *address, jlong capacity)
        gnu_classpath_Pointer32 *paddress;
 # endif
 
-       STATISTICS(jniinvokation());
+       TRACEJNICALLSENTER(("jni_NewDirectByteBuffer(env=%p, address=%p, capacity=%ld)", env, address, capacity));
 
        /* alocate a gnu.classpath.Pointer{32,64} object */
 
@@ -3615,9 +3624,38 @@ jobject _Jv_JNI_NewDirectByteBuffer(JNIEnv *env, void *address, jlong capacity)
 
        /* add local reference and return the value */
 
-       return _Jv_JNI_NewLocalRef(env, nbuf);
+       TRACEJNICALLSEXIT(("->%p", nbuf));
+
+       return jni_NewLocalRef(env, nbuf);
+
+# elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
+
+       jobject o;
+       int64_t addr;
+       int32_t cap;
+
+       TRACEJNICALLSENTER(("jni_NewDirectByteBuffer(env=%p, address=%p, capacity=%ld)", env, address, capacity));
+
+       /* Be paranoid about address sign-extension. */
+
+       addr = (int64_t) ((uintptr_t) address);
+       cap  = (int32_t) capacity;
+
+       o = (*env)->NewObject(env, (jclass) class_java_nio_DirectByteBuffer,
+                                                 (jmethodID) dbb_init, addr, cap);
+
+       /* Add local reference and return the value. */
+
+       TRACEJNICALLSEXIT(("->%p", o));
+
+       return jni_NewLocalRef(env, o);
+
+# else
+#  error unknown classpath configuration
+# endif
+
 #else
-       vm_abort("_Jv_JNI_NewDirectByteBuffer: not implemented in this configuration");
+       vm_abort("jni_NewDirectByteBuffer: Not implemented in this configuration.");
 
        /* keep compiler happy */
 
@@ -3635,43 +3673,85 @@ jobject _Jv_JNI_NewDirectByteBuffer(JNIEnv *env, void *address, jlong capacity)
 
 void *_Jv_JNI_GetDirectBufferAddress(JNIEnv *env, jobject buf)
 {
-#if defined(ENABLE_JAVASE) && defined(WITH_CLASSPATH_GNU)
+#if defined(ENABLE_JAVASE)
+       java_handle_t                 *h;
+
+# if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
+
        java_nio_DirectByteBufferImpl *nbuf;
-# if SIZEOF_VOID_P == 8
+       gnu_classpath_Pointer         *po;
+#  if SIZEOF_VOID_P == 8
        gnu_classpath_Pointer64       *paddress;
-# else
+       int64_t                        address;
+#  else
        gnu_classpath_Pointer32       *paddress;
-# endif
-       void                          *address;
+       int32_t                        address;
+#  endif
+       void                          *p;
 
-       STATISTICS(jniinvokation());
+       TRACEJNICALLS(("_Jv_JNI_GetDirectBufferAddress(env=%p, buf=%p)", env, buf));
+
+       /* Prevent compiler warning. */
+
+       h = (java_handle_t *) buf;
 
-       if (!builtin_instanceof(buf, class_java_nio_Buffer))
+       if ((h != NULL) && !builtin_instanceof(h, class_java_nio_Buffer))
                return NULL;
 
        nbuf = (java_nio_DirectByteBufferImpl *) buf;
 
-# if SIZEOF_VOID_P == 8
-       LLNI_field_get_ref(nbuf, address, paddress);
-       /* this was the cast to avaoid warning: (gnu_classpath_Pointer64 *) nbuf->address; */
-# else
-       LLNI_field_get_ref(nbuf, address, paddress); 
-       /* this was the cast to avaoid warning: (gnu_classpath_Pointer32 *) nbuf->address; */
-# endif
+       LLNI_field_get_ref(nbuf, address, po);
+
+#  if SIZEOF_VOID_P == 8
+       paddress = (gnu_classpath_Pointer64 *) po;
+#  else
+       paddress = (gnu_classpath_Pointer32 *) po;
+#  endif
 
        if (paddress == NULL)
                return NULL;
 
        LLNI_field_get_val(paddress, data, address);
-       /* this was the cast to avaoid warning: (void *) paddress->data */
 
-       return address;
+       p = (void *) (intptr_t) address;
+
+       return p;
+
+# elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
+
+       java_nio_Buffer *o;
+       int64_t          address;
+       void            *p;
+
+       TRACEJNICALLS(("_Jv_JNI_GetDirectBufferAddress(env=%p, buf=%p)", env, buf));
+
+       /* Prevent compiler warning. */
+
+       h = (java_handle_t *) buf;
+
+       if ((h != NULL) && !builtin_instanceof(h, class_sun_nio_ch_DirectBuffer))
+               return NULL;
+
+       o = (java_nio_Buffer *) buf;
+
+       LLNI_field_get_val(o, address, address);
+
+       p = (void *) (intptr_t) address;
+
+       return p;
+
+# else
+#  error unknown classpath configuration
+# endif
+
 #else
+
        vm_abort("_Jv_JNI_GetDirectBufferAddress: not implemented in this configuration");
 
        /* keep compiler happy */
 
        return NULL;
+
 #endif
 }
 
@@ -3685,7 +3765,7 @@ void *_Jv_JNI_GetDirectBufferAddress(JNIEnv *env, jobject buf)
 
 jlong _Jv_JNI_GetDirectBufferCapacity(JNIEnv* env, jobject buf)
 {
-#if defined(ENABLE_JAVASE) && defined(WITH_CLASSPATH_GNU)
+#if defined(ENABLE_JAVASE) && defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
        java_handle_t   *o;
        java_nio_Buffer *nbuf;
        jlong            capacity;
@@ -3712,6 +3792,22 @@ jlong _Jv_JNI_GetDirectBufferCapacity(JNIEnv* env, jobject buf)
 }
 
 
+/* GetObjectRefType ************************************************************
+
+   Returns the type of the object referred to by the obj argument. The
+   argument obj can either be a local, global or weak global
+   reference.
+
+*******************************************************************************/
+
+jobjectRefType jni_GetObjectRefType(JNIEnv *env, jobject obj)
+{
+       log_println("jni_GetObjectRefType: IMPLEMENT ME!");
+
+       return -1;
+}
+
+
 /* DestroyJavaVM ***************************************************************
 
    Unloads a Java VM and reclaims its resources. Only the main thread
@@ -3722,9 +3818,12 @@ jlong _Jv_JNI_GetDirectBufferCapacity(JNIEnv* env, jobject buf)
 
 jint _Jv_JNI_DestroyJavaVM(JavaVM *vm)
 {
-       s4 status;
+       int status;
 
-       STATISTICS(jniinvokation());
+       TRACEJNICALLS(("_Jv_JNI_DestroyJavaVM(vm=%p)", vm));
+
+       if (VM_is_created() == false)
+               return JNI_ERR;
 
     status = vm_destroy(vm);
 
@@ -3746,39 +3845,56 @@ jint _Jv_JNI_DestroyJavaVM(JavaVM *vm)
 
 *******************************************************************************/
 
-static s4 jni_attach_current_thread(void **p_env, void *thr_args, bool isdaemon)
+static int jni_attach_current_thread(void **p_env, void *thr_args, bool isdaemon)
 {
+#if defined(ENABLE_THREADS)
        JavaVMAttachArgs *vm_aargs;
+       bool              result;
 
-#if defined(ENABLE_THREADS)
-       if (threads_get_current_threadobject() == NULL) {
-               vm_aargs = (JavaVMAttachArgs *) thr_args;
+    /* If the current thread has already been attached, this operation
+          is a no-op. */
 
-               if (vm_aargs != NULL) {
-                       if ((vm_aargs->version != JNI_VERSION_1_2) &&
-                               (vm_aargs->version != JNI_VERSION_1_4))
-                               return JNI_EVERSION;
-               }
+       result = thread_current_is_attached();
+
+       if (result == true) {
+               *p_env = VM_get_jnienv();
+
+               return JNI_OK;
+       }
 
-               if (!threads_attach_current_thread(vm_aargs, false))
-                       return JNI_ERR;
+       vm_aargs = (JavaVMAttachArgs *) thr_args;
 
-               if (!localref_table_init())
-                       return JNI_ERR;
+       if (vm_aargs != NULL) {
+               if ((vm_aargs->version != JNI_VERSION_1_2) &&
+                       (vm_aargs->version != JNI_VERSION_1_4))
+                       return JNI_EVERSION;
        }
+
+       if (!thread_attach_current_external_thread(vm_aargs, false))
+               return JNI_ERR;
+
+       if (!localref_table_init())
+               return JNI_ERR;
 #endif
 
-       *p_env = _Jv_env;
+       *p_env = VM_get_jnienv();
 
        return JNI_OK;
 }
 
 
-jint _Jv_JNI_AttachCurrentThread(JavaVM *vm, void **p_env, void *thr_args)
+jint jni_AttachCurrentThread(JavaVM *vm, void **p_env, void *thr_args)
 {
-       STATISTICS(jniinvokation());
+       int result;
 
-       return jni_attach_current_thread(p_env, thr_args, false);
+       TRACEJNICALLS(("jni_AttachCurrentThread(vm=%p, p_env=%p, thr_args=%p)", vm, p_env, thr_args));
+
+       if (VM_is_created() == false)
+               return JNI_ERR;
+
+       result = jni_attach_current_thread(p_env, thr_args, false);
+
+       return result;
 }
 
 
@@ -3799,22 +3915,29 @@ jint _Jv_JNI_AttachCurrentThread(JavaVM *vm, void **p_env, void *thr_args)
 
 *******************************************************************************/
 
-jint _Jv_JNI_DetachCurrentThread(JavaVM *vm)
+jint jni_DetachCurrentThread(JavaVM *vm)
 {
 #if defined(ENABLE_THREADS)
-       threadobject *thread;
+       bool result;
 
-       STATISTICS(jniinvokation());
+       TRACEJNICALLS(("jni_DetachCurrentThread(vm=%p)", vm));
 
-       thread = threads_get_current_threadobject();
+    /* If the current thread has already been detached, this operation
+          is a no-op. */
 
-       if (thread == NULL)
-               return JNI_ERR;
+       result = thread_current_is_attached();
+
+       if (result == false)
+               return true;
 
-       if (!jni_free_localref_table())
+       /* We need to pop all frames before we can destroy the table. */
+
+       localref_frame_pop_all();
+
+       if (!localref_table_destroy())
                return JNI_ERR;
 
-       if (!threads_detach_thread(thread))
+       if (!thread_detach_current_external_thread())
                return JNI_ERR;
 #endif
 
@@ -3831,29 +3954,28 @@ jint _Jv_JNI_DetachCurrentThread(JavaVM *vm)
 
 *******************************************************************************/
 
-jint _Jv_JNI_GetEnv(JavaVM *vm, void **env, jint version)
+jint jni_GetEnv(JavaVM *vm, void **env, jint version)
 {
-       STATISTICS(jniinvokation());
+       TRACEJNICALLS(("jni_GetEnv(vm=%p, env=%p, version=%d)", vm, env, version));
+
+       if (VM_is_created() == false) {
+               *env = NULL;
+               return JNI_EDETACHED;
+       }
 
 #if defined(ENABLE_THREADS)
-       if (threads_get_current_threadobject() == NULL) {
+       if (thread_get_current() == NULL) {
                *env = NULL;
 
                return JNI_EDETACHED;
        }
 #endif
 
-       /* check the JNI version */
+       /* Check the JNI version. */
 
-       switch (version) {
-       case JNI_VERSION_1_1:
-       case JNI_VERSION_1_2:
-       case JNI_VERSION_1_4:
-               *env = _Jv_env;
+       if (jni_version_check(version) == true) {
+               *env = VM_get_jnienv();
                return JNI_OK;
-
-       default:
-               ;
        }
 
 #if defined(ENABLE_JVMTI)
@@ -3886,11 +4008,18 @@ jint _Jv_JNI_GetEnv(JavaVM *vm, void **env, jint version)
 
 *******************************************************************************/
 
-jint _Jv_JNI_AttachCurrentThreadAsDaemon(JavaVM *vm, void **penv, void *args)
+jint jni_AttachCurrentThreadAsDaemon(JavaVM *vm, void **penv, void *args)
 {
-       STATISTICS(jniinvokation());
+       int result;
+
+       TRACEJNICALLS(("jni_AttachCurrentThreadAsDaemon(vm=%p, penv=%p, args=%p)", vm, penv, args));
+
+       if (VM_is_created() == false)
+               return JNI_ERR;
 
-       return jni_attach_current_thread(penv, args, true);
+       result = jni_attach_current_thread(penv, args, true);
+
+       return result;
 }
 
 
@@ -3902,10 +4031,10 @@ const struct JNIInvokeInterface_ _Jv_JNIInvokeInterface = {
        NULL,
 
        _Jv_JNI_DestroyJavaVM,
-       _Jv_JNI_AttachCurrentThread,
-       _Jv_JNI_DetachCurrentThread,
-       _Jv_JNI_GetEnv,
-       _Jv_JNI_AttachCurrentThreadAsDaemon
+       jni_AttachCurrentThread,
+       jni_DetachCurrentThread,
+       jni_GetEnv,
+       jni_AttachCurrentThreadAsDaemon
 };
 
 
@@ -3919,9 +4048,9 @@ struct JNINativeInterface_ _Jv_JNINativeInterface = {
        _Jv_JNI_GetVersion,
 
        _Jv_JNI_DefineClass,
-       _Jv_JNI_FindClass,
-       _Jv_JNI_FromReflectedMethod,
-       _Jv_JNI_FromReflectedField,
+       jni_FindClass,
+       jni_FromReflectedMethod,
+       jni_FromReflectedField,
        _Jv_JNI_ToReflectedMethod,
        _Jv_JNI_GetSuperclass,
        _Jv_JNI_IsAssignableFrom,
@@ -3930,21 +4059,21 @@ struct JNINativeInterface_ _Jv_JNINativeInterface = {
        _Jv_JNI_Throw,
        _Jv_JNI_ThrowNew,
        _Jv_JNI_ExceptionOccurred,
-       _Jv_JNI_ExceptionDescribe,
-       _Jv_JNI_ExceptionClear,
+       jni_ExceptionDescribe,
+       jni_ExceptionClear,
        _Jv_JNI_FatalError,
-       _Jv_JNI_PushLocalFrame,
-       _Jv_JNI_PopLocalFrame,
+       jni_PushLocalFrame,
+       jni_PopLocalFrame,
 
-       _Jv_JNI_NewGlobalRef,
-       _Jv_JNI_DeleteGlobalRef,
-       _Jv_JNI_DeleteLocalRef,
+       jni_NewGlobalRef,
+       jni_DeleteGlobalRef,
+       jni_DeleteLocalRef,
        _Jv_JNI_IsSameObject,
-       _Jv_JNI_NewLocalRef,
-       _Jv_JNI_EnsureLocalCapacity,
+       jni_NewLocalRef,
+       jni_EnsureLocalCapacity,
 
        _Jv_JNI_AllocObject,
-       _Jv_JNI_NewObject,
+       jni_NewObject,
        _Jv_JNI_NewObjectV,
        _Jv_JNI_NewObjectA,
 
@@ -4158,13 +4287,13 @@ struct JNINativeInterface_ _Jv_JNINativeInterface = {
 
        _Jv_JNI_GetJavaVM,
 
-       /* new JNI 1.2 functions */
+       /* New JNI 1.2 functions. */
 
        _Jv_JNI_GetStringRegion,
        _Jv_JNI_GetStringUTFRegion,
 
-       _Jv_JNI_GetPrimitiveArrayCritical,
-       _Jv_JNI_ReleasePrimitiveArrayCritical,
+       jni_GetPrimitiveArrayCritical,
+       jni_ReleasePrimitiveArrayCritical,
 
        _Jv_JNI_GetStringCritical,
        _Jv_JNI_ReleaseStringCritical,
@@ -4174,11 +4303,15 @@ struct JNINativeInterface_ _Jv_JNINativeInterface = {
 
        _Jv_JNI_ExceptionCheck,
 
-       /* new JNI 1.4 functions */
+       /* New JNI 1.4 functions. */
 
-       _Jv_JNI_NewDirectByteBuffer,
+       jni_NewDirectByteBuffer,
        _Jv_JNI_GetDirectBufferAddress,
-       _Jv_JNI_GetDirectBufferCapacity
+       _Jv_JNI_GetDirectBufferCapacity,
+
+       /* New JNI 1.6 functions. */
+
+       jni_GetObjectRefType
 };
 
 
@@ -4229,14 +4362,14 @@ jint JNI_GetDefaultJavaVMInitArgs(void *vm_args)
 
 jint JNI_GetCreatedJavaVMs(JavaVM **vmBuf, jsize bufLen, jsize *nVMs)
 {
-       TRACEJNICALLS("JNI_GetCreatedJavaVMs(vmBuf=%p, jsize=%d, jsize=%p)", vmBuf, bufLen, nVMs);
+       TRACEJNICALLS(("JNI_GetCreatedJavaVMs(vmBuf=%p, jsize=%d, jsize=%p)", vmBuf, bufLen, nVMs));
 
        if (bufLen <= 0)
                return JNI_ERR;
 
        /* We currently only support 1 VM running. */
 
-       vmBuf[0] = (JavaVM *) _Jv_jvm;
+       vmBuf[0] = VM_get_javavm();
        *nVMs    = 1;
 
     return JNI_OK;
@@ -4252,11 +4385,11 @@ jint JNI_GetCreatedJavaVMs(JavaVM **vmBuf, jsize bufLen, jsize *nVMs)
 
 jint JNI_CreateJavaVM(JavaVM **p_vm, void **p_env, void *vm_args)
 {
-       TRACEJNICALLS("JNI_CreateJavaVM(p_vm=%p, p_env=%p, vm_args=%p)", p_vm, p_env, vm_args);
+       TRACEJNICALLS(("JNI_CreateJavaVM(p_vm=%p, p_env=%p, vm_args=%p)", p_vm, p_env, vm_args));
 
        /* actually create the JVM */
 
-       if (!vm_createjvm(p_vm, p_env, vm_args))
+       if (!VM_create(p_vm, p_env, vm_args))
                return JNI_ERR;
 
        return JNI_OK;