Merged revisions 8299-8320 via svnmerge from
[cacao.git] / src / native / jni.c
index fe9e3defc2cba77a40f0440e8143bf2eb0d32c83..aa7d44e92e3bbedbf4506339dddaf6c39ecf5db0 100644 (file)
@@ -1,9 +1,9 @@
-/* jni.c - implementation of the Java Native Interface functions
+/* src/native/jni.c - implementation of the Java Native Interface functions
 
-   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
-   R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser,
-   M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck,
-   P. Tomsich, J. Wenninger
+   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
 
    This file is part of CACAO.
 
 
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-   02111-1307, USA.
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA.
 
-   Contact: cacao@complang.tuwien.ac.at
+   $Id: jni.c 8321 2007-08-16 11:37:25Z michi $
 
-   Authors: ?
+*/
 
-   Changes: Joseph Wenninger
 
-   $Id: jni.c 1005 2004-03-30 23:01:45Z twisti $
+#include "config.h"
 
-*/
+#include <assert.h>
+#include <stdint.h>
+#include <string.h>
 
+#include "vm/types.h"
 
-#include <string.h>
-#include "jni.h"
-#include "global.h"
-#include "loader.h"
-#include "tables.h"
-#include "native.h"
-#include "builtin.h"
-#include "threads/thread.h"
-#include "toolbox/loging.h"
-#include "toolbox/memory.h"
-#include "nat/java_lang_Byte.h"
-#include "nat/java_lang_Character.h"
-#include "nat/java_lang_Short.h"
-#include "nat/java_lang_Integer.h"
-#include "nat/java_lang_Boolean.h"
-#include "nat/java_lang_Long.h"
-#include "nat/java_lang_Float.h"
-#include "nat/java_lang_Double.h"
-#include "nat/java_lang_Throwable.h"
-#include "jit/jit.h"
-#include "asmpart.h"   
-#define JNI_VERSION       0x00010002
-
-
-#define PTR_TO_ITEM(ptr)   ((u8)(size_t)(ptr))
-
-static utf* utf_char = 0;
-static utf* utf_bool = 0;
-static utf* utf_byte  =0;
-static utf* utf_short = 0;
-static utf* utf_int = 0;
-static utf* utf_long = 0;
-static utf* utf_float = 0;
-static utf* utf_double = 0;
-
-
-/********************* accessing instance-fields **********************************/
-
-#define setField(obj,typ,var,val) *((typ*) ((long int) obj + (long int) var->offset))=val;  
-#define getField(obj,typ,var)     *((typ*) ((long int) obj + (long int) var->offset))
-#define setfield_critical(clazz,obj,name,sig,jdatatype,val) setField(obj,jdatatype,getFieldID_critical(env,clazz,name,sig),val); 
-
-
-
-u4 get_parametercount(methodinfo *m)
-{
-       utf  *descr    =  m->descriptor;    /* method-descriptor */
-       char *utf_ptr  =  descr->text;      /* current position in utf-text */
-       char *desc_end =  utf_end(descr);   /* points behind utf string     */
-       u4 parametercount = 0;
-
-       /* skip '(' */
-       utf_nextu2(&utf_ptr);
-
-    /* determine number of parameters */
-       while (*utf_ptr != ')') {
-               get_type(&utf_ptr, desc_end, true);
-               parametercount++;
-       }
+#include "mm/gc-common.h"
+#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)
+#  include "native/include/gnu_classpath_Pointer.h"
+
+#  if SIZEOF_VOID_P == 8
+#   include "native/include/gnu_classpath_Pointer64.h"
+#  else
+#   include "native/include/gnu_classpath_Pointer32.h"
+#  endif
+# endif
+#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)
+#  include "native/include/java_nio_ByteBuffer.h"       /* required by j.l.CL */
+# endif
+
+# include "native/include/java_lang_ClassLoader.h"
+
+# include "native/include/java_lang_reflect_Constructor.h"
+# include "native/include/java_lang_reflect_Field.h"
+# include "native/include/java_lang_reflect_Method.h"
+
+# include "native/include/java_nio_Buffer.h"
+
+# if defined(WITH_CLASSPATH_GNU)
+#  include "native/include/java_nio_DirectByteBufferImpl.h"
+# endif
+#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 "toolbox/logging.h"
+
+#include "vm/builtin.h"
+#include "vm/exceptions.h"
+#include "vm/global.h"
+#include "vm/initialize.h"
+#include "vm/primitive.h"
+#include "vm/resolve.h"
+#include "vm/stringlocal.h"
+#include "vm/vm.h"
+
+#include "vm/jit/asmpart.h"
+#include "vm/jit/jit.h"
+#include "vm/jit/stacktrace.h"
+
+#include "vmcore/loader.h"
+#include "vmcore/options.h"
+#include "vmcore/statistics.h"
+
+
+/* debug **********************************************************************/
+
+#if !defined(NDEBUG)
+# define TRACEJNICALLS(format, ...) \
+    do { \
+        if (opt_TraceJNICalls) { \
+            log_println((format), __VA_ARGS__); \
+        } \
+    } while (0)
+#else
+# define TRACEJNICALLS(format, ...)
+#endif
 
-       return parametercount;
-}
 
+/* global variables ***********************************************************/
 
+/* global reference table *****************************************************/
 
-void fill_callblock(void *obj, utf *descr, jni_callblock blk[], va_list data, char ret)
+/* hashsize must be power of 2 */
+
+#define HASHTABLE_GLOBAL_REF_SIZE    64 /* initial size of globalref-hash     */
+
+static hashtable *hashtable_global_ref; /* hashtable for globalrefs           */
+
+
+/* direct buffer stuff ********************************************************/
+
+#if defined(ENABLE_JAVASE)
+static classinfo *class_java_nio_Buffer;
+static classinfo *class_java_nio_DirectByteBufferImpl;
+static classinfo *class_java_nio_DirectByteBufferImpl_ReadWrite;
+
+# if 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
+
+
+/* accessing instance fields macros *******************************************/
+
+#define SET_FIELD(o,type,f,value) \
+    *((type *) (((intptr_t) (o)) + ((intptr_t) ((fieldinfo *) (f))->offset))) = (type) (value)
+
+#define GET_FIELD(o,type,f) \
+    *((type *) (((intptr_t) (o)) + ((intptr_t) ((fieldinfo *) (f))->offset)))
+
+
+/* some forward declarations **************************************************/
+
+jobject _Jv_JNI_NewLocalRef(JNIEnv *env, jobject ref);
+jint _Jv_JNI_EnsureLocalCapacity(JNIEnv* env, jint capacity);
+
+
+/* jni_init ********************************************************************
+
+   Initialize the JNI subsystem.
+
+*******************************************************************************/
+
+bool jni_init(void)
 {
-    char *utf__ptr = descr->text;      /* current position in utf-text */
-    char **utf_ptr = &utf__ptr;
-    char *desc_end = utf_end(descr);   /* points behind utf string     */
-    int cnt;
-    u4 dummy;
-    char c;
+       /* create global ref hashtable */
 
-       /*
-    log_text("fill_callblock");
-    utf_display(descr);
-    log_text("====");
-       */
-    /* skip '(' */
-    utf_nextu2(utf_ptr);
-
-    /* determine number of parameters */
-       if (obj) {
-               blk[0].itemtype = TYPE_ADR;
-               blk[0].item = PTR_TO_ITEM(obj);
-               cnt = 1;
-       } else cnt = 0;
-
-       while (**utf_ptr != ')') {
-               if (*utf_ptr >= desc_end)
-               panic("illegal method descriptor");
-
-               switch (utf_nextu2(utf_ptr)) {
-                       /* primitive types */
-               case 'B':
-               case 'C':
-               case 'S': 
-               case 'Z':
-                       blk[cnt].itemtype = TYPE_INT;
-                       blk[cnt].item = (u8) va_arg(data, int);
-                       break;
-
-               case 'I':
-                       blk[cnt].itemtype = TYPE_INT;
-                       dummy = va_arg(data, u4);
-                       /*printf("fill_callblock: pos:%d, value:%d\n",cnt,dummy);*/
-                       blk[cnt].item = (u8) dummy;
-                       break;
-
-               case 'J':
-                       blk[cnt].itemtype = TYPE_LNG;
-                       blk[cnt].item = (u8) va_arg(data, jlong);
-                       break;
-
-               case 'F':
-                       blk[cnt].itemtype = TYPE_FLT;
-                       *((jfloat *) (&blk[cnt].item)) = (jfloat) va_arg(data, jdouble);
-                       break;
-
-               case 'D':
-                       blk[cnt].itemtype = TYPE_DBL;
-                       *((jdouble *) (&blk[cnt].item)) = (jdouble) va_arg(data, jdouble);
-                       break;
-
-               case 'V':
-                       panic ("V not allowed as function parameter");
-                       break;
-                       
-               case 'L':
-                       while (utf_nextu2(utf_ptr) != ';')
-                           blk[cnt].itemtype = TYPE_ADR;
-                       blk[cnt].item = PTR_TO_ITEM(va_arg(data, void*));
-                       break;
-                       
-               case '[':
-                       {
-                               /* XXX */
-                               /* arrayclass */
-/*                             char *start = *utf_ptr; */
-                               char ch;
-                               while ((ch = utf_nextu2(utf_ptr)) == '[')
-                                       if (ch == 'L') {
-                                               while (utf_nextu2(utf_ptr) != ';') {}
-                                       }
-       
-                               ch = utf_nextu2(utf_ptr);
-                               blk[cnt].itemtype = TYPE_ADR;
-                               blk[cnt].item = PTR_TO_ITEM(va_arg(data, void*));
-                               break;                  
-                       }
-               }
-               cnt++;
-       }
+       hashtable_global_ref = NEW(hashtable);
+
+       hashtable_create(hashtable_global_ref, HASHTABLE_GLOBAL_REF_SIZE);
 
-       /*the standard doesn't say anything about return value checking, but it appears to be usefull*/
-       c = utf_nextu2(utf_ptr);
-       c = utf_nextu2(utf_ptr);
-       /*printf("%c  %c\n",ret,c);*/
-       if (ret == 'O') {
-               if (!((c == 'L') || (c == '[')))
-                       log_text("\n====\nWarning call*Method called for function with wrong return type\n====");
-       } else if (ret != c)
-               log_text("\n====\nWarning call*Method called for function with wrong return type\n====");
+
+#if defined(ENABLE_JAVASE)
+       /* 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 (!(class_java_nio_DirectByteBufferImpl =
+                 load_class_bootstrap(utf_new_char("java/nio/DirectByteBufferImpl"))) ||
+               !link_class(class_java_nio_DirectByteBufferImpl))
+               return false;
+
+       if (!(class_java_nio_DirectByteBufferImpl_ReadWrite =
+                 load_class_bootstrap(utf_new_char("java/nio/DirectByteBufferImpl$ReadWrite"))) ||
+               !link_class(class_java_nio_DirectByteBufferImpl_ReadWrite))
+               return false;
+
+       if (!(dbbirw_init =
+               class_resolvemethod(class_java_nio_DirectByteBufferImpl_ReadWrite,
+                                                       utf_init,
+                                                       utf_new_char("(Ljava/lang/Object;Lgnu/classpath/Pointer;III)V"))))
+               return false;
+
+#  if SIZEOF_VOID_P == 8
+       if (!(class_gnu_classpath_Pointer64 =
+                 load_class_bootstrap(utf_new_char("gnu/classpath/Pointer64"))) ||
+               !link_class(class_gnu_classpath_Pointer64))
+               return false;
+#  else
+       if (!(class_gnu_classpath_Pointer32 =
+                 load_class_bootstrap(utf_new_char("gnu/classpath/Pointer32"))) ||
+               !link_class(class_gnu_classpath_Pointer32))
+               return false;
+#  endif
+# endif
+#endif /* defined(ENABLE_JAVASE) */
+
+       return true;
 }
 
 
-/* XXX it could be considered if we should do typechecking here in the future */
-char fill_callblock_objA(void *obj, utf *descr, jni_callblock blk[], java_objectarray* params)
+/* jni_init_localref_table *****************************************************
+
+   Frees the local references table of the current thread.
+
+*******************************************************************************/
+
+bool jni_free_localref_table(void)
 {
-    char *utf__ptr = descr->text;      /* current position in utf-text */
-    char **utf_ptr = &utf__ptr;
-    char *desc_end = utf_end(descr);   /* points behind utf string     */
+       localref_table *lrt;
 
-    jobject param;
-    int cnt;
-    int cnts;
-    char c;
+#if defined(ENABLE_GC_CACAO)
+       lrt = LOCALREFTABLE;
 
-#if defined(USE_THREADS) && !defined(NATIVE_THREADS)
-    intsDisable();
+       assert(lrt);
+       assert(lrt->prev == NULL);
+
+       FREE(lrt, localref_table);
+
+       LOCALREFTABLE = NULL;
 #endif
-       if (utf_char==0) {
-               utf_char=utf_new_char("java/lang/Character");
-               utf_bool=utf_new_char("java/lang/Boolean");
-               utf_byte=utf_new_char("java/lang/Byte");
-               utf_short=utf_new_char("java/lang/Short");
-               utf_int=utf_new_char("java/lang/Integer");
-               utf_long=utf_new_char("java/lang/Long");
-               utf_float=utf_new_char("java/lang/Float");
-               utf_double=utf_new_char("java/lang/Double");
+
+       return true;
+}
+
+
+/* _Jv_jni_CallObjectMethod ****************************************************
+
+   Internal function to call Java Object methods.
+
+*******************************************************************************/
+
+static java_handle_t *_Jv_jni_CallObjectMethod(java_handle_t *o,
+                                                                                          vftbl_t *vftbl,
+                                                                                          methodinfo *m, va_list ap)
+{
+       methodinfo    *resm;
+       java_handle_t *ro;
+
+       STATISTICS(jniinvokation());
+
+       if (m == NULL) {
+               exceptions_throw_nullpointerexception();
+               return NULL;
        }
-#if defined(USE_THREADS) && !defined(NATIVE_THREADS)
-    intsRestore();
-#endif
 
-       /*
-         log_text("fill_callblock");
-         utf_display(descr);
-         log_text("====");
-       */
-    /* skip '(' */
-    utf_nextu2(utf_ptr);
+       /* Class initialization is done by the JIT compiler.  This is ok
+          since a static method always belongs to the declaring class. */
 
-    /* determine number of parameters */
-       if (obj) {
-               blk[0].itemtype = TYPE_ADR;
-               blk[0].item = PTR_TO_ITEM(obj);
-               cnt=1;
+       if (m->flags & ACC_STATIC) {
+               /* For static methods we reset the object. */
+
+               if (o != NULL)
+                       o = NULL;
+
+               /* for convenience */
+
+               resm = m;
 
        } else {
-               cnt = 0;
+               /* For instance methods we make a virtual function table lookup. */
+
+               resm = method_vftbl_lookup(vftbl, m);
        }
 
-       cnts = 0;
-       while (**utf_ptr != ')') {
-               if (*utf_ptr >= desc_end)
-               panic("illegal method descriptor");
-
-               /* primitive types */
-               switch (utf_nextu2(utf_ptr)) {
-               case 'B':
-                       param = params->data[cnts];
-                       if (param == 0) {
-                               *exceptionptr = new_exception("java/lang/IllegalArgumentException");
-                               return 0;
-                       }
-                       if (param->vftbl->class->name == utf_byte) {
-                               blk[cnt].itemtype = TYPE_INT;
-                               blk[cnt].item = (u8) ((java_lang_Byte *) param)->value;
+       STATISTICS(jnicallXmethodnvokation());
 
-                       } else  {
-                               *exceptionptr = new_exception("java/lang/IllegalArgumentException");
-                               return 0;
-                       }
-                       break;
+       ro = vm_call_method_valist(resm, o, ap);
 
-               case 'C':
-                       param = params->data[cnts];
-                       if (param == 0) {
-                               *exceptionptr = new_exception("java/lang/IllegalArgumentException");
-                               return 0;
-                       }
-                       if (param->vftbl->class->name == utf_char) {
-                               blk[cnt].itemtype = TYPE_INT;
-                               blk[cnt].item = (u8) ((java_lang_Character *) param)->value;
+       return ro;
+}
 
-                       } else  {
-                               *exceptionptr = new_exception("java/lang/IllegalArgumentException");
-                               return 0;
-                       }
-                       break;
 
-               case 'S':
-                       param = params->data[cnts];
-                       if (param == 0) {
-                               *exceptionptr = new_exception("java/lang/IllegalArgumentException");
-                               return 0;
-                       }
-                       if (param->vftbl->class->name == utf_short) {
-                               blk[cnt].itemtype = TYPE_INT;
-                               blk[cnt].item = (u8) ((java_lang_Short *) param)->value;
-
-                       } else  {
-                               if (param->vftbl->class->name == utf_byte) {
-                                       blk[cnt].itemtype = TYPE_INT;
-                                       blk[cnt].item = (u8) ((java_lang_Byte *) param)->value;
-
-                               } else {
-                                       *exceptionptr = new_exception("java/lang/IllegalArgumentException");
-                                       return 0;
-                               }
-                       }
-                       break;
+/* _Jv_jni_CallObjectMethodA ***************************************************
 
-               case 'Z':
-                       param = params->data[cnts];
-                       if (param == 0) {
-                               *exceptionptr = new_exception("java/lang/IllegalArgumentException");
-                               return 0;
-                       }
-                       if (param->vftbl->class->name == utf_bool) {
-                               blk[cnt].itemtype = TYPE_INT;
-                               blk[cnt].item = (u8) ((java_lang_Boolean *) param)->value;
+   Internal function to call Java Object methods.
 
-                       } else {
-                               *exceptionptr = new_exception("java/lang/IllegalArgumentException");
-                               return 0;
-                       }
-                       break;
-
-               case 'I':
-                       /*log_text("fill_callblock_objA: param 'I'");*/
-                       param = params->data[cnts];
-                       if (param == 0) {
-                               *exceptionptr = new_exception("java/lang/IllegalArgumentException");
-                               return 0;
-                       }
-                       if (param->vftbl->class->name == utf_int) {
-                               blk[cnt].itemtype = TYPE_INT;
-                               blk[cnt].item = (u8) ((java_lang_Integer *) param)->value;
-                               /*printf("INT VALUE :%d\n",((struct java_lang_Integer * )param)->value);*/
-                       } else {
-                               if (param->vftbl->class->name == utf_short) {
-                                       blk[cnt].itemtype = TYPE_INT;
-                                       blk[cnt].item = (u8) ((java_lang_Short *) param)->value;
-
-                               } else  {
-                                       if (param->vftbl->class->name == utf_byte) {
-                                               blk[cnt].itemtype = TYPE_INT;
-                                               blk[cnt].item = (u8) ((java_lang_Byte *) param)->value;
-
-                                       } else  {
-                                               *exceptionptr = new_exception("java/lang/IllegalArgumentException");
-                                               return 0;
-                                       }
-                               }
-                       }
-                       break;
+*******************************************************************************/
 
-               case 'J':
-                       param = params->data[cnts];
-                       if (param == 0) {
-                               *exceptionptr = new_exception("java/lang/IllegalArgumentException");
-                               return 0;
-                       }
-                       if (param->vftbl->class->name == utf_long) {
-                               blk[cnt].itemtype = TYPE_LNG;
-                               blk[cnt].item = (u8) ((java_lang_Long *) param)->value;
-
-                       } else  {
-                               if (param->vftbl->class->name == utf_int) {
-                                       blk[cnt].itemtype = TYPE_LNG;
-                                       blk[cnt].item = (u8) ((java_lang_Integer *) param)->value;
-
-                               } else {
-                                       if (param->vftbl->class->name == utf_short) {
-                                               blk[cnt].itemtype = TYPE_LNG;
-                                               blk[cnt].item = (u8) ((java_lang_Short *) param)->value;
-
-                                       } else  {
-                                               if (param->vftbl->class->name == utf_byte) {
-                                                       blk[cnt].itemtype = TYPE_LNG;
-                                                       blk[cnt].item = (u8) ((java_lang_Byte *) param)->value;
-                                               } else  {
-                                                       *exceptionptr = new_exception("java/lang/IllegalArgumentException");
-                                                       return 0;
-                                               }
-                                       }
-                               }
+static java_handle_t *_Jv_jni_CallObjectMethodA(java_handle_t *o,
+                                                                                               vftbl_t *vftbl,
+                                                                                               methodinfo *m,
+                                                                                               const jvalue *args)
+{
+       methodinfo    *resm;
+       java_handle_t *ro;
 
-                       }
-                       break;
+       STATISTICS(jniinvokation());
 
-               case 'F':
-                       param = params->data[cnts];
-                       if (param == 0) {
-                               *exceptionptr = new_exception("java/lang/IllegalArgumentException");
-                               return 0;
-                       }
+       if (m == NULL) {
+               exceptions_throw_nullpointerexception();
+               return NULL;
+       }
 
-                       if (param->vftbl->class->name == utf_float) {
-                               blk[cnt].itemtype = TYPE_FLT;
-                               *((jfloat *) (&blk[cnt].item)) = (jfloat) ((java_lang_Float *) param)->value;
+       /* Class initialization is done by the JIT compiler.  This is ok
+          since a static method always belongs to the declaring class. */
 
-                       } else  {
-                               *exceptionptr = new_exception("java/lang/IllegalArgumentException");
-                               return 0;
-                       }
-                       break;
+       if (m->flags & ACC_STATIC) {
+               /* For static methods we reset the object. */
 
-               case 'D':
-                       param = params->data[cnts];
-                       if (param == 0) {
-                               *exceptionptr = new_exception("java/lang/IllegalArgumentException");
-                               return 0;
-                       }
+               if (o != NULL)
+                       o = NULL;
 
-                       if (param->vftbl->class->name == utf_double) {
-                               blk[cnt].itemtype = TYPE_DBL;
-                               *((jdouble *) (&blk[cnt].item)) = (jdouble) ((java_lang_Float *) param)->value;
+               /* for convenience */
 
-                       } else  {
-                               if (param->vftbl->class->name == utf_float) {
-                                       blk[cnt].itemtype = TYPE_DBL;
-                                       *((jdouble *) (&blk[cnt].item)) = (jdouble) ((java_lang_Float *) param)->value;
+               resm = m;
 
-                               } else  {
-                                       *exceptionptr = new_exception("java/lang/IllegalArgumentException");
-                                       return 0;
-                               }
-                       }
-                       break;
-
-               case 'V':
-                       panic("V not allowed as function parameter");
-                       break;
-
-               case 'L':
-                       {
-                               char *start = (*utf_ptr) - 1;
-                               char *end = NULL;
-
-                               while (utf_nextu2(utf_ptr) != ';')
-                                       end = (*utf_ptr) + 1;
-
-                               if (!builtin_instanceof(params->data[cnts], class_from_descriptor(start, end, 0, CLASSLOAD_LOAD))) {
-                                       if (params->data[cnts] != 0) {
-                                               *exceptionptr = new_exception("java/lang/IllegalArgumentException");
-                                               return 0;
-                                       }                       
-                               }
-
-                               blk[cnt].itemtype = TYPE_ADR;
-                               blk[cnt].item = PTR_TO_ITEM(params->data[cnts]);
-                               break;                  
-                       }
+       } else {
+               /* For instance methods we make a virtual function table lookup. */
 
-               case '[':
-                       {
-                               char *start = (*utf_ptr) - 1;
-                               char *end;
+               resm = method_vftbl_lookup(vftbl, m);
+       }
 
-                               char ch;
-                               while ((ch = utf_nextu2(utf_ptr)) == '[')
-                                       if (ch == 'L') {
-                                               while (utf_nextu2(utf_ptr) != ';') {}
-                                       }
+       STATISTICS(jnicallXmethodnvokation());
 
-                               end = (*utf_ptr) - 1;
-                               ch = utf_nextu2(utf_ptr);
+       ro = vm_call_method_jvalue(resm, o, args);
 
-                               if (!builtin_arrayinstanceof(params->data[cnts], class_from_descriptor(start, end, 0, CLASSLOAD_LOAD)->vftbl)) {
-                                       *exceptionptr = new_exception("java/lang/IllegalArgumentException");
-                                       return 0;
-                               }
-       
-                               blk[cnt].itemtype = TYPE_ADR;
-                               blk[cnt].item = PTR_TO_ITEM(params->data[cnts]);
-                               break;
-                       }
-               }
-               cnt++;
-               cnts++;
+       return ro;
+}
+
+
+/* _Jv_jni_CallIntMethod *******************************************************
+
+   Internal function to call Java integer class methods (boolean,
+   byte, char, short, int).
+
+*******************************************************************************/
+
+static jint _Jv_jni_CallIntMethod(java_handle_t *o, vftbl_t *vftbl,
+                                                                 methodinfo *m, va_list ap)
+{
+       methodinfo *resm;
+       jint        i;
+
+       STATISTICS(jniinvokation());
+
+       if (m == NULL) {
+               exceptions_throw_nullpointerexception();
+               return 0;
        }
+        
+       /* Class initialization is done by the JIT compiler.  This is ok
+          since a static method always belongs to the declaring class. */
+
+       if (m->flags & ACC_STATIC) {
+               /* For static methods we reset the object. */
+
+               if (o != NULL)
+                       o = NULL;
 
-       c = utf_nextu2(utf_ptr);
-       c = utf_nextu2(utf_ptr);
-       return c; /*return type needed usage of the right lowlevel methods*/
+               /* for convenience */
+
+               resm = m;
+
+       } else {
+               /* For instance methods we make a virtual function table lookup. */
+
+               resm = method_vftbl_lookup(vftbl, m);
+       }
+
+       STATISTICS(jnicallXmethodnvokation());
+
+       i = vm_call_method_int_valist(resm, o, ap);
+
+       return i;
 }
 
 
+/* _Jv_jni_CallIntMethodA ******************************************************
+
+   Internal function to call Java integer class methods (boolean,
+   byte, char, short, int).
 
+*******************************************************************************/
 
+static jint _Jv_jni_CallIntMethodA(java_handle_t *o, vftbl_t *vftbl,
+                                                                  methodinfo *m, const jvalue *args)
+{
+       methodinfo *resm;
+       jint        i;
 
+       STATISTICS(jniinvokation());
 
+       if (m == NULL) {
+               exceptions_throw_nullpointerexception();
+               return 0;
+       }
+        
+       /* Class initialization is done by the JIT compiler.  This is ok
+          since a static method always belongs to the declaring class. */
 
+       if (m->flags & ACC_STATIC) {
+               /* For static methods we reset the object. */
 
+               if (o != NULL)
+                       o = NULL;
 
+               /* for convenience */
 
+               resm = m;
 
+       } else {
+               /* For instance methods we make a virtual function table lookup. */
 
+               resm = method_vftbl_lookup(vftbl, m);
+       }
 
+       STATISTICS(jnicallXmethodnvokation());
 
+       i = vm_call_method_int_jvalue(resm, o, args);
 
-jmethodID get_virtual(jobject obj,jmethodID methodID) {
-       if (obj->vftbl->class==methodID->class) return methodID;
-       return class_resolvemethod (obj->vftbl->class, methodID->name, methodID->descriptor);
+       return i;
 }
 
-jmethodID get_nonvirtual(jclass clazz,jmethodID methodID) {
-       if (clazz==methodID->class) return methodID;
-       return class_resolvemethod (clazz, methodID->name, methodID->descriptor);
-}
 
+/* _Jv_jni_CallLongMethod ******************************************************
 
+   Internal function to call Java long methods.
 
-jobject callObjectMethod (jobject obj, jmethodID methodID, va_list args)
-{      
-       int argcount;
-       jni_callblock *blk;
-       jobject ret;
-
-       /*
-         log_text("JNI-Call: CallObjectMethodV");
-         utf_display(methodID->name);
-         utf_display(methodID->descriptor);
-         printf("\nParmaeter count: %d\n",argcount);
-         utf_display(obj->vftbl->class->name);
-         printf("\n");
-       */
+*******************************************************************************/
+
+static jlong _Jv_jni_CallLongMethod(java_handle_t *o, vftbl_t *vftbl,
+                                                                       methodinfo *m, va_list ap)
+{
+       methodinfo *resm;
+       jlong       l;
+
+       STATISTICS(jniinvokation());
 
-       if (methodID == 0) {
-               *exceptionptr = new_exception(string_java_lang_NoSuchMethodError); 
+       if (m == NULL) {
+               exceptions_throw_nullpointerexception();
                return 0;
        }
 
-       argcount = get_parametercount(methodID);
+       /* Class initialization is done by the JIT compiler.  This is ok
+          since a static method always belongs to the declaring class. */
 
-       if (!( ((methodID->flags & ACC_STATIC) && (obj == 0)) ||
-               ((!(methodID->flags & ACC_STATIC)) && (obj != 0)) )) {
-               *exceptionptr = new_exception(string_java_lang_NoSuchMethodError);
-               return 0;
+       if (m->flags & ACC_STATIC) {
+               /* For static methods we reset the object. */
+
+               if (o != NULL)
+                       o = NULL;
+
+               /* for convenience */
+
+               resm = m;
+
+       } else {
+               /* For instance methods we make a virtual function table lookup. */
+
+               resm = method_vftbl_lookup(vftbl, m);
        }
-       
-       if (obj && !builtin_instanceof(obj, methodID->class)) {
-               *exceptionptr = new_exception(string_java_lang_NoSuchMethodError);
+
+       STATISTICS(jnicallXmethodnvokation());
+
+       l = vm_call_method_long_valist(resm, o, ap);
+
+       return l;
+}
+
+
+/* _Jv_jni_CallLongMethodA *****************************************************
+
+   Internal function to call Java long methods.
+
+*******************************************************************************/
+
+static jlong _Jv_jni_CallLongMethodA(java_handle_t *o, vftbl_t *vftbl,
+                                                                        methodinfo *m, const jvalue *args)
+{
+       methodinfo *resm;
+       jlong       l;
+
+       STATISTICS(jniinvokation());
+
+       if (m == NULL) {
+               exceptions_throw_nullpointerexception();
                return 0;
        }
 
-       if (argcount > 3) {
-               *exceptionptr = native_new_and_init(loader_load(utf_new_char("java/lang/IllegalArgumentException")));
-               log_text("Too many arguments. CallObjectMethod does not support that");
-               return 0;
+       /* Class initialization is done by the JIT compiler.  This is ok
+          since a static method always belongs to the declaring class. */
+
+       if (m->flags & ACC_STATIC) {
+               /* For static methods we reset the object. */
+
+               if (o != NULL)
+                       o = NULL;
+
+               /* for convenience */
+
+               resm = m;
        }
+       else {
+               /* For instance methods we make a virtual function table lookup. */
 
-       blk = MNEW(jni_callblock, 4 /*argcount+2*/);
+               resm = method_vftbl_lookup(vftbl, m);
+       }
 
-       fill_callblock(obj, methodID->descriptor, blk, args, 'O');
+       STATISTICS(jnicallXmethodnvokation());
 
-       /*      printf("parameter: obj: %p",blk[0].item); */
-       ret = asm_calljavafunction2(methodID,
-                                                               argcount + 1,
-                                                               (argcount + 1) * sizeof(jni_callblock),
-                                                               blk);
+       l = vm_call_method_long_jvalue(resm, o, args);
 
-       MFREE(blk, jni_callblock, argcount + 1);
-       /*      printf("(CallObjectMethodV)-->%p\n",ret); */
-       return ret;
+       return l;
 }
 
 
-/*
-  core function for integer class methods (bool, byte, short, integer)
-  This is basically needed for i386
-*/
-jint callIntegerMethod(jobject obj, jmethodID methodID, char retType, va_list args)
-{
-       int argcount;
-       jni_callblock *blk;
-       jint ret;
-
-/*     printf("%p,     %c\n",retType,methodID,retType);*/
-
-        /*
-        log_text("JNI-Call: CallObjectMethodV");
-        utf_display(methodID->name);
-        utf_display(methodID->descriptor);
-        printf("\nParmaeter count: %d\n",argcount);
-        utf_display(obj->vftbl->class->name);
-        printf("\n");
-        */
-       if (methodID == 0) {
-               *exceptionptr = new_exception(string_java_lang_NoSuchMethodError); 
-               return 0;
+/* _Jv_jni_CallFloatMethod *****************************************************
+
+   Internal function to call Java float methods.
+
+*******************************************************************************/
+
+static jfloat _Jv_jni_CallFloatMethod(java_handle_t *o, vftbl_t *vftbl,
+                                                                         methodinfo *m, va_list ap)
+{
+       methodinfo *resm;
+       jfloat      f;
+
+       /* Class initialization is done by the JIT compiler.  This is ok
+          since a static method always belongs to the declaring class. */
+
+       if (m->flags & ACC_STATIC) {
+               /* For static methods we reset the object. */
+
+               if (o != NULL)
+                       o = NULL;
+
+               /* for convenience */
+
+               resm = m;
+
+       } else {
+               /* For instance methods we make a virtual function table lookup. */
+
+               resm = method_vftbl_lookup(vftbl, m);
        }
-        
-       argcount = get_parametercount(methodID);
 
-       if (!( ((methodID->flags & ACC_STATIC) && (obj == 0)) ||
-               ((!(methodID->flags & ACC_STATIC)) && (obj != 0)) )) {
-               *exceptionptr = new_exception(string_java_lang_NoSuchMethodError);
-               return 0;
+       STATISTICS(jnicallXmethodnvokation());
+
+       f = vm_call_method_float_valist(resm, o, ap);
+
+       return f;
+}
+
+
+/* _Jv_jni_CallFloatMethodA ****************************************************
+
+   Internal function to call Java float methods.
+
+*******************************************************************************/
+
+static jfloat _Jv_jni_CallFloatMethodA(java_handle_t *o, vftbl_t *vftbl,
+                                                                          methodinfo *m, const jvalue *args)
+{
+       methodinfo *resm;
+       jfloat      f;
+
+       /* Class initialization is done by the JIT compiler.  This is ok
+          since a static method always belongs to the declaring class. */
+
+       if (m->flags & ACC_STATIC) {
+               /* For static methods we reset the object. */
+
+               if (o != NULL)
+                       o = NULL;
+
+               /* for convenience */
+
+               resm = m;
        }
+       else {
+               /* For instance methods we make a virtual function table lookup. */
 
-       if (obj && !builtin_instanceof(obj, methodID->class)) {
-               *exceptionptr = new_exception(string_java_lang_NoSuchMethodError);
-               return 0;
+               resm = method_vftbl_lookup(vftbl, m);
        }
 
+       STATISTICS(jnicallXmethodnvokation());
 
-       if (argcount > 3) {
-               *exceptionptr = native_new_and_init(loader_load(utf_new_char("java/lang/IllegalArgumentException")));
-               log_text("Too many arguments. CallIntegerMethod does not support that");
-               return 0;
-       }
+       f = vm_call_method_float_jvalue(resm, o, args);
+
+       return f;
+}
+
+
+/* _Jv_jni_CallDoubleMethod ****************************************************
+
+   Internal function to call Java double methods.
+
+*******************************************************************************/
+
+static jdouble _Jv_jni_CallDoubleMethod(java_handle_t *o, vftbl_t *vftbl,
+                                                                               methodinfo *m, va_list ap)
+{
+       methodinfo *resm;
+       jdouble     d;
+
+       /* Class initialization is done by the JIT compiler.  This is ok
+          since a static method always belongs to the declaring class. */
+
+       if (m->flags & ACC_STATIC) {
+               /* For static methods we reset the object. */
+
+               if (o != NULL)
+                       o = NULL;
 
-       blk = MNEW(jni_callblock, 4 /*argcount+2*/);
+               /* for convenience */
 
-       fill_callblock(obj, methodID->descriptor, blk, args, retType);
+               resm = m;
 
-       /*      printf("parameter: obj: %p",blk[0].item); */
-       ret = (jint) asm_calljavafunction2(methodID,
-                                                                          argcount + 1,
-                                                                          (argcount + 1) * sizeof(jni_callblock),
-                                                                          blk);
+       } else {
+               /* For instance methods we make a virtual function table lookup. */
+
+               resm = method_vftbl_lookup(vftbl, m);
+       }
 
-       MFREE(blk, jni_callblock, argcount + 1);
-       /*      printf("(CallObjectMethodV)-->%p\n",ret); */
+       d = vm_call_method_double_valist(resm, o, ap);
 
-       return ret;
+       return d;
 }
 
 
-/*core function for long class functions*/
-jlong callLongMethod(jobject obj, jmethodID methodID, va_list args)
+/* _Jv_jni_CallDoubleMethodA ***************************************************
+
+   Internal function to call Java double methods.
+
+*******************************************************************************/
+
+static jdouble _Jv_jni_CallDoubleMethodA(java_handle_t *o, vftbl_t *vftbl,
+                                                                                methodinfo *m, const jvalue *args)
 {
-       int argcount;
-       jni_callblock *blk;
-       jlong ret;
+       methodinfo *resm;
+       jdouble     d;
 
-       /*
-        log_text("JNI-Call: CallObjectMethodV");
-        utf_display(methodID->name);
-        utf_display(methodID->descriptor);
-        printf("\nParmaeter count: %d\n",argcount);
-        utf_display(obj->vftbl->class->name);
-        printf("\n");
-        */
-       if (methodID == 0) {
-               *exceptionptr = new_exception(string_java_lang_NoSuchMethodError); 
-               return 0;
+       /* Class initialization is done by the JIT compiler.  This is ok
+          since a static method always belongs to the declaring class. */
+
+       if (m->flags & ACC_STATIC) {
+               /* For static methods we reset the object. */
+
+               if (o != NULL)
+                       o = NULL;
+
+               /* for convenience */
+
+               resm = m;
+       }
+       else {
+               /* For instance methods we make a virtual function table lookup. */
+
+               resm = method_vftbl_lookup(vftbl, m);
        }
 
-       argcount = get_parametercount(methodID);
+       d = vm_call_method_double_jvalue(resm, o, args);
 
-       if (!( ((methodID->flags & ACC_STATIC) && (obj == 0)) ||
-                  ((!(methodID->flags & ACC_STATIC)) && (obj!=0)) )) {
-               *exceptionptr = new_exception(string_java_lang_NoSuchMethodError);
-               return 0;
+       return d;
+}
+
+
+/* _Jv_jni_CallVoidMethod ******************************************************
+
+   Internal function to call Java void methods.
+
+*******************************************************************************/
+
+static void _Jv_jni_CallVoidMethod(java_handle_t *o, vftbl_t *vftbl,
+                                                                  methodinfo *m, va_list ap)
+{      
+       methodinfo *resm;
+
+       if (m == NULL) {
+               exceptions_throw_nullpointerexception();
+               return;
        }
 
-       if (obj && !builtin_instanceof(obj,methodID->class)) {
-               *exceptionptr = new_exception(string_java_lang_NoSuchMethodError);
-               return 0;
+       /* Class initialization is done by the JIT compiler.  This is ok
+          since a static method always belongs to the declaring class. */
+
+       if (m->flags & ACC_STATIC) {
+               /* For static methods we reset the object. */
+
+               if (o != NULL)
+                       o = NULL;
+
+               /* for convenience */
+
+               resm = m;
+
+       } else {
+               /* For instance methods we make a virtual function table lookup. */
+
+               resm = method_vftbl_lookup(vftbl, m);
        }
 
+       STATISTICS(jnicallXmethodnvokation());
 
-       if (argcount > 3) {
-               *exceptionptr = native_new_and_init(loader_load(utf_new_char("java/lang/IllegalArgumentException")));
-               log_text("Too many arguments. CallObjectMethod does not support that");
-               return 0;
+       (void) vm_call_method_valist(resm, o, ap);
+}
+
+
+/* _Jv_jni_CallVoidMethodA *****************************************************
+
+   Internal function to call Java void methods.
+
+*******************************************************************************/
+
+static void _Jv_jni_CallVoidMethodA(java_handle_t *o, vftbl_t *vftbl,
+                                                                       methodinfo *m, const jvalue *args)
+{      
+       methodinfo *resm;
+
+       if (m == NULL) {
+               exceptions_throw_nullpointerexception();
+               return;
        }
 
-       blk = MNEW(jni_callblock, 4 /*argcount+2*/);
+       /* Class initialization is done by the JIT compiler.  This is ok
+          since a static method always belongs to the declaring class. */
+
+       if (m->flags & ACC_STATIC) {
+               /* For static methods we reset the object. */
 
-       fill_callblock(obj, methodID->descriptor, blk, args, 'L');
+               if (o != NULL)
+                       o = NULL;
 
-       /*      printf("parameter: obj: %p",blk[0].item); */
-       ret = asm_calljavafunction2long(methodID,
-                                                                       argcount + 1,
-                                                                       (argcount + 1) * sizeof(jni_callblock),
-                                                                       blk);
+               /* for convenience */
 
-       MFREE(blk, jni_callblock, argcount + 1);
-       /*      printf("(CallObjectMethodV)-->%p\n",ret); */
+               resm = m;
 
-       return ret;
+       } else {
+               /* For instance methods we make a virtual function table lookup. */
+
+               resm = method_vftbl_lookup(vftbl, m);
+       }
+
+       STATISTICS(jnicallXmethodnvokation());
+
+       (void) vm_call_method_jvalue(resm, o, args);
 }
 
 
-/*core function for float class methods (float,double)*/
-jdouble callFloatMethod(jobject obj, jmethodID methodID, va_list args,char retType)
+/* _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_handle_objectarray_t *params)
 {
-       int argcount = get_parametercount(methodID);
-       jni_callblock *blk;
-       jdouble ret;
+       methodinfo    *resm;
+       java_handle_t *ro;
+       s4             argcount;
+       s4             paramcount;
+       java_handle_t *xptr;
+       int32_t        dumpsize;
+       uint64_t      *array;
+       imm_union          value;
 
-        /*
-        log_text("JNI-Call: CallObjectMethodV");
-        utf_display(methodID->name);
-        utf_display(methodID->descriptor);
-        printf("\nParmaeter count: %d\n",argcount);
-        utf_display(obj->vftbl->class->name);
-        printf("\n");
-        */
+       if (m == NULL) {
+               exceptions_throw_nullpointerexception();
+               return NULL;
+       }
 
-       if (argcount > 3) {
-               *exceptionptr = native_new_and_init(loader_load(utf_new_char("java/lang/IllegalArgumentException")));
-               log_text("Too many arguments. CallObjectMethod does not support that");
-               return 0;
+       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 && (LLNI_array_size(params) != 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;
        }
 
-       blk = MNEW(jni_callblock, 4 /*argcount+2*/);
+       /* for static methods, zero object to make subsequent code simpler */
+       if (m->flags & ACC_STATIC)
+               o = NULL;
 
-       fill_callblock(obj, methodID->descriptor, blk, args, retType);
+       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
+   minor version number in the lower 16 bits.
+
+*******************************************************************************/
+
+jint _Jv_JNI_GetVersion(JNIEnv *env)
+{
+       STATISTICS(jniinvokation());
+
+       /* we support JNI 1.4 */
+
+       return JNI_VERSION_1_4;
+}
+
+
+/* Class Operations ***********************************************************/
+
+/* DefineClass *****************************************************************
+
+   Loads a class from a buffer of raw class data. The buffer
+   containing the raw class data is not referenced by the VM after the
+   DefineClass call returns, and it may be discarded if desired.
+
+*******************************************************************************/
+
+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;
+
+       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;
+
+       c = class_define(u, cl, bufLen, (const uint8_t *) buf);
+
+       return (jclass) _Jv_JNI_NewLocalRef(env, (jobject) c);
+#else
+       vm_abort("_Jv_JNI_DefineClass: not implemented in this configuration");
+
+       /* keep compiler happy */
+
+       return 0;
+#endif
+}
+
+
+/* FindClass *******************************************************************
+
+   This function loads a locally-defined class. It searches the
+   directories and zip files specified by the CLASSPATH environment
+   variable for the class with the specified name.
+
+*******************************************************************************/
+
+jclass _Jv_JNI_FindClass(JNIEnv *env, const char *name)
+{
+#if defined(ENABLE_JAVASE)
+       utf       *u;
+       classinfo *cc;
+       classinfo *c;
+
+       STATISTICS(jniinvokation());
+
+       u = utf_new_char_classname((char *) name);
+
+       /* Check stacktrace for classloader, if one found use it,
+          otherwise use the system classloader. */
+
+       /* Quote from the JNI documentation:
+        
+          In the Java 2 Platform, FindClass locates the class loader
+          associated with the current native method.  If the native code
+          belongs to a system class, no class loader will be
+          involved. Otherwise, the proper class loader will be invoked to
+          load and link the named class. When FindClass is called through
+          the Invocation Interface, there is no current native method or
+          its associated class loader. In that case, the result of
+          ClassLoader.getBaseClassLoader is used." */
+
+       cc = stacktrace_getCurrentClass();
+
+       if (cc == NULL)
+               c = load_class_from_sysloader(u);
+       else
+               c = load_class_from_classloader(u, cc->classloader);
+
+       if (c == NULL)
+               return NULL;
+
+       if (!link_class(c))
+               return NULL;
+
+       return (jclass) _Jv_JNI_NewLocalRef(env, (jobject) c);
+#else
+       vm_abort("_Jv_JNI_FindClass: not implemented in this configuration");
+
+       /* keep compiler happy */
+
+       return NULL;
+#endif
+}
+  
+
+/* GetSuperclass ***************************************************************
+
+   If clazz represents any class other than the class Object, then
+   this function returns the object that represents the superclass of
+   the class specified by clazz.
+
+*******************************************************************************/
+jclass _Jv_JNI_GetSuperclass(JNIEnv *env, jclass sub)
+{
+       classinfo *c;
+       classinfo *super;
+
+       TRACEJNICALLS("_Jv_JNI_GetSuperclass(env=%p, sub=%p)", env, sub);
+
+       c = (classinfo *) sub;
+
+       if (c == NULL)
+               return NULL;
+
+       super = class_get_superclass(c);
+
+       return (jclass) _Jv_JNI_NewLocalRef(env, (jobject) super);
+}
+  
+/* IsAssignableFrom ************************************************************
+
+   Determines whether an object of sub can be safely cast to sup.
+
+*******************************************************************************/
+
+jboolean _Jv_JNI_IsAssignableFrom(JNIEnv *env, jclass sub, jclass sup)
+{
+       java_lang_Class *csup;
+       java_lang_Class *csub;
+
+       csup = (java_lang_Class *) sup;
+       csub = (java_lang_Class *) sub;
+
+       STATISTICS(jniinvokation());
+
+       return _Jv_java_lang_Class_isAssignableFrom(csup, csub);
+}
+
+
+/* Throw ***********************************************************************
+
+   Causes a java.lang.Throwable object to be thrown.
+
+*******************************************************************************/
+
+jint _Jv_JNI_Throw(JNIEnv *env, jthrowable obj)
+{
+       java_handle_t *o;
+
+       STATISTICS(jniinvokation());
+
+       o = (java_handle_t *) obj;
+
+       exceptions_set_exception(o);
+
+       return JNI_OK;
+}
+
+
+/* ThrowNew ********************************************************************
+
+   Constructs an exception object from the specified class with the
+   message specified by message and causes that exception to be
+   thrown.
+
+*******************************************************************************/
+
+jint _Jv_JNI_ThrowNew(JNIEnv* env, jclass clazz, const char *msg) 
+{
+       classinfo     *c;
+       java_handle_t *o;
+       java_handle_t *s;
 
-       /*      printf("parameter: obj: %p",blk[0].item); */
-       ret = asm_calljavafunction2double(methodID,
-                                                                         argcount + 1,
-                                                                         (argcount + 1) * sizeof(jni_callblock),
-                                                                         blk);
+       STATISTICS(jniinvokation());
 
-       MFREE(blk, jni_callblock, argcount + 1);
-       /*      printf("(CallObjectMethodV)-->%p\n",ret); */
+       c = (classinfo *) clazz;
+       if (msg == NULL)
+               msg = "";
+       s = javastring_new_from_utf_string(msg);
 
-       return ret;
-}
+       /* instantiate exception object */
 
+       o = native_new_and_init_string(c, s);
 
-/*************************** function: jclass_findfield ****************************
-       
-       searches for field with specified name and type in a 'classinfo'-structur
-       if no such field is found NULL is returned 
-
-************************************************************************************/
-
-fieldinfo *jclass_findfield (classinfo *c, utf *name, utf *desc)
-{
-       s4 i;
-/*     printf(" FieldCount: %d\n",c->fieldscount);
-       utf_display(c->name); */
-               for (i = 0; i < c->fieldscount; i++) {
-/*             utf_display(c->fields[i].name);
-               printf("\n");
-               utf_display(c->fields[i].descriptor);
-               printf("\n");*/
-               if ((c->fields[i].name == name) && (c->fields[i].descriptor == desc))
-                       return &(c->fields[i]);
-               }
+       if (o == NULL)
+               return -1;
 
-       if (c->super) return jclass_findfield(c->super,name,desc);
+       exceptions_set_exception(o);
 
-       return NULL;
+       return 0;
 }
 
-/********************* returns version of native method interface *****************/
 
-jint GetVersion (JNIEnv* env)
-{
-       return JNI_VERSION;
-}
+/* ExceptionOccurred ***********************************************************
 
-/****************** loads a class from a buffer of raw class data *****************/
+   Determines if an exception is being thrown. The exception stays
+   being thrown until either the native code calls ExceptionClear(),
+   or the Java code handles the exception.
 
-jclass DefineClass(JNIEnv* env, const char *name, jobject loader, const jbyte *buf, jsize len) 
+*******************************************************************************/
+
+jthrowable _Jv_JNI_ExceptionOccurred(JNIEnv *env)
 {
-        jclass clazz; 
+       java_handle_t *o;
 
-       /* change suck-mode, so subsequent class_load will read from memory-buffer */
-       classload_buffer( (u1*) buf,len);
+       STATISTICS(jniinvokation());
 
-        clazz = loader_load(utf_new_char ((char *) name));
+       o = exceptions_get_exception();
 
-       /* restore old suck-mode */
-       classload_buffer(NULL,0);
-       if (clazz) clazz->classloader=loader;
-       return clazz;
+       return _Jv_JNI_NewLocalRef(env, (jthrowable) o);
 }
 
 
-/*************** loads locally defined class with the specified name **************/
+/* ExceptionDescribe ***********************************************************
 
-jclass FindClass(JNIEnv* env, const char *name) 
-{
-       classinfo *c;  
-  
-/*     if (strcmp(name,"[B")==0) {
-               c = loader_load(utf_new_char("The_Array_Class"));
-       }
-       else*/
-               c = loader_load(utf_new_char_classname((char *) name));
+   Prints an exception and a backtrace of the stack to a system
+   error-reporting channel, such as stderr. This is a convenience
+   routine provided for debugging.
 
-       if (!c)
-               *exceptionptr = new_exception(string_java_lang_ClassFormatError);
+*******************************************************************************/
 
-       return c;
-}
-  
+void _Jv_JNI_ExceptionDescribe(JNIEnv *env)
+{
+       java_handle_t *o;
+       methodinfo    *m;
 
-/*********************************************************************************** 
+       STATISTICS(jniinvokation());
 
-       converts java.lang.reflect.Method or 
-       java.lang.reflect.Constructor object to a method ID  
-  
- **********************************************************************************/   
-  
-jmethodID FromReflectedMethod(JNIEnv* env, jobject method)
-{
-       /* log_text("JNI-Call: FromReflectedMethod"); */
+       o = exceptions_get_exception();
 
-       return 0;
-}
+       if (o == NULL) {
+               /* clear exception, because we are calling jit code again */
 
+               exceptions_clear_exception();
 
-/*************** return superclass of the class represented by sub ****************/
-jclass GetSuperclass(JNIEnv* env, jclass sub) 
-{
-       classinfo *c;
+               /* get printStackTrace method from exception class */
 
-       c = ((classinfo*) sub)->super;
+               m = class_resolveclassmethod(o->vftbl->class,
+                                                                        utf_printStackTrace,
+                                                                        utf_void__void,
+                                                                        NULL,
+                                                                        true);
 
-       if (!c) return NULL; 
+               if (m == NULL)
+                       /* XXX what should we do? */
+                       return;
 
-       use_class_as_object(c);
+               /* print the stacktrace */
 
-       return c;               
-}
-  
-/*********************** check whether sub can be cast to sup  ********************/
-  
-jboolean IsAssignableForm(JNIEnv* env, jclass sub, jclass sup)
-{
-       return builtin_isanysubclass(sub, sup);
+               (void) vm_call_method(m, o);
+       }
 }
 
 
-/***** converts a field ID derived from cls to a java.lang.reflect.Field object ***/
+/* ExceptionClear **************************************************************
 
-jobject ToReflectedField(JNIEnv* env, jclass cls, jfieldID fieldID, jboolean isStatic)
+   Clears any exception that is currently being thrown. If no
+   exception is currently being thrown, this routine has no effect.
+
+*******************************************************************************/
+
+void _Jv_JNI_ExceptionClear(JNIEnv *env)
 {
-       /* log_text("JNI-Call: ToReflectedField"); */
+       STATISTICS(jniinvokation());
 
-       return NULL;
+       exceptions_clear_exception();
 }
 
 
-/***************** throw java.lang.Throwable object  ******************************/
+/* FatalError ******************************************************************
 
-jint Throw(JNIEnv* env, jthrowable obj)
+   Raises a fatal error and does not expect the VM to recover. This
+   function does not return.
+
+*******************************************************************************/
+
+void _Jv_JNI_FatalError(JNIEnv *env, const char *msg)
 {
-       *exceptionptr = (java_objectheader*) obj;
+       STATISTICS(jniinvokation());
 
-       return 0;
+       /* this seems to be the best way */
+
+       vm_abort("JNI Fatal error: %s", msg);
 }
 
 
-/*******************************************************************************
+/* PushLocalFrame **************************************************************
 
-       create exception object from the class clazz with the 
-       specified message and cause it to be thrown
+   Creates a new local reference frame, in which at least a given
+   number of local references can be created.
 
 *******************************************************************************/
 
-jint ThrowNew(JNIEnv* env, jclass clazz, const char *msg) 
+jint _Jv_JNI_PushLocalFrame(JNIEnv* env, jint capacity)
 {
-       java_lang_Throwable *o;
-
-       /* instantiate exception object */
-       o = (java_lang_Throwable *) native_new_and_init((classinfo*) clazz);
+       STATISTICS(jniinvokation());
 
-       if (!o) return (-1);
+       if (capacity <= 0)
+               return -1;
 
-       o->detailMessage = (java_lang_String *) javastring_new_char((char *) msg);
+       /* add new local reference frame to current table */
 
-       *exceptionptr = (java_objectheader *) o;
+       if (!localref_frame_push(capacity))
+               return -1;
 
        return 0;
 }
 
 
-/************************* check if exception occured *****************************/
+/* PopLocalFrame ***************************************************************
 
-jthrowable ExceptionOccurred (JNIEnv* env) 
-{
-       return (jthrowable) *exceptionptr;
-}
+   Pops off the current local reference frame, frees all the local
+   references, and returns a local reference in the previous local
+   reference frame for the given result object.
 
-/********** print exception and a backtrace of the stack (for debugging) **********/
+*******************************************************************************/
 
-void ExceptionDescribe (JNIEnv* env) 
+jobject _Jv_JNI_PopLocalFrame(JNIEnv* env, jobject result)
 {
-       utf_display((*exceptionptr)->vftbl->class->name);
-       printf ("\n");
-       fflush (stdout);        
-}
-
+       STATISTICS(jniinvokation());
 
-/******************* clear any exception currently being thrown *******************/
+       /* release all current local frames */
 
-void ExceptionClear (JNIEnv* env) 
-{
-       *exceptionptr = NULL;   
-}
+       localref_frame_pop_all();
 
+       /* add local reference and return the value */
 
-/********** raises a fatal error and does not expect the VM to recover ************/
-
-void FatalError (JNIEnv* env, const char *msg)
-{
-       panic((char *) msg);    
+       return _Jv_JNI_NewLocalRef(env, result);
 }
 
-/******************* creates a new local reference frame **************************/ 
 
-jint PushLocalFrame(JNIEnv* env, jint capacity)
-{
-       /* empty */
+/* DeleteLocalRef **************************************************************
 
-       return 0;
-}
+   Deletes the local reference pointed to by localRef.
 
-/**************** Pops off the current local reference frame **********************/
+*******************************************************************************/
 
-jobject PopLocalFrame(JNIEnv* env, jobject result)
+void _Jv_JNI_DeleteLocalRef(JNIEnv *env, jobject localRef)
 {
-       /* empty */
+       java_handle_t  *o;
+       localref_table *lrt;
+       s4              i;
 
-       return NULL;
-}
-    
+       STATISTICS(jniinvokation());
 
-/** Creates a new global reference to the object referred to by the obj argument **/
-    
-jobject NewGlobalRef(JNIEnv* env, jobject lobj)
-{
-       return lobj;
-}
+       o = (java_handle_t *) localRef;
 
-/*************  Deletes the global reference pointed to by globalRef **************/
+       /* get local reference table (thread specific) */
 
-void DeleteGlobalRef (JNIEnv* env, jobject gref)
-{
-       /* empty */
-}
+       lrt = LOCALREFTABLE;
 
+       /* go through all local frames */
 
-/*************** Deletes the local reference pointed to by localRef ***************/
+       for (; lrt != NULL; lrt = lrt->prev) {
 
-void DeleteLocalRef (JNIEnv* env, jobject localRef)
-{
-       /* empty */
-}
+               /* and try to remove the reference */
 
-/********** Tests whether two references refer to the same Java object ************/
+               for (i = 0; i < lrt->capacity; i++) {
+                       if (lrt->refs[i] == o) {
+                               lrt->refs[i] = NULL;
+                               lrt->used--;
 
-jboolean IsSameObject (JNIEnv* env, jobject obj1, jobject obj2)
-{
-       return (obj1==obj2);
-}
+                               return;
+                       }
+               }
+       }
 
-/***** Creates a new local reference that refers to the same object as ref  *******/
+       /* this should not happen */
 
-jobject NewLocalRef (JNIEnv* env, jobject ref)
-{
-       return ref;
+/*     if (opt_checkjni) */
+/*     FatalError(env, "Bad global or local ref passed to JNI"); */
+       log_text("JNI-DeleteLocalRef: Local ref passed to JNI not found");
 }
 
-/*********************************************************************************** 
 
-       Ensures that at least a given number of local references can 
-       be created in the current thread
+/* IsSameObject ****************************************************************
 
- **********************************************************************************/   
+   Tests whether two references refer to the same Java object.
 
-jint EnsureLocalCapacity (JNIEnv* env, jint capacity)
+*******************************************************************************/
+
+jboolean _Jv_JNI_IsSameObject(JNIEnv *env, jobject ref1, jobject ref2)
 {
-       return 0; /* return 0 on success */
+       STATISTICS(jniinvokation());
+
+       if (ref1 == ref2)
+               return JNI_TRUE;
+       else
+               return JNI_FALSE;
 }
 
 
-/********* Allocates a new Java object without invoking a constructor *************/
+/* NewLocalRef *****************************************************************
 
-jobject AllocObject (JNIEnv* env, jclass clazz)
-{
-        java_objectheader *o = builtin_new(clazz);     
-       return o;
-}
+   Creates a new local reference that refers to the same object as ref.
+
+*******************************************************************************/
 
+jobject _Jv_JNI_NewLocalRef(JNIEnv *env, jobject ref)
+{
+       localref_table *lrt;
+       s4              i;
 
-/*********************************************************************************** 
+       STATISTICS(jniinvokation());
 
-       Constructs a new Java object
-       arguments that are to be passed to the constructor are placed after methodID
+       if (ref == NULL)
+               return NULL;
 
-***********************************************************************************/
+       /* get local reference table (thread specific) */
 
-jobject NewObject (JNIEnv* env, jclass clazz, jmethodID methodID, ...)
-{
-       java_objectheader *o;
-       void* args[3];
-       int argcount=get_parametercount(methodID);
-       int i;
-       va_list vaargs;
+       lrt = LOCALREFTABLE;
 
-       /* log_text("JNI-Call: NewObject"); */
+       /* 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... */
 
-       if  (argcount>3) {
-               *exceptionptr=native_new_and_init(loader_load(utf_new_char("java/lang/IllegalArgumentException")));
-               log_text("Too many arguments. NewObject does not support that");
-               return 0;
-       }
+       if (lrt->used == lrt->capacity) {
+               if (_Jv_JNI_EnsureLocalCapacity(env, 16) != 0)
+                       return NULL;
 
-       
-       o = builtin_new (clazz);         /*          create object */
-       
-       if (!o) return NULL;
+               /* get the new local reference table */
 
-       va_start(vaargs,methodID);
-       for (i=0;i<argcount;i++) {
-               args[i]=va_arg(vaargs,void*);
+               lrt = LOCALREFTABLE;
        }
-       va_end(vaargs);
-       asm_calljavafunction(methodID,o,args[0],args[1],args[2]);
 
-       return o;
-}
+       /* 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;
+               }
+       }
 
-       Constructs a new Java object
-       arguments that are to be passed to the constructor are placed in va_list args 
+       /* should not happen, just to be sure */
 
-***********************************************************************************/
+       assert(0);
 
-jobject NewObjectV(JNIEnv* env, jclass clazz, jmethodID methodID, va_list args)
-{
-       /* log_text("JNI-Call: NewObjectV"); */
+       /* keep compiler happy */
 
        return NULL;
 }
 
 
-/*********************************************************************************** 
+/* EnsureLocalCapacity *********************************************************
 
-       Constructs a new Java object
-       arguments that are to be passed to the constructor are placed in 
-       args array of jvalues 
+   Ensures that at least a given number of local references can be
+   created in the current thread
 
-***********************************************************************************/
+*******************************************************************************/
 
-jobject NewObjectA(JNIEnv* env, jclass clazz, jmethodID methodID, jvalue *args)
+jint _Jv_JNI_EnsureLocalCapacity(JNIEnv* env, jint capacity)
 {
-       /* log_text("JNI-Call: NewObjectA"); */
+       localref_table *lrt;
 
-       return NULL;
-}
+       STATISTICS(jniinvokation());
 
+       /* get local reference table (thread specific) */
 
-/************************ returns the class of an object **************************/ 
+       lrt = LOCALREFTABLE;
 
-jclass GetObjectClass(JNIEnv* env, jobject obj)
-{
-       classinfo *c = obj->vftbl->class;
+       /* check if capacity elements are available in the local references table */
 
-       use_class_as_object(c);
+       if ((lrt->used + capacity) > lrt->capacity)
+               return _Jv_JNI_PushLocalFrame(env, capacity);
 
-       return c;
+       return 0;
 }
 
 
-/************* tests whether an object is an instance of a class ******************/
+/* AllocObject *****************************************************************
 
-jboolean IsInstanceOf(JNIEnv* env, jobject obj, jclass clazz)
-{
-       return builtin_instanceof(obj,clazz);
-}
+   Allocates a new Java object without invoking any of the
+   constructors for the object. Returns a reference to the object.
 
+*******************************************************************************/
 
-/***************** converts a java.lang.reflect.Field to a field ID ***************/
-jfieldID FromReflectedField(JNIEnv* env, jobject field)
+jobject _Jv_JNI_AllocObject(JNIEnv *env, jclass clazz)
 {
-       log_text("JNI-Call: FromReflectedField");
+       classinfo     *c;
+       java_handle_t *o;
 
-       return 0;
+       STATISTICS(jniinvokation());
+
+       c = (classinfo *) clazz;
+
+       if ((c->flags & ACC_INTERFACE) || (c->flags & ACC_ABSTRACT)) {
+               exceptions_throw_instantiationexception(c);
+               return NULL;
+       }
+               
+       o = builtin_new(c);
+
+       return _Jv_JNI_NewLocalRef(env, (jobject) o);
 }
 
 
-/**********************************************************************************
+/* NewObject *******************************************************************
 
-       converts a method ID to a java.lang.reflect.Method or 
-       java.lang.reflect.Constructor object
+   Programmers place all arguments that are to be passed to the
+   constructor immediately following the methodID
+   argument. NewObject() accepts these arguments and passes them to
+   the Java method that the programmer wishes to invoke.
 
-**********************************************************************************/
+*******************************************************************************/
 
-jobject ToReflectedMethod(JNIEnv* env, jclass cls, jmethodID methodID, jboolean isStatic)
+jobject _Jv_JNI_NewObject(JNIEnv *env, jclass clazz, jmethodID methodID, ...)
 {
-       log_text("JNI-Call: ToReflectedMethod");
+       java_handle_t *o;
+       classinfo     *c;
+       methodinfo    *m;
+       va_list        ap;
 
-       return NULL;
-}
+       STATISTICS(jniinvokation());
 
+       c = (classinfo *) clazz;
+       m = (methodinfo *) methodID;
 
-/**************** returns the method ID for an instance method ********************/
+       /* create object */
 
-jmethodID GetMethodID(JNIEnv* env, jclass clazz, const char *name, const char *sig)
-{
-       jmethodID m;
+       o = builtin_new(c);
+       
+       if (o == NULL)
+               return NULL;
 
-       m = class_resolvemethod (
-               clazz, 
-               utf_new_char ((char*) name), 
-               utf_new_char ((char*) sig)
-       );
+       /* call constructor */
 
-       if (!m) *exceptionptr = new_exception(string_java_lang_NoSuchMethodError);      
+       va_start(ap, methodID);
+       _Jv_jni_CallVoidMethod(o, o->vftbl, m, ap);
+       va_end(ap);
 
-       return m;
+       return _Jv_JNI_NewLocalRef(env, (jobject) o);
 }
 
 
-/******************** JNI-functions for calling instance methods ******************/
+/* NewObjectV ******************************************************************
 
-jobject CallObjectMethod(JNIEnv *env, jobject obj, jmethodID methodID, ...)
-{
-       jobject ret;
-       va_list vaargs;
+   Programmers place all arguments that are to be passed to the
+   constructor in an args argument of type va_list that immediately
+   follows the methodID argument. NewObjectV() accepts these
+   arguments, and, in turn, passes them to the Java method that the
+   programmer wishes to invoke.
 
-/*     log_text("JNI-Call: CallObjectMethod");*/
+*******************************************************************************/
 
-       va_start(vaargs, methodID);
-       ret = callObjectMethod(obj, methodID, vaargs);
-       va_end(vaargs);
+jobject _Jv_JNI_NewObjectV(JNIEnv* env, jclass clazz, jmethodID methodID,
+                                                  va_list args)
+{
+       java_handle_t *o;
+       classinfo     *c;
+       methodinfo    *m;
 
-       return ret;
-}
+       STATISTICS(jniinvokation());
 
+       c = (classinfo *) clazz;
+       m = (methodinfo *) methodID;
 
-jobject CallObjectMethodV(JNIEnv *env, jobject obj, jmethodID methodID, va_list args)
-{
-       return callObjectMethod(obj,methodID,args);
-}
+       /* create object */
 
+       o = builtin_new(c);
+       
+       if (o == NULL)
+               return NULL;
 
-jobject CallObjectMethodA(JNIEnv *env, jobject obj, jmethodID methodID, jvalue * args)
-{
-       log_text("JNI-Call: CallObjectMethodA");
+       /* call constructor */
 
-       return NULL;
+       _Jv_jni_CallVoidMethod(o, o->vftbl, m, args);
+
+       return _Jv_JNI_NewLocalRef(env, (jobject) o);
 }
 
 
+/* NewObjectA ***************************************************************** 
 
+   Programmers place all arguments that are to be passed to the
+   constructor in an args array of jvalues that immediately follows
+   the methodID argument. NewObjectA() accepts the arguments in this
+   array, and, in turn, passes them to the Java method that the
+   programmer wishes to invoke.
+
+*******************************************************************************/
 
-jboolean CallBooleanMethod (JNIEnv *env, jobject obj, jmethodID methodID, ...)
+jobject _Jv_JNI_NewObjectA(JNIEnv* env, jclass clazz, jmethodID methodID,
+                                                  const jvalue *args)
 {
-       jboolean ret;
-       va_list vaargs;
+       java_handle_t *o;
+       classinfo     *c;
+       methodinfo    *m;
 
-/*     log_text("JNI-Call: CallBooleanMethod");*/
+       STATISTICS(jniinvokation());
 
-       va_start(vaargs,methodID);
-       ret = (jboolean)callIntegerMethod(obj,get_virtual(obj,methodID),'Z',vaargs);
-       va_end(vaargs);
-       return ret;
+       c = (classinfo *) clazz;
+       m = (methodinfo *) methodID;
 
-}
+       /* create object */
 
-jboolean CallBooleanMethodV (JNIEnv *env, jobject obj, jmethodID methodID, va_list args)
-{
-       return (jboolean)callIntegerMethod(obj,get_virtual(obj,methodID),'Z',args);
+       o = builtin_new(c);
+       
+       if (o == NULL)
+               return NULL;
 
-}
+       /* call constructor */
 
-jboolean CallBooleanMethodA (JNIEnv *env, jobject obj, jmethodID methodID, jvalue * args)
-{
-       log_text("JNI-Call: CallBooleanMethodA");
+       _Jv_jni_CallVoidMethodA(o, o->vftbl, m, args);
 
-       return 0;
+       return _Jv_JNI_NewLocalRef(env, (jobject) o);
 }
 
-jbyte CallByteMethod (JNIEnv *env, jobject obj, jmethodID methodID, ...)
-{
-       jbyte ret;
-       va_list vaargs;
 
-/*     log_text("JNI-Call: CallVyteMethod");*/
+/* GetObjectClass **************************************************************
 
-       va_start(vaargs,methodID);
-       ret = callIntegerMethod(obj,get_virtual(obj,methodID),'B',vaargs);
-       va_end(vaargs);
-       return ret;
+ Returns the class of an object.
 
-}
+*******************************************************************************/
 
-jbyte CallByteMethodV (JNIEnv *env, jobject obj, jmethodID methodID, va_list args)
+jclass _Jv_JNI_GetObjectClass(JNIEnv *env, jobject obj)
 {
-/*     log_text("JNI-Call: CallByteMethodV");*/
-       return callIntegerMethod(obj,methodID,'B',args);
-}
+       java_handle_t *o;
+       classinfo     *c;
 
+       STATISTICS(jniinvokation());
 
-jbyte CallByteMethodA(JNIEnv *env, jobject obj, jmethodID methodID, jvalue *args)
-{
-       log_text("JNI-Call: CallByteMethodA");
+       o = (java_handle_t *) obj;
 
-       return 0;
-}
+       if ((o == NULL) || (o->vftbl == NULL))
+               return NULL;
 
+       c = o->vftbl->class;
 
-jchar CallCharMethod(JNIEnv *env, jobject obj, jmethodID methodID, ...)
-{
-       jchar ret;
-       va_list vaargs;
+       return (jclass) _Jv_JNI_NewLocalRef(env, (jobject) c);
+}
 
-/*     log_text("JNI-Call: CallCharMethod");*/
 
-       va_start(vaargs,methodID);
-       ret = callIntegerMethod(obj, get_virtual(obj, methodID), 'C', vaargs);
-       va_end(vaargs);
+/* IsInstanceOf ****************************************************************
 
-       return ret;
-}
+   Tests whether an object is an instance of a class.
 
+*******************************************************************************/
 
-jchar CallCharMethodV(JNIEnv *env, jobject obj, jmethodID methodID, va_list args)
+jboolean _Jv_JNI_IsInstanceOf(JNIEnv *env, jobject obj, jclass clazz)
 {
-/*     log_text("JNI-Call: CallCharMethodV");*/
-       return callIntegerMethod(obj,get_virtual(obj,methodID),'C',args);
-}
+       java_lang_Class  *c;
+       java_lang_Object *o;
 
+       STATISTICS(jniinvokation());
 
-jchar CallCharMethodA(JNIEnv *env, jobject obj, jmethodID methodID, jvalue *args)
-{
-       log_text("JNI-Call: CallCharMethodA");
+       c = (java_lang_Class *) clazz;
+       o = (java_lang_Object *) obj;
 
-       return 0;
+       return _Jv_java_lang_Class_isInstance(c, o);
 }
 
 
-jshort CallShortMethod(JNIEnv *env, jobject obj, jmethodID methodID, ...)
-{
-       jshort ret;
-       va_list vaargs;
+/* Reflection Support *********************************************************/
 
-/*     log_text("JNI-Call: CallShortMethod");*/
+/* FromReflectedMethod *********************************************************
 
-       va_start(vaargs, methodID);
-       ret = callIntegerMethod(obj, get_virtual(obj, methodID), 'S', vaargs);
-       va_end(vaargs);
+   Converts java.lang.reflect.Method or java.lang.reflect.Constructor
+   object to a method ID.
+  
+*******************************************************************************/
+  
+jmethodID _Jv_JNI_FromReflectedMethod(JNIEnv *env, jobject method)
+{
+#if defined(ENABLE_JAVASE)
+       java_handle_t *o;
+       classinfo     *c;
+       methodinfo    *m;
+       s4             slot;
 
-       return ret;
-}
+       STATISTICS(jniinvokation());
 
+       o = (java_handle_t *) method;
 
-jshort CallShortMethodV(JNIEnv *env, jobject obj, jmethodID methodID, va_list args)
-{
-       return callIntegerMethod(obj, get_virtual(obj, methodID), 'S', args);
-}
+       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;
 
-jshort CallShortMethodA(JNIEnv *env, jobject obj, jmethodID methodID, jvalue *args)
-{
-       log_text("JNI-Call: CallShortMethodA");
+               rc   = (java_lang_reflect_Constructor *) method;
+               LLNI_field_get_cls(rc, clazz, c);
+               LLNI_field_get_val(rc, slot , slot);
+       }
+       else
+               return NULL;
 
-       return 0;
-}
+       m = &(c->methods[slot]);
 
+       return (jmethodID) m;
+#else
+       vm_abort("_Jv_JNI_FromReflectedMethod: not implemented in this configuration");
 
+       /* keep compiler happy */
 
-jint CallIntMethod(JNIEnv *env, jobject obj, jmethodID methodID, ...)
-{
-       jint ret;
-       va_list vaargs;
+       return NULL;
+#endif
+}
 
-       va_start(vaargs,methodID);
-       ret = callIntegerMethod(obj, get_virtual(obj, methodID), 'I', vaargs);
-       va_end(vaargs);
 
-       return ret;
-}
+/* FromReflectedField **********************************************************
 
+   Converts a java.lang.reflect.Field to a field ID.
 
-jint CallIntMethodV(JNIEnv *env, jobject obj, jmethodID methodID, va_list args)
+*******************************************************************************/
+jfieldID _Jv_JNI_FromReflectedField(JNIEnv* env, jobject field)
 {
-       return callIntegerMethod(obj, get_virtual(obj, methodID), 'I', args);
-}
+#if defined(ENABLE_JAVASE)
+       java_lang_reflect_Field *rf;
+       classinfo               *c;
+       fieldinfo               *f;
+       int32_t                  slot;
 
+       STATISTICS(jniinvokation());
 
-jint CallIntMethodA(JNIEnv *env, jobject obj, jmethodID methodID, jvalue *args)
-{
-       log_text("JNI-Call: CallIntMethodA");
+       rf = (java_lang_reflect_Field *) field;
 
-       return 0;
-}
+       if (rf == NULL)
+               return NULL;
 
+       LLNI_field_get_cls(rf, clazz, c);
+       LLNI_field_get_val(rf, slot , slot);
+       f = &(c->fields[slot]);
 
+       return (jfieldID) f;
+#else
+       vm_abort("_Jv_JNI_FromReflectedField: not implemented in this configuration");
 
-jlong CallLongMethod(JNIEnv *env, jobject obj, jmethodID methodID, ...)
-{
-       log_text("JNI-Call: CallLongMethod");
+       /* keep compiler happy */
 
-       return 0;
+       return NULL;
+#endif
 }
 
 
-jlong CallLongMethodV(JNIEnv *env, jobject obj, jmethodID methodID, va_list args)
-{
-       log_text("JNI-Call: CallLongMethodV");
+/* ToReflectedMethod ***********************************************************
 
-       return 0;
-}
+   Converts a method ID derived from cls to an instance of the
+   java.lang.reflect.Method class or to an instance of the
+   java.lang.reflect.Constructor class.
 
+*******************************************************************************/
 
-jlong CallLongMethodA(JNIEnv *env, jobject obj, jmethodID methodID, jvalue *args)
+jobject _Jv_JNI_ToReflectedMethod(JNIEnv* env, jclass cls, jmethodID methodID,
+                                                                 jboolean isStatic)
 {
-       log_text("JNI-Call: CallLongMethodA");
+#if defined(ENABLE_JAVASE)
+       methodinfo                    *m;
+       java_lang_reflect_Constructor *rc;
+       java_lang_reflect_Method      *rm;
 
-       return 0;
-}
+       STATISTICS(jniinvokation());
 
+       m = (methodinfo *) methodID;
 
+       /* HotSpot does the same assert. */
 
-jfloat CallFloatMethod(JNIEnv *env, jobject obj, jmethodID methodID, ...)
-{
-       jfloat ret;
-       va_list vaargs;
+       assert(((m->flags & ACC_STATIC) != 0) == (isStatic != 0));
 
-/*     log_text("JNI-Call: CallFloatMethod");*/
+       if (m->name == utf_init) {
+               rc = reflect_constructor_new(m);
 
-       va_start(vaargs,methodID);
-       ret = callFloatMethod(obj, get_virtual(obj, methodID), vaargs, 'F');
-       va_end(vaargs);
+               return (jobject) rc;
+       }
+       else {
+               rm = reflect_method_new(m);
 
-       return ret;
-}
+               return (jobject) rm;
+       }
+#else
+       vm_abort("_Jv_JNI_ToReflectedMethod: not implemented in this configuration");
 
+       /* keep compiler happy */
 
-jfloat CallFloatMethodV(JNIEnv *env, jobject obj, jmethodID methodID, va_list args)
-{
-       log_text("JNI-Call: CallFloatMethodV");
-       return callFloatMethod(obj, get_virtual(obj, methodID), args, 'F');
+       return NULL;
+#endif
 }
 
 
-jfloat CallFloatMethodA(JNIEnv *env, jobject obj, jmethodID methodID, jvalue *args)
-{
-       log_text("JNI-Call: CallFloatMethodA");
-
-       return 0;
-}
+/* ToReflectedField ************************************************************
 
+   Converts a field ID derived from cls to an instance of the
+   java.lang.reflect.Field class.
 
+*******************************************************************************/
 
-jdouble CallDoubleMethod(JNIEnv *env, jobject obj, jmethodID methodID, ...)
+jobject _Jv_JNI_ToReflectedField(JNIEnv* env, jclass cls, jfieldID fieldID,
+                                                                jboolean isStatic)
 {
-       jdouble ret;
-       va_list vaargs;
-
-/*     log_text("JNI-Call: CallDoubleMethod");*/
+       STATISTICS(jniinvokation());
 
-       va_start(vaargs,methodID);
-       ret = callFloatMethod(obj, get_virtual(obj, methodID), vaargs, 'D');
-       va_end(vaargs);
+       log_text("JNI-Call: ToReflectedField: IMPLEMENT ME!");
 
-       return ret;
+       return NULL;
 }
 
 
-jdouble CallDoubleMethodV(JNIEnv *env, jobject obj, jmethodID methodID, va_list args)
-{
-       log_text("JNI-Call: CallDoubleMethodV");
-       return callFloatMethod(obj, get_virtual(obj, methodID), args, 'D');
-}
+/* Calling Instance Methods ***************************************************/
 
+/* GetMethodID *****************************************************************
 
-jdouble CallDoubleMethodA(JNIEnv *env, jobject obj, jmethodID methodID, jvalue *args)
-{
-       log_text("JNI-Call: CallDoubleMethodA");
-       return 0;
-}
+   Returns the method ID for an instance (nonstatic) method of a class
+   or interface. The method may be defined in one of the clazz's
+   superclasses and inherited by clazz. The method is determined by
+   its name and signature.
 
+   GetMethodID() causes an uninitialized class to be initialized.
 
+*******************************************************************************/
 
-void CallVoidMethod(JNIEnv *env, jobject obj, jmethodID methodID, ...)
+jmethodID _Jv_JNI_GetMethodID(JNIEnv* env, jclass clazz, const char *name,
+                                                         const char *sig)
 {
-       va_list vaargs;
+       classinfo  *c;
+       utf        *uname;
+       utf        *udesc;
+       methodinfo *m;
 
-/*      log_text("JNI-Call: CallVoidMethod");*/
+       STATISTICS(jniinvokation());
 
-       va_start(vaargs,methodID);
-       (void) callIntegerMethod(obj, get_virtual(obj, methodID), 'V', vaargs);
-       va_end(vaargs);
-}
+       c = (classinfo *) clazz;
 
+       if (c == NULL)
+               return NULL;
 
-void CallVoidMethodV (JNIEnv *env, jobject obj, jmethodID methodID, va_list args)
-{
-       log_text("JNI-Call: CallVoidMethodV");
-       (void)callIntegerMethod(obj,get_virtual(obj,methodID),'V',args);
-}
+       if (!(c->state & CLASS_INITIALIZED))
+               if (!initialize_class(c))
+                       return NULL;
 
+       /* try to get the method of the class or one of it's superclasses */
 
-void CallVoidMethodA (JNIEnv *env, jobject obj, jmethodID methodID, jvalue * args)
-{
-       log_text("JNI-Call: CallVoidMethodA");
-}
+       uname = utf_new_char((char *) name);
+       udesc = utf_new_char((char *) sig);
 
+       m = class_resolvemethod(c, uname, udesc);
 
+       if ((m == NULL) || (m->flags & ACC_STATIC)) {
+               exceptions_throw_nosuchmethoderror(c, uname, udesc);
 
-jobject CallNonvirtualObjectMethod (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...)
-{
-       log_text("JNI-Call: CallNonvirtualObjectMethod");
+               return NULL;
+       }
 
-       return NULL;
+       return (jmethodID) m;
+}
+
+
+/* JNI-functions for calling instance methods *********************************/
+
+#define JNI_CALL_VIRTUAL_METHOD(name, type, intern)         \
+type _Jv_JNI_Call##name##Method(JNIEnv *env, jobject obj,   \
+                                                               jmethodID methodID, ...)    \
+{                                                           \
+       java_handle_t *o;                                       \
+       methodinfo    *m;                                       \
+       va_list        ap;                                      \
+       type           ret;                                     \
+                                                            \
+       o = (java_handle_t *) obj;                              \
+       m = (methodinfo *) methodID;                            \
+                                                            \
+       va_start(ap, methodID);                                 \
+       ret = _Jv_jni_Call##intern##Method(o, o->vftbl, m, ap); \
+       va_end(ap);                                             \
+                                                            \
+       return ret;                                             \
 }
 
+JNI_CALL_VIRTUAL_METHOD(Boolean, jboolean, Int)
+JNI_CALL_VIRTUAL_METHOD(Byte,    jbyte,    Int)
+JNI_CALL_VIRTUAL_METHOD(Char,    jchar,    Int)
+JNI_CALL_VIRTUAL_METHOD(Short,   jshort,   Int)
+JNI_CALL_VIRTUAL_METHOD(Int,     jint,     Int)
+JNI_CALL_VIRTUAL_METHOD(Long,    jlong,    Long)
+JNI_CALL_VIRTUAL_METHOD(Float,   jfloat,   Float)
+JNI_CALL_VIRTUAL_METHOD(Double,  jdouble,  Double)
 
-jobject CallNonvirtualObjectMethodV (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, va_list args)
-{
-       log_text("JNI-Call: CallNonvirtualObjectMethodV");
 
-       return NULL;
+#define JNI_CALL_VIRTUAL_METHOD_V(name, type, intern)              \
+type _Jv_JNI_Call##name##MethodV(JNIEnv *env, jobject obj,         \
+                                                                jmethodID methodID, va_list args) \
+{                                                                  \
+       java_handle_t *o;                                              \
+       methodinfo    *m;                                              \
+       type           ret;                                            \
+                                                                   \
+       o = (java_handle_t *) obj;                                     \
+       m = (methodinfo *) methodID;                                   \
+                                                                   \
+       ret = _Jv_jni_Call##intern##Method(o, o->vftbl, m, args);      \
+                                                                   \
+       return ret;                                                    \
 }
 
+JNI_CALL_VIRTUAL_METHOD_V(Boolean, jboolean, Int)
+JNI_CALL_VIRTUAL_METHOD_V(Byte,    jbyte,    Int)
+JNI_CALL_VIRTUAL_METHOD_V(Char,    jchar,    Int)
+JNI_CALL_VIRTUAL_METHOD_V(Short,   jshort,   Int)
+JNI_CALL_VIRTUAL_METHOD_V(Int,     jint,     Int)
+JNI_CALL_VIRTUAL_METHOD_V(Long,    jlong,    Long)
+JNI_CALL_VIRTUAL_METHOD_V(Float,   jfloat,   Float)
+JNI_CALL_VIRTUAL_METHOD_V(Double,  jdouble,  Double)
 
-jobject CallNonvirtualObjectMethodA (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, jvalue * args)
-{
-       log_text("JNI-Call: CallNonvirtualObjectMethodA");
 
-       return NULL;
+#define JNI_CALL_VIRTUAL_METHOD_A(name, type, intern)          \
+type _Jv_JNI_Call##name##MethodA(JNIEnv *env, jobject obj,     \
+                                                                jmethodID methodID,           \
+                                                                const jvalue *args)           \
+{                                                              \
+       java_handle_t *o;                                          \
+       methodinfo    *m;                                          \
+       type           ret;                                        \
+                                                               \
+       o = (java_handle_t *) obj;                                 \
+       m = (methodinfo *) methodID;                               \
+                                                               \
+       ret = _Jv_jni_Call##intern##MethodA(o, o->vftbl, m, args); \
+                                                               \
+       return ret;                                                \
 }
 
+JNI_CALL_VIRTUAL_METHOD_A(Boolean, jboolean, Int)
+JNI_CALL_VIRTUAL_METHOD_A(Byte,    jbyte,    Int)
+JNI_CALL_VIRTUAL_METHOD_A(Char,    jchar,    Int)
+JNI_CALL_VIRTUAL_METHOD_A(Short,   jshort,   Int)
+JNI_CALL_VIRTUAL_METHOD_A(Int,     jint,     Int)
+JNI_CALL_VIRTUAL_METHOD_A(Long,    jlong,    Long)
+JNI_CALL_VIRTUAL_METHOD_A(Float,   jfloat,   Float)
+JNI_CALL_VIRTUAL_METHOD_A(Double,  jdouble,  Double)
 
 
-jboolean CallNonvirtualBooleanMethod (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...)
+jobject _Jv_JNI_CallObjectMethod(JNIEnv *env, jobject obj, jmethodID methodID,
+                                                                ...)
 {
-       jboolean ret;
-       va_list vaargs;
+       java_handle_t *o;
+       methodinfo    *m;
+       java_handle_t *ret;
+       va_list        ap;
 
-/*     log_text("JNI-Call: CallNonvirtualBooleanMethod");*/
+       o = (java_handle_t *) obj;
+       m = (methodinfo *) methodID;
 
-       va_start(vaargs,methodID);
-       ret = (jboolean)callIntegerMethod(obj,get_nonvirtual(clazz,methodID),'Z',vaargs);
-       va_end(vaargs);
-       return ret;
+       va_start(ap, methodID);
+       ret = _Jv_jni_CallObjectMethod(o, o->vftbl, m, ap);
+       va_end(ap);
 
+       return _Jv_JNI_NewLocalRef(env, (jobject) ret);
 }
 
 
-jboolean CallNonvirtualBooleanMethodV (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, va_list args)
+jobject _Jv_JNI_CallObjectMethodV(JNIEnv *env, jobject obj, jmethodID methodID,
+                                                                 va_list args)
 {
-/*     log_text("JNI-Call: CallNonvirtualBooleanMethodV");*/
-       return (jboolean)callIntegerMethod(obj,get_nonvirtual(clazz,methodID),'Z',args);
-}
+       java_handle_t *o;
+       methodinfo    *m;
+       java_handle_t *ret;
 
+       o = (java_handle_t *) obj;
+       m = (methodinfo *) methodID;
 
-jboolean CallNonvirtualBooleanMethodA (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, jvalue * args)
-{
-       log_text("JNI-Call: CallNonvirtualBooleanMethodA");
+       ret = _Jv_jni_CallObjectMethod(o, o->vftbl, m, args);
 
-       return 0;
+       return _Jv_JNI_NewLocalRef(env, (jobject) ret);
 }
 
 
-
-jbyte CallNonvirtualByteMethod (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...)
+jobject _Jv_JNI_CallObjectMethodA(JNIEnv *env, jobject obj, jmethodID methodID,
+                                                                 const jvalue *args)
 {
-       jbyte ret;
-       va_list vaargs;
+       java_handle_t *o;
+       methodinfo    *m;
+       java_handle_t *ret;
+
+       o = (java_handle_t *) obj;
+       m = (methodinfo *) methodID;
 
-/*     log_text("JNI-Call: CallNonvirutalByteMethod");*/
+       ret = _Jv_jni_CallObjectMethodA(o, o->vftbl, m, args);
 
-       va_start(vaargs,methodID);
-       ret = callIntegerMethod(obj,get_nonvirtual(clazz,methodID),'B',vaargs);
-       va_end(vaargs);
-       return ret;
+       return _Jv_JNI_NewLocalRef(env, (jobject) ret);
 }
 
 
-jbyte CallNonvirtualByteMethodV (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, va_list args)
+
+void _Jv_JNI_CallVoidMethod(JNIEnv *env, jobject obj, jmethodID methodID, ...)
 {
-       /*log_text("JNI-Call: CallNonvirtualByteMethodV"); */
-       return callIntegerMethod(obj,get_nonvirtual(clazz,methodID),'B',args);
+       java_handle_t *o;
+       methodinfo    *m;
+       va_list        ap;
+
+       o = (java_handle_t *) obj;
+       m = (methodinfo *) methodID;
 
+       va_start(ap, methodID);
+       _Jv_jni_CallVoidMethod(o, o->vftbl, m, ap);
+       va_end(ap);
 }
 
 
-jbyte CallNonvirtualByteMethodA (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, jvalue *args)
+void _Jv_JNI_CallVoidMethodV(JNIEnv *env, jobject obj, jmethodID methodID,
+                                                        va_list args)
 {
-       log_text("JNI-Call: CallNonvirtualByteMethodA");
+       java_handle_t *o;
+       methodinfo    *m;
 
-       return 0;
-}
+       o = (java_handle_t *) obj;
+       m = (methodinfo *) methodID;
 
+       _Jv_jni_CallVoidMethod(o, o->vftbl, m, args);
+}
 
 
-jchar CallNonvirtualCharMethod (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...)
+void _Jv_JNI_CallVoidMethodA(JNIEnv *env, jobject obj, jmethodID methodID,
+                                                        const jvalue *args)
 {
-       jchar ret;
-       va_list vaargs;
+       java_handle_t *o;
+       methodinfo    *m;
 
-/*     log_text("JNI-Call: CallNonVirtualCharMethod");*/
+       o = (java_handle_t *) obj;
+       m = (methodinfo *) methodID;
 
-       va_start(vaargs,methodID);
-       ret = callIntegerMethod(obj,get_nonvirtual(clazz,methodID),'C',vaargs);
-       va_end(vaargs);
-       return ret;
+       _Jv_jni_CallVoidMethodA(o, o->vftbl, m, args);
 }
 
 
-jchar CallNonvirtualCharMethodV (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, va_list args)
-{
-       /*log_text("JNI-Call: CallNonvirtualCharMethodV");*/
-       return callIntegerMethod(obj,get_nonvirtual(clazz,methodID),'C',args);
+
+#define JNI_CALL_NONVIRTUAL_METHOD(name, type, intern)                      \
+type _Jv_JNI_CallNonvirtual##name##Method(JNIEnv *env, jobject obj,         \
+                                                                                 jclass clazz, jmethodID methodID, \
+                                                                                 ...)                              \
+{                                                                           \
+       java_handle_t *o;                                                       \
+       classinfo     *c;                                                       \
+       methodinfo    *m;                                                       \
+       va_list        ap;                                                      \
+       type           ret;                                                     \
+                                                                            \
+       o = (java_handle_t *) obj;                                              \
+       c = (classinfo *) clazz;                                                \
+       m = (methodinfo *) methodID;                                            \
+                                                                            \
+       va_start(ap, methodID);                                                 \
+       ret = _Jv_jni_Call##intern##Method(o, c->vftbl, m, ap);                 \
+       va_end(ap);                                                             \
+                                                                            \
+       return ret;                                                             \
 }
 
+JNI_CALL_NONVIRTUAL_METHOD(Boolean, jboolean, Int)
+JNI_CALL_NONVIRTUAL_METHOD(Byte,    jbyte,    Int)
+JNI_CALL_NONVIRTUAL_METHOD(Char,    jchar,    Int)
+JNI_CALL_NONVIRTUAL_METHOD(Short,   jshort,   Int)
+JNI_CALL_NONVIRTUAL_METHOD(Int,     jint,     Int)
+JNI_CALL_NONVIRTUAL_METHOD(Long,    jlong,    Long)
+JNI_CALL_NONVIRTUAL_METHOD(Float,   jfloat,   Float)
+JNI_CALL_NONVIRTUAL_METHOD(Double,  jdouble,  Double)
 
-jchar CallNonvirtualCharMethodA (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, jvalue *args)
-{
-       log_text("JNI-Call: CallNonvirtualCharMethodA");
 
-       return 0;
+#define JNI_CALL_NONVIRTUAL_METHOD_V(name, type, intern)                     \
+type _Jv_JNI_CallNonvirtual##name##MethodV(JNIEnv *env, jobject obj,         \
+                                                                                  jclass clazz, jmethodID methodID, \
+                                                                                  va_list args)                     \
+{                                                                            \
+       java_handle_t *o;                                                        \
+       classinfo     *c;                                                        \
+       methodinfo    *m;                                                        \
+       type           ret;                                                      \
+                                                                             \
+       o = (java_handle_t *) obj;                                               \
+       c = (classinfo *) clazz;                                                 \
+       m = (methodinfo *) methodID;                                             \
+                                                                             \
+       ret = _Jv_jni_CallIntMethod(o, c->vftbl, m, args);                       \
+                                                                             \
+       return ret;                                                              \
 }
 
+JNI_CALL_NONVIRTUAL_METHOD_V(Boolean, jboolean, Int)
+JNI_CALL_NONVIRTUAL_METHOD_V(Byte,    jbyte,    Int)
+JNI_CALL_NONVIRTUAL_METHOD_V(Char,    jchar,    Int)
+JNI_CALL_NONVIRTUAL_METHOD_V(Short,   jshort,   Int)
+JNI_CALL_NONVIRTUAL_METHOD_V(Int,     jint,     Int)
+JNI_CALL_NONVIRTUAL_METHOD_V(Long,    jlong,    Long)
+JNI_CALL_NONVIRTUAL_METHOD_V(Float,   jfloat,   Float)
+JNI_CALL_NONVIRTUAL_METHOD_V(Double,  jdouble,  Double)
+
 
+#define JNI_CALL_NONVIRTUAL_METHOD_A(name, type, intern)                     \
+type _Jv_JNI_CallNonvirtual##name##MethodA(JNIEnv *env, jobject obj,         \
+                                                                                  jclass clazz, jmethodID methodID, \
+                                                                                  const jvalue *args)               \
+{                                                                            \
+       log_text("JNI-Call: CallNonvirtual##name##MethodA: IMPLEMENT ME!");      \
+                                                                             \
+       return 0;                                                                \
+}
+
+JNI_CALL_NONVIRTUAL_METHOD_A(Boolean, jboolean, Int)
+JNI_CALL_NONVIRTUAL_METHOD_A(Byte,    jbyte,    Int)
+JNI_CALL_NONVIRTUAL_METHOD_A(Char,    jchar,    Int)
+JNI_CALL_NONVIRTUAL_METHOD_A(Short,   jshort,   Int)
+JNI_CALL_NONVIRTUAL_METHOD_A(Int,     jint,     Int)
+JNI_CALL_NONVIRTUAL_METHOD_A(Long,    jlong,    Long)
+JNI_CALL_NONVIRTUAL_METHOD_A(Float,   jfloat,   Float)
+JNI_CALL_NONVIRTUAL_METHOD_A(Double,  jdouble,  Double)
 
-jshort CallNonvirtualShortMethod (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...)
+jobject _Jv_JNI_CallNonvirtualObjectMethod(JNIEnv *env, jobject obj,
+                                                                                  jclass clazz, jmethodID methodID,
+                                                                                  ...)
 {
-       jshort ret;
-       va_list vaargs;
+       java_handle_t *o;
+       classinfo     *c;
+       methodinfo    *m;
+       java_handle_t *r;
+       va_list        ap;
 
-       /*log_text("JNI-Call: CallNonvirtualShortMethod");*/
+       o = (java_handle_t *) obj;
+       c = (classinfo *) clazz;
+       m = (methodinfo *) methodID;
 
-       va_start(vaargs,methodID);
-       ret = callIntegerMethod(obj,get_nonvirtual(clazz,methodID),'S',vaargs);
-       va_end(vaargs);
-       return ret;
+       va_start(ap, methodID);
+       r = _Jv_jni_CallObjectMethod(o, c->vftbl, m, ap);
+       va_end(ap);
+
+       return _Jv_JNI_NewLocalRef(env, (jobject) r);
 }
 
 
-jshort CallNonvirtualShortMethodV (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, va_list args)
+jobject _Jv_JNI_CallNonvirtualObjectMethodV(JNIEnv *env, jobject obj,
+                                                                                       jclass clazz, jmethodID methodID,
+                                                                                       va_list args)
 {
-       /*log_text("JNI-Call: CallNonvirtualShortMethodV");*/
-       return callIntegerMethod(obj,get_nonvirtual(clazz,methodID),'S',args);
+       java_handle_t *o;
+       classinfo     *c;
+       methodinfo    *m;
+       java_handle_t *r;
+
+       o = (java_handle_t *) obj;
+       c = (classinfo *) clazz;
+       m = (methodinfo *) methodID;
+
+       r = _Jv_jni_CallObjectMethod(o, c->vftbl, m, args);
+
+       return _Jv_JNI_NewLocalRef(env, (jobject) r);
 }
 
 
-jshort CallNonvirtualShortMethodA (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, jvalue *args)
+jobject _Jv_JNI_CallNonvirtualObjectMethodA(JNIEnv *env, jobject obj,
+                                                                                       jclass clazz, jmethodID methodID,
+                                                                                       const jvalue *args)
 {
-       log_text("JNI-Call: CallNonvirtualShortMethodA");
+       log_text("JNI-Call: CallNonvirtualObjectMethodA: IMPLEMENT ME!");
 
-       return 0;
+       return _Jv_JNI_NewLocalRef(env, NULL);
 }
 
 
-
-jint CallNonvirtualIntMethod (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...)
+void _Jv_JNI_CallNonvirtualVoidMethod(JNIEnv *env, jobject obj, jclass clazz,
+                                                                         jmethodID methodID, ...)
 {
+       java_handle_t *o;
+       classinfo     *c;
+       methodinfo    *m;
+       va_list        ap;
 
-        jint ret;
-        va_list vaargs;
+       o = (java_handle_t *) obj;
+       c = (classinfo *) clazz;
+       m = (methodinfo *) methodID;
 
-       /*log_text("JNI-Call: CallNonvirtualIntMethod");*/
-
-        va_start(vaargs,methodID);
-        ret = callIntegerMethod(obj,get_nonvirtual(clazz,methodID),'I',vaargs);
-        va_end(vaargs);
-        return ret;
+       va_start(ap, methodID);
+       _Jv_jni_CallVoidMethod(o, c->vftbl, m, ap);
+       va_end(ap);
 }
 
 
-jint CallNonvirtualIntMethodV (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, va_list args)
+void _Jv_JNI_CallNonvirtualVoidMethodV(JNIEnv *env, jobject obj, jclass clazz,
+                                                                          jmethodID methodID, va_list args)
 {
-       /*log_text("JNI-Call: CallNonvirtualIntMethodV");*/
-        return callIntegerMethod(obj,get_nonvirtual(clazz,methodID),'I',args);
+       java_handle_t *o;
+       classinfo     *c;
+       methodinfo    *m;
+
+       o = (java_handle_t *) obj;
+       c = (classinfo *) clazz;
+       m = (methodinfo *) methodID;
+
+       _Jv_jni_CallVoidMethod(o, c->vftbl, m, args);
 }
 
 
-jint CallNonvirtualIntMethodA (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, jvalue *args)
-{
-       log_text("JNI-Call: CallNonvirtualIntMethodA");
+void _Jv_JNI_CallNonvirtualVoidMethodA(JNIEnv *env, jobject obj, jclass clazz,
+                                                                          jmethodID methodID, const jvalue * args)
+{      
+       java_handle_t *o;
+       classinfo     *c;
+       methodinfo    *m;
 
-       return 0;
+       o = (java_handle_t *) obj;
+       c = (classinfo *) clazz;
+       m = (methodinfo *) methodID;
+
+       _Jv_jni_CallVoidMethodA(o, c->vftbl, m, args);
 }
 
 
+/* Accessing Fields of Objects ************************************************/
 
-jlong CallNonvirtualLongMethod (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...)
-{
-       log_text("JNI-Call: CallNonvirtualLongMethod");
+/* GetFieldID ******************************************************************
 
-       return 0;
-}
+   Returns the field ID for an instance (nonstatic) field of a
+   class. The field is specified by its name and signature. The
+   Get<type>Field and Set<type>Field families of accessor functions
+   use field IDs to retrieve object fields.
 
+*******************************************************************************/
 
-jlong CallNonvirtualLongMethodV (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, va_list args)
+jfieldID _Jv_JNI_GetFieldID(JNIEnv *env, jclass clazz, const char *name,
+                                                       const char *sig)
 {
-       log_text("JNI-Call: CallNonvirtualLongMethodV");
+       classinfo *c;
+       fieldinfo *f;
+       utf       *uname;
+       utf       *udesc;
 
-       return 0;
-}
+       STATISTICS(jniinvokation());
 
+       c = (classinfo *) clazz;
 
-jlong CallNonvirtualLongMethodA (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, jvalue *args)
-{
-       log_text("JNI-Call: CallNonvirtualLongMethodA");
+       /* XXX NPE check? */
 
-       return 0;
-}
+       uname = utf_new_char((char *) name);
+       udesc = utf_new_char((char *) sig);
 
+       f = class_findfield(c, uname, udesc); 
+       
+       if (f == NULL)
+               exceptions_throw_nosuchfielderror(c, uname);  
 
+       return (jfieldID) f;
+}
 
-jfloat CallNonvirtualFloatMethod (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...)
-{
-       jfloat ret;
-       va_list vaargs;
 
-       /*log_text("JNI-Call: CallNonvirtualFloatMethod");*/
+/* Get<type>Field Routines *****************************************************
 
+   This family of accessor routines returns the value of an instance
+   (nonstatic) field of an object. The field to access is specified by
+   a field ID obtained by calling GetFieldID().
 
-       va_start(vaargs,methodID);
-       ret = callFloatMethod(obj,get_nonvirtual(clazz,methodID),vaargs,'F');
-       va_end(vaargs);
-       return ret;
+*******************************************************************************/
 
+#define JNI_GET_FIELD(name, type, intern)                                 \
+type _Jv_JNI_Get##name##Field(JNIEnv *env, jobject obj, jfieldID fieldID) \
+{                                                                         \
+       intern ret;                                                           \
+                                                                          \
+       STATISTICS(jniinvokation());                                          \
+                                                                          \
+       ret = GET_FIELD(obj, intern, fieldID);                                \
+                                                                          \
+       return (type) ret;                                                    \
 }
 
+JNI_GET_FIELD(Boolean, jboolean, s4)
+JNI_GET_FIELD(Byte,    jbyte,    s4)
+JNI_GET_FIELD(Char,    jchar,    s4)
+JNI_GET_FIELD(Short,   jshort,   s4)
+JNI_GET_FIELD(Int,     jint,     s4)
+JNI_GET_FIELD(Long,    jlong,    s8)
+JNI_GET_FIELD(Float,   jfloat,   float)
+JNI_GET_FIELD(Double,  jdouble,  double)
+
 
-jfloat CallNonvirtualFloatMethodV (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, va_list args)
+jobject _Jv_JNI_GetObjectField(JNIEnv *env, jobject obj, jfieldID fieldID)
 {
-       log_text("JNI-Call: CallNonvirtualFloatMethodV");
-       return callFloatMethod(obj,get_nonvirtual(clazz,methodID),args,'F');
-}
+       java_handle_t *o;
 
+       STATISTICS(jniinvokation());
 
-jfloat CallNonvirtualFloatMethodA (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, jvalue *args)
-{
-       log_text("JNI-Call: CallNonvirtualFloatMethodA");
+#warning this needs to be fixed
+       o = GET_FIELD(obj, java_handle_t*, fieldID);
 
-       return 0;
+       return _Jv_JNI_NewLocalRef(env, (jobject) o);
 }
 
 
+/* Set<type>Field Routines *****************************************************
 
-jdouble CallNonvirtualDoubleMethod (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...)
-{
-       jdouble ret;
-       va_list vaargs;
-       log_text("JNI-Call: CallNonvirtualDoubleMethod");
+   This family of accessor routines sets the value of an instance
+   (nonstatic) field of an object. The field to access is specified by
+   a field ID obtained by calling GetFieldID().
 
-       va_start(vaargs,methodID);
-       ret = callFloatMethod(obj,get_nonvirtual(clazz,methodID),vaargs,'D');
-       va_end(vaargs);
-       return ret;
+*******************************************************************************/
 
+#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);                               \
 }
 
-
-jdouble CallNonvirtualDoubleMethodV (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, va_list args)
-{
-/*     log_text("JNI-Call: CallNonvirtualDoubleMethodV");*/
-       return callFloatMethod(obj,get_nonvirtual(clazz,methodID),args,'D');
-}
+JNI_SET_FIELD(Boolean, jboolean, s4)
+JNI_SET_FIELD(Byte,    jbyte,    s4)
+JNI_SET_FIELD(Char,    jchar,    s4)
+JNI_SET_FIELD(Short,   jshort,   s4)
+JNI_SET_FIELD(Int,     jint,     s4)
+JNI_SET_FIELD(Long,    jlong,    s8)
+JNI_SET_FIELD(Float,   jfloat,   float)
+JNI_SET_FIELD(Double,  jdouble,  double)
 
 
-jdouble CallNonvirtualDoubleMethodA (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, jvalue *args)
+void _Jv_JNI_SetObjectField(JNIEnv *env, jobject obj, jfieldID fieldID,
+                                                       jobject value)
 {
-       log_text("JNI-Call: CallNonvirtualDoubleMethodA");
+       STATISTICS(jniinvokation());
 
-       return 0;
+#warning this needs to be fixed
+       SET_FIELD(obj, java_handle_t*, fieldID, value);
 }
 
 
+/* Calling Static Methods *****************************************************/
 
-void CallNonvirtualVoidMethod (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...)
-{
-        va_list vaargs;
-
-/*      log_text("JNI-Call: CallNonvirtualVoidMethod");*/
+/* GetStaticMethodID ***********************************************************
 
-        va_start(vaargs,methodID);
-        (void)callIntegerMethod(obj,get_nonvirtual(clazz,methodID),'V',vaargs);
-        va_end(vaargs);
+   Returns the method ID for a static method of a class. The method is
+   specified by its name and signature.
 
-}
+   GetStaticMethodID() causes an uninitialized class to be
+   initialized.
 
+*******************************************************************************/
 
-void CallNonvirtualVoidMethodV (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, va_list args)
+jmethodID _Jv_JNI_GetStaticMethodID(JNIEnv *env, jclass clazz, const char *name,
+                                                                       const char *sig)
 {
-/*     log_text("JNI-Call: CallNonvirtualVoidMethodV");*/
-
-        (void)callIntegerMethod(obj,get_nonvirtual(clazz,methodID),'V',args);
+       classinfo  *c;
+       utf        *uname;
+       utf        *udesc;
+       methodinfo *m;
 
-}
+       STATISTICS(jniinvokation());
 
+       c = (classinfo *) clazz;
 
-void CallNonvirtualVoidMethodA (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, jvalue * args)
-{
-       log_text("JNI-Call: CallNonvirtualVoidMethodA");
-}
+       if (!c)
+               return NULL;
 
-/************************* JNI-functions for accessing fields ************************/
+       if (!(c->state & CLASS_INITIALIZED))
+               if (!initialize_class(c))
+                       return NULL;
 
-jfieldID GetFieldID (JNIEnv *env, jclass clazz, const char *name, const char *sig) 
-{
-       jfieldID f;
+       /* try to get the static method of the class */
 
-/*     log_text("========================= searching for:");
-       log_text(name);
-       log_text(sig);*/
-       f = jclass_findfield(clazz,
-                           utf_new_char ((char*) name), 
-                           utf_new_char ((char*) sig)
-                           ); 
-       
-       if (!f) { 
-/*             utf_display(clazz->name);
-               log_text(name);
-               log_text(sig);*/
-               *exceptionptr = new_exception(string_java_lang_NoSuchFieldError);  
-       }
-       return f;
-}
+       uname = utf_new_char((char *) name);
+       udesc = utf_new_char((char *) sig);
 
-/*************************** retrieve fieldid, abort on error ************************/
+       m = class_resolvemethod(c, uname, udesc);
 
-jfieldID getFieldID_critical(JNIEnv *env, jclass clazz, char *name, char *sig)
-{
-    jfieldID id = GetFieldID(env, clazz, name, sig);
+       if ((m == NULL) || !(m->flags & ACC_STATIC)) {
+               exceptions_throw_nosuchmethoderror(c, uname, udesc);
 
-    if (!id) {
-       log_text("class:");
-       utf_display(clazz->name);
-       log_text("\nfield:");
-       log_text(name);
-       log_text("sig:");
-       log_text(sig);
+               return NULL;
+       }
 
-       panic("setfield_critical failed"); 
-    }
-    return id;
+       return (jmethodID) m;
 }
 
-jobject GetObjectField (JNIEnv *env, jobject obj, jfieldID fieldID)
-{
-       return getField(obj,jobject,fieldID);
+
+#define JNI_CALL_STATIC_METHOD(name, type, intern)               \
+type _Jv_JNI_CallStatic##name##Method(JNIEnv *env, jclass clazz, \
+                                                                         jmethodID methodID, ...)   \
+{                                                                \
+       methodinfo *m;                                               \
+       va_list     ap;                                              \
+       type        res;                                             \
+                                                                 \
+       m = (methodinfo *) methodID;                                 \
+                                                                 \
+       va_start(ap, methodID);                                      \
+       res = _Jv_jni_Call##intern##Method(NULL, NULL, m, ap);       \
+       va_end(ap);                                                  \
+                                                                 \
+       return res;                                                  \
 }
 
-jboolean GetBooleanField (JNIEnv *env, jobject obj, jfieldID fieldID)
-{
-       return getField(obj,jboolean,fieldID);
-}
+JNI_CALL_STATIC_METHOD(Boolean, jboolean, Int)
+JNI_CALL_STATIC_METHOD(Byte,    jbyte,    Int)
+JNI_CALL_STATIC_METHOD(Char,    jchar,    Int)
+JNI_CALL_STATIC_METHOD(Short,   jshort,   Int)
+JNI_CALL_STATIC_METHOD(Int,     jint,     Int)
+JNI_CALL_STATIC_METHOD(Long,    jlong,    Long)
+JNI_CALL_STATIC_METHOD(Float,   jfloat,   Float)
+JNI_CALL_STATIC_METHOD(Double,  jdouble,  Double)
 
 
-jbyte GetByteField (JNIEnv *env, jobject obj, jfieldID fieldID)
-{
-               return getField(obj,jbyte,fieldID);
+#define JNI_CALL_STATIC_METHOD_V(name, type, intern)                     \
+type _Jv_JNI_CallStatic##name##MethodV(JNIEnv *env, jclass clazz,        \
+                                                                          jmethodID methodID, va_list args) \
+{                                                                        \
+       methodinfo *m;                                                       \
+       type        res;                                                     \
+                                                                         \
+       m = (methodinfo *) methodID;                                         \
+                                                                         \
+       res = _Jv_jni_Call##intern##Method(NULL, NULL, m, args);             \
+                                                                         \
+       return res;                                                          \
 }
 
+JNI_CALL_STATIC_METHOD_V(Boolean, jboolean, Int)
+JNI_CALL_STATIC_METHOD_V(Byte,    jbyte,    Int)
+JNI_CALL_STATIC_METHOD_V(Char,    jchar,    Int)
+JNI_CALL_STATIC_METHOD_V(Short,   jshort,   Int)
+JNI_CALL_STATIC_METHOD_V(Int,     jint,     Int)
+JNI_CALL_STATIC_METHOD_V(Long,    jlong,    Long)
+JNI_CALL_STATIC_METHOD_V(Float,   jfloat,   Float)
+JNI_CALL_STATIC_METHOD_V(Double,  jdouble,  Double)
 
-jchar GetCharField (JNIEnv *env, jobject obj, jfieldID fieldID)
-{
-       return getField(obj,jchar,fieldID);
+
+#define JNI_CALL_STATIC_METHOD_A(name, type, intern)                           \
+type _Jv_JNI_CallStatic##name##MethodA(JNIEnv *env, jclass clazz,              \
+                                                                          jmethodID methodID, const jvalue *args) \
+{                                                                              \
+       methodinfo *m;                                                             \
+       type        res;                                                           \
+                                                                               \
+       m = (methodinfo *) methodID;                                               \
+                                                                               \
+       res = _Jv_jni_Call##intern##MethodA(NULL, NULL, m, args);                  \
+                                                                               \
+       return res;                                                                \
 }
 
+JNI_CALL_STATIC_METHOD_A(Boolean, jboolean, Int)
+JNI_CALL_STATIC_METHOD_A(Byte,    jbyte,    Int)
+JNI_CALL_STATIC_METHOD_A(Char,    jchar,    Int)
+JNI_CALL_STATIC_METHOD_A(Short,   jshort,   Int)
+JNI_CALL_STATIC_METHOD_A(Int,     jint,     Int)
+JNI_CALL_STATIC_METHOD_A(Long,    jlong,    Long)
+JNI_CALL_STATIC_METHOD_A(Float,   jfloat,   Float)
+JNI_CALL_STATIC_METHOD_A(Double,  jdouble,  Double)
+
 
-jshort GetShortField (JNIEnv *env, jobject obj, jfieldID fieldID)
+jobject _Jv_JNI_CallStaticObjectMethod(JNIEnv *env, jclass clazz,
+                                                                          jmethodID methodID, ...)
 {
-       return getField(obj,jshort,fieldID);
-}
+       methodinfo    *m;
+       java_handle_t *o;
+       va_list        ap;
 
+       m = (methodinfo *) methodID;
 
-jint GetIntField (JNIEnv *env, jobject obj, jfieldID fieldID)
-{
-       return getField(obj,jint,fieldID);
+       va_start(ap, methodID);
+       o = _Jv_jni_CallObjectMethod(NULL, NULL, m, ap);
+       va_end(ap);
+
+       return _Jv_JNI_NewLocalRef(env, (jobject) o);
 }
 
 
-jlong GetLongField (JNIEnv *env, jobject obj, jfieldID fieldID)
+jobject _Jv_JNI_CallStaticObjectMethodV(JNIEnv *env, jclass clazz,
+                                                                               jmethodID methodID, va_list args)
 {
-       return getField(obj,jlong,fieldID);
-}
+       methodinfo    *m;
+       java_handle_t *o;
 
+       m = (methodinfo *) methodID;
 
-jfloat GetFloatField (JNIEnv *env, jobject obj, jfieldID fieldID)
-{
-       return getField(obj,jfloat,fieldID);
+       o = _Jv_jni_CallObjectMethod(NULL, NULL, m, args);
+
+       return _Jv_JNI_NewLocalRef(env, (jobject) o);
 }
 
 
-jdouble GetDoubleField (JNIEnv *env, jobject obj, jfieldID fieldID)
+jobject _Jv_JNI_CallStaticObjectMethodA(JNIEnv *env, jclass clazz,
+                                                                               jmethodID methodID, const jvalue *args)
 {
-       return getField(obj,jdouble,fieldID);
-}
+       methodinfo    *m;
+       java_handle_t *o;
 
-void SetObjectField (JNIEnv *env, jobject obj, jfieldID fieldID, jobject val)
-{
-        setField(obj,jobject,fieldID,val);
-}
+       m = (methodinfo *) methodID;
 
+       o = _Jv_jni_CallObjectMethodA(NULL, NULL, m, args);
 
-void SetBooleanField (JNIEnv *env, jobject obj, jfieldID fieldID, jboolean val)
-{
-        setField(obj,jboolean,fieldID,val);
+       return _Jv_JNI_NewLocalRef(env, (jobject) o);
 }
 
 
-void SetByteField (JNIEnv *env, jobject obj, jfieldID fieldID, jbyte val)
+void _Jv_JNI_CallStaticVoidMethod(JNIEnv *env, jclass clazz,
+                                                                 jmethodID methodID, ...)
 {
-        setField(obj,jbyte,fieldID,val);
-}
+       methodinfo *m;
+       va_list     ap;
 
+       m = (methodinfo *) methodID;
 
-void SetCharField (JNIEnv *env, jobject obj, jfieldID fieldID, jchar val)
-{
-        setField(obj,jchar,fieldID,val);
+       va_start(ap, methodID);
+       _Jv_jni_CallVoidMethod(NULL, NULL, m, ap);
+       va_end(ap);
 }
 
 
-void SetShortField (JNIEnv *env, jobject obj, jfieldID fieldID, jshort val)
+void _Jv_JNI_CallStaticVoidMethodV(JNIEnv *env, jclass clazz,
+                                                                  jmethodID methodID, va_list args)
 {
-        setField(obj,jshort,fieldID,val);
-}
+       methodinfo *m;
 
+       m = (methodinfo *) methodID;
 
-void SetIntField (JNIEnv *env, jobject obj, jfieldID fieldID, jint val)
-{
-        setField(obj,jint,fieldID,val);
+       _Jv_jni_CallVoidMethod(NULL, NULL, m, args);
 }
 
 
-void SetLongField (JNIEnv *env, jobject obj, jfieldID fieldID, jlong val)
+void _Jv_JNI_CallStaticVoidMethodA(JNIEnv *env, jclass clazz,
+                                                                  jmethodID methodID, const jvalue * args)
 {
-        setField(obj,jlong,fieldID,val);
-}
+       methodinfo *m;
 
+       m = (methodinfo *) methodID;
 
-void SetFloatField (JNIEnv *env, jobject obj, jfieldID fieldID, jfloat val)
-{
-        setField(obj,jfloat,fieldID,val);
+       _Jv_jni_CallVoidMethodA(NULL, NULL, m, args);
 }
 
 
-void SetDoubleField (JNIEnv *env, jobject obj, jfieldID fieldID, jdouble val)
-{
-        setField(obj,jdouble,fieldID,val);
-}
+/* Accessing Static Fields ****************************************************/
 
+/* GetStaticFieldID ************************************************************
 
-/**************** JNI-functions for calling static methods **********************/ 
+   Returns the field ID for a static field of a class. The field is
+   specified by its name and signature. The GetStatic<type>Field and
+   SetStatic<type>Field families of accessor functions use field IDs
+   to retrieve static fields.
+
+*******************************************************************************/
 
-jmethodID GetStaticMethodID(JNIEnv *env, jclass clazz, const char *name, const char *sig)
+jfieldID _Jv_JNI_GetStaticFieldID(JNIEnv *env, jclass clazz, const char *name,
+                                                                 const char *sig)
 {
-       jmethodID m;
+       classinfo *c;
+       fieldinfo *f;
+       utf       *uname;
+       utf       *usig;
+
+       STATISTICS(jniinvokation());
 
-       m = class_resolvemethod(clazz,
-                                                       utf_new_char((char *) name),
-                                                       utf_new_char((char *) sig));
+       c = (classinfo *) clazz;
 
-       if (!m) *exceptionptr = new_exception(string_java_lang_NoSuchMethodError);
+       uname = utf_new_char((char *) name);
+       usig  = utf_new_char((char *) sig);
+
+       f = class_findfield(c, uname, usig);
+       
+       if (f == NULL)
+               exceptions_throw_nosuchfielderror(c, uname);
 
-       return m;
+       return (jfieldID) f;
 }
 
 
-jobject CallStaticObjectMethod(JNIEnv *env, jclass clazz, jmethodID methodID, ...)
-{
-       log_text("JNI-Call: CallStaticObjectMethod");
+/* GetStatic<type>Field ********************************************************
 
-       return NULL;
-}
+   This family of accessor routines returns the value of a static
+   field of an object.
 
+*******************************************************************************/
 
-jobject CallStaticObjectMethodV(JNIEnv *env, jclass clazz, jmethodID methodID, va_list args)
+#define JNI_GET_STATIC_FIELD(name, type, field)                \
+type _Jv_JNI_GetStatic##name##Field(JNIEnv *env, jclass clazz, \
+                                                                       jfieldID fieldID)          \
+{                                                              \
+       classinfo *c;                                              \
+       fieldinfo *f;                                              \
+                                                               \
+       STATISTICS(jniinvokation());                               \
+                                                               \
+       c = (classinfo *) clazz;                                   \
+       f = (fieldinfo *) fieldID;                                 \
+                                                               \
+       if (!(c->state & CLASS_INITIALIZED))                       \
+               if (!initialize_class(c))                              \
+                       return 0;                                          \
+                                                               \
+       return f->value->field;                                    \
+}
+
+JNI_GET_STATIC_FIELD(Boolean, jboolean, i)
+JNI_GET_STATIC_FIELD(Byte,    jbyte,    i)
+JNI_GET_STATIC_FIELD(Char,    jchar,    i)
+JNI_GET_STATIC_FIELD(Short,   jshort,   i)
+JNI_GET_STATIC_FIELD(Int,     jint,     i)
+JNI_GET_STATIC_FIELD(Long,    jlong,    l)
+JNI_GET_STATIC_FIELD(Float,   jfloat,   f)
+JNI_GET_STATIC_FIELD(Double,  jdouble,  d)
+
+
+jobject _Jv_JNI_GetStaticObjectField(JNIEnv *env, jclass clazz,
+                                                                        jfieldID fieldID)
 {
-       log_text("JNI-Call: CallStaticObjectMethodV");
+       classinfo *c;
+       fieldinfo *f;
 
-       return NULL;
-}
+       STATISTICS(jniinvokation());
 
+       c = (classinfo *) clazz;
+       f = (fieldinfo *) fieldID;
 
-jobject CallStaticObjectMethodA(JNIEnv *env, jclass clazz, jmethodID methodID, jvalue *args)
-{
-       log_text("JNI-Call: CallStaticObjectMethodA");
+       if (!(c->state & CLASS_INITIALIZED))
+               if (!initialize_class(c))
+                       return NULL;
 
-       return NULL;
+       return _Jv_JNI_NewLocalRef(env, f->value->a);
 }
 
 
-jboolean CallStaticBooleanMethod(JNIEnv *env, jclass clazz, jmethodID methodID, ...)
-{
-       jboolean ret;
-       va_list vaargs;
+/*  SetStatic<type>Field *******************************************************
 
-       /*      log_text("JNI-Call: CallStaticBooleanMethod");*/
+       This family of accessor routines sets the value of a static field
+       of an object.
 
-       va_start(vaargs, methodID);
-       ret = (jboolean) callIntegerMethod(0, methodID, 'Z', vaargs);
-       va_end(vaargs);
+*******************************************************************************/
 
-       return ret;
-}
+#define JNI_SET_STATIC_FIELD(name, type, field)                \
+void _Jv_JNI_SetStatic##name##Field(JNIEnv *env, jclass clazz, \
+                                                                       jfieldID fieldID,          \
+                                                                       type value)                \
+{                                                              \
+       classinfo *c;                                              \
+       fieldinfo *f;                                              \
+                                                               \
+       STATISTICS(jniinvokation());                               \
+                                                               \
+       c = (classinfo *) clazz;                                   \
+       f = (fieldinfo *) fieldID;                                 \
+                                                               \
+       if (!(c->state & CLASS_INITIALIZED))                       \
+               if (!initialize_class(c))                              \
+                       return;                                            \
+                                                               \
+       f->value->field = value;                                   \
+}
+
+JNI_SET_STATIC_FIELD(Boolean, jboolean, i)
+JNI_SET_STATIC_FIELD(Byte,    jbyte,    i)
+JNI_SET_STATIC_FIELD(Char,    jchar,    i)
+JNI_SET_STATIC_FIELD(Short,   jshort,   i)
+JNI_SET_STATIC_FIELD(Int,     jint,     i)
+JNI_SET_STATIC_FIELD(Long,    jlong,    l)
+JNI_SET_STATIC_FIELD(Float,   jfloat,   f)
+JNI_SET_STATIC_FIELD(Double,  jdouble,  d)
+
+
+void _Jv_JNI_SetStaticObjectField(JNIEnv *env, jclass clazz, jfieldID fieldID,
+                                                                 jobject value)
+{
+       classinfo *c;
+       fieldinfo *f;
 
+       STATISTICS(jniinvokation());
 
-jboolean CallStaticBooleanMethodV(JNIEnv *env, jclass clazz, jmethodID methodID, va_list args)
-{
-       return (jboolean) callIntegerMethod(0, methodID, 'Z', args);
+       c = (classinfo *) clazz;
+       f = (fieldinfo *) fieldID;
+
+       if (!(c->state & CLASS_INITIALIZED))
+               if (!initialize_class(c))
+                       return;
+
+       f->value->a = value;
 }
 
 
-jboolean CallStaticBooleanMethodA(JNIEnv *env, jclass clazz, jmethodID methodID, jvalue *args)
-{
-       log_text("JNI-Call: CallStaticBooleanMethodA");
+/* String Operations **********************************************************/
 
-       return 0;
-}
+/* NewString *******************************************************************
 
+   Create new java.lang.String object from an array of Unicode
+   characters.
 
-jbyte CallStaticByteMethod(JNIEnv *env, jclass clazz, jmethodID methodID, ...)
+*******************************************************************************/
+
+jstring _Jv_JNI_NewString(JNIEnv *env, const jchar *buf, jsize len)
 {
-       jbyte ret;
-       va_list vaargs;
+       java_lang_String        *s;
+       java_handle_chararray_t *a;
+       u4                       i;
 
-       /*      log_text("JNI-Call: CallStaticByteMethod");*/
+       STATISTICS(jniinvokation());
+       
+       s = (java_lang_String *) builtin_new(class_java_lang_String);
+       a = builtin_newarray_char(len);
 
-       va_start(vaargs, methodID);
-       ret = (jbyte) callIntegerMethod(0, methodID, 'B', vaargs);
-       va_end(vaargs);
+       /* javastring or characterarray could not be created */
+       if ((a == NULL) || (s == NULL))
+               return NULL;
 
-       return ret;
-}
+       /* copy text */
+       for (i = 0; i < len; 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);
 
-jbyte CallStaticByteMethodV(JNIEnv *env, jclass clazz, jmethodID methodID, va_list args)
-{
-       return (jbyte) callIntegerMethod(0, methodID, 'B', args);
+       return (jstring) _Jv_JNI_NewLocalRef(env, (jobject) s);
 }
 
 
-jbyte CallStaticByteMethodA(JNIEnv *env, jclass clazz, jmethodID methodID, jvalue *args)
-{
-       log_text("JNI-Call: CallStaticByteMethodA");
+static jchar emptyStringJ[]={0,0};
 
-       return 0;
-}
+/* GetStringLength *************************************************************
 
+   Returns the length (the count of Unicode characters) of a Java
+   string.
 
-jchar CallStaticCharMethod(JNIEnv *env, jclass clazz, jmethodID methodID, ...)
+*******************************************************************************/
+
+jsize _Jv_JNI_GetStringLength(JNIEnv *env, jstring str)
 {
-       jchar ret;
-       va_list vaargs;
+       java_lang_String *s;
+       jsize             len;
+
+       TRACEJNICALLS("_Jv_JNI_GetStringLength(env=%p, str=%p)", env, str);
 
-       /*      log_text("JNI-Call: CallStaticByteMethod");*/
+       s = (java_lang_String *) str;
 
-       va_start(vaargs, methodID);
-       ret = (jchar) callIntegerMethod(0, methodID, 'C', vaargs);
-       va_end(vaargs);
+       LLNI_field_get_val(s, count, len);
 
-       return ret;
+       return len;
 }
 
 
-jchar CallStaticCharMethodV(JNIEnv *env, jclass clazz, jmethodID methodID, va_list args)
+/********************  convertes javastring to u2-array ****************************/
+       
+u2 *javastring_tou2(jstring so) 
 {
-       return (jchar) callIntegerMethod(0, methodID, 'C', args);
-}
+       java_lang_String        *s;
+       java_handle_chararray_t *a;
+       u2                      *stringbuffer;
+       u4                       i;
+       int32_t                  count;
+       int32_t                  offset;
 
+       STATISTICS(jniinvokation());
+       
+       s = (java_lang_String *) so;
 
-jchar CallStaticCharMethodA(JNIEnv *env, jclass clazz, jmethodID methodID, jvalue *args)
-{
-       log_text("JNI-Call: CallStaticCharMethodA");
+       if (!s)
+               return NULL;
 
-       return 0;
-}
+       LLNI_field_get_ref(s, value, a);
 
+       if (!a)
+               return NULL;
 
+       LLNI_field_get_val(s, count, count);
+       LLNI_field_get_val(s, offset, offset);
 
-jshort CallStaticShortMethod(JNIEnv *env, jclass clazz, jmethodID methodID, ...)
-{
-       jshort ret;
-       va_list vaargs;
+       /* allocate memory */
 
-       /*      log_text("JNI-Call: CallStaticByteMethod");*/
+       stringbuffer = MNEW(u2, count + 1);
 
-       va_start(vaargs, methodID);
-       ret = (jshort) callIntegerMethod(0, methodID, 'S', vaargs);
-       va_end(vaargs);
+       /* copy text */
 
-       return ret;
-}
+       for (i = 0; i < count; i++)
+               stringbuffer[i] = LLNI_array_direct(a, offset + i);
+       
+       /* terminate string */
 
+       stringbuffer[i] = '\0';
 
-jshort CallStaticShortMethodV(JNIEnv *env, jclass clazz, jmethodID methodID, va_list args)
-{
-       /*log_text("JNI-Call: CallStaticShortMethodV");*/
-       return (jshort) callIntegerMethod(0, methodID, 'S', args);
+       return stringbuffer;
 }
 
 
-jshort CallStaticShortMethodA(JNIEnv *env, jclass clazz, jmethodID methodID, jvalue *args)
-{
-       log_text("JNI-Call: CallStaticShortMethodA");
+/* GetStringChars **************************************************************
 
-       return 0;
-}
+   Returns a pointer to the array of Unicode characters of the
+   string. This pointer is valid until ReleaseStringChars() is called.
 
+*******************************************************************************/
 
+const jchar *_Jv_JNI_GetStringChars(JNIEnv *env, jstring str, jboolean *isCopy)
+{      
+       jchar *jc;
 
-jint CallStaticIntMethod(JNIEnv *env, jclass clazz, jmethodID methodID, ...)
-{
-       jint ret;
-       va_list vaargs;
+       STATISTICS(jniinvokation());
 
-       /*      log_text("JNI-Call: CallStaticIntMethod");*/
+       jc = javastring_tou2(str);
 
-       va_start(vaargs, methodID);
-       ret = callIntegerMethod(0, methodID, 'I', vaargs);
-       va_end(vaargs);
+       if (jc) {
+               if (isCopy)
+                       *isCopy = JNI_TRUE;
+
+               return jc;
+       }
 
-       return ret;
+       if (isCopy)
+               *isCopy = JNI_TRUE;
+
+       return emptyStringJ;
 }
 
 
-jint CallStaticIntMethodV(JNIEnv *env, jclass clazz, jmethodID methodID, va_list args)
-{
-       log_text("JNI-Call: CallStaticIntMethodV");
+/* ReleaseStringChars **********************************************************
 
-       return callIntegerMethod(0, methodID, 'I', args);
-}
+   Informs the VM that the native code no longer needs access to
+   chars. The chars argument is a pointer obtained from string using
+   GetStringChars().
 
+*******************************************************************************/
 
-jint CallStaticIntMethodA(JNIEnv *env, jclass clazz, jmethodID methodID, jvalue *args)
+void _Jv_JNI_ReleaseStringChars(JNIEnv *env, jstring str, const jchar *chars)
 {
-       log_text("JNI-Call: CallStaticIntMethodA");
+       java_lang_String *s;
 
-       return 0;
-}
+       STATISTICS(jniinvokation());
 
+       if (chars == emptyStringJ)
+               return;
 
+       s = (java_lang_String *) str;
 
-jlong CallStaticLongMethod(JNIEnv *env, jclass clazz, jmethodID methodID, ...)
-{
-       jlong ret;
-       va_list vaargs;
+       MFREE(((jchar *) chars), jchar, LLNI_field_direct(s, count) + 1);
+}
 
-       /*      log_text("JNI-Call: CallStaticLongMethod");*/
 
-       va_start(vaargs, methodID);
-       ret = callLongMethod(0, methodID, vaargs);
-       va_end(vaargs);
+/* NewStringUTF ****************************************************************
 
-       return ret;
-}
+   Constructs a new java.lang.String object from an array of UTF-8
+   characters.
 
+*******************************************************************************/
 
-jlong CallStaticLongMethodV(JNIEnv *env, jclass clazz, jmethodID methodID, va_list args)
+jstring _Jv_JNI_NewStringUTF(JNIEnv *env, const char *bytes)
 {
-       log_text("JNI-Call: CallStaticLongMethodV");
-       
-       return callLongMethod(0,methodID,args);
-}
+       java_lang_String *s;
 
+       TRACEJNICALLS("_Jv_JNI_NewStringUTF(env=%p, bytes=%s)", env, bytes);
 
-jlong CallStaticLongMethodA(JNIEnv *env, jclass clazz, jmethodID methodID, jvalue *args)
-{
-       log_text("JNI-Call: CallStaticLongMethodA");
+       s = (java_lang_String *) javastring_safe_new_from_utf8(bytes);
 
-       return 0;
+    return (jstring) _Jv_JNI_NewLocalRef(env, (jobject) s);
 }
 
 
+/****************** returns the utf8 length in bytes of a string *******************/
 
-jfloat CallStaticFloatMethod(JNIEnv *env, jclass clazz, jmethodID methodID, ...)
-{
-       jfloat ret;
-       va_list vaargs;
+jsize _Jv_JNI_GetStringUTFLength(JNIEnv *env, jstring string)
+{   
+       java_lang_String *s;
+       s4                length;
 
-       /*      log_text("JNI-Call: CallStaticLongMethod");*/
+       TRACEJNICALLS("_Jv_JNI_GetStringUTFLength(env=%p, string=%p)", env, string);
 
-       va_start(vaargs, methodID);
-       ret = callFloatMethod(0, methodID, vaargs, 'F');
-       va_end(vaargs);
+       s = (java_lang_String *) string;
 
-       return ret;
-}
+       length = u2_utflength(LLNI_field_direct(s, value)->data, LLNI_field_direct(s, count));
 
+       return length;
+}
 
-jfloat CallStaticFloatMethodV(JNIEnv *env, jclass clazz, jmethodID methodID, va_list args)
-{
 
-       return callFloatMethod(0, methodID, args, 'F');
+/* GetStringUTFChars ***********************************************************
 
-}
+   Returns a pointer to an array of UTF-8 characters of the
+   string. This array is valid until it is released by
+   ReleaseStringUTFChars().
 
+*******************************************************************************/
 
-jfloat CallStaticFloatMethodA(JNIEnv *env, jclass clazz, jmethodID methodID, jvalue *args)
+const char *_Jv_JNI_GetStringUTFChars(JNIEnv *env, jstring string,
+                                                                         jboolean *isCopy)
 {
-       log_text("JNI-Call: CallStaticFloatMethodA");
+       utf *u;
 
-       return 0;
-}
+       STATISTICS(jniinvokation());
 
+       if (string == NULL)
+               return "";
 
+       if (isCopy)
+               *isCopy = JNI_TRUE;
+       
+       u = javastring_toutf((java_handle_t *) string, false);
 
-jdouble CallStaticDoubleMethod(JNIEnv *env, jclass clazz, jmethodID methodID, ...)
-{
-       jdouble ret;
-       va_list vaargs;
+       if (u != NULL)
+               return u->text;
+
+       return "";
+}
 
-       /*      log_text("JNI-Call: CallStaticDoubleMethod");*/
 
-       va_start(vaargs,methodID);
-       ret = callFloatMethod(0, methodID, vaargs, 'D');
-       va_end(vaargs);
+/* ReleaseStringUTFChars *******************************************************
 
-       return ret;
-}
+   Informs the VM that the native code no longer needs access to
+   utf. The utf argument is a pointer derived from string using
+   GetStringUTFChars().
 
+*******************************************************************************/
 
-jdouble CallStaticDoubleMethodV(JNIEnv *env, jclass clazz, jmethodID methodID, va_list args)
+void _Jv_JNI_ReleaseStringUTFChars(JNIEnv *env, jstring string, const char *utf)
 {
-       log_text("JNI-Call: CallStaticDoubleMethodV");
+       STATISTICS(jniinvokation());
 
-       return callFloatMethod(0, methodID, args, 'D');
+    /* XXX we don't release utf chars right now, perhaps that should be done 
+          later. Since there is always one reference the garbage collector will
+          never get them */
 }
 
 
-jdouble CallStaticDoubleMethodA(JNIEnv *env, jclass clazz, jmethodID methodID, jvalue *args)
-{
-       log_text("JNI-Call: CallStaticDoubleMethodA");
+/* Array Operations ***********************************************************/
 
-       return 0;
-}
+/* GetArrayLength **************************************************************
 
+   Returns the number of elements in the array.
+
+*******************************************************************************/
 
-void CallStaticVoidMethod(JNIEnv *env, jclass cls, jmethodID methodID, ...)
+jsize _Jv_JNI_GetArrayLength(JNIEnv *env, jarray array)
 {
-       va_list vaargs;
+       java_handle_t *a;
+       jsize          size;
 
-/*      log_text("JNI-Call: CallStaticVoidMethod");*/
+       STATISTICS(jniinvokation());
 
-       va_start(vaargs, methodID);
-       (void) callIntegerMethod(0, methodID, 'V', vaargs);
-       va_end(vaargs);
-}
+       a = (java_handle_t *) array;
 
+       size = LLNI_array_size(a);
 
-void CallStaticVoidMethodV(JNIEnv *env, jclass cls, jmethodID methodID, va_list args)
-{
-       log_text("JNI-Call: CallStaticVoidMethodV");
-       (void)callIntegerMethod(0, methodID, 'V', args);
+       return size;
 }
 
 
-void CallStaticVoidMethodA(JNIEnv *env, jclass cls, jmethodID methodID, jvalue * args)
-{
-       log_text("JNI-Call: CallStaticVoidMethodA");
-}
+/* NewObjectArray **************************************************************
 
+   Constructs a new array holding objects in class elementClass. All
+   elements are initially set to initialElement.
 
-/****************** JNI-functions for accessing static fields ********************/
+*******************************************************************************/
 
-jfieldID GetStaticFieldID (JNIEnv *env, jclass clazz, const char *name, const char *sig) 
+jobjectArray _Jv_JNI_NewObjectArray(JNIEnv *env, jsize length,
+                                                                       jclass elementClass, jobject initialElement)
 {
-       jfieldID f;
+       classinfo                 *c;
+       java_handle_t             *o;
+       java_handle_objectarray_t *oa;
+       s4                         i;
 
-       f = jclass_findfield(clazz,
-                           utf_new_char ((char*) name), 
-                           utf_new_char ((char*) sig)
-                           ); 
-       
-       if (!f) *exceptionptr = new_exception(string_java_lang_NoSuchFieldError);  
+       STATISTICS(jniinvokation());
 
-       return f;
-}
+       c = (classinfo *) elementClass;
+       o = (java_handle_t *) initialElement;
 
+       if (length < 0) {
+               exceptions_throw_negativearraysizeexception();
+               return NULL;
+       }
 
-jobject GetStaticObjectField (JNIEnv *env, jclass clazz, jfieldID fieldID)
-{
-       class_init(clazz);
-       return fieldID->value.a;       
-}
+    oa = builtin_anewarray(length, c);
 
+       if (oa == NULL)
+               return NULL;
 
-jboolean GetStaticBooleanField (JNIEnv *env, jclass clazz, jfieldID fieldID)
-{
-       class_init(clazz);
-       return fieldID->value.i;       
-}
+       /* set all elements to initialElement */
 
+       for (i = 0; i < length; i++)
+               LLNI_objectarray_element_set(oa, i, o);
 
-jbyte GetStaticByteField (JNIEnv *env, jclass clazz, jfieldID fieldID)
-{
-       class_init(clazz);
-       return fieldID->value.i;       
+       return (jobjectArray) _Jv_JNI_NewLocalRef(env, (jobject) oa);
 }
 
 
-jchar GetStaticCharField (JNIEnv *env, jclass clazz, jfieldID fieldID)
+jobject _Jv_JNI_GetObjectArrayElement(JNIEnv *env, jobjectArray array,
+                                                                         jsize index)
 {
-       class_init(clazz);
-       return fieldID->value.i;       
-}
-
+       java_handle_objectarray_t *oa;
+       java_handle_t             *o;
 
-jshort GetStaticShortField (JNIEnv *env, jclass clazz, jfieldID fieldID)
-{
-       class_init(clazz);
-       return fieldID->value.i;       
-}
+       STATISTICS(jniinvokation());
 
+       oa = (java_handle_objectarray_t *) array;
 
-jint GetStaticIntField (JNIEnv *env, jclass clazz, jfieldID fieldID)
-{
-       class_init(clazz);
-       return fieldID->value.i;       
-}
+       if (index >= LLNI_array_size(oa)) {
+               exceptions_throw_arrayindexoutofboundsexception();
+               return NULL;
+       }
 
+       LLNI_objectarray_element_get(oa, index, o);
 
-jlong GetStaticLongField (JNIEnv *env, jclass clazz, jfieldID fieldID)
-{
-       class_init(clazz);
-       return fieldID->value.l;
+       return _Jv_JNI_NewLocalRef(env, (jobject) o);
 }
 
 
-jfloat GetStaticFloatField (JNIEnv *env, jclass clazz, jfieldID fieldID)
+void _Jv_JNI_SetObjectArrayElement(JNIEnv *env, jobjectArray array,
+                                                                  jsize index, jobject val)
 {
-       class_init(clazz);
-       return fieldID->value.f;
-}
+       java_handle_objectarray_t *oa;
+       java_handle_t             *o;
 
+       STATISTICS(jniinvokation());
 
-jdouble GetStaticDoubleField (JNIEnv *env, jclass clazz, jfieldID fieldID)
-{
-       class_init(clazz);
-       return fieldID->value.d;
-}
+       oa = (java_handle_objectarray_t *) array;
+       o  = (java_handle_t *) val;
 
+       if (index >= LLNI_array_size(oa)) {
+               exceptions_throw_arrayindexoutofboundsexception();
+               return;
+       }
 
+       /* check if the class of value is a subclass of the element class
+          of the array */
 
-void SetStaticObjectField (JNIEnv *env, jclass clazz, jfieldID fieldID, jobject value)
-{
-       class_init(clazz);
-       fieldID->value.a = value;
+       if (!builtin_canstore(oa, o))
+               return;
+
+       LLNI_objectarray_element_set(oa, index, o);
 }
 
 
-void SetStaticBooleanField (JNIEnv *env, jclass clazz, jfieldID fieldID, jboolean value)
-{
-       class_init(clazz);
-       fieldID->value.i = value;
+#define JNI_NEW_ARRAY(name, type, intern)                \
+type _Jv_JNI_New##name##Array(JNIEnv *env, jsize len)    \
+{                                                        \
+       java_handle_##intern##array_t *a;                    \
+                                                         \
+       STATISTICS(jniinvokation());                         \
+                                                         \
+       if (len < 0) {                                       \
+               exceptions_throw_negativearraysizeexception();   \
+               return NULL;                                     \
+       }                                                    \
+                                                         \
+       a = builtin_newarray_##intern(len);                  \
+                                                         \
+       return (type) _Jv_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(Int,     jintArray,     int)
+JNI_NEW_ARRAY(Long,    jlongArray,    long)
+JNI_NEW_ARRAY(Float,   jfloatArray,   float)
+JNI_NEW_ARRAY(Double,  jdoubleArray,  double)
 
-void SetStaticByteField (JNIEnv *env, jclass clazz, jfieldID fieldID, jbyte value)
-{
-       class_init(clazz);
-       fieldID->value.i = value;
-}
 
+/* Get<PrimitiveType>ArrayElements *********************************************
 
-void SetStaticCharField (JNIEnv *env, jclass clazz, jfieldID fieldID, jchar value)
-{
-       class_init(clazz);
-       fieldID->value.i = value;
-}
+   A family of functions that returns the body of the primitive array.
 
+*******************************************************************************/
 
-void SetStaticShortField (JNIEnv *env, jclass clazz, jfieldID fieldID, jshort value)
-{
-       class_init(clazz);
-       fieldID->value.i = value;
-}
+#define JNI_GET_ARRAY_ELEMENTS(name, type, intern)                     \
+type *_Jv_JNI_Get##name##ArrayElements(JNIEnv *env, type##Array array, \
+                                                                                jboolean *isCopy)             \
+{                                                                      \
+       java_handle_##intern##array_t *a;                                  \
+                                                                       \
+       STATISTICS(jniinvokation());                                       \
+                                                                       \
+       a = (java_handle_##intern##array_t *) array;                       \
+                                                                       \
+       if (isCopy)                                                        \
+               *isCopy = JNI_FALSE;                                           \
+                                                                       \
+       return LLNI_array_data(a);                                         \
+}
+
+JNI_GET_ARRAY_ELEMENTS(Boolean, jboolean, boolean)
+JNI_GET_ARRAY_ELEMENTS(Byte,    jbyte,    byte)
+JNI_GET_ARRAY_ELEMENTS(Char,    jchar,    char)
+JNI_GET_ARRAY_ELEMENTS(Short,   jshort,   short)
+JNI_GET_ARRAY_ELEMENTS(Int,     jint,     int)
+JNI_GET_ARRAY_ELEMENTS(Long,    jlong,    long)
+JNI_GET_ARRAY_ELEMENTS(Float,   jfloat,   float)
+JNI_GET_ARRAY_ELEMENTS(Double,  jdouble,  double)
+
+
+/* Release<PrimitiveType>ArrayElements *****************************************
+
+   A family of functions that informs the VM that the native code no
+   longer needs access to elems. The elems argument is a pointer
+   derived from array using the corresponding
+   Get<PrimitiveType>ArrayElements() function. If necessary, this
+   function copies back all changes made to elems to the original
+   array.
 
+*******************************************************************************/
 
-void SetStaticIntField (JNIEnv *env, jclass clazz, jfieldID fieldID, jint value)
-{
-       class_init(clazz);
-       fieldID->value.i = value;
-}
+#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 != 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)
+JNI_RELEASE_ARRAY_ELEMENTS(Byte,    jbyte,    byte,    s1)
+JNI_RELEASE_ARRAY_ELEMENTS(Char,    jchar,    char,    u2)
+JNI_RELEASE_ARRAY_ELEMENTS(Short,   jshort,   short,   s2)
+JNI_RELEASE_ARRAY_ELEMENTS(Int,     jint,     int,     s4)
+JNI_RELEASE_ARRAY_ELEMENTS(Long,    jlong,    long,    s8)
+JNI_RELEASE_ARRAY_ELEMENTS(Float,   jfloat,   float,   float)
+JNI_RELEASE_ARRAY_ELEMENTS(Double,  jdouble,  double,  double)
+
+
+/*  Get<PrimitiveType>ArrayRegion **********************************************
+
+       A family of functions that copies a region of a primitive array
+       into a buffer.
 
+*******************************************************************************/
 
-void SetStaticLongField (JNIEnv *env, jclass clazz, jfieldID fieldID, jlong value)
-{
-       class_init(clazz);
-       fieldID->value.l = value;
-}
+#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;                                   \
+                                                                        \
+       STATISTICS(jniinvokation());                                        \
+                                                                        \
+       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)
+JNI_GET_ARRAY_REGION(Byte,    jbyte,    byte,    s1)
+JNI_GET_ARRAY_REGION(Char,    jchar,    char,    u2)
+JNI_GET_ARRAY_REGION(Short,   jshort,   short,   s2)
+JNI_GET_ARRAY_REGION(Int,     jint,     int,     s4)
+JNI_GET_ARRAY_REGION(Long,    jlong,    long,    s8)
+JNI_GET_ARRAY_REGION(Float,   jfloat,   float,   float)
+JNI_GET_ARRAY_REGION(Double,  jdouble,  double,  double)
+
+
+/*  Set<PrimitiveType>ArrayRegion **********************************************
+
+       A family of functions that copies back a region of a primitive
+       array from a buffer.
 
+*******************************************************************************/
 
-void SetStaticFloatField (JNIEnv *env, jclass clazz, jfieldID fieldID, jfloat value)
-{
-       class_init(clazz);
-       fieldID->value.f = value;
-}
+#define JNI_SET_ARRAY_REGION(name, type, intern, intern2)                    \
+void _Jv_JNI_Set##name##ArrayRegion(JNIEnv *env, type##Array array,          \
+                                                                       jsize start, jsize len, const type *buf) \
+{                                                                            \
+       java_handle_##intern##array_t *a;                                        \
+                                                                             \
+       STATISTICS(jniinvokation());                                             \
+                                                                             \
+       a = (java_handle_##intern##array_t *) array;                             \
+                                                                             \
+       if ((start < 0) || (len < 0) || (start + len > LLNI_array_size(a)))      \
+               exceptions_throw_arrayindexoutofboundsexception();                   \
+       else                                                                     \
+               MCOPY(&LLNI_array_direct(a, start), buf, intern2, len);              \
+}
+
+JNI_SET_ARRAY_REGION(Boolean, jboolean, boolean, u1)
+JNI_SET_ARRAY_REGION(Byte,    jbyte,    byte,    s1)
+JNI_SET_ARRAY_REGION(Char,    jchar,    char,    u2)
+JNI_SET_ARRAY_REGION(Short,   jshort,   short,   s2)
+JNI_SET_ARRAY_REGION(Int,     jint,     int,     s4)
+JNI_SET_ARRAY_REGION(Long,    jlong,    long,    s8)
+JNI_SET_ARRAY_REGION(Float,   jfloat,   float,   float)
+JNI_SET_ARRAY_REGION(Double,  jdouble,  double,  double)
+
+
+/* Registering Native Methods *************************************************/
+
+/* RegisterNatives *************************************************************
+
+   Registers native methods with the class specified by the clazz
+   argument. The methods parameter specifies an array of
+   JNINativeMethod structures that contain the names, signatures, and
+   function pointers of the native methods. The nMethods parameter
+   specifies the number of native methods in the array.
 
+*******************************************************************************/
 
-void SetStaticDoubleField (JNIEnv *env, jclass clazz, jfieldID fieldID, jdouble value)
+jint _Jv_JNI_RegisterNatives(JNIEnv *env, jclass clazz,
+                                                        const JNINativeMethod *methods, jint nMethods)
 {
-       class_init(clazz);
-       fieldID->value.d = value;
-}
-
+       classinfo *c;
 
-/*****  create new java.lang.String object from an array of Unicode characters ****/ 
+       STATISTICS(jniinvokation());
 
-jstring NewString (JNIEnv *env, const jchar *buf, jsize len)
-{
-       u4 i;
-       java_lang_String *s;
-       java_chararray *a;
-       
-       s = (java_lang_String*) builtin_new (class_java_lang_String);
-       a = builtin_newarray_char (len);
+       c = (classinfo *) clazz;
 
-       /* javastring or characterarray could not be created */
-       if ( (!a) || (!s) ) return NULL;
+       /* XXX: if implemented this needs a call to jvmti_NativeMethodBind
+       if (jvmti) jvmti_NativeMethodBind(method, address,  new_address_ptr);
+       */
 
-       /* copy text */
-       for (i=0; i<len; i++) a->data[i] = buf[i];
-       s -> value = a;
-       s -> offset = 0;
-       s -> count = len;
+       native_method_register(c->name, methods, nMethods);
 
-       return (jstring) s;
+    return 0;
 }
 
 
-static char emptyString[]="";
-static jchar emptyStringJ[]={0,0};
+/* UnregisterNatives ***********************************************************
 
-/******************* returns the length of a Java string ***************************/
+   Unregisters native methods of a class. The class goes back to the
+   state before it was linked or registered with its native method
+   functions.
 
-jsize GetStringLength (JNIEnv *env, jstring str)
-{
-       return ((java_lang_String*) str)->count;
-}
+   This function should not be used in normal native code. Instead, it
+   provides special programs a way to reload and relink native
+   libraries.
 
+*******************************************************************************/
 
-/********************  convertes javastring to u2-array ****************************/
-       
-u2 *javastring_tou2 (jstring so) 
+jint _Jv_JNI_UnregisterNatives(JNIEnv *env, jclass clazz)
 {
-       java_lang_String *s = (java_lang_String*) so;
-       java_chararray *a;
-       u4 i;
-       u2 *stringbuffer;
-       
-       if (!s) return NULL;
+       STATISTICS(jniinvokation());
 
-       a = s->value;
-       if (!a) return NULL;
-
-       /* allocate memory */
-       stringbuffer = MNEW( u2 , s->count + 1 );
+       /* XXX TWISTI hmm, maybe we should not support that (like kaffe) */
 
-       /* copy text */
-       for (i=0; i<s->count; i++) stringbuffer[i] = a->data[s->offset+i];
-       
-       /* terminate string */
-       stringbuffer[i] = '\0';
+    log_text("JNI-Call: UnregisterNatives: IMPLEMENT ME!!!");
 
-       return stringbuffer;
+    return 0;
 }
 
-/********* returns a pointer to an array of Unicode characters of the string *******/
-
-const jchar *GetStringChars (JNIEnv *env, jstring str, jboolean *isCopy)
-{      
-       jchar *jc=javastring_tou2(str);
 
-       if (jc) {
-               if (isCopy) *isCopy=JNI_TRUE;
-               return jc;
-       }
-       if (isCopy) *isCopy=JNI_TRUE;
-       return emptyStringJ;
-}
+/* Monitor Operations *********************************************************/
 
-/**************** native code no longer needs access to chars **********************/
+/* MonitorEnter ****************************************************************
 
-void ReleaseStringChars (JNIEnv *env, jstring str, const jchar *chars)
-{
-       if (chars==emptyStringJ) return;
-       MFREE(((jchar*) chars),jchar,((java_lang_String*) str)->count+1);
-}
+   Enters the monitor associated with the underlying Java object
+   referred to by obj.
 
-/************ create new java.lang.String object from utf8-characterarray **********/
+*******************************************************************************/
 
-jstring NewStringUTF (JNIEnv *env, const char *utf)
+jint _Jv_JNI_MonitorEnter(JNIEnv *env, jobject obj)
 {
-/*    log_text("NewStringUTF called");*/
-    return (jstring) javastring_new(utf_new_char((char *) utf));
-}
+       STATISTICS(jniinvokation());
 
-/****************** returns the utf8 length in bytes of a string *******************/
+       if (obj == NULL) {
+               exceptions_throw_nullpointerexception();
+               return JNI_ERR;
+       }
 
-jsize GetStringUTFLength (JNIEnv *env, jstring string)
-{   
-    java_lang_String *s = (java_lang_String*) string;
+       LOCK_MONITOR_ENTER(obj);
 
-    return (jsize) u2_utflength(s->value->data, s->count); 
+       return JNI_OK;
 }
 
 
-/************ converts a Javastring to an array of UTF-8 characters ****************/
+/* MonitorExit *****************************************************************
 
-const char* GetStringUTFChars(JNIEnv *env, jstring string, jboolean *isCopy)
+   The current thread must be the owner of the monitor associated with
+   the underlying Java object referred to by obj. The thread
+   decrements the counter indicating the number of times it has
+   entered this monitor. If the value of the counter becomes zero, the
+   current thread releases the monitor.
+
+*******************************************************************************/
+
+jint _Jv_JNI_MonitorExit(JNIEnv *env, jobject obj)
 {
-    utf *u;
+       STATISTICS(jniinvokation());
 
-    u = javastring_toutf((java_lang_String *) string, false);
+       if (obj == NULL) {
+               exceptions_throw_nullpointerexception();
+               return JNI_ERR;
+       }
 
-    if (isCopy)
-               *isCopy = JNI_FALSE;
-       
-    if (u)
-               return u->text;
+       LOCK_MONITOR_EXIT(obj);
 
-    return emptyString;
-       
+       return JNI_OK;
 }
 
 
-/***************** native code no longer needs access to utf ***********************/
+/* JavaVM Interface ***********************************************************/
 
-void ReleaseStringUTFChars (JNIEnv *env, jstring str, const char* chars)
-{
-    /*we don't release utf chars right now, perhaps that should be done later. Since there is always one reference
-       the garbage collector will never get them*/
-       /*
-    log_text("JNI-Call: ReleaseStringUTFChars");
-    utf_display(utf_new_char(chars));
-       */
-}
+/* GetJavaVM *******************************************************************
 
-/************************** array operations ***************************************/
+   Returns the Java VM interface (used in the Invocation API)
+   associated with the current thread. The result is placed at the
+   location pointed to by the second argument, vm.
+
+*******************************************************************************/
 
-jsize GetArrayLength(JNIEnv *env, jarray array)
+jint _Jv_JNI_GetJavaVM(JNIEnv *env, JavaVM **vm)
 {
-    return array->size;
-}
+       STATISTICS(jniinvokation());
 
+    *vm = (JavaVM *) _Jv_jvm;
 
-jobjectArray NewObjectArray (JNIEnv *env, jsize len, jclass clazz, jobject init)
-{
-       java_objectarray *j;
+       return 0;
+}
 
-    if (len < 0) {
-               *exceptionptr = new_exception(string_java_lang_NegativeArraySizeException);
-               return NULL;
-    }
 
-    j = builtin_anewarray(len, clazz);
+/* GetStringRegion *************************************************************
 
-    if (!j)
-               *exceptionptr = new_exception(string_java_lang_OutOfMemoryError);
+   Copies len number of Unicode characters beginning at offset start
+   to the given buffer buf.
 
-    return j;
-}
+   Throws StringIndexOutOfBoundsException on index overflow.
 
+*******************************************************************************/
 
-jobject GetObjectArrayElement(JNIEnv *env, jobjectArray array, jsize index)
+void _Jv_JNI_GetStringRegion(JNIEnv* env, jstring str, jsize start, jsize len,
+                                                        jchar *buf)
 {
-    jobject j = NULL;
-
-    if (index < array->header.size)    
-               j = array->data[index];
-    else
-               *exceptionptr = new_exception(string_java_lang_ArrayIndexOutOfBoundsException);
-    
-    return j;
-}
+       java_lang_String        *s;
+       java_handle_chararray_t *ca;
 
+       STATISTICS(jniinvokation());
 
-void SetObjectArrayElement(JNIEnv *env, jobjectArray array, jsize index, jobject val)
-{
-    if (index >= array->header.size)
-               *exceptionptr = new_exception(string_java_lang_ArrayIndexOutOfBoundsException);
+       s  = (java_lang_String *) str;
+       LLNI_field_get_ref(s, value, ca);
 
-    else {
-               /* check if the class of value is a subclass of the element class of the array */
-               if (!builtin_canstore((java_objectarray *) array, (java_objectheader *) val))
-                       *exceptionptr = new_exception(string_java_lang_ArrayStoreException);
+       if ((start < 0) || (len < 0) || (start > LLNI_field_direct(s, count)) ||
+               (start + len > LLNI_field_direct(s, count))) {
+               exceptions_throw_stringindexoutofboundsexception();
+               return;
+       }
 
-               else
-                       array->data[index] = val;
-    }
+       MCOPY(buf, &LLNI_array_direct(ca, start), u2, len);
 }
 
 
+/* GetStringUTFRegion **********************************************************
+
+    Translates len number of Unicode characters beginning at offset
+    start into UTF-8 format and place the result in the given buffer
+    buf.
+
+    Throws StringIndexOutOfBoundsException on index overflow. 
+
+*******************************************************************************/
 
-jbooleanArray NewBooleanArray(JNIEnv *env, jsize len)
+void _Jv_JNI_GetStringUTFRegion(JNIEnv* env, jstring str, jsize start,
+                                                               jsize len, char *buf)
 {
-       java_booleanarray *j;
+       java_lang_String        *s;
+       java_handle_chararray_t *ca;
+       s4                       i;
+       int32_t                  count;
+       int32_t                  offset;
 
-    if (len < 0) {
-               *exceptionptr = new_exception(string_java_lang_NegativeArraySizeException);
-               return NULL;
-    }
+       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);
 
-    j = builtin_newarray_boolean(len);
+       if ((start < 0) || (len < 0) || (start > count) || (start + len > count)) {
+               exceptions_throw_stringindexoutofboundsexception();
+               return;
+       }
 
-    if (!j)
-               *exceptionptr = new_exception(string_java_lang_OutOfMemoryError);
+       for (i = 0; i < len; i++)
+               buf[i] = LLNI_array_direct(ca, offset + start + i);
 
-    return j;
+       buf[i] = '\0';
 }
 
 
-jbyteArray NewByteArray(JNIEnv *env, jsize len)
+/* GetPrimitiveArrayCritical ***************************************************
+
+   Obtain a direct pointer to array elements.
+
+*******************************************************************************/
+
+void *_Jv_JNI_GetPrimitiveArrayCritical(JNIEnv *env, jarray array,
+                                                                               jboolean *isCopy)
 {
-       java_bytearray *j;
+       java_handle_bytearray_t *ba;
+       jbyte                   *bp;
 
-    if (len < 0) {
-               *exceptionptr = new_exception(string_java_lang_NegativeArraySizeException);
-               return NULL;
-    }
+       ba = (java_handle_bytearray_t *) array;
 
-    j = builtin_newarray_byte(len);
+       /* do the same as Kaffe does */
 
-    if (!j)
-               *exceptionptr = new_exception(string_java_lang_OutOfMemoryError);
+       bp = _Jv_JNI_GetByteArrayElements(env, (jbyteArray) ba, isCopy);
 
-    return j;
+       return (void *) bp;
 }
 
 
-jcharArray NewCharArray(JNIEnv *env, jsize len)
-{
-       java_chararray *j;
+/* ReleasePrimitiveArrayCritical ***********************************************
 
-    if (len < 0) {
-               *exceptionptr = new_exception(string_java_lang_NegativeArraySizeException);
-               return NULL;
-    }
+   No specific documentation.
+
+*******************************************************************************/
 
-    j = builtin_newarray_char(len);
+void _Jv_JNI_ReleasePrimitiveArrayCritical(JNIEnv *env, jarray array,
+                                                                                  void *carray, jint mode)
+{
+       STATISTICS(jniinvokation());
 
-    if (!j)
-               *exceptionptr = new_exception(string_java_lang_OutOfMemoryError);
+       /* do the same as Kaffe does */
 
-    return j;
+       _Jv_JNI_ReleaseByteArrayElements(env, (jbyteArray) array, (jbyte *) carray,
+                                                                        mode);
 }
 
 
-jshortArray NewShortArray(JNIEnv *env, jsize len)
-{
-       java_shortarray *j;
+/* GetStringCritical ***********************************************************
 
-    if (len < 0) {
-               *exceptionptr = new_exception(string_java_lang_NegativeArraySizeException);
-               return NULL;
-    }
+   The semantics of these two functions are similar to the existing
+   Get/ReleaseStringChars functions.
 
-    j = builtin_newarray_short(len);
+*******************************************************************************/
 
-    if (!j)
-               *exceptionptr = new_exception(string_java_lang_OutOfMemoryError);
+const jchar *_Jv_JNI_GetStringCritical(JNIEnv *env, jstring string,
+                                                                          jboolean *isCopy)
+{
+       STATISTICS(jniinvokation());
 
-    return j;
+       return _Jv_JNI_GetStringChars(env, string, isCopy);
 }
 
 
-jintArray NewIntArray(JNIEnv *env, jsize len)
+void _Jv_JNI_ReleaseStringCritical(JNIEnv *env, jstring string,
+                                                                  const jchar *cstring)
 {
-       java_intarray *j;
+       STATISTICS(jniinvokation());
+
+       _Jv_JNI_ReleaseStringChars(env, string, cstring);
+}
 
-    if (len < 0) {
-               *exceptionptr = new_exception(string_java_lang_NegativeArraySizeException);
-               return NULL;
-    }
 
-    j = builtin_newarray_int(len);
+jweak _Jv_JNI_NewWeakGlobalRef(JNIEnv* env, jobject obj)
+{
+       STATISTICS(jniinvokation());
 
-    if (!j)
-               *exceptionptr = new_exception(string_java_lang_OutOfMemoryError);
+       log_text("JNI-Call: NewWeakGlobalRef: IMPLEMENT ME!");
 
-    return j;
+       return obj;
 }
 
 
-jlongArray NewLongArray(JNIEnv *env, jsize len)
+void _Jv_JNI_DeleteWeakGlobalRef(JNIEnv* env, jweak ref)
 {
-       java_longarray *j;
-
-    if (len < 0) {
-               *exceptionptr = new_exception(string_java_lang_NegativeArraySizeException);
-               return NULL;
-    }
+       STATISTICS(jniinvokation());
 
-    j = builtin_newarray_long(len);
+       log_text("JNI-Call: DeleteWeakGlobalRef: IMPLEMENT ME");
+}
 
-    if (!j)
-               *exceptionptr = new_exception(string_java_lang_OutOfMemoryError);
 
-    return j;
-}
+/* NewGlobalRef ****************************************************************
 
+   Creates a new global reference to the object referred to by the obj
+   argument.
 
-jfloatArray NewFloatArray(JNIEnv *env, jsize len)
+*******************************************************************************/
+    
+jobject _Jv_JNI_NewGlobalRef(JNIEnv* env, jobject obj)
 {
-       java_floatarray *j;
+       hashtable_global_ref_entry *gre;
+       u4   key;                           /* hashkey                            */
+       u4   slot;                          /* slot in hashtable                  */
+       java_handle_t *o;
 
-    if (len < 0) {
-               *exceptionptr = new_exception(string_java_lang_NegativeArraySizeException);
-               return NULL;
-    }
+       STATISTICS(jniinvokation());
 
-    j = builtin_newarray_float(len);
+       o = (java_handle_t *) obj;
 
-    if (!j)
-               *exceptionptr = new_exception(string_java_lang_OutOfMemoryError);
+       LOCK_MONITOR_ENTER(hashtable_global_ref->header);
 
-    return j;
-}
+       /* normally addresses are aligned to 4, 8 or 16 bytes */
 
+       key  = ((u4) (ptrint) obj) >> 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 */
 
-jdoubleArray NewDoubleArray(JNIEnv *env, jsize len)
-{
-       java_doublearray *j;
+       while (gre) {
+               if (gre->o == o) {
+                       /* global object found, increment the reference */
 
-    if (len < 0) {
-               *exceptionptr = new_exception(string_java_lang_NegativeArraySizeException);
-               return NULL;
-    }
+                       gre->refs++;
 
-    j = builtin_newarray_double(len);
+                       LOCK_MONITOR_EXIT(hashtable_global_ref->header);
 
-    if (!j)
-               *exceptionptr = new_exception(string_java_lang_OutOfMemoryError);
+                       return obj;
+               }
 
-    return j;
-}
+               gre = gre->hashlink;                /* next element in external chain */
+       }
 
+       /* global ref not found, create a new one */
 
-jboolean * GetBooleanArrayElements (JNIEnv *env, jbooleanArray array, jboolean *isCopy)
-{
-    if (isCopy) *isCopy = JNI_FALSE;
-    return array->data;
-}
+       gre = NEW(hashtable_global_ref_entry);
 
+#if defined(ENABLE_GC_CACAO)
+       /* register global ref with the GC */
 
-jbyte * GetByteArrayElements (JNIEnv *env, jbyteArray array, jboolean *isCopy)
-{
-    if (isCopy) *isCopy = JNI_FALSE;
-    return array->data;
-}
+       gc_reference_register(&(gre->o));
+#endif
 
+       gre->o    = o;
+       gre->refs = 1;
 
-jchar * GetCharArrayElements (JNIEnv *env, jcharArray array, jboolean *isCopy)
-{
-    if (isCopy) *isCopy = JNI_FALSE;
-    return array->data;
-}
+       /* insert entry into hashtable */
 
+       gre->hashlink = hashtable_global_ref->ptr[slot];
 
-jshort * GetShortArrayElements (JNIEnv *env, jshortArray array, jboolean *isCopy)
-{
-    if (isCopy) *isCopy = JNI_FALSE;
-    return array->data;
-}
+       hashtable_global_ref->ptr[slot] = gre;
 
+       /* update number of hashtable-entries */
 
-jint * GetIntArrayElements (JNIEnv *env, jintArray array, jboolean *isCopy)
-{
-    if (isCopy) *isCopy = JNI_FALSE;
-    return array->data;
-}
+       hashtable_global_ref->entries++;
 
+       LOCK_MONITOR_EXIT(hashtable_global_ref->header);
 
-jlong * GetLongArrayElements (JNIEnv *env, jlongArray array, jboolean *isCopy)
-{
-    if (isCopy) *isCopy = JNI_FALSE;
-    return array->data;
+       return obj;
 }
 
 
-jfloat * GetFloatArrayElements (JNIEnv *env, jfloatArray array, jboolean *isCopy)
-{
-    if (isCopy) *isCopy = JNI_FALSE;
-    return array->data;
-}
+/* DeleteGlobalRef *************************************************************
+
+   Deletes the global reference pointed to by globalRef.
 
+*******************************************************************************/
 
-jdouble * GetDoubleArrayElements (JNIEnv *env, jdoubleArray array, jboolean *isCopy)
+void _Jv_JNI_DeleteGlobalRef(JNIEnv* env, jobject globalRef)
 {
-    if (isCopy) *isCopy = JNI_FALSE;
-    return array->data;
-}
+       hashtable_global_ref_entry *gre;
+       hashtable_global_ref_entry *prevgre;
+       u4   key;                           /* hashkey                            */
+       u4   slot;                          /* slot in hashtable                  */
+       java_handle_t              *o;
 
+       STATISTICS(jniinvokation());
 
+       o = (java_handle_t *) globalRef;
 
-void ReleaseBooleanArrayElements (JNIEnv *env, jbooleanArray array, jboolean *elems, jint mode)
-{
-    /* empty */
-}
+       LOCK_MONITOR_ENTER(hashtable_global_ref->header);
 
+       /* normally addresses are aligned to 4, 8 or 16 bytes */
 
-void ReleaseByteArrayElements (JNIEnv *env, jbyteArray array, jbyte *elems, jint mode)
-{
-    /* empty */
-}
+       key  = ((u4) (ptrint) globalRef) >> 4;     /* align to 16-byte boundaries */
+       slot = key & (hashtable_global_ref->size - 1);
+       gre  = hashtable_global_ref->ptr[slot];
 
+       /* initialize prevgre */
 
-void ReleaseCharArrayElements (JNIEnv *env, jcharArray array, jchar *elems, jint mode)
-{
-    /* empty */
-}
+       prevgre = NULL;
 
+       /* search external hash chain for the entry */
 
-void ReleaseShortArrayElements (JNIEnv *env, jshortArray array, jshort *elems, jint mode)
-{
-    /* empty */
-}
+       while (gre) {
+               if (gre->o == o) {
+                       /* global object found, decrement the reference count */
 
+                       gre->refs--;
 
-void ReleaseIntArrayElements (JNIEnv *env, jintArray array, jint *elems, jint mode)
-{
-    /* empty */
-}
+                       /* if reference count is 0, remove the entry */
 
+                       if (gre->refs == 0) {
+                               /* special handling if it's the first in the chain */
 
-void ReleaseLongArrayElements (JNIEnv *env, jlongArray array, jlong *elems, jint mode)
-{
-    /* empty */
-}
+                               if (prevgre == NULL)
+                                       hashtable_global_ref->ptr[slot] = gre->hashlink;
+                               else
+                                       prevgre->hashlink = gre->hashlink;
 
+#if defined(ENABLE_GC_CACAO)
+                               /* unregister global ref with the GC */
 
-void ReleaseFloatArrayElements (JNIEnv *env, jfloatArray array, jfloat *elems, jint mode)
-{
-    /* empty */
-}
+                               gc_reference_unregister(&(gre->o));
+#endif
 
+                               FREE(gre, hashtable_global_ref_entry);
+                       }
 
-void ReleaseDoubleArrayElements (JNIEnv *env, jdoubleArray array, jdouble *elems, jint mode)
-{
-    /* empty */
-}
+                       LOCK_MONITOR_EXIT(hashtable_global_ref->header);
 
+                       return;
+               }
 
-void GetBooleanArrayRegion(JNIEnv* env, jbooleanArray array, jsize start, jsize len, jboolean *buf)
-{
-    if (start < 0 || len < 0 || start + len > array->header.size)
-               *exceptionptr = new_exception(string_java_lang_ArrayIndexOutOfBoundsException);
+               prevgre = gre;                    /* save current pointer for removal */
+               gre     = gre->hashlink;            /* next element in external chain */
+       }
+
+       log_println("JNI-DeleteGlobalRef: global reference not found");
 
-    else
-               memcpy(buf, &array->data[start], len * sizeof(array->data[0]));
+       LOCK_MONITOR_EXIT(hashtable_global_ref->header);
 }
 
 
-void GetByteArrayRegion(JNIEnv* env, jbyteArray array, jsize start, jsize len, jbyte *buf)
-{
-    if (start < 0 || len < 0 || start + len > array->header.size) 
-               *exceptionptr = new_exception(string_java_lang_ArrayIndexOutOfBoundsException);
+/* ExceptionCheck **************************************************************
 
-    else
-               memcpy(buf, &array->data[start], len * sizeof(array->data[0]));
-}
+   Returns JNI_TRUE when there is a pending exception; otherwise,
+   returns JNI_FALSE.
 
+*******************************************************************************/
 
-void GetCharArrayRegion(JNIEnv* env, jcharArray array, jsize start, jsize len, jchar *buf)
+jboolean _Jv_JNI_ExceptionCheck(JNIEnv *env)
 {
-    if (start < 0 || len < 0 || start + len > array->header.size)
-               *exceptionptr = new_exception(string_java_lang_ArrayIndexOutOfBoundsException);
-
-    else
-               memcpy(buf, &array->data[start], len * sizeof(array->data[0]));
-}
+       java_handle_t *o;
 
+       STATISTICS(jniinvokation());
 
-void GetShortArrayRegion(JNIEnv* env, jshortArray array, jsize start, jsize len, jshort *buf)
-{
-    if (start < 0 || len < 0 || start + len > array->header.size)
-               *exceptionptr = new_exception(string_java_lang_ArrayIndexOutOfBoundsException);
+       o = exceptions_get_exception();
 
-    else       
-               memcpy(buf, &array->data[start], len * sizeof(array->data[0]));
+       return (o != NULL) ? JNI_TRUE : JNI_FALSE;
 }
 
 
-void GetIntArrayRegion(JNIEnv* env, jintArray array, jsize start, jsize len, jint *buf)
-{
-    if (start < 0 || len < 0 || start + len > array->header.size)
-               *exceptionptr = new_exception(string_java_lang_ArrayIndexOutOfBoundsException);
+/* New JNI 1.4 functions ******************************************************/
 
-    else
-               memcpy(buf, &array->data[start], len * sizeof(array->data[0]));
-}
+/* NewDirectByteBuffer *********************************************************
 
+   Allocates and returns a direct java.nio.ByteBuffer referring to the
+   block of memory starting at the memory address address and
+   extending capacity bytes.
 
-void GetLongArrayRegion(JNIEnv* env, jlongArray array, jsize start, jsize len, jlong *buf)
+*******************************************************************************/
+
+jobject _Jv_JNI_NewDirectByteBuffer(JNIEnv *env, void *address, jlong capacity)
 {
-    if (start < 0 || len < 0 || start + len > array->header.size)
-               *exceptionptr = new_exception(string_java_lang_ArrayIndexOutOfBoundsException);
+#if defined(ENABLE_JAVASE) && defined(WITH_CLASSPATH_GNU)
+       java_handle_t           *nbuf;
 
-    else
-               memcpy(buf, &array->data[start], len * sizeof(array->data[0]));
-}
+# if SIZEOF_VOID_P == 8
+       gnu_classpath_Pointer64 *paddress;
+# else
+       gnu_classpath_Pointer32 *paddress;
+# endif
 
+       STATISTICS(jniinvokation());
 
-void GetFloatArrayRegion(JNIEnv* env, jfloatArray array, jsize start, jsize len, jfloat *buf)
-{
-    if (start < 0 || len < 0 || start + len > array->header.size)
-               *exceptionptr = new_exception(string_java_lang_ArrayIndexOutOfBoundsException);
+       /* alocate a gnu.classpath.Pointer{32,64} object */
 
-    else
-               memcpy(buf, &array->data[start], len * sizeof(array->data[0]));
-}
+# if SIZEOF_VOID_P == 8
+       if (!(paddress = (gnu_classpath_Pointer64 *)
+                 builtin_new(class_gnu_classpath_Pointer64)))
+# else
+       if (!(paddress = (gnu_classpath_Pointer32 *)
+                 builtin_new(class_gnu_classpath_Pointer32)))
+# endif
+               return NULL;
 
+       /* fill gnu.classpath.Pointer{32,64} with address */
 
-void GetDoubleArrayRegion(JNIEnv* env, jdoubleArray array, jsize start, jsize len, jdouble *buf)
-{
-    if (start < 0 || len < 0 || start+len>array->header.size)
-               *exceptionptr = new_exception(string_java_lang_ArrayIndexOutOfBoundsException);
+       LLNI_field_set_val(paddress, data, (ptrint) address);
 
-    else
-               memcpy(buf, &array->data[start], len * sizeof(array->data[0]));
-}
+       /* create a java.nio.DirectByteBufferImpl$ReadWrite object */
 
+       nbuf = (*env)->NewObject(env, class_java_nio_DirectByteBufferImpl_ReadWrite,
+                                                        (jmethodID) dbbirw_init, NULL, paddress,
+                                                        (jint) capacity, (jint) capacity, (jint) 0);
 
-void SetBooleanArrayRegion(JNIEnv* env, jbooleanArray array, jsize start, jsize len, jboolean *buf)
-{
-    if (start < 0 || len < 0 || start + len > array->header.size)
-               *exceptionptr = new_exception(string_java_lang_ArrayIndexOutOfBoundsException);
+       /* add local reference and return the value */
+
+       return _Jv_JNI_NewLocalRef(env, nbuf);
+#else
+       vm_abort("_Jv_JNI_NewDirectByteBuffer: not implemented in this configuration");
+
+       /* keep compiler happy */
 
-    else
-               memcpy(&array->data[start], buf, len * sizeof(array->data[0]));
+       return NULL;
+#endif
 }
 
 
-void SetByteArrayRegion(JNIEnv* env, jbyteArray array, jsize start, jsize len, jbyte *buf)
-{
-    if (start < 0 || len < 0 || start + len > array->header.size)
-               *exceptionptr = new_exception(string_java_lang_ArrayIndexOutOfBoundsException);
+/* GetDirectBufferAddress ******************************************************
 
-    else
-               memcpy(&array->data[start], buf, len * sizeof(array->data[0]));
-}
+   Fetches and returns the starting address of the memory region
+   referenced by the given direct java.nio.Buffer.
 
+*******************************************************************************/
 
-void SetCharArrayRegion(JNIEnv* env, jcharArray array, jsize start, jsize len, jchar *buf)
+void *_Jv_JNI_GetDirectBufferAddress(JNIEnv *env, jobject buf)
 {
-    if (start < 0 || len < 0 || start + len > array->header.size)
-               *exceptionptr = new_exception(string_java_lang_ArrayIndexOutOfBoundsException);
+#if defined(ENABLE_JAVASE) && defined(WITH_CLASSPATH_GNU)
+       java_nio_DirectByteBufferImpl *nbuf;
+# if SIZEOF_VOID_P == 8
+       gnu_classpath_Pointer64       *paddress;
+# else
+       gnu_classpath_Pointer32       *paddress;
+# endif
+       void                          *address;
 
-    else
-               memcpy(&array->data[start], buf, len * sizeof(array->data[0]));
+       STATISTICS(jniinvokation());
 
-}
+       if (!builtin_instanceof(buf, class_java_nio_Buffer))
+               return NULL;
 
+       nbuf = (java_nio_DirectByteBufferImpl *) buf;
 
-void SetShortArrayRegion(JNIEnv* env, jshortArray array, jsize start, jsize len, jshort *buf)
-{
-    if (start < 0 || len < 0 || start + len > array->header.size)
-               *exceptionptr = new_exception(string_java_lang_ArrayIndexOutOfBoundsException);
+# 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
 
-    else
-               memcpy(&array->data[start], buf, len * sizeof(array->data[0]));
-}
+       if (paddress == NULL)
+               return NULL;
 
+       LLNI_field_get_val(paddress, data, address);
+       /* this was the cast to avaoid warning: (void *) paddress->data */
 
-void SetIntArrayRegion(JNIEnv* env, jintArray array, jsize start, jsize len, jint *buf)
-{
-    if (start < 0 || len < 0 || start + len > array->header.size)
-               *exceptionptr = new_exception(string_java_lang_ArrayIndexOutOfBoundsException);
+       return address;
+#else
+       vm_abort("_Jv_JNI_GetDirectBufferAddress: not implemented in this configuration");
 
-    else
-               memcpy(&array->data[start], buf, len * sizeof(array->data[0]));
+       /* keep compiler happy */
 
+       return NULL;
+#endif
 }
 
 
-void SetLongArrayRegion(JNIEnv* env, jlongArray array, jsize start, jsize len, jlong *buf)
-{
-    if (start < 0 || len < 0 || start + len > array->header.size)
-               *exceptionptr = new_exception(string_java_lang_ArrayIndexOutOfBoundsException);
-
-    else
-               memcpy(&array->data[start], buf, len * sizeof(array->data[0]));
+/* GetDirectBufferCapacity *****************************************************
 
-}
+   Fetches and returns the capacity in bytes of the memory region
+   referenced by the given direct java.nio.Buffer.
 
+*******************************************************************************/
 
-void SetFloatArrayRegion(JNIEnv* env, jfloatArray array, jsize start, jsize len, jfloat *buf)
+jlong _Jv_JNI_GetDirectBufferCapacity(JNIEnv* env, jobject buf)
 {
-    if (start < 0 || len < 0 || start + len > array->header.size)
-               *exceptionptr = new_exception(string_java_lang_ArrayIndexOutOfBoundsException);
+#if defined(ENABLE_JAVASE) && defined(WITH_CLASSPATH_GNU)
+       java_handle_t   *o;
+       java_nio_Buffer *nbuf;
+       jlong            capacity;
 
-    else
-               memcpy(&array->data[start], buf, len * sizeof(array->data[0]));
+       STATISTICS(jniinvokation());
 
-}
+       o = (java_handle_t *) buf;
 
+       if (!builtin_instanceof(o, class_java_nio_DirectByteBufferImpl))
+               return -1;
 
-void SetDoubleArrayRegion(JNIEnv* env, jdoubleArray array, jsize start, jsize len, jdouble *buf)
-{
-    if (start < 0 || len < 0 || start + len > array->header.size)
-               *exceptionptr = new_exception(string_java_lang_ArrayIndexOutOfBoundsException);
+       nbuf = (java_nio_Buffer *) o;
 
-    else
-               memcpy(&array->data[start], buf, len * sizeof(array->data[0]));
-}
+       LLNI_field_get_val(nbuf, cap, capacity);
 
+       return capacity;
+#else
+       vm_abort("_Jv_JNI_GetDirectBufferCapacity: not implemented in this configuration");
 
-jint RegisterNatives (JNIEnv* env, jclass clazz, const JNINativeMethod *methods, jint nMethods)
-{
-    log_text("JNI-Call: RegisterNatives");
-    return 0;
+       /* keep compiler happy */
+
+       return 0;
+#endif
 }
 
 
-jint UnregisterNatives (JNIEnv* env, jclass clazz)
-{
-    log_text("JNI-Call: UnregisterNatives");
-    return 0;
-}
+/* DestroyJavaVM ***************************************************************
 
-/******************************* monitor operations ********************************/
+   Unloads a Java VM and reclaims its resources. Only the main thread
+   can unload the VM. The system waits until the main thread is only
+   remaining user thread before it destroys the VM.
+
+*******************************************************************************/
 
-jint MonitorEnter (JNIEnv* env, jobject obj)
+jint _Jv_JNI_DestroyJavaVM(JavaVM *vm)
 {
-    builtin_monitorenter(obj);
-    return 0;
-}
+       s4 status;
 
+       STATISTICS(jniinvokation());
 
-jint MonitorExit (JNIEnv* env, jobject obj)
-{
-    builtin_monitorexit(obj);
-    return 0;
+    status = vm_destroy(vm);
+
+       return status;
 }
 
 
-/************************************* JavaVM interface ****************************/
-#ifdef __cplusplus
-#error CPP mode not supported yet
-#else
-jint GetJavaVM (JNIEnv* env, JavaVM **vm)
-{
-    log_text("JNI-Call: GetJavaVM");
-    *vm=&javaVM;
-    return 0;
-}
-#endif /*__cplusplus*/
+/* AttachCurrentThread *********************************************************
 
-void GetStringRegion (JNIEnv* env, jstring str, jsize start, jsize len, jchar *buf)
-{
-    log_text("JNI-Call: GetStringRegion");
+   Attaches the current thread to a Java VM. Returns a JNI interface
+   pointer in the JNIEnv argument.
 
-}
+   Trying to attach a thread that is already attached is a no-op.
 
-void GetStringUTFRegion (JNIEnv* env, jstring str, jsize start, jsize len, char *buf)
-{
-    log_text("JNI-Call: GetStringUTFRegion");
+   A native thread cannot be attached simultaneously to two Java VMs.
 
-}
+   When a thread is attached to the VM, the context class loader is
+   the bootstrap loader.
 
-/************** obtain direct pointer to array elements ***********************/
+*******************************************************************************/
 
-void * GetPrimitiveArrayCritical (JNIEnv* env, jarray array, jboolean *isCopy)
+static s4 jni_attach_current_thread(void **p_env, void *thr_args, bool isdaemon)
 {
-       java_objectheader *s = (java_objectheader*) array;
-       arraydescriptor *desc = s->vftbl->arraydesc;
+       JavaVMAttachArgs *vm_aargs;
 
-       if (!desc) return NULL;
+#if defined(ENABLE_THREADS)
+       if (threads_get_current_threadobject() == NULL) {
+               vm_aargs = (JavaVMAttachArgs *) thr_args;
 
-       return ((u1*)s) + desc->dataoffset;
-}
+               if (vm_aargs != NULL) {
+                       if ((vm_aargs->version != JNI_VERSION_1_2) &&
+                               (vm_aargs->version != JNI_VERSION_1_4))
+                               return JNI_EVERSION;
+               }
 
+               if (!threads_attach_current_thread(vm_aargs, false))
+                       return JNI_ERR;
 
-void ReleasePrimitiveArrayCritical (JNIEnv* env, jarray array, void *carray, jint mode)
-{
-       log_text("JNI-Call: ReleasePrimitiveArrayCritical");
+               if (!localref_table_init())
+                       return JNI_ERR;
+       }
+#endif
+
+       *p_env = _Jv_env;
 
-       /* empty */
+       return JNI_OK;
 }
 
-/**** returns a pointer to an array of Unicode characters of the string *******/
 
-const jchar * GetStringCritical (JNIEnv* env, jstring string, jboolean *isCopy)
+jint _Jv_JNI_AttachCurrentThread(JavaVM *vm, void **p_env, void *thr_args)
 {
-       log_text("JNI-Call: GetStringCritical");
+       STATISTICS(jniinvokation());
 
-       return GetStringChars(env,string,isCopy);
+       return jni_attach_current_thread(p_env, thr_args, false);
 }
 
-/*********** native code no longer needs access to chars **********************/
 
-void ReleaseStringCritical (JNIEnv* env, jstring string, const jchar *cstring)
-{
-       log_text("JNI-Call: ReleaseStringCritical");
+/* DetachCurrentThread *********************************************************
 
-       ReleaseStringChars(env,string,cstring);
-}
+   Detaches the current thread from a Java VM. All Java monitors held
+   by this thread are released. All Java threads waiting for this
+   thread to die are notified.
 
+   In JDK 1.1, the main thread cannot be detached from the VM. It must
+   call DestroyJavaVM to unload the entire VM.
 
-jweak NewWeakGlobalRef (JNIEnv* env, jobject obj)
-{
-       log_text("JNI-Call: NewWeakGlobalRef");
+   In the JDK, the main thread can be detached from the VM.
 
-       return obj;
-}
+   The main thread, which is the thread that created the Java VM,
+   cannot be detached from the VM. Instead, the main thread must call
+   JNI_DestroyJavaVM() to unload the entire VM.
 
+*******************************************************************************/
 
-void DeleteWeakGlobalRef (JNIEnv* env, jweak ref)
+jint _Jv_JNI_DetachCurrentThread(JavaVM *vm)
 {
-       log_text("JNI-Call: DeleteWeakGlobalRef");
+#if defined(ENABLE_THREADS)
+       threadobject *thread;
 
-       /* empty */
-}
+       STATISTICS(jniinvokation());
 
+       thread = threads_get_current_threadobject();
 
-/******************************* check for pending exception ***********************/
+       if (thread == NULL)
+               return JNI_ERR;
 
+       if (!jni_free_localref_table())
+               return JNI_ERR;
 
-jboolean ExceptionCheck(JNIEnv* env)
-{
-       log_text("JNI-Call: ExceptionCheck");
+       if (!threads_detach_thread(thread))
+               return JNI_ERR;
+#endif
 
-       return *exceptionptr ? JNI_TRUE : JNI_FALSE;
+       return JNI_OK;
 }
 
 
+/* GetEnv **********************************************************************
 
+   If the current thread is not attached to the VM, sets *env to NULL,
+   and returns JNI_EDETACHED. If the specified version is not
+   supported, sets *env to NULL, and returns JNI_EVERSION. Otherwise,
+   sets *env to the appropriate interface, and returns JNI_OK.
 
+*******************************************************************************/
 
-
-jint DestroyJavaVM(JavaVM *vm)
+jint _Jv_JNI_GetEnv(JavaVM *vm, void **env, jint version)
 {
-       log_text("DestroyJavaVM called");
+       STATISTICS(jniinvokation());
 
-       return 0;
-}
+#if defined(ENABLE_THREADS)
+       if (threads_get_current_threadobject() == NULL) {
+               *env = NULL;
 
+               return JNI_EDETACHED;
+       }
+#endif
 
-jint AttachCurrentThread(JavaVM *vm, void **par1, void *par2)
-{
-       log_text("AttachCurrentThread called");
+       /* check the JNI version */
 
-       return 0;
-}
+       switch (version) {
+       case JNI_VERSION_1_1:
+       case JNI_VERSION_1_2:
+       case JNI_VERSION_1_4:
+               *env = _Jv_env;
+               return JNI_OK;
+
+       default:
+               ;
+       }
 
+#if defined(ENABLE_JVMTI)
+       if ((version & JVMTI_VERSION_MASK_INTERFACE_TYPE) 
+               == JVMTI_VERSION_INTERFACE_JVMTI) {
 
-jint DetachCurrentThread(JavaVM *vm)
-{
-       log_text("DetachCurrentThread called");
+               *env = (void *) jvmti_new_environment();
 
-       return 0;
+               if (env != NULL)
+                       return JNI_OK;
+       }
+#endif
+       
+       *env = NULL;
+
+       return JNI_EVERSION;
 }
 
 
-jint GetEnv(JavaVM *vm, void **environment, jint jniversion)
-{
-       *environment = &env;
+/* AttachCurrentThreadAsDaemon *************************************************
 
-       return 0;
-}
+   Same semantics as AttachCurrentThread, but the newly-created
+   java.lang.Thread instance is a daemon.
 
+   If the thread has already been attached via either
+   AttachCurrentThread or AttachCurrentThreadAsDaemon, this routine
+   simply sets the value pointed to by penv to the JNIEnv of the
+   current thread. In this case neither AttachCurrentThread nor this
+   routine have any effect on the daemon status of the thread.
+
+*******************************************************************************/
 
-jint AttachCurrentThreadAsDaemon(JavaVM *vm, void **par1, void *par2)
+jint _Jv_JNI_AttachCurrentThreadAsDaemon(JavaVM *vm, void **penv, void *args)
 {
-       log_text("AttachCurrentThreadAsDaemon called");
+       STATISTICS(jniinvokation());
 
-       return 0;
+       return jni_attach_current_thread(penv, args, true);
 }
 
 
-/********************************* JNI invocation table ******************************/
+/* JNI invocation table *******************************************************/
+
+const struct JNIInvokeInterface_ _Jv_JNIInvokeInterface = {
+       NULL,
+       NULL,
+       NULL,
 
-struct _JavaVM javaVMTable={
-   NULL,
-   NULL,
-   NULL,
-   &DestroyJavaVM,
-   &AttachCurrentThread,
-   &DetachCurrentThread,
-   &GetEnv,
-   &AttachCurrentThreadAsDaemon
+       _Jv_JNI_DestroyJavaVM,
+       _Jv_JNI_AttachCurrentThread,
+       _Jv_JNI_DetachCurrentThread,
+       _Jv_JNI_GetEnv,
+       _Jv_JNI_AttachCurrentThreadAsDaemon
 };
 
-JavaVM javaVM = &javaVMTable;
-
-
-/********************************* JNI function table ******************************/
-
-struct JNI_Table envTable = {   
-    NULL,
-    NULL,
-    NULL,
-    NULL,    
-    &GetVersion,
-    &DefineClass,
-    &FindClass,
-    &FromReflectedMethod,
-    &FromReflectedField,
-    &ToReflectedMethod,
-    &GetSuperclass,
-    &IsAssignableForm,
-    &ToReflectedField,
-    &Throw,
-    &ThrowNew,
-    &ExceptionOccurred,
-    &ExceptionDescribe,
-    &ExceptionClear,
-    &FatalError,
-    &PushLocalFrame,
-    &PopLocalFrame,
-    &NewGlobalRef,
-    &DeleteGlobalRef,
-    &DeleteLocalRef,
-    &IsSameObject,
-    &NewLocalRef,
-    &EnsureLocalCapacity,
-    &AllocObject,
-    &NewObject,
-    &NewObjectV,
-    &NewObjectA,
-    &GetObjectClass,
-    &IsInstanceOf,
-    &GetMethodID,
-    &CallObjectMethod,
-    &CallObjectMethodV,
-    &CallObjectMethodA,
-    &CallBooleanMethod,
-    &CallBooleanMethodV,
-    &CallBooleanMethodA,
-    &CallByteMethod,
-    &CallByteMethodV,
-    &CallByteMethodA,
-    &CallCharMethod,
-    &CallCharMethodV,
-    &CallCharMethodA,
-    &CallShortMethod,
-    &CallShortMethodV,
-    &CallShortMethodA,
-    &CallIntMethod,
-    &CallIntMethodV,
-    &CallIntMethodA,
-    &CallLongMethod,
-    &CallLongMethodV,
-    &CallLongMethodA,
-    &CallFloatMethod,
-    &CallFloatMethodV,
-    &CallFloatMethodA,
-    &CallDoubleMethod,
-    &CallDoubleMethodV,
-    &CallDoubleMethodA,
-    &CallVoidMethod,
-    &CallVoidMethodV,
-    &CallVoidMethodA,
-    &CallNonvirtualObjectMethod,
-    &CallNonvirtualObjectMethodV,
-    &CallNonvirtualObjectMethodA,
-    &CallNonvirtualBooleanMethod,
-    &CallNonvirtualBooleanMethodV,
-    &CallNonvirtualBooleanMethodA,
-    &CallNonvirtualByteMethod,
-    &CallNonvirtualByteMethodV,
-    &CallNonvirtualByteMethodA,
-    &CallNonvirtualCharMethod,
-    &CallNonvirtualCharMethodV,
-    &CallNonvirtualCharMethodA,
-    &CallNonvirtualShortMethod,
-    &CallNonvirtualShortMethodV,
-    &CallNonvirtualShortMethodA,
-    &CallNonvirtualIntMethod,
-    &CallNonvirtualIntMethodV,
-    &CallNonvirtualIntMethodA,
-    &CallNonvirtualLongMethod,
-    &CallNonvirtualLongMethodV,
-    &CallNonvirtualLongMethodA,
-    &CallNonvirtualFloatMethod,
-    &CallNonvirtualFloatMethodV,
-    &CallNonvirtualFloatMethodA,
-    &CallNonvirtualDoubleMethod,
-    &CallNonvirtualDoubleMethodV,
-    &CallNonvirtualDoubleMethodA,
-    &CallNonvirtualVoidMethod,
-    &CallNonvirtualVoidMethodV,
-    &CallNonvirtualVoidMethodA,
-    &GetFieldID,
-    &GetObjectField,
-    &GetBooleanField,
-    &GetByteField,
-    &GetCharField,
-    &GetShortField,
-    &GetIntField,
-    &GetLongField,
-    &GetFloatField,
-    &GetDoubleField,
-    &SetObjectField,
-    &SetBooleanField,
-    &SetByteField,
-    &SetCharField,
-    &SetShortField,
-    &SetIntField,
-    &SetLongField,
-    &SetFloatField,
-    &SetDoubleField,
-    &GetStaticMethodID,
-    &CallStaticObjectMethod,
-    &CallStaticObjectMethodV,
-    &CallStaticObjectMethodA,
-    &CallStaticBooleanMethod,
-    &CallStaticBooleanMethodV,
-    &CallStaticBooleanMethodA,
-    &CallStaticByteMethod,
-    &CallStaticByteMethodV,
-    &CallStaticByteMethodA,
-    &CallStaticCharMethod,
-    &CallStaticCharMethodV,
-    &CallStaticCharMethodA,
-    &CallStaticShortMethod,
-    &CallStaticShortMethodV,
-    &CallStaticShortMethodA,
-    &CallStaticIntMethod,
-    &CallStaticIntMethodV,
-    &CallStaticIntMethodA,
-    &CallStaticLongMethod,
-    &CallStaticLongMethodV,
-    &CallStaticLongMethodA,
-    &CallStaticFloatMethod,
-    &CallStaticFloatMethodV,
-    &CallStaticFloatMethodA,
-    &CallStaticDoubleMethod,
-    &CallStaticDoubleMethodV,
-    &CallStaticDoubleMethodA,
-    &CallStaticVoidMethod,
-    &CallStaticVoidMethodV,
-    &CallStaticVoidMethodA,
-    &GetStaticFieldID,
-    &GetStaticObjectField,
-    &GetStaticBooleanField,
-    &GetStaticByteField,
-    &GetStaticCharField,
-    &GetStaticShortField,
-    &GetStaticIntField,
-    &GetStaticLongField,
-    &GetStaticFloatField,
-    &GetStaticDoubleField,
-    &SetStaticObjectField,
-    &SetStaticBooleanField,
-    &SetStaticByteField,
-    &SetStaticCharField,
-    &SetStaticShortField,
-    &SetStaticIntField,
-    &SetStaticLongField,
-    &SetStaticFloatField,
-    &SetStaticDoubleField,
-    &NewString,
-    &GetStringLength,
-    &GetStringChars,
-    &ReleaseStringChars,
-    &NewStringUTF,
-    &GetStringUTFLength,
-    &GetStringUTFChars,
-    &ReleaseStringUTFChars,
-    &GetArrayLength,
-    &NewObjectArray,
-    &GetObjectArrayElement,
-    &SetObjectArrayElement,
-    &NewBooleanArray,
-    &NewByteArray,
-    &NewCharArray,
-    &NewShortArray,
-    &NewIntArray,
-    &NewLongArray,
-    &NewFloatArray,
-    &NewDoubleArray,
-    &GetBooleanArrayElements,
-    &GetByteArrayElements,
-    &GetCharArrayElements,
-    &GetShortArrayElements,
-    &GetIntArrayElements,
-    &GetLongArrayElements,
-    &GetFloatArrayElements,
-    &GetDoubleArrayElements,
-    &ReleaseBooleanArrayElements,
-    &ReleaseByteArrayElements,
-    &ReleaseCharArrayElements,
-    &ReleaseShortArrayElements,
-    &ReleaseIntArrayElements,
-    &ReleaseLongArrayElements,
-    &ReleaseFloatArrayElements,
-    &ReleaseDoubleArrayElements,
-    &GetBooleanArrayRegion,
-    &GetByteArrayRegion,
-    &GetCharArrayRegion,
-    &GetShortArrayRegion,
-    &GetIntArrayRegion,
-    &GetLongArrayRegion,
-    &GetFloatArrayRegion,
-    &GetDoubleArrayRegion,
-    &SetBooleanArrayRegion,
-    &SetByteArrayRegion,
-    &SetCharArrayRegion,
-    &SetShortArrayRegion,
-    &SetIntArrayRegion,
-    &SetLongArrayRegion,
-    &SetFloatArrayRegion,
-    &SetDoubleArrayRegion,
-    &RegisterNatives,
-    &UnregisterNatives,
-    &MonitorEnter,
-    &MonitorExit,
-    &GetJavaVM,
-    &GetStringRegion,
-    &GetStringUTFRegion,
-    &GetPrimitiveArrayCritical,
-    &ReleasePrimitiveArrayCritical,
-    &GetStringCritical,
-    &ReleaseStringCritical,
-    &NewWeakGlobalRef,
-    &DeleteWeakGlobalRef,
-    &ExceptionCheck
+
+/* JNI function table *********************************************************/
+
+struct JNINativeInterface_ _Jv_JNINativeInterface = {
+       NULL,
+       NULL,
+       NULL,
+       NULL,    
+       _Jv_JNI_GetVersion,
+
+       _Jv_JNI_DefineClass,
+       _Jv_JNI_FindClass,
+       _Jv_JNI_FromReflectedMethod,
+       _Jv_JNI_FromReflectedField,
+       _Jv_JNI_ToReflectedMethod,
+       _Jv_JNI_GetSuperclass,
+       _Jv_JNI_IsAssignableFrom,
+       _Jv_JNI_ToReflectedField,
+
+       _Jv_JNI_Throw,
+       _Jv_JNI_ThrowNew,
+       _Jv_JNI_ExceptionOccurred,
+       _Jv_JNI_ExceptionDescribe,
+       _Jv_JNI_ExceptionClear,
+       _Jv_JNI_FatalError,
+       _Jv_JNI_PushLocalFrame,
+       _Jv_JNI_PopLocalFrame,
+
+       _Jv_JNI_NewGlobalRef,
+       _Jv_JNI_DeleteGlobalRef,
+       _Jv_JNI_DeleteLocalRef,
+       _Jv_JNI_IsSameObject,
+       _Jv_JNI_NewLocalRef,
+       _Jv_JNI_EnsureLocalCapacity,
+
+       _Jv_JNI_AllocObject,
+       _Jv_JNI_NewObject,
+       _Jv_JNI_NewObjectV,
+       _Jv_JNI_NewObjectA,
+
+       _Jv_JNI_GetObjectClass,
+       _Jv_JNI_IsInstanceOf,
+
+       _Jv_JNI_GetMethodID,
+
+       _Jv_JNI_CallObjectMethod,
+       _Jv_JNI_CallObjectMethodV,
+       _Jv_JNI_CallObjectMethodA,
+       _Jv_JNI_CallBooleanMethod,
+       _Jv_JNI_CallBooleanMethodV,
+       _Jv_JNI_CallBooleanMethodA,
+       _Jv_JNI_CallByteMethod,
+       _Jv_JNI_CallByteMethodV,
+       _Jv_JNI_CallByteMethodA,
+       _Jv_JNI_CallCharMethod,
+       _Jv_JNI_CallCharMethodV,
+       _Jv_JNI_CallCharMethodA,
+       _Jv_JNI_CallShortMethod,
+       _Jv_JNI_CallShortMethodV,
+       _Jv_JNI_CallShortMethodA,
+       _Jv_JNI_CallIntMethod,
+       _Jv_JNI_CallIntMethodV,
+       _Jv_JNI_CallIntMethodA,
+       _Jv_JNI_CallLongMethod,
+       _Jv_JNI_CallLongMethodV,
+       _Jv_JNI_CallLongMethodA,
+       _Jv_JNI_CallFloatMethod,
+       _Jv_JNI_CallFloatMethodV,
+       _Jv_JNI_CallFloatMethodA,
+       _Jv_JNI_CallDoubleMethod,
+       _Jv_JNI_CallDoubleMethodV,
+       _Jv_JNI_CallDoubleMethodA,
+       _Jv_JNI_CallVoidMethod,
+       _Jv_JNI_CallVoidMethodV,
+       _Jv_JNI_CallVoidMethodA,
+
+       _Jv_JNI_CallNonvirtualObjectMethod,
+       _Jv_JNI_CallNonvirtualObjectMethodV,
+       _Jv_JNI_CallNonvirtualObjectMethodA,
+       _Jv_JNI_CallNonvirtualBooleanMethod,
+       _Jv_JNI_CallNonvirtualBooleanMethodV,
+       _Jv_JNI_CallNonvirtualBooleanMethodA,
+       _Jv_JNI_CallNonvirtualByteMethod,
+       _Jv_JNI_CallNonvirtualByteMethodV,
+       _Jv_JNI_CallNonvirtualByteMethodA,
+       _Jv_JNI_CallNonvirtualCharMethod,
+       _Jv_JNI_CallNonvirtualCharMethodV,
+       _Jv_JNI_CallNonvirtualCharMethodA,
+       _Jv_JNI_CallNonvirtualShortMethod,
+       _Jv_JNI_CallNonvirtualShortMethodV,
+       _Jv_JNI_CallNonvirtualShortMethodA,
+       _Jv_JNI_CallNonvirtualIntMethod,
+       _Jv_JNI_CallNonvirtualIntMethodV,
+       _Jv_JNI_CallNonvirtualIntMethodA,
+       _Jv_JNI_CallNonvirtualLongMethod,
+       _Jv_JNI_CallNonvirtualLongMethodV,
+       _Jv_JNI_CallNonvirtualLongMethodA,
+       _Jv_JNI_CallNonvirtualFloatMethod,
+       _Jv_JNI_CallNonvirtualFloatMethodV,
+       _Jv_JNI_CallNonvirtualFloatMethodA,
+       _Jv_JNI_CallNonvirtualDoubleMethod,
+       _Jv_JNI_CallNonvirtualDoubleMethodV,
+       _Jv_JNI_CallNonvirtualDoubleMethodA,
+       _Jv_JNI_CallNonvirtualVoidMethod,
+       _Jv_JNI_CallNonvirtualVoidMethodV,
+       _Jv_JNI_CallNonvirtualVoidMethodA,
+
+       _Jv_JNI_GetFieldID,
+
+       _Jv_JNI_GetObjectField,
+       _Jv_JNI_GetBooleanField,
+       _Jv_JNI_GetByteField,
+       _Jv_JNI_GetCharField,
+       _Jv_JNI_GetShortField,
+       _Jv_JNI_GetIntField,
+       _Jv_JNI_GetLongField,
+       _Jv_JNI_GetFloatField,
+       _Jv_JNI_GetDoubleField,
+       _Jv_JNI_SetObjectField,
+       _Jv_JNI_SetBooleanField,
+       _Jv_JNI_SetByteField,
+       _Jv_JNI_SetCharField,
+       _Jv_JNI_SetShortField,
+       _Jv_JNI_SetIntField,
+       _Jv_JNI_SetLongField,
+       _Jv_JNI_SetFloatField,
+       _Jv_JNI_SetDoubleField,
+
+       _Jv_JNI_GetStaticMethodID,
+
+       _Jv_JNI_CallStaticObjectMethod,
+       _Jv_JNI_CallStaticObjectMethodV,
+       _Jv_JNI_CallStaticObjectMethodA,
+       _Jv_JNI_CallStaticBooleanMethod,
+       _Jv_JNI_CallStaticBooleanMethodV,
+       _Jv_JNI_CallStaticBooleanMethodA,
+       _Jv_JNI_CallStaticByteMethod,
+       _Jv_JNI_CallStaticByteMethodV,
+       _Jv_JNI_CallStaticByteMethodA,
+       _Jv_JNI_CallStaticCharMethod,
+       _Jv_JNI_CallStaticCharMethodV,
+       _Jv_JNI_CallStaticCharMethodA,
+       _Jv_JNI_CallStaticShortMethod,
+       _Jv_JNI_CallStaticShortMethodV,
+       _Jv_JNI_CallStaticShortMethodA,
+       _Jv_JNI_CallStaticIntMethod,
+       _Jv_JNI_CallStaticIntMethodV,
+       _Jv_JNI_CallStaticIntMethodA,
+       _Jv_JNI_CallStaticLongMethod,
+       _Jv_JNI_CallStaticLongMethodV,
+       _Jv_JNI_CallStaticLongMethodA,
+       _Jv_JNI_CallStaticFloatMethod,
+       _Jv_JNI_CallStaticFloatMethodV,
+       _Jv_JNI_CallStaticFloatMethodA,
+       _Jv_JNI_CallStaticDoubleMethod,
+       _Jv_JNI_CallStaticDoubleMethodV,
+       _Jv_JNI_CallStaticDoubleMethodA,
+       _Jv_JNI_CallStaticVoidMethod,
+       _Jv_JNI_CallStaticVoidMethodV,
+       _Jv_JNI_CallStaticVoidMethodA,
+
+       _Jv_JNI_GetStaticFieldID,
+
+       _Jv_JNI_GetStaticObjectField,
+       _Jv_JNI_GetStaticBooleanField,
+       _Jv_JNI_GetStaticByteField,
+       _Jv_JNI_GetStaticCharField,
+       _Jv_JNI_GetStaticShortField,
+       _Jv_JNI_GetStaticIntField,
+       _Jv_JNI_GetStaticLongField,
+       _Jv_JNI_GetStaticFloatField,
+       _Jv_JNI_GetStaticDoubleField,
+       _Jv_JNI_SetStaticObjectField,
+       _Jv_JNI_SetStaticBooleanField,
+       _Jv_JNI_SetStaticByteField,
+       _Jv_JNI_SetStaticCharField,
+       _Jv_JNI_SetStaticShortField,
+       _Jv_JNI_SetStaticIntField,
+       _Jv_JNI_SetStaticLongField,
+       _Jv_JNI_SetStaticFloatField,
+       _Jv_JNI_SetStaticDoubleField,
+
+       _Jv_JNI_NewString,
+       _Jv_JNI_GetStringLength,
+       _Jv_JNI_GetStringChars,
+       _Jv_JNI_ReleaseStringChars,
+
+       _Jv_JNI_NewStringUTF,
+       _Jv_JNI_GetStringUTFLength,
+       _Jv_JNI_GetStringUTFChars,
+       _Jv_JNI_ReleaseStringUTFChars,
+
+       _Jv_JNI_GetArrayLength,
+
+       _Jv_JNI_NewObjectArray,
+       _Jv_JNI_GetObjectArrayElement,
+       _Jv_JNI_SetObjectArrayElement,
+
+       _Jv_JNI_NewBooleanArray,
+       _Jv_JNI_NewByteArray,
+       _Jv_JNI_NewCharArray,
+       _Jv_JNI_NewShortArray,
+       _Jv_JNI_NewIntArray,
+       _Jv_JNI_NewLongArray,
+       _Jv_JNI_NewFloatArray,
+       _Jv_JNI_NewDoubleArray,
+
+       _Jv_JNI_GetBooleanArrayElements,
+       _Jv_JNI_GetByteArrayElements,
+       _Jv_JNI_GetCharArrayElements,
+       _Jv_JNI_GetShortArrayElements,
+       _Jv_JNI_GetIntArrayElements,
+       _Jv_JNI_GetLongArrayElements,
+       _Jv_JNI_GetFloatArrayElements,
+       _Jv_JNI_GetDoubleArrayElements,
+
+       _Jv_JNI_ReleaseBooleanArrayElements,
+       _Jv_JNI_ReleaseByteArrayElements,
+       _Jv_JNI_ReleaseCharArrayElements,
+       _Jv_JNI_ReleaseShortArrayElements,
+       _Jv_JNI_ReleaseIntArrayElements,
+       _Jv_JNI_ReleaseLongArrayElements,
+       _Jv_JNI_ReleaseFloatArrayElements,
+       _Jv_JNI_ReleaseDoubleArrayElements,
+
+       _Jv_JNI_GetBooleanArrayRegion,
+       _Jv_JNI_GetByteArrayRegion,
+       _Jv_JNI_GetCharArrayRegion,
+       _Jv_JNI_GetShortArrayRegion,
+       _Jv_JNI_GetIntArrayRegion,
+       _Jv_JNI_GetLongArrayRegion,
+       _Jv_JNI_GetFloatArrayRegion,
+       _Jv_JNI_GetDoubleArrayRegion,
+       _Jv_JNI_SetBooleanArrayRegion,
+       _Jv_JNI_SetByteArrayRegion,
+       _Jv_JNI_SetCharArrayRegion,
+       _Jv_JNI_SetShortArrayRegion,
+       _Jv_JNI_SetIntArrayRegion,
+       _Jv_JNI_SetLongArrayRegion,
+       _Jv_JNI_SetFloatArrayRegion,
+       _Jv_JNI_SetDoubleArrayRegion,
+
+       _Jv_JNI_RegisterNatives,
+       _Jv_JNI_UnregisterNatives,
+
+       _Jv_JNI_MonitorEnter,
+       _Jv_JNI_MonitorExit,
+
+       _Jv_JNI_GetJavaVM,
+
+       /* new JNI 1.2 functions */
+
+       _Jv_JNI_GetStringRegion,
+       _Jv_JNI_GetStringUTFRegion,
+
+       _Jv_JNI_GetPrimitiveArrayCritical,
+       _Jv_JNI_ReleasePrimitiveArrayCritical,
+
+       _Jv_JNI_GetStringCritical,
+       _Jv_JNI_ReleaseStringCritical,
+
+       _Jv_JNI_NewWeakGlobalRef,
+       _Jv_JNI_DeleteWeakGlobalRef,
+
+       _Jv_JNI_ExceptionCheck,
+
+       /* new JNI 1.4 functions */
+
+       _Jv_JNI_NewDirectByteBuffer,
+       _Jv_JNI_GetDirectBufferAddress,
+       _Jv_JNI_GetDirectBufferCapacity
 };
 
-JNIEnv env = &envTable;
 
+/* Invocation API Functions ***************************************************/
+
+/* JNI_GetDefaultJavaVMInitArgs ************************************************
 
-jobject *jni_method_invokeNativeHelper(JNIEnv *env, struct methodinfo *methodID, jobject obj, java_objectarray *params)
+   Returns a default configuration for the Java VM.
+
+*******************************************************************************/
+
+jint JNI_GetDefaultJavaVMInitArgs(void *vm_args)
 {
-       int argcount;
-       jni_callblock *blk;
-       char retT;
-       jobject retVal;
+       JavaVMInitArgs *_vm_args;
 
-       if (methodID == 0) {
-               *exceptionptr = new_exception(string_java_lang_NoSuchMethodError); 
-               return NULL;
-       }
+       _vm_args = (JavaVMInitArgs *) vm_args;
 
-       argcount = get_parametercount(methodID);
+       /* GNU classpath currently supports JNI 1.2 */
 
-       if (obj && (!builtin_instanceof((java_objectheader *) obj, methodID->class))) {
-               (*env)->ThrowNew(env, loader_load(utf_new_char("java/lang/IllegalArgumentException")),
-                                                "Object parameter of wrong type in Java_java_lang_reflect_Method_invokeNative");
-               return 0;
+       switch (_vm_args->version) {
+    case JNI_VERSION_1_1:
+               _vm_args->version = JNI_VERSION_1_1;
+               break;
+
+    case JNI_VERSION_1_2:
+    case JNI_VERSION_1_4:
+               _vm_args->ignoreUnrecognized = JNI_FALSE;
+               _vm_args->options = NULL;
+               _vm_args->nOptions = 0;
+               break;
+
+    default:
+               return -1;
        }
+  
+       return 0;
+}
 
 
+/* JNI_GetCreatedJavaVMs *******************************************************
 
-       if (argcount > 3) {
-               *exceptionptr = native_new_and_init(loader_load(utf_new_char("java/lang/IllegalArgumentException")));
-               log_text("Too many arguments. invokeNativeHelper does not support that");
-               return 0;
-       }
+   Returns all Java VMs that have been created. Pointers to VMs are written in
+   the buffer vmBuf in the order they are created. At most bufLen number of
+   entries will be written. The total number of created VMs is returned in
+   *nVMs.
 
-       if (((!params) && (argcount != 0)) || (params && (params->header.size != argcount))) {
-               *exceptionptr = native_new_and_init(loader_load(utf_new_char("java/lang/IllegalArgumentException")));
-               return 0;
-       }
+*******************************************************************************/
 
+jint JNI_GetCreatedJavaVMs(JavaVM **vmBuf, jsize bufLen, jsize *nVMs)
+{
+       TRACEJNICALLS("JNI_GetCreatedJavaVMs(vmBuf=%p, jsize=%d, jsize=%p)", vmBuf, bufLen, nVMs);
 
-       if (!(methodID->flags & ACC_STATIC) && (!obj))  {
-               (*env)->ThrowNew(env, loader_load(utf_new_char("java/lang/NullPointerException")),
-                                                "Static mismatch in Java_java_lang_reflect_Method_invokeNative");
-               return 0;
-       }
+       if (bufLen <= 0)
+               return JNI_ERR;
 
-       if ((methodID->flags & ACC_STATIC) && (obj)) obj = 0;
+       /* We currently only support 1 VM running. */
 
-       blk = MNEW(jni_callblock, 4 /*argcount+2*/);
+       vmBuf[0] = (JavaVM *) _Jv_jvm;
+       *nVMs    = 1;
 
-       retT = fill_callblock_objA(obj, methodID->descriptor, blk, params);
+    return JNI_OK;
+}
 
-       switch (retT) {
-       case 'V':
-               (void) asm_calljavafunction2(methodID,
-                                                                        argcount + 1,
-                                                                        (argcount + 1) * sizeof(jni_callblock),
-                                                                        blk);
-               retVal = NULL; /*native_new_and_init(loader_load(utf_new_char("java/lang/Void")));*/
-               break;
 
-       case 'I': {
-               s4 intVal;      
-               intVal = (s4) asm_calljavafunction2(methodID,
-                                                                                       argcount + 1,
-                                                                                       (argcount + 1) * sizeof(jni_callblock),
-                                                                                       blk);
-               retVal = builtin_new(loader_load_sysclass(NULL,
-                                                                                                 utf_new_char("java/lang/Integer")));
-               CallVoidMethod(env,
-                                          retVal,
-                                          class_resolvemethod(retVal->vftbl->class,
-                                                                                  utf_new_char("<init>"),
-                                                                                  utf_new_char("(I)V")),
-                                          intVal);
-       }
-       break;
-
-       case 'B': {
-               s4 intVal;      
-               intVal = (s4) asm_calljavafunction2(methodID,
-                                                                                       argcount + 1,
-                                                                                       (argcount + 1) * sizeof(jni_callblock),
-                                                                                       blk);
-               retVal = builtin_new(loader_load_sysclass(NULL,
-                                                                                                 utf_new_char("java/lang/Byte")));
-               CallVoidMethod(env,
-                                          retVal,
-                                          class_resolvemethod(retVal->vftbl->class,
-                                                                                  utf_new_char("<init>"),
-                                                                                  utf_new_char("(B)V")),
-                                          intVal);
-       }
-       break;
-
-       case 'C': {
-               s4 intVal;      
-               intVal = (s4) asm_calljavafunction2(methodID,
-                                                                                       argcount + 1,
-                                                                                       (argcount + 1) * sizeof(jni_callblock),
-                                                                                       blk);
-               retVal = builtin_new(loader_load_sysclass(NULL,
-                                                                                                 utf_new_char("java/lang/Character")));
-               CallVoidMethod(env,
-                                          retVal,
-                                          class_resolvemethod(retVal->vftbl->class,
-                                                                                  utf_new_char("<init>"),
-                                                                                  utf_new_char("(C)V")),
-                                          intVal);
-       }
-       break;
-
-       case 'S': {
-               s4 intVal;      
-               intVal = (s4) asm_calljavafunction2(methodID,
-                                                                                       argcount + 1,
-                                                                                       (argcount + 1) * sizeof(jni_callblock),
-                                                                                       blk);
-               retVal = builtin_new(loader_load_sysclass(NULL,
-                                                                                                 utf_new_char("java/lang/Short")));
-               CallVoidMethod(env,
-                                          retVal,
-                                          class_resolvemethod(retVal->vftbl->class,
-                                                                                  utf_new_char("<init>"),
-                                                                                  utf_new_char("(S)V")),
-                                          intVal);
-       }
-       break;
-
-       case 'Z': {
-               s4 intVal;      
-               intVal = (s4) asm_calljavafunction2(methodID,
-                                                                                       argcount + 1,
-                                                                                       (argcount + 1) * sizeof(jni_callblock),
-                                                                                       blk);
-               retVal = builtin_new(loader_load_sysclass(NULL,
-                                                                                                 utf_new_char("java/lang/Boolean")));
-               CallVoidMethod(env,
-                                          retVal,
-                                          class_resolvemethod(retVal->vftbl->class,
-                                                                                  utf_new_char("<init>"),
-                                                                                  utf_new_char("(Z)V")),
-                                          intVal);
-       }
-       break;
-
-       case 'J': {
-               jlong intVal;   
-               intVal = asm_calljavafunction2long(methodID,
-                                                                                  argcount + 1,
-                                                                                  (argcount + 1) * sizeof(jni_callblock),
-                                                                                  blk);
-               retVal = builtin_new(loader_load_sysclass(NULL,
-                                                                                                 utf_new_char("java/lang/Long")));
-               CallVoidMethod(env,
-                                          retVal,
-                                          class_resolvemethod(retVal->vftbl->class,
-                                                                                  utf_new_char("<init>"),
-                                                                                  utf_new_char("(J)V")),
-                                          intVal);
-       }
-       break;
-
-       case 'F': {
-               jdouble floatVal;       
-               floatVal = asm_calljavafunction2double(methodID,
-                                                                                          argcount + 1,
-                                                                                          (argcount + 1) * sizeof(jni_callblock),
-                                                                                          blk);
-               retVal = builtin_new(loader_load_sysclass(NULL,
-                                                                                                 utf_new_char("java/lang/Float")));
-               CallVoidMethod(env,
-                                          retVal,
-                                          class_resolvemethod(retVal->vftbl->class,
-                                                                                  utf_new_char("<init>"),
-                                                                                  utf_new_char("(F)V")),
-                                          floatVal);
-       }
-       break;
-
-       case 'D': {
-               jdouble floatVal;       
-               floatVal = asm_calljavafunction2double(methodID,
-                                                                                          argcount + 1,
-                                                                                          (argcount + 1) * sizeof(jni_callblock),
-                                                                                          blk);
-               retVal = builtin_new(loader_load_sysclass(NULL,
-                                                                                                 utf_new_char("java/lang/Double")));
-               CallVoidMethod(env,
-                                          retVal,
-                                          class_resolvemethod(retVal->vftbl->class,
-                                                                                  utf_new_char("<init>"),
-                                                                                  utf_new_char("(D)V")),
-                                          floatVal);
-       }
-       break;
-
-       case 'L': /* fall through */
-       case '[':
-               retVal = asm_calljavafunction2(methodID,
-                                                                          argcount + 1,
-                                                                          (argcount + 1) * sizeof(jni_callblock),
-                                                                          blk);
-               break;
+/* JNI_CreateJavaVM ************************************************************
 
-       default:
-               /* if this happens the acception has already been set by fill_callblock_objA*/
-               MFREE(blk, jni_callblock, 4 /*argcount+2*/);
-               return (jobject *) 0;
-       }
+   Loads and initializes a Java VM. The current thread becomes the main thread.
+   Sets the env argument to the JNI interface pointer of the main thread.
 
-       MFREE(blk, jni_callblock, 4 /*argcount+2*/);
-
-       if (*exceptionptr) {
-               java_objectheader *exceptionToWrap=*exceptionptr;
-               classinfo *ivtec;
-               java_objectheader *ivte;
-
-               *exceptionptr=0;
-               ivtec = loader_load_sysclass(NULL,
-                                                                                               utf_new_char("java/lang/reflect/InvocationTargetException"));
-               ivte = builtin_new(ivtec);
-               asm_calljavafunction(class_resolvemethod(ivtec,
-                                                                                                utf_new_char("<init>"),
-                                                                                                utf_new_char("(Ljava/lang/Throwable;)V")),
-                                                        ivte,
-                                                        exceptionToWrap,
-                                                        0,
-                                                        0);
-
-               if (*exceptionptr != NULL)
-                       panic("jni.c: error while creating InvocationTargetException wrapper");
-
-               *exceptionptr = ivte;
-       }
+*******************************************************************************/
+
+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);
+
+       /* actually create the JVM */
+
+       if (!vm_createjvm(p_vm, p_env, vm_args))
+               return JNI_ERR;
 
-       return (jobject *) retVal;
+       return JNI_OK;
 }
 
 
@@ -3564,4 +4287,5 @@ jobject *jni_method_invokeNativeHelper(JNIEnv *env, struct methodinfo *methodID,
  * c-basic-offset: 4
  * tab-width: 4
  * End:
+ * vim:noexpandtab:sw=4:ts=4:
  */