* exceptions_throw_illegalargumentexception,
[cacao.git] / src / native / jni.c
index 43600a18842eb9831bce9b16d51b2513e25ec524..c1711f00ada23c40ad4bb476e2b3fb52a9745c6c 100644 (file)
             Martin Platter
             Christian Thalinger
 
-   $Id: jni.c 2849 2005-06-28 12:46:42Z twisti $
+   $Id: jni.c 4123 2006-01-10 20:46:50Z twisti $
 
 */
 
 
+#include "config.h"
+
 #include <assert.h>
 #include <string.h>
 
-#include "config.h"
+#include "vm/types.h"
+
 #include "mm/boehm.h"
 #include "mm/memory.h"
 #include "native/jni.h"
 #include "native/native.h"
+
+#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
+
 #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_Class.h" /* for java_lang_VMClass.h */
 #include "native/include/java_lang_VMClass.h"
 #include "native/include/java_lang_VMClassLoader.h"
+#include "native/include/java_nio_Buffer.h"
+#include "native/include/java_nio_DirectByteBufferImpl.h"
+
+#if defined(ENABLE_JVMTI)
+# include "native/jvmti/jvmti.h"
+#endif
 
 #if defined(USE_THREADS)
 # if defined(NATIVE_THREADS)
 #include "vm/resolve.h"
 #include "vm/statistics.h"
 #include "vm/stringlocal.h"
-#include "vm/tables.h"
 #include "vm/jit/asmpart.h"
 #include "vm/jit/jit.h"
 #include "vm/statistics.h"
 
 
 /* XXX TWISTI hack: define it extern so they can be found in this file */
+
 extern const struct JNIInvokeInterface JNI_JavaVMTable;
 extern struct JNINativeInterface JNI_JNIEnvTable;
 
 /* pointers to VM and the environment needed by GetJavaVM and GetEnv */
+
 static JavaVM ptr_jvm = (JavaVM) &JNI_JavaVMTable;
-static void* ptr_env = (void*) &JNI_JNIEnvTable;
+void *ptr_env = (void*) &JNI_JNIEnvTable;
 
 
 #define PTR_TO_ITEM(ptr)   ((u8)(size_t)(ptr))
 
-/* global reference table */
-static jobject *global_ref_table;
-static bool initrunning=false;
+/* global variables ***********************************************************/
+
+/* global reference table *****************************************************/
+
+static java_objectheader **global_ref_table;
 
 /* jmethodID and jclass caching variables for NewGlobalRef and DeleteGlobalRef*/
-static jmethodID getmid = NULL;
-static jmethodID putmid = NULL;
-static jclass intclass = NULL;
-static jmethodID intvalue = NULL;
-static jmethodID newint = NULL;
-static jclass ihmclass = NULL;
-static jmethodID removemid = NULL;
+static classinfo *ihmclass = NULL;
+static methodinfo *putmid = NULL;
+static methodinfo *getmid = NULL;
+static methodinfo *removemid = NULL;
+
+
+/* direct buffer stuff ********************************************************/
+
+static utf *utf_java_nio_DirectByteBufferImpl_ReadWrite;
+#if SIZEOF_VOID_P == 8
+static utf *utf_gnu_classpath_Pointer64;
+#else
+static utf *utf_gnu_classpath_Pointer32;
+#endif
+
+static classinfo *class_java_nio_DirectByteBufferImpl_ReadWrite;
+#if SIZEOF_VOID_P == 8
+static classinfo *class_gnu_classpath_Pointer64;
+#else
+static classinfo *class_gnu_classpath_Pointer32;
+#endif
+
+static methodinfo *dbbirw_init;
+
+
+/* local reference table ******************************************************/
+
+#if !defined(USE_THREADS)
+localref_table *_no_threads_localref_table;
+#endif
+
+
+/* accessing instance fields macros *******************************************/
+
+#define SET_FIELD(obj,type,var,value) \
+    *((type *) ((ptrint) (obj) + (ptrint) (var)->offset)) = (type) (value)
+
+#define GET_FIELD(obj,type,var) \
+    *((type *) ((ptrint) (obj) + (ptrint) (var)->offset))
+
+
+/* some forward declarations **************************************************/
+
+jobject NewLocalRef(JNIEnv *env, jobject ref);
+
+
+/* jni_init ********************************************************************
+
+   Initialize the JNI subsystem.
+
+*******************************************************************************/
+
+bool jni_init(void)
+{
+       /* initalize global reference table */
+
+       if (!(ihmclass =
+                 load_class_bootstrap(utf_new_char("java/util/IdentityHashMap"))))
+               return false;
+
+       global_ref_table = GCNEW(jobject, 1);
+
+       if (!(*global_ref_table = native_new_and_init(ihmclass)))
+               return false;
+
+       if (!(getmid = class_resolvemethod(ihmclass, utf_get,
+                                                                          utf_java_lang_Object__java_lang_Object)))
+               return false;
+
+       if (!(putmid = class_resolvemethod(ihmclass, utf_put,
+                                                                          utf_new_char("(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"))))
+               return false;
+
+       if (!(removemid =
+                 class_resolvemethod(ihmclass, utf_remove,
+                                                         utf_java_lang_Object__java_lang_Object)))
+               return false;
+
+
+       /* direct buffer stuff */
+
+       utf_java_nio_DirectByteBufferImpl_ReadWrite =
+               utf_new_char("java/nio/DirectByteBufferImpl$ReadWrite");
+
+       if (!(class_java_nio_DirectByteBufferImpl_ReadWrite =
+                 load_class_bootstrap(utf_java_nio_DirectByteBufferImpl_ReadWrite)))
+               return false;
+
+       if (!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
+       utf_gnu_classpath_Pointer64 = utf_new_char("gnu/classpath/Pointer64");
 
-#define JWCLINITDEBUG(x)
+       if (!(class_gnu_classpath_Pointer64 =
+                 load_class_bootstrap(utf_gnu_classpath_Pointer64)))
+               return false;
+
+       if (!link_class(class_gnu_classpath_Pointer64))
+               return false;
+#else
+       utf_gnu_classpath_Pointer32 = utf_new_char("gnu/classpath/Pointer32");
 
+       if (!(class_gnu_classpath_Pointer32 =
+                 load_class_bootstrap(utf_gnu_classpath_Pointer32)))
+               return false;
 
-/********************* accessing instance-fields **********************************/
+       if (!link_class(class_gnu_classpath_Pointer32))
+               return false;
+#endif
 
-#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); 
+       return true;
+}
 
 
 static void fill_callblock_from_vargs(void *obj, methoddesc *descr,
@@ -125,7 +249,6 @@ static void fill_callblock_from_vargs(void *obj, methoddesc *descr,
                                                                          s4 rettype)
 {
        typedesc *paramtypes;
-    u4        dummy;
        s4        i;
 
        paramtypes = descr->paramtypes;
@@ -151,23 +274,28 @@ static void fill_callblock_from_vargs(void *obj, methoddesc *descr,
                case PRIMITIVETYPE_SHORT: 
                case PRIMITIVETYPE_BOOLEAN: 
                        blk[i].itemtype = TYPE_INT;
-                       blk[i].item = (u8) va_arg(data, int);
+                       blk[i].item = (s8) va_arg(data, s4);
                        break;
 
                case PRIMITIVETYPE_INT:
                        blk[i].itemtype = TYPE_INT;
-                       dummy = va_arg(data, u4);
-                       blk[i].item = (u8) dummy;
+                       blk[i].item = (s8) va_arg(data, s4);
                        break;
 
                case PRIMITIVETYPE_LONG:
                        blk[i].itemtype = TYPE_LNG;
-                       blk[i].item = (u8) va_arg(data, jlong);
+                       blk[i].item = (s8) va_arg(data, s8);
                        break;
 
                case PRIMITIVETYPE_FLOAT:
                        blk[i].itemtype = TYPE_FLT;
+#if defined(__ALPHA__)
+                       /* this keeps the assembler function much simpler */
+
+                       *((jdouble *) (&blk[i].item)) = (jdouble) va_arg(data, jdouble);
+#else
                        *((jfloat *) (&blk[i].item)) = (jfloat) va_arg(data, jdouble);
+#endif
                        break;
 
                case PRIMITIVETYPE_DOUBLE:
@@ -241,54 +369,54 @@ static bool fill_callblock_from_objectarray(void *obj, methoddesc *descr,
                        switch (paramtypes->decltype) {
                        case PRIMITIVETYPE_BOOLEAN:
                                if (c == primitivetype_table[paramtypes->decltype].class_wrap)
-                                       blk[i].item = (u8) ((java_lang_Boolean *) param)->value;
+                                       blk[i].item = (s8) ((java_lang_Boolean *) param)->value;
                                else
                                        goto illegal_arg;
                                break;
 
                        case PRIMITIVETYPE_BYTE:
                                if (c == primitivetype_table[paramtypes->decltype].class_wrap)
-                                       blk[i].item = (u8) ((java_lang_Byte *) param)->value;
+                                       blk[i].item = (s8) ((java_lang_Byte *) param)->value;
                                else
                                        goto illegal_arg;
                                break;
 
                        case PRIMITIVETYPE_CHAR:
                                if (c == primitivetype_table[paramtypes->decltype].class_wrap)
-                                       blk[i].item = (u8) ((java_lang_Character *) param)->value;
+                                       blk[i].item = (s8) ((java_lang_Character *) param)->value;
                                else
                                        goto illegal_arg;
                                break;
 
                        case PRIMITIVETYPE_SHORT:
                                if (c == primitivetype_table[paramtypes->decltype].class_wrap)
-                                       blk[i].item = (u8) ((java_lang_Short *) param)->value;
+                                       blk[i].item = (s8) ((java_lang_Short *) param)->value;
                                else if (c == primitivetype_table[PRIMITIVETYPE_BYTE].class_wrap)
-                                       blk[i].item = (u8) ((java_lang_Byte *) param)->value;
+                                       blk[i].item = (s8) ((java_lang_Byte *) param)->value;
                                else
                                        goto illegal_arg;
                                break;
 
                        case PRIMITIVETYPE_INT:
                                if (c == primitivetype_table[paramtypes->decltype].class_wrap)
-                                       blk[i].item = (u8) ((java_lang_Integer *) param)->value;
+                                       blk[i].item = (s8) ((java_lang_Integer *) param)->value;
                                else if (c == primitivetype_table[PRIMITIVETYPE_SHORT].class_wrap)
-                                       blk[i].item = (u8) ((java_lang_Short *) param)->value;
+                                       blk[i].item = (s8) ((java_lang_Short *) param)->value;
                                else if (c == primitivetype_table[PRIMITIVETYPE_BYTE].class_wrap)
-                                       blk[i].item = (u8) ((java_lang_Byte *) param)->value;
+                                       blk[i].item = (s8) ((java_lang_Byte *) param)->value;
                                else
                                        goto illegal_arg;
                                break;
 
                        case PRIMITIVETYPE_LONG:
                                if (c == primitivetype_table[paramtypes->decltype].class_wrap)
-                                       blk[i].item = (u8) ((java_lang_Long *) param)->value;
+                                       blk[i].item = (s8) ((java_lang_Long *) param)->value;
                                else if (c == primitivetype_table[PRIMITIVETYPE_INT].class_wrap)
-                                       blk[i].item = (u8) ((java_lang_Integer *) param)->value;
+                                       blk[i].item = (s8) ((java_lang_Integer *) param)->value;
                                else if (c == primitivetype_table[PRIMITIVETYPE_SHORT].class_wrap)
-                                       blk[i].item = (u8) ((java_lang_Short *) param)->value;
+                                       blk[i].item = (s8) ((java_lang_Short *) param)->value;
                                else if (c == primitivetype_table[PRIMITIVETYPE_BYTE].class_wrap)
-                                       blk[i].item = (u8) ((java_lang_Byte *) param)->value;
+                                       blk[i].item = (s8) ((java_lang_Byte *) param)->value;
                                else
                                        goto illegal_arg;
                                break;
@@ -320,7 +448,7 @@ static bool fill_callblock_from_objectarray(void *obj, methoddesc *descr,
 
                                if (params->data[j] != 0) {
                                        if (paramtypes->arraydim > 0) {
-                                               if (!builtin_arrayinstanceof(params->data[j], c->vftbl))
+                                               if (!builtin_arrayinstanceof(params->data[j], c))
                                                        goto illegal_arg;
 
                                        } else {
@@ -344,7 +472,7 @@ static bool fill_callblock_from_objectarray(void *obj, methoddesc *descr,
        return true;
 
 illegal_arg:
-       *exceptionptr = new_exception(string_java_lang_IllegalArgumentException);
+       exceptions_throw_illegalargumentexception();
        return false;
 }
 
@@ -375,15 +503,11 @@ static jobject callObjectMethod(jobject obj, jmethodID methodID, va_list args)
        jni_callblock *blk;
        jobject ret;
 
-
-
        if (methodID == 0) {
                *exceptionptr = new_exception(string_java_lang_NoSuchMethodError); 
                return 0;
        }
 
-       argcount = methodID->parseddesc->paramcount;
-
        if (!( ((methodID->flags & ACC_STATIC) && (obj == 0)) ||
                ((!(methodID->flags & ACC_STATIC)) && (obj != 0)) )) {
                *exceptionptr = new_exception(string_java_lang_NoSuchMethodError);
@@ -395,26 +519,20 @@ static jobject callObjectMethod(jobject obj, jmethodID methodID, va_list args)
                return 0;
        }
 
-#ifdef arglimit
-
-       if (argcount > 3) {
-               *exceptionptr = new_exception(string_java_lang_IllegalArgumentException);
-               log_text("Too many arguments. CallObjectMethod does not support that");
-               return 0;
-       }
-#endif
+       argcount = methodID->parseddesc->paramcount;
 
-       blk = MNEW(jni_callblock, /*4 */argcount+2);
+       blk = MNEW(jni_callblock, argcount);
 
        fill_callblock_from_vargs(obj, methodID->parseddesc, blk, args, TYPE_ADR);
-       /*      printf("parameter: obj: %p",blk[0].item); */
-       STATS(jnicallXmethodnvokation();)
+
+       STATISTICS(jnicallXmethodnvokation());
+
        ret = asm_calljavafunction2(methodID,
-                                                               argcount + 1,
-                                                               (argcount + 1) * sizeof(jni_callblock),
+                                                               argcount,
+                                                               argcount * sizeof(jni_callblock),
                                                                blk);
-       MFREE(blk, jni_callblock, argcount + 1);
-       /*      printf("(CallObjectMethodV)-->%p\n",ret); */
+
+       MFREE(blk, jni_callblock, argcount);
 
        return ret;
 }
@@ -430,7 +548,7 @@ static jint callIntegerMethod(jobject obj, jmethodID methodID, int retType, va_l
        jni_callblock *blk;
        jint ret;
 
-       STATS(jniinvokation();)
+       STATISTICS(jniinvokation());
 
         /*
         log_text("JNI-Call: CallObjectMethodV");
@@ -445,8 +563,6 @@ static jint callIntegerMethod(jobject obj, jmethodID methodID, int retType, va_l
                return 0;
        }
         
-       argcount = methodID->parseddesc->paramcount;
-
        if (!( ((methodID->flags & ACC_STATIC) && (obj == 0)) ||
                ((!(methodID->flags & ACC_STATIC)) && (obj != 0)) )) {
                *exceptionptr = new_exception(string_java_lang_NoSuchMethodError);
@@ -458,88 +574,69 @@ static jint callIntegerMethod(jobject obj, jmethodID methodID, int retType, va_l
                return 0;
        }
 
-#ifdef arglimit
-       if (argcount > 3) {
-               *exceptionptr = new_exception(string_java_lang_IllegalArgumentException);
-               log_text("Too many arguments. CallIntegerMethod does not support that");
-               return 0;
-       }
-#endif
+       argcount = methodID->parseddesc->paramcount;
 
-       blk = MNEW(jni_callblock, /*4 */ argcount+2);
+       blk = MNEW(jni_callblock, argcount);
 
        fill_callblock_from_vargs(obj, methodID->parseddesc, blk, args, retType);
 
-       /*      printf("parameter: obj: %p",blk[0].item); */
-       STATS(jnicallXmethodnvokation();)
+       STATISTICS(jnicallXmethodnvokation());
+
        ret = asm_calljavafunction2int(methodID,
-                                                                  argcount + 1,
-                                                                  (argcount + 1) * sizeof(jni_callblock),
+                                                                  argcount,
+                                                                  argcount * sizeof(jni_callblock),
                                                                   blk);
 
-       MFREE(blk, jni_callblock, argcount + 1);
-       /*      printf("(CallObjectMethodV)-->%p\n",ret); */
+       MFREE(blk, jni_callblock, argcount);
 
        return ret;
 }
 
 
-/*core function for long class functions*/
+/* callLongMethod **************************************************************
+
+   Core function for long class functions.
+
+*******************************************************************************/
+
 static jlong callLongMethod(jobject obj, jmethodID methodID, va_list args)
 {
-       int argcount;
+       s4             argcount;
        jni_callblock *blk;
-       jlong ret;
+       jlong          ret;
 
-       STATS(jniinvokation();)
+       STATISTICS(jniinvokation());
 
-/*     
-        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;
        }
 
-       argcount = methodID->parseddesc->paramcount;
-
        if (!( ((methodID->flags & ACC_STATIC) && (obj == 0)) ||
-                  ((!(methodID->flags & ACC_STATIC)) && (obj!=0)) )) {
+                  ((!(methodID->flags & ACC_STATIC)) && (obj != 0)) )) {
                *exceptionptr = new_exception(string_java_lang_NoSuchMethodError);
                return 0;
        }
 
-       if (obj && !builtin_instanceof(obj,methodID->class)) {
+       if (obj && !builtin_instanceof(obj, methodID->class)) {
                *exceptionptr = new_exception(string_java_lang_NoSuchMethodError);
                return 0;
        }
 
-#ifdef arglimit
-       if (argcount > 3) {
-               *exceptionptr = new_exception(string_java_lang_IllegalArgumentException);
-               log_text("Too many arguments. CallObjectMethod does not support that");
-               return 0;
-       }
-#endif
+       argcount = methodID->parseddesc->paramcount;
 
-       blk = MNEW(jni_callblock,/* 4 */argcount+2);
+       blk = MNEW(jni_callblock, argcount);
 
        fill_callblock_from_vargs(obj, methodID->parseddesc, blk, args, TYPE_LNG);
 
-       /*      printf("parameter: obj: %p",blk[0].item); */
-       STATS(jnicallXmethodnvokation();)
+       STATISTICS(jnicallXmethodnvokation());
+
        ret = asm_calljavafunction2long(methodID,
-                                                                       argcount + 1,
-                                                                       (argcount + 1) * sizeof(jni_callblock),
+                                                                       argcount,
+                                                                       argcount * sizeof(jni_callblock),
                                                                        blk);
 
-       MFREE(blk, jni_callblock, argcount + 1);
-       /*      printf("(CallObjectMethodV)-->%p\n",ret); */
+       MFREE(blk, jni_callblock, argcount);
 
        return ret;
 }
@@ -552,31 +649,24 @@ static jdouble callFloatMethod(jobject obj, jmethodID methodID, va_list args,int
        jni_callblock *blk;
        jdouble ret;
 
-       STATS(jniinvokation();)
+       STATISTICS(jniinvokation());
 
-        /*
-        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");
-        */
+       assert(0);
 
-#ifdef arglimit
        if (argcount > 3) {
                *exceptionptr = new_exception(string_java_lang_IllegalArgumentException);
                log_text("Too many arguments. CallObjectMethod does not support that");
                return 0;
        }
-#endif
 
        blk = MNEW(jni_callblock, /*4 */ argcount+2);
 
        fill_callblock_from_vargs(obj, methodID->parseddesc, blk, args, retType);
 
        /*      printf("parameter: obj: %p",blk[0].item); */
-       STATS(jnicallXmethodnvokation();)
+
+       STATISTICS(jnicallXmethodnvokation());
+
        ret = asm_calljavafunction2double(methodID,
                                                                          argcount + 1,
                                                                          (argcount + 1) * sizeof(jni_callblock),
@@ -589,32 +679,47 @@ static jdouble callFloatMethod(jobject obj, jmethodID methodID, va_list args,int
 }
 
 
-/*************************** function: jclass_findfield ****************************
-       
-       searches for field with specified name and type in a 'classinfo'-structur
-       if no such field is found NULL is returned 
+static void cacao_jni_CallVoidMethod(jobject obj, jmethodID m, va_list ap)
+{      
+       s4             paramcount;
+       jni_callblock *blk;
+
+       if (m == 0) {
+               *exceptionptr = new_exception(string_java_lang_NoSuchMethodError); 
+               return;
+       }
 
-************************************************************************************/
+       if (!( ((m->flags & ACC_STATIC) && (obj == 0)) ||
+               ((!(m->flags & ACC_STATIC)) && (obj != 0)) )) {
+               *exceptionptr = new_exception(string_java_lang_NoSuchMethodError);
+               return;
+       }
 
-static fieldinfo *jclass_findfield (classinfo *c, utf *name, utf *desc)
-{
-       s4 i;
-       STATS(jniinvokation();)
-
-/*     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 (obj && !builtin_instanceof(obj, m->class)) {
+               *exceptionptr = new_exception(string_java_lang_NoSuchMethodError);
+               return;
+       }
 
-       if (c->super.cls) return jclass_findfield(c->super.cls,name,desc);
+       paramcount = m->parseddesc->paramcount;
 
-       return NULL;
+/* #error XXX does not work on intrp, but on JIT */
+       if (!(m->flags & ACC_STATIC))
+               paramcount++;
+
+       blk = MNEW(jni_callblock, paramcount);
+
+       fill_callblock_from_vargs(obj, m->parseddesc, blk, ap, TYPE_VOID);
+
+       STATISTICS(jnicallXmethodnvokation());
+
+       (void) asm_calljavafunction2(m,
+                                                                paramcount,
+                                                                paramcount * sizeof(jni_callblock),
+                                                                blk);
+
+       MFREE(blk, jni_callblock, paramcount);
+
+       return;
 }
 
 
@@ -627,9 +732,11 @@ static fieldinfo *jclass_findfield (classinfo *c, utf *name, utf *desc)
 
 jint GetVersion(JNIEnv *env)
 {
-       /* GNU classpath currently supports JNI 1.2 */
-       STATS(jniinvokation();)
-       return JNI_VERSION_1_2;
+       STATISTICS(jniinvokation());
+
+       /* we support JNI 1.4 */
+
+       return JNI_VERSION_1_4;
 }
 
 
@@ -651,7 +758,7 @@ jclass DefineClass(JNIEnv *env, const char *name, jobject loader,
        java_bytearray        *ba;
        jclass                 c;
 
-       STATS(jniinvokation();)
+       STATISTICS(jniinvokation());
 
        cl = (java_lang_ClassLoader *) loader;
        s = javastring_new_char(name);
@@ -660,7 +767,7 @@ jclass DefineClass(JNIEnv *env, const char *name, jobject loader,
        c = (jclass) Java_java_lang_VMClassLoader_defineClass(env, NULL, cl, s, ba,
                                                                                                                  0, bufLen, NULL);
 
-       return c;
+       return (jclass) NewLocalRef(env, (jobject) c);
 }
 
 
@@ -678,17 +785,26 @@ jclass FindClass(JNIEnv *env, const char *name)
        classinfo         *c;
        java_objectheader *cl;
 
-       STATS(jniinvokation();)
+       STATISTICS(jniinvokation());
 
        u = utf_new_char_classname((char *) name);
 
        /* check stacktrace for classloader, if one found use it, otherwise use */
        /* the system classloader */
 
-#if defined(__I386__) || defined(__X86_64__) || defined(__ALPHA__)
+#if defined(__ALPHA__) || defined(__ARM__) || defined(__I386__) || defined(__MIPS__) || defined(__POWERPC__) || defined(__X86_64__)
+       /* these JITs support stacktraces, and so does the interpreter */
+
        cl = cacao_currentClassLoader();
 #else
-       cl = NULL;
+# if defined(ENABLE_INTRP)
+       /* the interpreter supports stacktraces, even if the JIT does not */
+
+       if (opt_intrp)
+               cl = cacao_currentClassLoader();
+       else
+# endif
+               cl = NULL;
 #endif
 
        if (!(c = load_class_from_classloader(u, cl)))
@@ -697,9 +813,7 @@ jclass FindClass(JNIEnv *env, const char *name)
        if (!link_class(c))
                return NULL;
 
-       use_class_as_object(c);
-
-       return c;
+       return (jclass) NewLocalRef(env, (jobject) c);
 }
   
 
@@ -716,7 +830,7 @@ jmethodID FromReflectedMethod(JNIEnv *env, jobject method)
        classinfo  *c;
        s4          slot;
 
-       STATS(jniinvokation();)
+       STATISTICS(jniinvokation());
 
        if (method == NULL)
                return NULL;
@@ -762,16 +876,15 @@ jmethodID FromReflectedMethod(JNIEnv *env, jobject method)
 jclass GetSuperclass(JNIEnv *env, jclass sub)
 {
        classinfo *c;
-       STATS(jniinvokation();)
+
+       STATISTICS(jniinvokation());
 
        c = ((classinfo *) sub)->super.cls;
 
        if (!c)
                return NULL;
 
-       use_class_as_object(c);
-
-       return c;
+       return (jclass) NewLocalRef(env, (jobject) c);
 }
   
  
@@ -783,7 +896,8 @@ jclass GetSuperclass(JNIEnv *env, jclass sub)
 
 jboolean IsAssignableFrom(JNIEnv *env, jclass sub, jclass sup)
 {
-       STATS(jniinvokation();)
+       STATISTICS(jniinvokation());
+
        return Java_java_lang_VMClass_isAssignableFrom(env,
                                                                                                   NULL,
                                                                                                   (java_lang_Class *) sup,
@@ -791,16 +905,6 @@ jboolean IsAssignableFrom(JNIEnv *env, jclass sub, jclass sup)
 }
 
 
-/***** converts a field ID derived from cls to a java.lang.reflect.Field object ***/
-
-jobject ToReflectedField(JNIEnv* env, jclass cls, jfieldID fieldID, jboolean isStatic)
-{
-       log_text("JNI-Call: ToReflectedField: IMPLEMENT ME!!!");
-       STATS(jniinvokation();)
-       return NULL;
-}
-
-
 /* Throw ***********************************************************************
 
    Causes a java.lang.Throwable object to be thrown.
@@ -809,8 +913,9 @@ jobject ToReflectedField(JNIEnv* env, jclass cls, jfieldID fieldID, jboolean isS
 
 jint Throw(JNIEnv *env, jthrowable obj)
 {
+       STATISTICS(jniinvokation());
+
        *exceptionptr = (java_objectheader *) obj;
-       STATS(jniinvokation();)
 
        return JNI_OK;
 }
@@ -828,7 +933,8 @@ jint ThrowNew(JNIEnv* env, jclass clazz, const char *msg)
 {
        java_lang_Throwable *o;
        java_lang_String    *s;
-       STATS(jniinvokation();)
+
+       STATISTICS(jniinvokation());
 
        s = (java_lang_String *) javastring_new_char(msg);
 
@@ -856,8 +962,13 @@ jint ThrowNew(JNIEnv* env, jclass clazz, const char *msg)
 
 jthrowable ExceptionOccurred(JNIEnv *env)
 {
-       STATS(jniinvokation();)
-       return (jthrowable) *exceptionptr;
+       java_objectheader *e;
+
+       STATISTICS(jniinvokation());
+
+       e = *exceptionptr;
+
+       return NewLocalRef(env, (jthrowable) e);
 }
 
 
@@ -873,7 +984,8 @@ void ExceptionDescribe(JNIEnv *env)
 {
        java_objectheader *e;
        methodinfo        *m;
-       STATS(jniinvokation();)
+
+       STATISTICS(jniinvokation());
 
        e = *exceptionptr;
 
@@ -910,7 +1022,8 @@ void ExceptionDescribe(JNIEnv *env)
 
 void ExceptionClear(JNIEnv *env)
 {
-       STATS(jniinvokation();)
+       STATISTICS(jniinvokation());
+
        *exceptionptr = NULL;
 }
 
@@ -924,29 +1037,49 @@ void ExceptionClear(JNIEnv *env)
 
 void FatalError(JNIEnv *env, const char *msg)
 {
-       STATS(jniinvokation();)
+       STATISTICS(jniinvokation());
+
        throw_cacao_exception_exit(string_java_lang_InternalError, msg);
 }
 
 
-/******************* creates a new local reference frame **************************/ 
+/* PushLocalFrame **************************************************************
+
+   Creates a new local reference frame, in which at least a given
+   number of local references can be created.
+
+*******************************************************************************/
 
 jint PushLocalFrame(JNIEnv* env, jint capacity)
 {
+       STATISTICS(jniinvokation());
+
        log_text("JNI-Call: PushLocalFrame: IMPLEMENT ME!");
-       STATS(jniinvokation();)
+
+       assert(0);
 
        return 0;
 }
 
-/**************** Pops off the current local reference frame **********************/
+/* PopLocalFrame ***************************************************************
+
+   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.
+
+*******************************************************************************/
 
 jobject PopLocalFrame(JNIEnv* env, jobject result)
 {
+       STATISTICS(jniinvokation());
+
        log_text("JNI-Call: PopLocalFrame: IMPLEMENT ME!");
-       STATS(jniinvokation();)
 
-       return NULL;
+       assert(0);
+
+       /* add local reference and return the value */
+
+       return NewLocalRef(env, NULL);
 }
 
 
@@ -958,9 +1091,34 @@ jobject PopLocalFrame(JNIEnv* env, jobject result)
 
 void DeleteLocalRef(JNIEnv *env, jobject localRef)
 {
-       log_text("JNI-Call: DeleteLocalRef: IMPLEMENT ME!");
-       STATS(jniinvokation();)
+       java_objectheader *o;
+       localref_table    *lrt;
+       s4                 i;
 
+       STATISTICS(jniinvokation());
+
+       o = (java_objectheader *) localRef;
+
+       /* get local reference table (thread specific) */
+
+       lrt = LOCALREFTABLE;
+
+       /* remove the reference */
+
+       for (i = 0; i < lrt->capacity; i++) {
+               if (lrt->refs[i] == o) {
+                       lrt->refs[i] = NULL;
+                       lrt->used--;
+
+                       return;
+               }
+       }
+
+       /* this should not happen */
+
+/*     if (opt_checkjni) */
+/*     FatalError(env, "Bad global or local ref passed to JNI"); */
+       log_text("JNI-DeleteLocalRef: Bad global or local ref passed to JNI");
 }
 
 
@@ -972,8 +1130,12 @@ void DeleteLocalRef(JNIEnv *env, jobject localRef)
 
 jboolean IsSameObject(JNIEnv *env, jobject ref1, jobject ref2)
 {
-       STATS(jniinvokation();)
-       return (ref1 == ref2);
+       STATISTICS(jniinvokation());
+
+       if (ref1 == ref2)
+               return JNI_TRUE;
+       else
+               return JNI_FALSE;
 }
 
 
@@ -985,22 +1147,70 @@ jboolean IsSameObject(JNIEnv *env, jobject ref1, jobject ref2)
 
 jobject NewLocalRef(JNIEnv *env, jobject ref)
 {
-       log_text("JNI-Call: NewLocalRef: IMPLEMENT ME!");
-       STATS(jniinvokation();)
-       return ref;
+       localref_table *lrt;
+       s4              i;
+
+       STATISTICS(jniinvokation());
+
+       if (ref == NULL)
+               return NULL;
+
+       /* get local reference table (thread specific) */
+
+       lrt = LOCALREFTABLE;
+
+       /* check if we have space for the requested reference */
+
+       if (lrt->used == lrt->capacity)
+               throw_cacao_exception_exit(string_java_lang_InternalError,
+                                                                  "Too many local references");
+
+       /* insert the reference */
+
+       for (i = 0; i < lrt->capacity; i++) {
+               if (lrt->refs[i] == NULL) {
+                       lrt->refs[i] = (java_objectheader *) ref;
+                       lrt->used++;
+
+                       return ref;
+               }
+       }
+
+       /* should not happen, just to be sure */
+
+       assert(0);
+
+       /* keep compiler happy */
+
+       return NULL;
 }
 
-/*********************************************************************************** 
 
-       Ensures that at least a given number of local references can 
-       be created in the current thread
+/* EnsureLocalCapacity *********************************************************
 
- **********************************************************************************/   
+   Ensures that at least a given number of local references can be
+   created in the current thread
+
+*******************************************************************************/
 
-jint EnsureLocalCapacity (JNIEnv* env, jint capacity)
+jint EnsureLocalCapacity(JNIEnv* env, jint capacity)
 {
-       STATS(jniinvokation();)
-       return 0; /* return 0 on success */
+       localref_table *lrt;
+
+       STATISTICS(jniinvokation());
+
+       /* get local reference table (thread specific) */
+
+       lrt = LOCALREFTABLE;
+
+       /* check if capacity elements are available in the local references table */
+
+       if ((lrt->used + capacity) > lrt->capacity) {
+               *exceptionptr = new_exception(string_java_lang_OutOfMemoryError);
+               return -1;
+       }
+
+       return 0;
 }
 
 
@@ -1014,7 +1224,8 @@ jint EnsureLocalCapacity (JNIEnv* env, jint capacity)
 jobject AllocObject(JNIEnv *env, jclass clazz)
 {
        java_objectheader *o;
-       STATS(jniinvokation();)
+
+       STATISTICS(jniinvokation());
 
        if ((clazz->flags & ACC_INTERFACE) || (clazz->flags & ACC_ABSTRACT)) {
                *exceptionptr =
@@ -1025,35 +1236,25 @@ jobject AllocObject(JNIEnv *env, jclass clazz)
                
        o = builtin_new(clazz);
 
-       return o;
+       return NewLocalRef(env, o);
 }
 
 
 /* NewObject *******************************************************************
 
-   Constructs a new Java object. The method ID indicates which
-   constructor method to invoke. This ID must be obtained by calling
-   GetMethodID() with <init> as the method name and void (V) as the
-   return type.
+   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 NewObject(JNIEnv *env, jclass clazz, jmethodID methodID, ...)
 {
        java_objectheader *o;
-       void* args[3];
-       int argcount=methodID->parseddesc->paramcount;
-       int i;
-       va_list vaargs;
-       STATS(jniinvokation();)
+       va_list            ap;
 
-#ifdef arglimit
-       if (argcount > 3) {
-               *exceptionptr = new_exception(string_java_lang_IllegalArgumentException);
-               log_text("Too many arguments. NewObject does not support that");
-               return 0;
-       }
-#endif
+       STATISTICS(jniinvokation());
 
        /* create object */
 
@@ -1062,17 +1263,13 @@ jobject NewObject(JNIEnv *env, jclass clazz, jmethodID methodID, ...)
        if (!o)
                return NULL;
 
-       va_start(vaargs, methodID);
-       for (i = 0; i < argcount; i++) {
-               args[i] = va_arg(vaargs, void*);
-       }
-       va_end(vaargs);
-
        /* call constructor */
 
-       asm_calljavafunction(methodID, o, args[0], args[1], args[2]);
+       va_start(ap, methodID);
+       cacao_jni_CallVoidMethod(o, methodID, ap);
+       va_end(ap);
 
-       return o;
+       return NewLocalRef(env, o);
 }
 
 
@@ -1085,10 +1282,11 @@ jobject NewObject(JNIEnv *env, jclass clazz, jmethodID methodID, ...)
 
 jobject NewObjectV(JNIEnv* env, jclass clazz, jmethodID methodID, va_list args)
 {
-       log_text("JNI-Call: NewObjectV");
-       STATS(jniinvokation();)
+       STATISTICS(jniinvokation());
 
-       return NULL;
+       log_text("JNI-Call: NewObjectV: IMPLEMENT ME!");
+
+       return NewLocalRef(env, NULL);
 }
 
 
@@ -1102,10 +1300,11 @@ jobject NewObjectV(JNIEnv* env, jclass clazz, jmethodID methodID, va_list args)
 
 jobject NewObjectA(JNIEnv* env, jclass clazz, jmethodID methodID, jvalue *args)
 {
-       log_text("JNI-Call: NewObjectA");
-       STATS(jniinvokation();)
+       STATISTICS(jniinvokation());
 
-       return NULL;
+       log_text("JNI-Call: NewObjectA: IMPLEMENT ME!");
+
+       return NewLocalRef(env, NULL);
 }
 
 
@@ -1118,14 +1317,15 @@ jobject NewObjectA(JNIEnv* env, jclass clazz, jmethodID methodID, jvalue *args)
 jclass GetObjectClass(JNIEnv *env, jobject obj)
 {
        classinfo *c;
-       STATS(jniinvokation();)
+
+       STATISTICS(jniinvokation());
        
        if (!obj || !obj->vftbl)
                return NULL;
 
        c = obj->vftbl->class;
-       use_class_as_object(c);
-       return c;
+
+       return (jclass) NewLocalRef(env, (jobject) c);
 }
 
 
@@ -1137,7 +1337,7 @@ jclass GetObjectClass(JNIEnv *env, jobject obj)
 
 jboolean IsInstanceOf(JNIEnv *env, jobject obj, jclass clazz)
 {
-       STATS(jniinvokation();)
+       STATISTICS(jniinvokation());
 
        return Java_java_lang_VMClass_isInstance(env,
                                                                                         NULL,
@@ -1153,7 +1353,9 @@ jfieldID FromReflectedField(JNIEnv* env, jobject field)
        java_lang_reflect_Field *f;
        classinfo *c;
        jfieldID fid;   /* the JNI-fieldid of the wrapping object */
-       STATS(jniinvokation();)
+
+       STATISTICS(jniinvokation());
+
        /*log_text("JNI-Call: FromReflectedField");*/
 
        f=(java_lang_reflect_Field *)field;
@@ -1170,40 +1372,83 @@ jfieldID FromReflectedField(JNIEnv* env, jobject field)
 }
 
 
-/**********************************************************************************
+/* ToReflectedMethod ***********************************************************
 
-       converts a method ID to a java.lang.reflect.Method or 
-       java.lang.reflect.Constructor object
+   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.
 
-**********************************************************************************/
+*******************************************************************************/
 
 jobject ToReflectedMethod(JNIEnv* env, jclass cls, jmethodID methodID, jboolean isStatic)
 {
-       log_text("JNI-Call: ToReflectedMethod");
-       STATS(jniinvokation();)
+       STATISTICS(jniinvokation());
+
+       log_text("JNI-Call: ToReflectedMethod: IMPLEMENT ME!");
+
+       return NULL;
+}
+
+
+/* ToReflectedField ************************************************************
+
+   Converts a field ID derived from cls to an instance of the
+   java.lang.reflect.Field class.
+
+*******************************************************************************/
+
+jobject ToReflectedField(JNIEnv* env, jclass cls, jfieldID fieldID,
+                                                jboolean isStatic)
+{
+       STATISTICS(jniinvokation());
+
+       log_text("JNI-Call: ToReflectedField: IMPLEMENT ME!");
 
        return NULL;
 }
 
 
+/* Calling Instance Methods ***************************************************/
+
 /* GetMethodID *****************************************************************
 
-   returns the method ID for an instance method
+   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.
 
 *******************************************************************************/
 
-jmethodID GetMethodID(JNIEnv* env, jclass clazz, const char *name, const char *sig)
+jmethodID GetMethodID(JNIEnv* env, jclass clazz, const char *name,
+                                         const char *sig)
 {
-       jmethodID m;
-       STATS(jniinvokation();)
+       classinfo  *c;
+       utf        *uname;
+       utf        *udesc;
+       methodinfo *m;
+
+       STATISTICS(jniinvokation());
+
+       c = (classinfo *) clazz;
+
+       if (!c)
+               return NULL;
+
+       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 */
+
+       uname = utf_new_char((char *) name);
+       udesc = utf_new_char((char *) sig);
 
-       m = class_resolvemethod(clazz, 
-                                                       utf_new_char((char *) name), 
-                                                       utf_new_char((char *) sig));
+       m = class_resolvemethod(clazz, uname, udesc);
 
        if (!m || (m->flags & ACC_STATIC)) {
-               *exceptionptr =
-                       new_exception_message(string_java_lang_NoSuchMethodError, name);
+               *exceptionptr = exceptions_new_nosuchmethoderror(c, uname, udesc);
 
                return NULL;
        }
@@ -1216,33 +1461,38 @@ jmethodID GetMethodID(JNIEnv* env, jclass clazz, const char *name, const char *s
 
 jobject CallObjectMethod(JNIEnv *env, jobject obj, jmethodID methodID, ...)
 {
-       jobject ret;
-       va_list vaargs;
-       STATS(jniinvokation();)
+       java_objectheader* ret;
+       va_list            vaargs;
 
-/*     log_text("JNI-Call: CallObjectMethod");*/
+       STATISTICS(jniinvokation());
 
        va_start(vaargs, methodID);
        ret = callObjectMethod(obj, methodID, vaargs);
        va_end(vaargs);
 
-       return ret;
+       return NewLocalRef(env, ret);
 }
 
 
 jobject CallObjectMethodV(JNIEnv *env, jobject obj, jmethodID methodID, va_list args)
 {
-       STATS(jniinvokation();)
-       return callObjectMethod(obj,methodID,args);
+       java_objectheader* ret;
+
+       STATISTICS(jniinvokation());
+
+       ret = callObjectMethod(obj, methodID, args);
+
+       return NewLocalRef(env, ret);
 }
 
 
 jobject CallObjectMethodA(JNIEnv *env, jobject obj, jmethodID methodID, jvalue * args)
 {
-       log_text("JNI-Call: CallObjectMethodA");
-       STATS(jniinvokation();)
+       STATISTICS(jniinvokation());
 
-       return NULL;
+       log_text("JNI-Call: CallObjectMethodA: IMPLEMENT ME!");
+
+       return NewLocalRef(env, NULL);
 }
 
 
@@ -1252,7 +1502,8 @@ jboolean CallBooleanMethod (JNIEnv *env, jobject obj, jmethodID methodID, ...)
 {
        jboolean ret;
        va_list vaargs;
-       STATS(jniinvokation();)
+
+       STATISTICS(jniinvokation());
 
 /*     log_text("JNI-Call: CallBooleanMethod");*/
 
@@ -1265,7 +1516,7 @@ jboolean CallBooleanMethod (JNIEnv *env, jobject obj, jmethodID methodID, ...)
 
 jboolean CallBooleanMethodV (JNIEnv *env, jobject obj, jmethodID methodID, va_list args)
 {
-       STATS(jniinvokation();)
+       STATISTICS(jniinvokation());
 
        return (jboolean)callIntegerMethod(obj,get_virtual(obj,methodID),PRIMITIVETYPE_BOOLEAN,args);
 
@@ -1273,7 +1524,8 @@ jboolean CallBooleanMethodV (JNIEnv *env, jobject obj, jmethodID methodID, va_li
 
 jboolean CallBooleanMethodA (JNIEnv *env, jobject obj, jmethodID methodID, jvalue * args)
 {
-       STATS(jniinvokation();)
+       STATISTICS(jniinvokation());
+
        log_text("JNI-Call: CallBooleanMethodA");
 
        return 0;
@@ -1283,7 +1535,8 @@ jbyte CallByteMethod (JNIEnv *env, jobject obj, jmethodID methodID, ...)
 {
        jbyte ret;
        va_list vaargs;
-       STATS(jniinvokation();)
+
+       STATISTICS(jniinvokation());
 
 /*     log_text("JNI-Call: CallVyteMethod");*/
 
@@ -1297,7 +1550,8 @@ jbyte CallByteMethod (JNIEnv *env, jobject obj, jmethodID methodID, ...)
 jbyte CallByteMethodV (JNIEnv *env, jobject obj, jmethodID methodID, va_list args)
 {
 /*     log_text("JNI-Call: CallByteMethodV");*/
-       STATS(jniinvokation();)
+
+       STATISTICS(jniinvokation());
 
        return callIntegerMethod(obj,methodID,PRIMITIVETYPE_BYTE,args);
 }
@@ -1305,8 +1559,9 @@ jbyte CallByteMethodV (JNIEnv *env, jobject obj, jmethodID methodID, va_list arg
 
 jbyte CallByteMethodA(JNIEnv *env, jobject obj, jmethodID methodID, jvalue *args)
 {
-       log_text("JNI-Call: CallByteMethodA");
-       STATS(jniinvokation();)
+       STATISTICS(jniinvokation());
+
+       log_text("JNI-Call: CallByteMethodA: IMPLEMENT ME!");
 
        return 0;
 }
@@ -1316,7 +1571,8 @@ jchar CallCharMethod(JNIEnv *env, jobject obj, jmethodID methodID, ...)
 {
        jchar ret;
        va_list vaargs;
-       STATS(jniinvokation();)
+
+       STATISTICS(jniinvokation());
 
 /*     log_text("JNI-Call: CallCharMethod");*/
 
@@ -1330,18 +1586,19 @@ jchar CallCharMethod(JNIEnv *env, jobject obj, jmethodID methodID, ...)
 
 jchar CallCharMethodV(JNIEnv *env, jobject obj, jmethodID methodID, va_list args)
 {
-       STATS(jniinvokation();)
+       STATISTICS(jniinvokation());
 
 /*     log_text("JNI-Call: CallCharMethodV");*/
+
        return callIntegerMethod(obj,get_virtual(obj,methodID),PRIMITIVETYPE_CHAR,args);
 }
 
 
 jchar CallCharMethodA(JNIEnv *env, jobject obj, jmethodID methodID, jvalue *args)
 {
-       STATS(jniinvokation();)
+       STATISTICS(jniinvokation());
 
-       log_text("JNI-Call: CallCharMethodA");
+       log_text("JNI-Call: CallCharMethodA: IMPLEMENT ME!");
 
        return 0;
 }
@@ -1351,7 +1608,8 @@ jshort CallShortMethod(JNIEnv *env, jobject obj, jmethodID methodID, ...)
 {
        jshort ret;
        va_list vaargs;
-       STATS(jniinvokation();)
+
+       STATISTICS(jniinvokation());
 
 /*     log_text("JNI-Call: CallShortMethod");*/
 
@@ -1365,15 +1623,17 @@ jshort CallShortMethod(JNIEnv *env, jobject obj, jmethodID methodID, ...)
 
 jshort CallShortMethodV(JNIEnv *env, jobject obj, jmethodID methodID, va_list args)
 {
-       STATS(jniinvokation();)
+       STATISTICS(jniinvokation());
+
        return callIntegerMethod(obj, get_virtual(obj, methodID),PRIMITIVETYPE_SHORT, args);
 }
 
 
 jshort CallShortMethodA(JNIEnv *env, jobject obj, jmethodID methodID, jvalue *args)
 {
-       STATS(jniinvokation();)
-       log_text("JNI-Call: CallShortMethodA");
+       STATISTICS(jniinvokation());
+
+       log_text("JNI-Call: CallShortMethodA: IMPLEMENT ME!");
 
        return 0;
 }
@@ -1384,7 +1644,8 @@ jint CallIntMethod(JNIEnv *env, jobject obj, jmethodID methodID, ...)
 {
        jint ret;
        va_list vaargs;
-       STATS(jniinvokation();)
+
+       STATISTICS(jniinvokation());
 
        va_start(vaargs,methodID);
        ret = callIntegerMethod(obj, get_virtual(obj, methodID),PRIMITIVETYPE_INT, vaargs);
@@ -1396,15 +1657,17 @@ jint CallIntMethod(JNIEnv *env, jobject obj, jmethodID methodID, ...)
 
 jint CallIntMethodV(JNIEnv *env, jobject obj, jmethodID methodID, va_list args)
 {
-       STATS(jniinvokation();)
+       STATISTICS(jniinvokation());
+
        return callIntegerMethod(obj, get_virtual(obj, methodID),PRIMITIVETYPE_INT, args);
 }
 
 
 jint CallIntMethodA(JNIEnv *env, jobject obj, jmethodID methodID, jvalue *args)
 {
-       STATS(jniinvokation();)
-       log_text("JNI-Call: CallIntMethodA");
+       STATISTICS(jniinvokation());
+
+       log_text("JNI-Call: CallIntMethodA: IMPLEMENT ME!");
 
        return 0;
 }
@@ -1415,8 +1678,9 @@ jlong CallLongMethod(JNIEnv *env, jobject obj, jmethodID methodID, ...)
 {
        jlong ret;
        va_list vaargs;
-       STATS(jniinvokation();)
-       
+
+       STATISTICS(jniinvokation());
+
        va_start(vaargs,methodID);
        ret = callLongMethod(obj,get_virtual(obj, methodID),vaargs);
        va_end(vaargs);
@@ -1427,15 +1691,17 @@ jlong CallLongMethod(JNIEnv *env, jobject obj, jmethodID methodID, ...)
 
 jlong CallLongMethodV(JNIEnv *env, jobject obj, jmethodID methodID, va_list args)
 {
-       STATS(jniinvokation();)
+       STATISTICS(jniinvokation());
+
        return  callLongMethod(obj,get_virtual(obj, methodID),args);
 }
 
 
 jlong CallLongMethodA(JNIEnv *env, jobject obj, jmethodID methodID, jvalue *args)
 {
-       STATS(jniinvokation();)
-       log_text("JNI-Call: CallLongMethodA");
+       STATISTICS(jniinvokation());
+
+       log_text("JNI-Call: CallLongMethodA: IMPLEMENT ME!");
 
        return 0;
 }
@@ -1447,7 +1713,8 @@ jfloat CallFloatMethod(JNIEnv *env, jobject obj, jmethodID methodID, ...)
        jfloat ret;
        va_list vaargs;
 
-       STATS(jniinvokation();)
+       STATISTICS(jniinvokation());
+
 /*     log_text("JNI-Call: CallFloatMethod");*/
 
        va_start(vaargs,methodID);
@@ -1460,16 +1727,19 @@ jfloat CallFloatMethod(JNIEnv *env, jobject obj, jmethodID methodID, ...)
 
 jfloat CallFloatMethodV(JNIEnv *env, jobject obj, jmethodID methodID, va_list args)
 {
-       STATS(jniinvokation();)
-       log_text("JNI-Call: CallFloatMethodV");
+       STATISTICS(jniinvokation());
+
+/*     log_text("JNI-Call: CallFloatMethodV"); */
+
        return callFloatMethod(obj, get_virtual(obj, methodID), args, PRIMITIVETYPE_FLOAT);
 }
 
 
 jfloat CallFloatMethodA(JNIEnv *env, jobject obj, jmethodID methodID, jvalue *args)
 {
-       STATS(jniinvokation();)
-       log_text("JNI-Call: CallFloatMethodA");
+       STATISTICS(jniinvokation());
+
+       log_text("JNI-Call: CallFloatMethodA: IMPLEMENT ME!");
 
        return 0;
 }
@@ -1480,7 +1750,8 @@ jdouble CallDoubleMethod(JNIEnv *env, jobject obj, jmethodID methodID, ...)
 {
        jdouble ret;
        va_list vaargs;
-       STATS(jniinvokation();)
+
+       STATISTICS(jniinvokation());
 
 /*     log_text("JNI-Call: CallDoubleMethod");*/
 
@@ -1494,16 +1765,20 @@ jdouble CallDoubleMethod(JNIEnv *env, jobject obj, jmethodID methodID, ...)
 
 jdouble CallDoubleMethodV(JNIEnv *env, jobject obj, jmethodID methodID, va_list args)
 {
-       STATS(jniinvokation();)
-       log_text("JNI-Call: CallDoubleMethodV");
+       STATISTICS(jniinvokation());
+
+/*     log_text("JNI-Call: CallDoubleMethodV"); */
+
        return callFloatMethod(obj, get_virtual(obj, methodID), args, PRIMITIVETYPE_DOUBLE);
 }
 
 
 jdouble CallDoubleMethodA(JNIEnv *env, jobject obj, jmethodID methodID, jvalue *args)
 {
-       STATS(jniinvokation();)
-       log_text("JNI-Call: CallDoubleMethodA");
+       STATISTICS(jniinvokation());
+
+       log_text("JNI-Call: CallDoubleMethodA: IMPLEMENT ME!");
+
        return 0;
 }
 
@@ -1512,7 +1787,8 @@ jdouble CallDoubleMethodA(JNIEnv *env, jobject obj, jmethodID methodID, jvalue *
 void CallVoidMethod(JNIEnv *env, jobject obj, jmethodID methodID, ...)
 {
        va_list vaargs;
-       STATS(jniinvokation();)
+
+       STATISTICS(jniinvokation());
 
        va_start(vaargs,methodID);
        (void) callIntegerMethod(obj, get_virtual(obj, methodID),TYPE_VOID, vaargs);
@@ -1520,46 +1796,52 @@ void CallVoidMethod(JNIEnv *env, jobject obj, jmethodID methodID, ...)
 }
 
 
-void CallVoidMethodV (JNIEnv *env, jobject obj, jmethodID methodID, va_list args)
+void CallVoidMethodV(JNIEnv *env, jobject obj, jmethodID methodID, va_list args)
 {
-       log_text("JNI-Call: CallVoidMethodV");
-       STATS(jniinvokation();)
-       (void)callIntegerMethod(obj,get_virtual(obj,methodID),TYPE_VOID,args);
+       STATISTICS(jniinvokation());
+
+/*     log_text("JNI-Call: CallVoidMethodV"); */
+
+       (void) callIntegerMethod(obj, get_virtual(obj, methodID), TYPE_VOID,args);
 }
 
 
-void CallVoidMethodA (JNIEnv *env, jobject obj, jmethodID methodID, jvalue * args)
+void CallVoidMethodA(JNIEnv *env, jobject obj, jmethodID methodID, jvalue *args)
 {
-       STATS(jniinvokation();)
-       log_text("JNI-Call: CallVoidMethodA");
+       STATISTICS(jniinvokation());
+
+       log_text("JNI-Call: CallVoidMethodA: IMPLEMENT ME!");
 }
 
 
 
-jobject CallNonvirtualObjectMethod (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...)
+jobject CallNonvirtualObjectMethod(JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...)
 {
-       STATS(jniinvokation();)
-       log_text("JNI-Call: CallNonvirtualObjectMethod");
+       STATISTICS(jniinvokation());
 
-       return NULL;
+       log_text("JNI-Call: CallNonvirtualObjectMethod: IMPLEMENT ME!");
+
+       return NewLocalRef(env, NULL);
 }
 
 
-jobject CallNonvirtualObjectMethodV (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, va_list args)
+jobject CallNonvirtualObjectMethodV(JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, va_list args)
 {
-       STATS(jniinvokation();)
-       log_text("JNI-Call: CallNonvirtualObjectMethodV");
+       STATISTICS(jniinvokation());
 
-       return NULL;
+       log_text("JNI-Call: CallNonvirtualObjectMethodV: IMPLEMENT ME!");
+
+       return NewLocalRef(env, NULL);
 }
 
 
-jobject CallNonvirtualObjectMethodA (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, jvalue * args)
+jobject CallNonvirtualObjectMethodA(JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, jvalue *args)
 {
-       STATS(jniinvokation();)
-       log_text("JNI-Call: CallNonvirtualObjectMethodA");
+       STATISTICS(jniinvokation());
 
-       return NULL;
+       log_text("JNI-Call: CallNonvirtualObjectMethodA: IMPLEMENT ME!");
+
+       return NewLocalRef(env, NULL);
 }
 
 
@@ -1568,13 +1850,15 @@ jboolean CallNonvirtualBooleanMethod (JNIEnv *env, jobject obj, jclass clazz, jm
 {
        jboolean ret;
        va_list vaargs;
-       STATS(jniinvokation();)
+
+       STATISTICS(jniinvokation());
 
 /*     log_text("JNI-Call: CallNonvirtualBooleanMethod");*/
 
        va_start(vaargs,methodID);
        ret = (jboolean)callIntegerMethod(obj,get_nonvirtual(clazz,methodID),PRIMITIVETYPE_BOOLEAN,vaargs);
        va_end(vaargs);
+
        return ret;
 
 }
@@ -1582,83 +1866,94 @@ jboolean CallNonvirtualBooleanMethod (JNIEnv *env, jobject obj, jclass clazz, jm
 
 jboolean CallNonvirtualBooleanMethodV (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, va_list args)
 {
-       STATS(jniinvokation();)
+       STATISTICS(jniinvokation());
+
 /*     log_text("JNI-Call: CallNonvirtualBooleanMethodV");*/
+
        return (jboolean)callIntegerMethod(obj,get_nonvirtual(clazz,methodID),PRIMITIVETYPE_BOOLEAN,args);
 }
 
 
-jboolean CallNonvirtualBooleanMethodA (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, jvalue * args)
+jboolean CallNonvirtualBooleanMethodA(JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, jvalue *args)
 {
-       STATS(jniinvokation();)
-       log_text("JNI-Call: CallNonvirtualBooleanMethodA");
+       STATISTICS(jniinvokation());
+
+       log_text("JNI-Call: CallNonvirtualBooleanMethodA: IMPLEMENT ME!");
 
        return 0;
 }
 
 
-
 jbyte CallNonvirtualByteMethod (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...)
 {
        jbyte ret;
        va_list vaargs;
 
-       STATS(jniinvokation();)
+       STATISTICS(jniinvokation());
+
 /*     log_text("JNI-Call: CallNonvirutalByteMethod");*/
 
        va_start(vaargs,methodID);
        ret = callIntegerMethod(obj,get_nonvirtual(clazz,methodID),PRIMITIVETYPE_BYTE,vaargs);
        va_end(vaargs);
+
        return ret;
 }
 
 
 jbyte CallNonvirtualByteMethodV (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, va_list args)
 {
-       STATS(jniinvokation();)
+       STATISTICS(jniinvokation());
+
        /*log_text("JNI-Call: CallNonvirtualByteMethodV"); */
-       return callIntegerMethod(obj,get_nonvirtual(clazz,methodID),PRIMITIVETYPE_BYTE,args);
 
+       return callIntegerMethod(obj,get_nonvirtual(clazz,methodID),PRIMITIVETYPE_BYTE,args);
 }
 
 
-jbyte CallNonvirtualByteMethodA (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, jvalue *args)
+jbyte CallNonvirtualByteMethodA(JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, jvalue *args)
 {
-       STATS(jniinvokation();)
-       log_text("JNI-Call: CallNonvirtualByteMethodA");
+       STATISTICS(jniinvokation());
+
+       log_text("JNI-Call: CallNonvirtualByteMethodA: IMPLEMENT ME!");
 
        return 0;
 }
 
 
 
-jchar CallNonvirtualCharMethod (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...)
+jchar CallNonvirtualCharMethod(JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...)
 {
        jchar ret;
        va_list vaargs;
 
-       STATS(jniinvokation();)
+       STATISTICS(jniinvokation());
+
 /*     log_text("JNI-Call: CallNonVirtualCharMethod");*/
 
        va_start(vaargs,methodID);
        ret = callIntegerMethod(obj,get_nonvirtual(clazz,methodID),PRIMITIVETYPE_CHAR,vaargs);
        va_end(vaargs);
+
        return ret;
 }
 
 
 jchar CallNonvirtualCharMethodV (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, va_list args)
 {
-       STATS(jniinvokation();)
+       STATISTICS(jniinvokation());
+
        /*log_text("JNI-Call: CallNonvirtualCharMethodV");*/
+
        return callIntegerMethod(obj,get_nonvirtual(clazz,methodID),PRIMITIVETYPE_CHAR,args);
 }
 
 
 jchar CallNonvirtualCharMethodA (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, jvalue *args)
 {
-       STATS(jniinvokation();)
-       log_text("JNI-Call: CallNonvirtualCharMethodA");
+       STATISTICS(jniinvokation());
+
+       log_text("JNI-Call: CallNonvirtualCharMethodA: IMPLEMENT ME!");
 
        return 0;
 }
@@ -1669,29 +1964,34 @@ jshort CallNonvirtualShortMethod (JNIEnv *env, jobject obj, jclass clazz, jmetho
 {
        jshort ret;
        va_list vaargs;
-       STATS(jniinvokation();)
+
+       STATISTICS(jniinvokation());
 
        /*log_text("JNI-Call: CallNonvirtualShortMethod");*/
 
        va_start(vaargs,methodID);
        ret = callIntegerMethod(obj,get_nonvirtual(clazz,methodID),PRIMITIVETYPE_SHORT,vaargs);
        va_end(vaargs);
+
        return ret;
 }
 
 
 jshort CallNonvirtualShortMethodV (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, va_list args)
 {
-       STATS(jniinvokation();)
+       STATISTICS(jniinvokation());
+
        /*log_text("JNI-Call: CallNonvirtualShortMethodV");*/
+
        return callIntegerMethod(obj,get_nonvirtual(clazz,methodID),PRIMITIVETYPE_SHORT,args);
 }
 
 
 jshort CallNonvirtualShortMethodA (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, jvalue *args)
 {
-       STATS(jniinvokation();)
-       log_text("JNI-Call: CallNonvirtualShortMethodA");
+       STATISTICS(jniinvokation());
+
+       log_text("JNI-Call: CallNonvirtualShortMethodA: IMPLEMENT ME!");
 
        return 0;
 }
@@ -1700,32 +2000,36 @@ jshort CallNonvirtualShortMethodA (JNIEnv *env, jobject obj, jclass clazz, jmeth
 
 jint CallNonvirtualIntMethod (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...)
 {
+       jint ret;
+       va_list vaargs;
 
-        jint ret;
-        va_list vaargs;
-       STATS(jniinvokation();)
+       STATISTICS(jniinvokation());
 
        /*log_text("JNI-Call: CallNonvirtualIntMethod");*/
 
-        va_start(vaargs,methodID);
-        ret = callIntegerMethod(obj,get_nonvirtual(clazz,methodID),PRIMITIVETYPE_INT,vaargs);
-        va_end(vaargs);
-        return ret;
+       va_start(vaargs,methodID);
+       ret = callIntegerMethod(obj,get_nonvirtual(clazz,methodID),PRIMITIVETYPE_INT,vaargs);
+       va_end(vaargs);
+
+       return ret;
 }
 
 
 jint CallNonvirtualIntMethodV (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, va_list args)
 {
-       STATS(jniinvokation();)
+       STATISTICS(jniinvokation());
+
        /*log_text("JNI-Call: CallNonvirtualIntMethodV");*/
-        return callIntegerMethod(obj,get_nonvirtual(clazz,methodID),PRIMITIVETYPE_INT,args);
+
+       return callIntegerMethod(obj,get_nonvirtual(clazz,methodID),PRIMITIVETYPE_INT,args);
 }
 
 
 jint CallNonvirtualIntMethodA (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, jvalue *args)
 {
-       STATS(jniinvokation();)
-       log_text("JNI-Call: CallNonvirtualIntMethodA");
+       STATISTICS(jniinvokation());
+
+       log_text("JNI-Call: CallNonvirtualIntMethodA: IMPLEMENT ME!");
 
        return 0;
 }
@@ -1734,8 +2038,9 @@ jint CallNonvirtualIntMethodA (JNIEnv *env, jobject obj, jclass clazz, jmethodID
 
 jlong CallNonvirtualLongMethod (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...)
 {
-       STATS(jniinvokation();)
-       log_text("JNI-Call: CallNonvirtualLongMethod");
+       STATISTICS(jniinvokation());
+
+       log_text("JNI-Call: CallNonvirtualLongMethod: IMPLEMENT ME!");
 
        return 0;
 }
@@ -1743,8 +2048,9 @@ jlong CallNonvirtualLongMethod (JNIEnv *env, jobject obj, jclass clazz, jmethodI
 
 jlong CallNonvirtualLongMethodV (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, va_list args)
 {
-       STATS(jniinvokation();)
-       log_text("JNI-Call: CallNonvirtualLongMethodV");
+       STATISTICS(jniinvokation());
+
+       log_text("JNI-Call: CallNonvirtualLongMethodV: IMPLEMENT ME!");
 
        return 0;
 }
@@ -1752,8 +2058,9 @@ jlong CallNonvirtualLongMethodV (JNIEnv *env, jobject obj, jclass clazz, jmethod
 
 jlong CallNonvirtualLongMethodA (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, jvalue *args)
 {
-       STATS(jniinvokation();)
-       log_text("JNI-Call: CallNonvirtualLongMethodA");
+       STATISTICS(jniinvokation());
+
+       log_text("JNI-Call: CallNonvirtualLongMethodA: IMPLEMENT ME!");
 
        return 0;
 }
@@ -1764,31 +2071,34 @@ jfloat CallNonvirtualFloatMethod (JNIEnv *env, jobject obj, jclass clazz, jmetho
 {
        jfloat ret;
        va_list vaargs;
-       STATS(jniinvokation();)
 
-       /*log_text("JNI-Call: CallNonvirtualFloatMethod");*/
+       STATISTICS(jniinvokation());
 
+       /*log_text("JNI-Call: CallNonvirtualFloatMethod");*/
 
        va_start(vaargs,methodID);
        ret = callFloatMethod(obj,get_nonvirtual(clazz,methodID),vaargs,PRIMITIVETYPE_FLOAT);
        va_end(vaargs);
-       return ret;
 
+       return ret;
 }
 
 
 jfloat CallNonvirtualFloatMethodV (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, va_list args)
 {
-       STATS(jniinvokation();)
-       log_text("JNI-Call: CallNonvirtualFloatMethodV");
+       STATISTICS(jniinvokation());
+
+/*     log_text("JNI-Call: CallNonvirtualFloatMethodV"); */
+
        return callFloatMethod(obj,get_nonvirtual(clazz,methodID),args,PRIMITIVETYPE_FLOAT);
 }
 
 
 jfloat CallNonvirtualFloatMethodA (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, jvalue *args)
 {
-       STATS(jniinvokation();)
-       log_text("JNI-Call: CallNonvirtualFloatMethodA");
+       STATISTICS(jniinvokation());
+
+       log_text("JNI-Call: CallNonvirtualFloatMethodA: IMPLEMENT ME!");
 
        return 0;
 }
@@ -1799,29 +2109,34 @@ jdouble CallNonvirtualDoubleMethod (JNIEnv *env, jobject obj, jclass clazz, jmet
 {
        jdouble ret;
        va_list vaargs;
-       STATS(jniinvokation();)
-       log_text("JNI-Call: CallNonvirtualDoubleMethod");
+
+       STATISTICS(jniinvokation());
+
+/*     log_text("JNI-Call: CallNonvirtualDoubleMethod"); */
 
        va_start(vaargs,methodID);
        ret = callFloatMethod(obj,get_nonvirtual(clazz,methodID),vaargs,PRIMITIVETYPE_DOUBLE);
        va_end(vaargs);
-       return ret;
 
+       return ret;
 }
 
 
 jdouble CallNonvirtualDoubleMethodV (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, va_list args)
 {
-       STATS(jniinvokation();)
+       STATISTICS(jniinvokation());
+
 /*     log_text("JNI-Call: CallNonvirtualDoubleMethodV");*/
+
        return callFloatMethod(obj,get_nonvirtual(clazz,methodID),args,PRIMITIVETYPE_DOUBLE);
 }
 
 
 jdouble CallNonvirtualDoubleMethodA (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, jvalue *args)
 {
-       STATS(jniinvokation();)
-       log_text("JNI-Call: CallNonvirtualDoubleMethodA");
+       STATISTICS(jniinvokation());
+
+       log_text("JNI-Call: CallNonvirtualDoubleMethodA: IMPLEMENT ME!");
 
        return 0;
 }
@@ -1830,246 +2145,304 @@ jdouble CallNonvirtualDoubleMethodA (JNIEnv *env, jobject obj, jclass clazz, jme
 
 void CallNonvirtualVoidMethod (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, ...)
 {
-        va_list vaargs;
-       STATS(jniinvokation();)
+       va_list vaargs;
 
-/*      log_text("JNI-Call: CallNonvirtualVoidMethod");*/
+       STATISTICS(jniinvokation());
 
-        va_start(vaargs,methodID);
-        (void)callIntegerMethod(obj,get_nonvirtual(clazz,methodID),TYPE_VOID,vaargs);
-        va_end(vaargs);
+/*      log_text("JNI-Call: CallNonvirtualVoidMethod");*/
 
+       va_start(vaargs,methodID);
+       (void)callIntegerMethod(obj,get_nonvirtual(clazz,methodID),TYPE_VOID,vaargs);
+       va_end(vaargs);
 }
 
 
 void CallNonvirtualVoidMethodV (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, va_list args)
 {
-/*     log_text("JNI-Call: CallNonvirtualVoidMethodV");*/
-       STATS(jniinvokation();)
+       STATISTICS(jniinvokation());
 
-        (void)callIntegerMethod(obj,get_nonvirtual(clazz,methodID),TYPE_VOID,args);
+/*     log_text("JNI-Call: CallNonvirtualVoidMethodV");*/
 
+       (void)callIntegerMethod(obj,get_nonvirtual(clazz,methodID),TYPE_VOID,args);
 }
 
 
 void CallNonvirtualVoidMethodA (JNIEnv *env, jobject obj, jclass clazz, jmethodID methodID, jvalue * args)
 {
-       STATS(jniinvokation();)
-       log_text("JNI-Call: CallNonvirtualVoidMethodA");
+       STATISTICS(jniinvokation());
+
+       log_text("JNI-Call: CallNonvirtualVoidMethodA: IMPLEMENT ME!");
 }
 
-/************************* JNI-functions for accessing fields ************************/
 
-jfieldID GetFieldID (JNIEnv *env, jclass clazz, const char *name, const char *sig) 
+/* Accessing Fields of Objects ************************************************/
+
+/* GetFieldID ******************************************************************
+
+   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.
+
+*******************************************************************************/
+
+jfieldID GetFieldID(JNIEnv *env, jclass clazz, const char *name,
+                                       const char *sig) 
 {
-       jfieldID f;
-       STATS(jniinvokation();)
-
-/*     log_text("========================= searching for:");
-       log_text(name);
-       log_text(sig);*/
-       f = jclass_findfield(clazz,
-                           utf_new_char ((char*) name), 
-                           utf_new_char ((char*) sig)
-                           ); 
+       fieldinfo *f;
+       utf       *uname;
+       utf       *udesc;
+
+       STATISTICS(jniinvokation());
+
+       uname = utf_new_char((char *) name);
+       udesc = utf_new_char((char *) sig);
+
+       f = class_findfield(clazz, uname, udesc); 
        
-       if (!f) { 
-               /*utf_display(clazz->name);
-               log_text(name);
-               log_text(sig);*/
+       if (!f)
                *exceptionptr = new_exception(string_java_lang_NoSuchFieldError);  
-       }
+
        return f;
 }
 
-/*************************** retrieve fieldid, abort on error ************************/
 
-jfieldID getFieldID_critical(JNIEnv *env, jclass clazz, char *name, char *sig)
-{
-    jfieldID id = GetFieldID(env, clazz, name, sig);
-       STATS(jniinvokation();)
+/* Get<type>Field Routines *****************************************************
 
-    if (!id) {
-       log_text("class:");
-       utf_display(clazz->name);
-       log_text("\nfield:");
-       log_text(name);
-       log_text("sig:");
-       log_text(sig);
+   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().
 
-       log_text("setfield_critical failed");
-          assert(0);
-    }
-    return id;
-}
+*******************************************************************************/
 
-jobject GetObjectField (JNIEnv *env, jobject obj, jfieldID fieldID)
+jobject GetObjectField(JNIEnv *env, jobject obj, jfieldID fieldID)
 {
-       /*
-       jobject dbg,dretval,*dpretval;  
-       long int dli1, dli2, dli3;
+       java_objectheader *o;
 
-       printf("GetObjectField(1): thread: %s obj: %p name: %s desc: %s \n",GetStringUTFChars(env,
-                        ((threadobject *) THREADOBJECT)->o
-                        .thread->name,NULL)
-                        ,obj,((fieldinfo*)fieldID)->name->text,(fieldID->descriptor)->text);
+       STATISTICS(jniinvokation());
 
-       dbg = getField(obj,jobject,fieldID);
-       dli1 = (long int) obj;
-       dli2 = (long int) fieldID->offset;
-       dli3 = dli1+dli2;
-       dpretval = (jobject*) dli3;
-       dretval = *dpretval;
-       jclass tmp;
-       jmethodID mid;
-       jstring jstr;
+       o = GET_FIELD(obj, java_objectheader*, fieldID);
 
-       tmp = FindClass(env, "java/lang/Object");
-       mid = GetMethodID(env,tmp,"toString","()Ljava/lang/String;");
-       jstr = CallObjectMethod(env,dbg,mid);*/
+       return NewLocalRef(env, o);
+}
 
-/*     printf("GetObjectField(2): retval %p (obj: %#lx + offset: %#lx = %#lx (jobject*) %p (jobject) %p\n"
-       ,dbg, dli1, dli2, dli3,dpretval, dretval);*/
 
+jboolean GetBooleanField(JNIEnv *env, jobject obj, jfieldID fieldID)
+{
+       s4 i;
 
-/*     return dbg;*/
-       STATS(jniinvokation();)
+       STATISTICS(jniinvokation());
 
-       return getField(obj,jobject,fieldID);
-}
+       i = GET_FIELD(obj, s4, fieldID);
 
-jboolean GetBooleanField (JNIEnv *env, jobject obj, jfieldID fieldID)
-{
-       STATS(jniinvokation();)
-       return getField(obj,jboolean,fieldID);
+       return (jboolean) i;
 }
 
 
-jbyte GetByteField (JNIEnv *env, jobject obj, jfieldID fieldID)
+jbyte GetByteField(JNIEnv *env, jobject obj, jfieldID fieldID)
 {
-       STATS(jniinvokation();)
-               return getField(obj,jbyte,fieldID);
+       s4 i;
+
+       STATISTICS(jniinvokation());
+
+       i = GET_FIELD(obj, s4, fieldID);
+
+       return (jbyte) i;
 }
 
 
-jchar GetCharField (JNIEnv *env, jobject obj, jfieldID fieldID)
+jchar GetCharField(JNIEnv *env, jobject obj, jfieldID fieldID)
 {
-       STATS(jniinvokation();)
-       return getField(obj,jchar,fieldID);
+       s4 i;
+
+       STATISTICS(jniinvokation());
+
+       i = GET_FIELD(obj, s4, fieldID);
+
+       return (jchar) i;
 }
 
 
-jshort GetShortField (JNIEnv *env, jobject obj, jfieldID fieldID)
+jshort GetShortField(JNIEnv *env, jobject obj, jfieldID fieldID)
 {
-       STATS(jniinvokation();)
-       return getField(obj,jshort,fieldID);
+       s4 i;
+
+       STATISTICS(jniinvokation());
+
+       i = GET_FIELD(obj, s4, fieldID);
+
+       return (jshort) i;
 }
 
 
-jint GetIntField (JNIEnv *env, jobject obj, jfieldID fieldID)
+jint GetIntField(JNIEnv *env, jobject obj, jfieldID fieldID)
 {
-       STATS(jniinvokation();)
-       return getField(obj,jint,fieldID);
+       s4 i;
+
+       STATISTICS(jniinvokation());
+
+       i = GET_FIELD(obj, s4, fieldID);
+
+       return i;
 }
 
 
-jlong GetLongField (JNIEnv *env, jobject obj, jfieldID fieldID)
+jlong GetLongField(JNIEnv *env, jobject obj, jfieldID fieldID)
 {
-       STATS(jniinvokation();)
-       return getField(obj,jlong,fieldID);
+       s8 l;
+
+       STATISTICS(jniinvokation());
+
+       l = GET_FIELD(obj, s8, fieldID);
+
+       return l;
 }
 
 
-jfloat GetFloatField (JNIEnv *env, jobject obj, jfieldID fieldID)
+jfloat GetFloatField(JNIEnv *env, jobject obj, jfieldID fieldID)
 {
-       STATS(jniinvokation();)
-       return getField(obj,jfloat,fieldID);
+       float f;
+
+       STATISTICS(jniinvokation());
+
+       f = GET_FIELD(obj, float, fieldID);
+
+       return f;
 }
 
 
-jdouble GetDoubleField (JNIEnv *env, jobject obj, jfieldID fieldID)
+jdouble GetDoubleField(JNIEnv *env, jobject obj, jfieldID fieldID)
 {
-       STATS(jniinvokation();)
-       return getField(obj,jdouble,fieldID);
+       double d;
+
+       STATISTICS(jniinvokation());
+
+       d = GET_FIELD(obj, double, fieldID);
+
+       return d;
 }
 
-void SetObjectField (JNIEnv *env, jobject obj, jfieldID fieldID, jobject val)
+
+/* Set<type>Field Routines *****************************************************
+
+   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().
+
+*******************************************************************************/
+
+void SetObjectField(JNIEnv *env, jobject obj, jfieldID fieldID, jobject value)
 {
-       STATS(jniinvokation();)
-        setField(obj,jobject,fieldID,val);
+       STATISTICS(jniinvokation());
+
+       SET_FIELD(obj, java_objectheader*, fieldID, value);
 }
 
 
-void SetBooleanField (JNIEnv *env, jobject obj, jfieldID fieldID, jboolean val)
+void SetBooleanField(JNIEnv *env, jobject obj, jfieldID fieldID, jboolean value)
 {
-       STATS(jniinvokation();)
-        setField(obj,jboolean,fieldID,val);
+       STATISTICS(jniinvokation());
+
+       SET_FIELD(obj, s4, fieldID, value);
 }
 
 
-void SetByteField (JNIEnv *env, jobject obj, jfieldID fieldID, jbyte val)
+void SetByteField(JNIEnv *env, jobject obj, jfieldID fieldID, jbyte value)
 {
-       STATS(jniinvokation();)
-        setField(obj,jbyte,fieldID,val);
+       STATISTICS(jniinvokation());
+
+       SET_FIELD(obj, s4, fieldID, value);
 }
 
 
-void SetCharField (JNIEnv *env, jobject obj, jfieldID fieldID, jchar val)
+void SetCharField(JNIEnv *env, jobject obj, jfieldID fieldID, jchar value)
 {
-       STATS(jniinvokation();)
-        setField(obj,jchar,fieldID,val);
+       STATISTICS(jniinvokation());
+
+       SET_FIELD(obj, s4, fieldID, value);
 }
 
 
-void SetShortField (JNIEnv *env, jobject obj, jfieldID fieldID, jshort val)
+void SetShortField(JNIEnv *env, jobject obj, jfieldID fieldID, jshort value)
 {
-       STATS(jniinvokation();)
-        setField(obj,jshort,fieldID,val);
+       STATISTICS(jniinvokation());
+
+       SET_FIELD(obj, s4, fieldID, value);
 }
 
 
-void SetIntField (JNIEnv *env, jobject obj, jfieldID fieldID, jint val)
+void SetIntField(JNIEnv *env, jobject obj, jfieldID fieldID, jint value)
 {
-       STATS(jniinvokation();)
-        setField(obj,jint,fieldID,val);
+       STATISTICS(jniinvokation());
+
+       SET_FIELD(obj, s4, fieldID, value);
 }
 
 
-void SetLongField (JNIEnv *env, jobject obj, jfieldID fieldID, jlong val)
+void SetLongField(JNIEnv *env, jobject obj, jfieldID fieldID, jlong value)
 {
-       STATS(jniinvokation();)
-        setField(obj,jlong,fieldID,val);
+       STATISTICS(jniinvokation());
+
+       SET_FIELD(obj, s8, fieldID, value);
 }
 
 
-void SetFloatField (JNIEnv *env, jobject obj, jfieldID fieldID, jfloat val)
+void SetFloatField(JNIEnv *env, jobject obj, jfieldID fieldID, jfloat value)
 {
-       STATS(jniinvokation();)
-        setField(obj,jfloat,fieldID,val);
+       STATISTICS(jniinvokation());
+
+       SET_FIELD(obj, float, fieldID, value);
 }
 
 
-void SetDoubleField (JNIEnv *env, jobject obj, jfieldID fieldID, jdouble val)
+void SetDoubleField(JNIEnv *env, jobject obj, jfieldID fieldID, jdouble value)
 {
-       STATS(jniinvokation();)
-        setField(obj,jdouble,fieldID,val);
+       STATISTICS(jniinvokation());
+
+       SET_FIELD(obj, double, fieldID, value);
 }
 
 
-/**************** JNI-functions for calling static methods **********************/ 
+/* Calling Static Methods *****************************************************/
+
+/* GetStaticMethodID ***********************************************************
 
-jmethodID GetStaticMethodID(JNIEnv *env, jclass clazz, const char *name, const char *sig)
+   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.
+
+*******************************************************************************/
+
+jmethodID GetStaticMethodID(JNIEnv *env, jclass clazz, const char *name,
+                                                       const char *sig)
 {
-       jmethodID m;
-       STATS(jniinvokation();)
+       classinfo  *c;
+       utf        *uname;
+       utf        *udesc;
+       methodinfo *m;
+
+       STATISTICS(jniinvokation());
+
+       c = (classinfo *) clazz;
+
+       if (!c)
+               return NULL;
+
+       if (!(c->state & CLASS_INITIALIZED))
+               if (!initialize_class(c))
+                       return NULL;
+
+       /* try to get the static method of the class */
 
-       m = class_resolvemethod(clazz,
-                                                       utf_new_char((char *) name),
-                                                       utf_new_char((char *) sig));
+       uname = utf_new_char((char *) name);
+       udesc = utf_new_char((char *) sig);
+
+       m = class_resolvemethod(c, uname, udesc);
 
        if (!m || !(m->flags & ACC_STATIC)) {
-               *exceptionptr =
-                       new_exception_message(string_java_lang_NoSuchMethodError, name);
+               *exceptionptr = exceptions_new_nosuchmethoderror(c, uname, udesc);
 
                return NULL;
        }
@@ -2080,43 +2453,47 @@ jmethodID GetStaticMethodID(JNIEnv *env, jclass clazz, const char *name, const c
 
 jobject CallStaticObjectMethod(JNIEnv *env, jclass clazz, jmethodID methodID, ...)
 {
-       jobject ret;
-       va_list vaargs;
-       STATS(jniinvokation();)
+       java_objectheader *ret;
+       va_list            vaargs;
 
-       /* log_text("JNI-Call: CallStaticObjectMethod");*/
+       STATISTICS(jniinvokation());
 
        va_start(vaargs, methodID);
        ret = callObjectMethod(0, methodID, vaargs);
        va_end(vaargs);
 
-       return ret;
+       return NewLocalRef(env, ret);
 }
 
 
 jobject CallStaticObjectMethodV(JNIEnv *env, jclass clazz, jmethodID methodID, va_list args)
 {
-       STATS(jniinvokation();)
-       /* log_text("JNI-Call: CallStaticObjectMethodV"); */
+       java_objectheader *ret;
+
+       STATISTICS(jniinvokation());
        
-       return callObjectMethod(0,methodID,args);
+       ret = callObjectMethod(0, methodID, args);
+
+       return NewLocalRef(env, ret);
 }
 
 
 jobject CallStaticObjectMethodA(JNIEnv *env, jclass clazz, jmethodID methodID, jvalue *args)
 {
-       STATS(jniinvokation();)
-       log_text("JNI-Call: CallStaticObjectMethodA");
+       STATISTICS(jniinvokation());
 
-       return NULL;
+       log_text("JNI-Call: CallStaticObjectMethodA: IMPLEMENT ME!");
+
+       return NewLocalRef(env, NULL);
 }
 
 
 jboolean CallStaticBooleanMethod(JNIEnv *env, jclass clazz, jmethodID methodID, ...)
 {
+       va_list  vaargs;
        jboolean ret;
-       va_list vaargs;
-       STATS(jniinvokation();)
+
+       STATISTICS(jniinvokation());
 
        va_start(vaargs, methodID);
        ret = (jboolean) callIntegerMethod(0, methodID, PRIMITIVETYPE_BOOLEAN, vaargs);
@@ -2128,15 +2505,17 @@ jboolean CallStaticBooleanMethod(JNIEnv *env, jclass clazz, jmethodID methodID,
 
 jboolean CallStaticBooleanMethodV(JNIEnv *env, jclass clazz, jmethodID methodID, va_list args)
 {
-       STATS(jniinvokation();)
+       STATISTICS(jniinvokation());
+
        return (jboolean) callIntegerMethod(0, methodID, PRIMITIVETYPE_BOOLEAN, args);
 }
 
 
 jboolean CallStaticBooleanMethodA(JNIEnv *env, jclass clazz, jmethodID methodID, jvalue *args)
 {
-       STATS(jniinvokation();)
-       log_text("JNI-Call: CallStaticBooleanMethodA");
+       STATISTICS(jniinvokation());
+
+       log_text("JNI-Call: CallStaticBooleanMethodA: IMPLEMENT ME!");
 
        return 0;
 }
@@ -2144,11 +2523,10 @@ jboolean CallStaticBooleanMethodA(JNIEnv *env, jclass clazz, jmethodID methodID,
 
 jbyte CallStaticByteMethod(JNIEnv *env, jclass clazz, jmethodID methodID, ...)
 {
-       jbyte ret;
        va_list vaargs;
-       STATS(jniinvokation();)
+       jbyte   ret;
 
-       /*      log_text("JNI-Call: CallStaticByteMethod");*/
+       STATISTICS(jniinvokation());
 
        va_start(vaargs, methodID);
        ret = (jbyte) callIntegerMethod(0, methodID, PRIMITIVETYPE_BYTE, vaargs);
@@ -2160,15 +2538,17 @@ jbyte CallStaticByteMethod(JNIEnv *env, jclass clazz, jmethodID methodID, ...)
 
 jbyte CallStaticByteMethodV(JNIEnv *env, jclass clazz, jmethodID methodID, va_list args)
 {
-       STATS(jniinvokation();)
+       STATISTICS(jniinvokation());
+
        return (jbyte) callIntegerMethod(0, methodID, PRIMITIVETYPE_BYTE, args);
 }
 
 
 jbyte CallStaticByteMethodA(JNIEnv *env, jclass clazz, jmethodID methodID, jvalue *args)
 {
-       STATS(jniinvokation();)
-       log_text("JNI-Call: CallStaticByteMethodA");
+       STATISTICS(jniinvokation());
+
+       log_text("JNI-Call: CallStaticByteMethodA: IMPLEMENT ME!");
 
        return 0;
 }
@@ -2176,11 +2556,10 @@ jbyte CallStaticByteMethodA(JNIEnv *env, jclass clazz, jmethodID methodID, jvalu
 
 jchar CallStaticCharMethod(JNIEnv *env, jclass clazz, jmethodID methodID, ...)
 {
-       jchar ret;
        va_list vaargs;
-       STATS(jniinvokation();)
+       jchar   ret;
 
-       /*      log_text("JNI-Call: CallStaticByteMethod");*/
+       STATISTICS(jniinvokation());
 
        va_start(vaargs, methodID);
        ret = (jchar) callIntegerMethod(0, methodID, PRIMITIVETYPE_CHAR, vaargs);
@@ -2192,28 +2571,28 @@ jchar CallStaticCharMethod(JNIEnv *env, jclass clazz, jmethodID methodID, ...)
 
 jchar CallStaticCharMethodV(JNIEnv *env, jclass clazz, jmethodID methodID, va_list args)
 {
-       STATS(jniinvokation();)
+       STATISTICS(jniinvokation());
+
        return (jchar) callIntegerMethod(0, methodID, PRIMITIVETYPE_CHAR, args);
 }
 
 
 jchar CallStaticCharMethodA(JNIEnv *env, jclass clazz, jmethodID methodID, jvalue *args)
 {
-       STATS(jniinvokation();)
-       log_text("JNI-Call: CallStaticCharMethodA");
+       STATISTICS(jniinvokation());
+
+       log_text("JNI-Call: CallStaticCharMethodA: IMPLEMENT ME!");
 
        return 0;
 }
 
 
-
 jshort CallStaticShortMethod(JNIEnv *env, jclass clazz, jmethodID methodID, ...)
 {
-       jshort ret;
        va_list vaargs;
-       STATS(jniinvokation();)
+       jshort  ret;
 
-       /*      log_text("JNI-Call: CallStaticByteMethod");*/
+       STATISTICS(jniinvokation());
 
        va_start(vaargs, methodID);
        ret = (jshort) callIntegerMethod(0, methodID, PRIMITIVETYPE_SHORT, vaargs);
@@ -2225,29 +2604,28 @@ jshort CallStaticShortMethod(JNIEnv *env, jclass clazz, jmethodID methodID, ...)
 
 jshort CallStaticShortMethodV(JNIEnv *env, jclass clazz, jmethodID methodID, va_list args)
 {
-       STATS(jniinvokation();)
-       /*log_text("JNI-Call: CallStaticShortMethodV");*/
+       STATISTICS(jniinvokation());
+
        return (jshort) callIntegerMethod(0, methodID, PRIMITIVETYPE_SHORT, args);
 }
 
 
 jshort CallStaticShortMethodA(JNIEnv *env, jclass clazz, jmethodID methodID, jvalue *args)
 {
-       STATS(jniinvokation();)
-       log_text("JNI-Call: CallStaticShortMethodA");
+       STATISTICS(jniinvokation());
+
+       log_text("JNI-Call: CallStaticShortMethodA: IMPLEMENT ME!");
 
        return 0;
 }
 
 
-
 jint CallStaticIntMethod(JNIEnv *env, jclass clazz, jmethodID methodID, ...)
 {
-       jint ret;
        va_list vaargs;
-       STATS(jniinvokation();)
+       jint    ret;
 
-       /*      log_text("JNI-Call: CallStaticIntMethod");*/
+       STATISTICS(jniinvokation());
 
        va_start(vaargs, methodID);
        ret = callIntegerMethod(0, methodID, PRIMITIVETYPE_INT, vaargs);
@@ -2259,8 +2637,7 @@ jint CallStaticIntMethod(JNIEnv *env, jclass clazz, jmethodID methodID, ...)
 
 jint CallStaticIntMethodV(JNIEnv *env, jclass clazz, jmethodID methodID, va_list args)
 {
-       STATS(jniinvokation();)
-       log_text("JNI-Call: CallStaticIntMethodV");
+       STATISTICS(jniinvokation());
 
        return callIntegerMethod(0, methodID, PRIMITIVETYPE_INT, args);
 }
@@ -2268,21 +2645,20 @@ jint CallStaticIntMethodV(JNIEnv *env, jclass clazz, jmethodID methodID, va_list
 
 jint CallStaticIntMethodA(JNIEnv *env, jclass clazz, jmethodID methodID, jvalue *args)
 {
-       STATS(jniinvokation();)
-       log_text("JNI-Call: CallStaticIntMethodA");
+       STATISTICS(jniinvokation());
+
+       log_text("JNI-Call: CallStaticIntMethodA: IMPLEMENT ME!");
 
        return 0;
 }
 
 
-
 jlong CallStaticLongMethod(JNIEnv *env, jclass clazz, jmethodID methodID, ...)
 {
-       jlong ret;
        va_list vaargs;
-       STATS(jniinvokation();)
+       jlong   ret;
 
-       /*      log_text("JNI-Call: CallStaticLongMethod");*/
+       STATISTICS(jniinvokation());
 
        va_start(vaargs, methodID);
        ret = callLongMethod(0, methodID, vaargs);
@@ -2292,19 +2668,20 @@ jlong CallStaticLongMethod(JNIEnv *env, jclass clazz, jmethodID methodID, ...)
 }
 
 
-jlong CallStaticLongMethodV(JNIEnv *env, jclass clazz, jmethodID methodID, va_list args)
+jlong CallStaticLongMethodV(JNIEnv *env, jclass clazz, jmethodID methodID,
+                                                       va_list args)
 {
-       STATS(jniinvokation();)
-       log_text("JNI-Call: CallStaticLongMethodV");
+       STATISTICS(jniinvokation());
        
-       return callLongMethod(0,methodID,args);
+       return callLongMethod(0, methodID, args);
 }
 
 
 jlong CallStaticLongMethodA(JNIEnv *env, jclass clazz, jmethodID methodID, jvalue *args)
 {
-       STATS(jniinvokation();)
-       log_text("JNI-Call: CallStaticLongMethodA");
+       STATISTICS(jniinvokation());
+
+       log_text("JNI-Call: CallStaticLongMethodA: IMPLEMENT ME!");
 
        return 0;
 }
@@ -2313,11 +2690,10 @@ jlong CallStaticLongMethodA(JNIEnv *env, jclass clazz, jmethodID methodID, jvalu
 
 jfloat CallStaticFloatMethod(JNIEnv *env, jclass clazz, jmethodID methodID, ...)
 {
-       jfloat ret;
        va_list vaargs;
-       STATS(jniinvokation();)
+       jfloat  ret;
 
-       /*      log_text("JNI-Call: CallStaticLongMethod");*/
+       STATISTICS(jniinvokation());
 
        va_start(vaargs, methodID);
        ret = callFloatMethod(0, methodID, vaargs, PRIMITIVETYPE_FLOAT);
@@ -2329,7 +2705,7 @@ jfloat CallStaticFloatMethod(JNIEnv *env, jclass clazz, jmethodID methodID, ...)
 
 jfloat CallStaticFloatMethodV(JNIEnv *env, jclass clazz, jmethodID methodID, va_list args)
 {
-       STATS(jniinvokation();)
+       STATISTICS(jniinvokation());
 
        return callFloatMethod(0, methodID, args, PRIMITIVETYPE_FLOAT);
 
@@ -2338,21 +2714,20 @@ jfloat CallStaticFloatMethodV(JNIEnv *env, jclass clazz, jmethodID methodID, va_
 
 jfloat CallStaticFloatMethodA(JNIEnv *env, jclass clazz, jmethodID methodID, jvalue *args)
 {
-       STATS(jniinvokation();)
-       log_text("JNI-Call: CallStaticFloatMethodA");
+       STATISTICS(jniinvokation());
+
+       log_text("JNI-Call: CallStaticFloatMethodA: IMPLEMENT ME!");
 
        return 0;
 }
 
 
-
 jdouble CallStaticDoubleMethod(JNIEnv *env, jclass clazz, jmethodID methodID, ...)
 {
-       jdouble ret;
        va_list vaargs;
-       STATS(jniinvokation();)
+       jdouble ret;
 
-       /*      log_text("JNI-Call: CallStaticDoubleMethod");*/
+       STATISTICS(jniinvokation());
 
        va_start(vaargs,methodID);
        ret = callFloatMethod(0, methodID, vaargs, PRIMITIVETYPE_DOUBLE);
@@ -2364,8 +2739,7 @@ jdouble CallStaticDoubleMethod(JNIEnv *env, jclass clazz, jmethodID methodID, ..
 
 jdouble CallStaticDoubleMethodV(JNIEnv *env, jclass clazz, jmethodID methodID, va_list args)
 {
-       STATS(jniinvokation();)
-       log_text("JNI-Call: CallStaticDoubleMethodV");
+       STATISTICS(jniinvokation());
 
        return callFloatMethod(0, methodID, args, PRIMITIVETYPE_DOUBLE);
 }
@@ -2373,8 +2747,9 @@ jdouble CallStaticDoubleMethodV(JNIEnv *env, jclass clazz, jmethodID methodID, v
 
 jdouble CallStaticDoubleMethodA(JNIEnv *env, jclass clazz, jmethodID methodID, jvalue *args)
 {
-       STATS(jniinvokation();)
-       log_text("JNI-Call: CallStaticDoubleMethodA");
+       STATISTICS(jniinvokation());
+
+       log_text("JNI-Call: CallStaticDoubleMethodA: IMPLEMENT ME!");
 
        return 0;
 }
@@ -2383,7 +2758,8 @@ jdouble CallStaticDoubleMethodA(JNIEnv *env, jclass clazz, jmethodID methodID, j
 void CallStaticVoidMethod(JNIEnv *env, jclass cls, jmethodID methodID, ...)
 {
        va_list vaargs;
-       STATS(jniinvokation();)
+
+       STATISTICS(jniinvokation());
 
        va_start(vaargs, methodID);
        (void) callIntegerMethod(0, methodID, TYPE_VOID, vaargs);
@@ -2393,16 +2769,17 @@ void CallStaticVoidMethod(JNIEnv *env, jclass cls, jmethodID methodID, ...)
 
 void CallStaticVoidMethodV(JNIEnv *env, jclass cls, jmethodID methodID, va_list args)
 {
-       log_text("JNI-Call: CallStaticVoidMethodV");
-       STATS(jniinvokation();)
-       (void)callIntegerMethod(0, methodID, TYPE_VOID, args);
+       STATISTICS(jniinvokation());
+
+       (void) callIntegerMethod(0, methodID, TYPE_VOID, args);
 }
 
 
 void CallStaticVoidMethodA(JNIEnv *env, jclass cls, jmethodID methodID, jvalue * args)
 {
-       STATS(jniinvokation();)
-       log_text("JNI-Call: CallStaticVoidMethodA");
+       STATISTICS(jniinvokation());
+
+       log_text("JNI-Call: CallStaticVoidMethodA: IMPLEMENT ME!");
 }
 
 
@@ -2420,14 +2797,15 @@ void CallStaticVoidMethodA(JNIEnv *env, jclass cls, jmethodID methodID, jvalue *
 jfieldID GetStaticFieldID(JNIEnv *env, jclass clazz, const char *name, const char *sig)
 {
        jfieldID f;
-       STATS(jniinvokation();)
 
-       f = jclass_findfield(clazz,
-                                                utf_new_char((char *) name),
-                                                utf_new_char((char *) sig)); 
+       STATISTICS(jniinvokation());
+
+       f = class_findfield(clazz,
+                                               utf_new_char((char *) name),
+                                               utf_new_char((char *) sig));
        
        if (!f)
-               *exceptionptr = new_exception(string_java_lang_NoSuchFieldError);  
+               *exceptionptr = new_exception(string_java_lang_NoSuchFieldError);
 
        return f;
 }
@@ -2442,22 +2820,23 @@ jfieldID GetStaticFieldID(JNIEnv *env, jclass clazz, const char *name, const cha
 
 jobject GetStaticObjectField(JNIEnv *env, jclass clazz, jfieldID fieldID)
 {
-       STATS(jniinvokation();)
-       JWCLINITDEBUG(printf("GetStaticObjectField: calling initialize_class %s\n",clazz->name->text);)
-       if (!initialize_class(clazz))
-               return NULL;
+       STATISTICS(jniinvokation());
+
+       if (!(clazz->state & CLASS_INITIALIZED))
+               if (!initialize_class(clazz))
+                       return NULL;
 
-       return fieldID->value.a;       
+       return NewLocalRef(env, fieldID->value.a);
 }
 
 
 jboolean GetStaticBooleanField(JNIEnv *env, jclass clazz, jfieldID fieldID)
 {
-       STATS(jniinvokation();)
-       JWCLINITDEBUG(printf("GetStaticBooleanField: calling initialize_class %s\n",clazz->name->text);)
+       STATISTICS(jniinvokation());
 
-       if (!initialize_class(clazz))
-               return false;
+       if (!(clazz->state & CLASS_INITIALIZED))
+               if (!initialize_class(clazz))
+                       return false;
 
        return fieldID->value.i;       
 }
@@ -2465,11 +2844,11 @@ jboolean GetStaticBooleanField(JNIEnv *env, jclass clazz, jfieldID fieldID)
 
 jbyte GetStaticByteField(JNIEnv *env, jclass clazz, jfieldID fieldID)
 {
-       STATS(jniinvokation();)
-       JWCLINITDEBUG(printf("GetStaticByteField: calling initialize_class %s\n",clazz->name->text);)
+       STATISTICS(jniinvokation());
 
-       if (!initialize_class(clazz))
-               return 0;
+       if (!(clazz->state & CLASS_INITIALIZED))
+               if (!initialize_class(clazz))
+                       return 0;
 
        return fieldID->value.i;       
 }
@@ -2477,11 +2856,11 @@ jbyte GetStaticByteField(JNIEnv *env, jclass clazz, jfieldID fieldID)
 
 jchar GetStaticCharField(JNIEnv *env, jclass clazz, jfieldID fieldID)
 {
-       STATS(jniinvokation();)
-       JWCLINITDEBUG(printf("GetStaticCharField: calling initialize_class %s\n",clazz->name->text);)
+       STATISTICS(jniinvokation());
 
-       if (!initialize_class(clazz))
-               return 0;
+       if (!(clazz->state & CLASS_INITIALIZED))
+               if (!initialize_class(clazz))
+                       return 0;
 
        return fieldID->value.i;       
 }
@@ -2489,10 +2868,11 @@ jchar GetStaticCharField(JNIEnv *env, jclass clazz, jfieldID fieldID)
 
 jshort GetStaticShortField(JNIEnv *env, jclass clazz, jfieldID fieldID)
 {
-       STATS(jniinvokation();)
-       JWCLINITDEBUG(printf("GetStaticShorttField: calling initialize_class %s\n",clazz->name->text);)
-       if (!initialize_class(clazz))
-               return 0;
+       STATISTICS(jniinvokation());
+
+       if (!(clazz->state & CLASS_INITIALIZED))
+               if (!initialize_class(clazz))
+                       return 0;
 
        return fieldID->value.i;       
 }
@@ -2500,10 +2880,11 @@ jshort GetStaticShortField(JNIEnv *env, jclass clazz, jfieldID fieldID)
 
 jint GetStaticIntField(JNIEnv *env, jclass clazz, jfieldID fieldID)
 {
-       STATS(jniinvokation();)
-       JWCLINITDEBUG(printf("GetStaticIntField: calling initialize_class %s\n",clazz->name->text);)
-       if (!initialize_class(clazz))
-               return 0;
+       STATISTICS(jniinvokation());
+
+       if (!(clazz->state & CLASS_INITIALIZED))
+               if (!initialize_class(clazz))
+                       return 0;
 
        return fieldID->value.i;       
 }
@@ -2511,10 +2892,11 @@ jint GetStaticIntField(JNIEnv *env, jclass clazz, jfieldID fieldID)
 
 jlong GetStaticLongField(JNIEnv *env, jclass clazz, jfieldID fieldID)
 {
-       STATS(jniinvokation();)
-       JWCLINITDEBUG(printf("GetStaticLongField: calling initialize_class %s\n",clazz->name->text);)
-       if (!initialize_class(clazz))
-               return 0;
+       STATISTICS(jniinvokation());
+
+       if (!(clazz->state & CLASS_INITIALIZED))
+               if (!initialize_class(clazz))
+                       return 0;
 
        return fieldID->value.l;
 }
@@ -2522,10 +2904,11 @@ jlong GetStaticLongField(JNIEnv *env, jclass clazz, jfieldID fieldID)
 
 jfloat GetStaticFloatField(JNIEnv *env, jclass clazz, jfieldID fieldID)
 {
-       STATS(jniinvokation();)
-       JWCLINITDEBUG(printf("GetStaticFloatField: calling initialize_class %s\n",clazz->name->text);)
-       if (!initialize_class(clazz))
-               return 0.0;
+       STATISTICS(jniinvokation());
+
+       if (!(clazz->state & CLASS_INITIALIZED))
+               if (!initialize_class(clazz))
+                       return 0.0;
 
        return fieldID->value.f;
 }
@@ -2533,10 +2916,11 @@ jfloat GetStaticFloatField(JNIEnv *env, jclass clazz, jfieldID fieldID)
 
 jdouble GetStaticDoubleField(JNIEnv *env, jclass clazz, jfieldID fieldID)
 {
-       STATS(jniinvokation();)
-       JWCLINITDEBUG(printf("GetStaticDoubleField: calling initialize_class %s\n",clazz->name->text);)
-       if (!initialize_class(clazz))
-               return 0.0;
+       STATISTICS(jniinvokation());
+
+       if (!(clazz->state & CLASS_INITIALIZED))
+               if (!initialize_class(clazz))
+                       return 0.0;
 
        return fieldID->value.d;
 }
@@ -2551,10 +2935,11 @@ jdouble GetStaticDoubleField(JNIEnv *env, jclass clazz, jfieldID fieldID)
 
 void SetStaticObjectField(JNIEnv *env, jclass clazz, jfieldID fieldID, jobject value)
 {
-       STATS(jniinvokation();)
-       JWCLINITDEBUG(printf("SetStaticObjectField: calling initialize_class %s\n",clazz->name->text);)
-       if (!initialize_class(clazz))
-               return;
+       STATISTICS(jniinvokation());
+
+       if (!(clazz->state & CLASS_INITIALIZED))
+               if (!initialize_class(clazz))
+                       return;
 
        fieldID->value.a = value;
 }
@@ -2562,10 +2947,11 @@ void SetStaticObjectField(JNIEnv *env, jclass clazz, jfieldID fieldID, jobject v
 
 void SetStaticBooleanField(JNIEnv *env, jclass clazz, jfieldID fieldID, jboolean value)
 {
-       STATS(jniinvokation();)
-       JWCLINITDEBUG(printf("SetStaticBooleanField: calling initialize_class %s\n",clazz->name->text);)
-       if (!initialize_class(clazz))
-               return;
+       STATISTICS(jniinvokation());
+
+       if (!(clazz->state & CLASS_INITIALIZED))
+               if (!initialize_class(clazz))
+                       return;
 
        fieldID->value.i = value;
 }
@@ -2573,10 +2959,11 @@ void SetStaticBooleanField(JNIEnv *env, jclass clazz, jfieldID fieldID, jboolean
 
 void SetStaticByteField(JNIEnv *env, jclass clazz, jfieldID fieldID, jbyte value)
 {
-       STATS(jniinvokation();)
-       JWCLINITDEBUG(printf("SetStaticByteField: calling initialize_class %s\n",clazz->name->text);)
-       if (!initialize_class(clazz))
-               return;
+       STATISTICS(jniinvokation());
+
+       if (!(clazz->state & CLASS_INITIALIZED))
+               if (!initialize_class(clazz))
+                       return;
 
        fieldID->value.i = value;
 }
@@ -2584,10 +2971,11 @@ void SetStaticByteField(JNIEnv *env, jclass clazz, jfieldID fieldID, jbyte value
 
 void SetStaticCharField(JNIEnv *env, jclass clazz, jfieldID fieldID, jchar value)
 {
-       STATS(jniinvokation();)
-       JWCLINITDEBUG(printf("SetStaticCharField: calling initialize_class %s\n",clazz->name->text);)
-       if (!initialize_class(clazz))
-               return;
+       STATISTICS(jniinvokation());
+
+       if (!(clazz->state & CLASS_INITIALIZED))
+               if (!initialize_class(clazz))
+                       return;
 
        fieldID->value.i = value;
 }
@@ -2595,10 +2983,11 @@ void SetStaticCharField(JNIEnv *env, jclass clazz, jfieldID fieldID, jchar value
 
 void SetStaticShortField(JNIEnv *env, jclass clazz, jfieldID fieldID, jshort value)
 {
-       STATS(jniinvokation();)
-       JWCLINITDEBUG(printf("SetStaticShortField: calling initialize_class %s\n",clazz->name->text);)
-       if (!initialize_class(clazz))
-               return;
+       STATISTICS(jniinvokation());
+
+       if (!(clazz->state & CLASS_INITIALIZED))
+               if (!initialize_class(clazz))
+                       return;
 
        fieldID->value.i = value;
 }
@@ -2606,10 +2995,11 @@ void SetStaticShortField(JNIEnv *env, jclass clazz, jfieldID fieldID, jshort val
 
 void SetStaticIntField(JNIEnv *env, jclass clazz, jfieldID fieldID, jint value)
 {
-       STATS(jniinvokation();)
-       JWCLINITDEBUG(printf("SetStaticIntField: calling initialize_class %s\n",clazz->name->text);)
-       if (!initialize_class(clazz))
-               return;
+       STATISTICS(jniinvokation());
+
+       if (!(clazz->state & CLASS_INITIALIZED))
+               if (!initialize_class(clazz))
+                       return;
 
        fieldID->value.i = value;
 }
@@ -2617,10 +3007,11 @@ void SetStaticIntField(JNIEnv *env, jclass clazz, jfieldID fieldID, jint value)
 
 void SetStaticLongField(JNIEnv *env, jclass clazz, jfieldID fieldID, jlong value)
 {
-       STATS(jniinvokation();)
-       JWCLINITDEBUG(printf("SetStaticLongField: calling initialize_class %s\n",clazz->name->text);)
-       if (!initialize_class(clazz))
-               return;
+       STATISTICS(jniinvokation());
+
+       if (!(clazz->state & CLASS_INITIALIZED))
+               if (!initialize_class(clazz))
+                       return;
 
        fieldID->value.l = value;
 }
@@ -2628,10 +3019,11 @@ void SetStaticLongField(JNIEnv *env, jclass clazz, jfieldID fieldID, jlong value
 
 void SetStaticFloatField(JNIEnv *env, jclass clazz, jfieldID fieldID, jfloat value)
 {
-       STATS(jniinvokation();)
-       JWCLINITDEBUG(printf("SetStaticFloatField: calling initialize_class %s\n",clazz->name->text);)
-       if (!initialize_class(clazz))
-               return;
+       STATISTICS(jniinvokation());
+
+       if (!(clazz->state & CLASS_INITIALIZED))
+               if (!initialize_class(clazz))
+                       return;
 
        fieldID->value.f = value;
 }
@@ -2639,15 +3031,18 @@ void SetStaticFloatField(JNIEnv *env, jclass clazz, jfieldID fieldID, jfloat val
 
 void SetStaticDoubleField(JNIEnv *env, jclass clazz, jfieldID fieldID, jdouble value)
 {
-       STATS(jniinvokation();)
-       JWCLINITDEBUG(printf("SetStaticDoubleField: calling initialize_class %s\n",clazz->name->text);)
-       if (!initialize_class(clazz))
-               return;
+       STATISTICS(jniinvokation());
+
+       if (!(clazz->state & CLASS_INITIALIZED))
+               if (!initialize_class(clazz))
+                       return;
 
        fieldID->value.d = value;
 }
 
 
+/* String Operations **********************************************************/
+
 /* NewString *******************************************************************
 
    Create new java.lang.String object from an array of Unicode
@@ -2660,7 +3055,8 @@ jstring NewString(JNIEnv *env, const jchar *buf, jsize len)
        java_lang_String *s;
        java_chararray   *a;
        u4                i;
-       STATS(jniinvokation();)
+
+       STATISTICS(jniinvokation());
        
        s = (java_lang_String *) builtin_new(class_java_lang_String);
        a = builtin_newarray_char(len);
@@ -2677,69 +3073,108 @@ jstring NewString(JNIEnv *env, const jchar *buf, jsize len)
        s->offset = 0;
        s->count = len;
 
-       return (jstring) s;
+       return (jstring) NewLocalRef(env, (jobject) s);
 }
 
 
 static jchar emptyStringJ[]={0,0};
 
-/******************* returns the length of a Java string ***************************/
+/* GetStringLength *************************************************************
+
+   Returns the length (the count of Unicode characters) of a Java
+   string.
 
-jsize GetStringLength (JNIEnv *env, jstring str)
+*******************************************************************************/
+
+jsize GetStringLength(JNIEnv *env, jstring str)
 {
-       return ((java_lang_String*) str)->count;
+       return ((java_lang_String *) str)->count;
 }
 
 
 /********************  convertes javastring to u2-array ****************************/
        
-u2 *javastring_tou2 (jstring so) 
+u2 *javastring_tou2(jstring so) 
 {
-       java_lang_String *s = (java_lang_String*) so;
-       java_chararray *a;
-       u4 i;
-       u2 *stringbuffer;
-       STATS(jniinvokation();)
+       java_lang_String *s;
+       java_chararray   *a;
+       u2               *stringbuffer;
+       u4                i;
+
+       STATISTICS(jniinvokation());
        
-       if (!s) return NULL;
+       s = (java_lang_String *) so;
+
+       if (!s)
+               return NULL;
 
        a = s->value;
-       if (!a) return NULL;
+
+       if (!a)
+               return NULL;
 
        /* allocate memory */
-       stringbuffer = MNEW( u2 , s->count + 1 );
+
+       stringbuffer = MNEW(u2, s->count + 1);
 
        /* copy text */
-       for (i=0; i<s->count; i++) stringbuffer[i] = a->data[s->offset+i];
+
+       for (i = 0; i < s->count; i++)
+               stringbuffer[i] = a->data[s->offset + i];
        
        /* terminate string */
+
        stringbuffer[i] = '\0';
 
        return stringbuffer;
 }
 
-/********* returns a pointer to an array of Unicode characters of the string *******/
 
-const jchar *GetStringChars (JNIEnv *env, jstring str, jboolean *isCopy)
+/* GetStringChars **************************************************************
+
+   Returns a pointer to the array of Unicode characters of the
+   string. This pointer is valid until ReleaseStringchars() is called.
+
+*******************************************************************************/
+
+const jchar *GetStringChars(JNIEnv *env, jstring str, jboolean *isCopy)
 {      
-       jchar *jc=javastring_tou2(str);
-       STATS(jniinvokation();)
+       jchar *jc;
+
+       STATISTICS(jniinvokation());
+
+       jc = javastring_tou2(str);
 
        if (jc) {
-               if (isCopy) *isCopy=JNI_TRUE;
+               if (isCopy)
+                       *isCopy = JNI_TRUE;
+
                return jc;
        }
-       if (isCopy) *isCopy=JNI_TRUE;
+
+       if (isCopy)
+               *isCopy = JNI_TRUE;
+
        return emptyStringJ;
 }
 
-/**************** native code no longer needs access to chars **********************/
 
-void ReleaseStringChars (JNIEnv *env, jstring str, const jchar *chars)
+/* ReleaseStringChars **********************************************************
+
+   Informs the VM that the native code no longer needs access to
+   chars. The chars argument is a pointer obtained from string using
+   GetStringChars().
+
+*******************************************************************************/
+
+void ReleaseStringChars(JNIEnv *env, jstring str, const jchar *chars)
 {
-       STATS(jniinvokation();)
-       if (chars==emptyStringJ) return;
-       MFREE(((jchar*) chars),jchar,((java_lang_String*) str)->count+1);
+       STATISTICS(jniinvokation());
+
+       if (chars == emptyStringJ)
+               return;
+
+       MFREE(((jchar *) chars), jchar, ((java_lang_String *) str)->count + 1);
 }
 
 
@@ -2751,8 +3186,13 @@ void ReleaseStringChars (JNIEnv *env, jstring str, const jchar *chars)
 
 jstring NewStringUTF(JNIEnv *env, const char *bytes)
 {
-       STATS(jniinvokation();)
-    return (jstring) javastring_new(utf_new_char(bytes));
+       java_lang_String *s;
+
+       STATISTICS(jniinvokation());
+
+       s = javastring_new(utf_new_char(bytes));
+
+    return (jstring) NewLocalRef(env, (jobject) s);
 }
 
 
@@ -2761,7 +3201,8 @@ jstring NewStringUTF(JNIEnv *env, const char *bytes)
 jsize GetStringUTFLength (JNIEnv *env, jstring string)
 {   
     java_lang_String *s = (java_lang_String*) string;
-       STATS(jniinvokation();)
+
+       STATISTICS(jniinvokation());
 
     return (jsize) u2_utflength(s->value->data, s->count); 
 }
@@ -2778,7 +3219,8 @@ jsize GetStringUTFLength (JNIEnv *env, jstring string)
 const char *GetStringUTFChars(JNIEnv *env, jstring string, jboolean *isCopy)
 {
        utf *u;
-       STATS(jniinvokation();)
+
+       STATISTICS(jniinvokation());
 
        if (!string)
                return "";
@@ -2795,27 +3237,37 @@ const char *GetStringUTFChars(JNIEnv *env, jstring string, jboolean *isCopy)
 }
 
 
-/***************** native code no longer needs access to utf ***********************/
+/* ReleaseStringUTFChars *******************************************************
 
-void ReleaseStringUTFChars (JNIEnv *env, jstring str, const char* chars)
+   Informs the VM that the native code no longer needs access to
+   utf. The utf argument is a pointer derived from string using
+   GetStringUTFChars().
+
+*******************************************************************************/
+
+void ReleaseStringUTFChars(JNIEnv *env, jstring string, const char *utf)
 {
-       STATS(jniinvokation();)
+       STATISTICS(jniinvokation());
 
-    /*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));
-       */
+    /* 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 */
 }
 
-/************************** array operations ***************************************/
+
+/* Array Operations ***********************************************************/
+
+/* GetArrayLength **************************************************************
+
+   Returns the number of elements in the array.
+
+*******************************************************************************/
 
 jsize GetArrayLength(JNIEnv *env, jarray array)
 {
-       STATS(jniinvokation();)
+       STATISTICS(jniinvokation());
 
-    return array->size;
+       return array->size;
 }
 
 
@@ -2829,11 +3281,12 @@ jsize GetArrayLength(JNIEnv *env, jarray array)
 jobjectArray NewObjectArray(JNIEnv *env, jsize length, jclass elementClass, jobject initialElement)
 {
        java_objectarray *oa;
-       s4 i;
-       STATS(jniinvokation();)
+       s4                i;
+
+       STATISTICS(jniinvokation());
 
        if (length < 0) {
-               *exceptionptr = new_negativearraysizeexception();
+               exceptions_throw_negativearraysizeexception();
                return NULL;
        }
 
@@ -2847,482 +3300,723 @@ jobjectArray NewObjectArray(JNIEnv *env, jsize length, jclass elementClass, jobj
        for (i = 0; i < length; i++)
                oa->data[i] = initialElement;
 
-       return oa;
+       return (jobjectArray) NewLocalRef(env, (jobject) oa);
 }
 
 
 jobject GetObjectArrayElement(JNIEnv *env, jobjectArray array, jsize index)
 {
-    jobject j = NULL;
-       STATS(jniinvokation();)
+    jobject o;
 
-    if (index < array->header.size)    
-               j = array->data[index];
-    else
-               *exceptionptr = new_exception(string_java_lang_ArrayIndexOutOfBoundsException);
+       STATISTICS(jniinvokation());
+
+       if (index >= array->header.size) {
+               exceptions_throw_arrayindexoutofboundsexception();
+               return NULL;
+       }
+
+       o = array->data[index];
     
-    return j;
+    return NewLocalRef(env, o);
 }
 
 
 void SetObjectArrayElement(JNIEnv *env, jobjectArray array, jsize index, jobject val)
 {
-       STATS(jniinvokation();)
-    if (index >= array->header.size)
-               *exceptionptr = new_exception(string_java_lang_ArrayIndexOutOfBoundsException);
+       java_objectarray  *oa;
+       java_objectheader *o;
 
-    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);
+       STATISTICS(jniinvokation());
 
-               else
-                       array->data[index] = val;
-    }
-}
+       oa = (java_objectarray *) array;
+       o  = (java_objectheader *) val;
+
+    if (index >= array->header.size) {
+               exceptions_throw_arrayindexoutofboundsexception();
+               return;
+       }
+
+       /* check if the class of value is a subclass of the element class
+          of the array */
+
+       if (!builtin_canstore(oa, o)) {
+               *exceptionptr = new_exception(string_java_lang_ArrayStoreException);
+
+               return;
+       }
 
+       array->data[index] = val;
+}
 
 
 jbooleanArray NewBooleanArray(JNIEnv *env, jsize len)
 {
-       java_booleanarray *j;
-       STATS(jniinvokation();)
+       java_booleanarray *ba;
+
+       STATISTICS(jniinvokation());
 
-    if (len < 0) {
-               *exceptionptr = new_exception(string_java_lang_NegativeArraySizeException);
+       if (len < 0) {
+               exceptions_throw_negativearraysizeexception();
                return NULL;
-    }
+       }
 
-    j = builtin_newarray_boolean(len);
+       ba = builtin_newarray_boolean(len);
 
-    return j;
+       return (jbooleanArray) NewLocalRef(env, (jobject) ba);
 }
 
 
 jbyteArray NewByteArray(JNIEnv *env, jsize len)
 {
-       java_bytearray *j;
-       STATS(jniinvokation();)
+       java_bytearray *ba;
+
+       STATISTICS(jniinvokation());
 
-    if (len < 0) {
-               *exceptionptr = new_exception(string_java_lang_NegativeArraySizeException);
+       if (len < 0) {
+               exceptions_throw_negativearraysizeexception();
                return NULL;
-    }
+       }
 
-    j = builtin_newarray_byte(len);
+       ba = builtin_newarray_byte(len);
 
-    return j;
+       return (jbyteArray) NewLocalRef(env, (jobject) ba);
 }
 
 
 jcharArray NewCharArray(JNIEnv *env, jsize len)
 {
-       java_chararray *j;
-       STATS(jniinvokation();)
+       java_chararray *ca;
+
+       STATISTICS(jniinvokation());
 
-    if (len < 0) {
-               *exceptionptr = new_exception(string_java_lang_NegativeArraySizeException);
+       if (len < 0) {
+               exceptions_throw_negativearraysizeexception();
                return NULL;
-    }
+       }
 
-    j = builtin_newarray_char(len);
+       ca = builtin_newarray_char(len);
 
-    return j;
+       return (jcharArray) NewLocalRef(env, (jobject) ca);
 }
 
 
 jshortArray NewShortArray(JNIEnv *env, jsize len)
 {
-       java_shortarray *j;
-       STATS(jniinvokation();)
+       java_shortarray *sa;
 
-    if (len < 0) {
-               *exceptionptr = new_exception(string_java_lang_NegativeArraySizeException);
+       STATISTICS(jniinvokation());
+
+       if (len < 0) {
+               exceptions_throw_negativearraysizeexception();
                return NULL;
-    }
+       }
 
-    j = builtin_newarray_short(len);
+       sa = builtin_newarray_short(len);
 
-    return j;
+       return (jshortArray) NewLocalRef(env, (jobject) sa);
 }
 
 
 jintArray NewIntArray(JNIEnv *env, jsize len)
 {
-       java_intarray *j;
-       STATS(jniinvokation();)
+       java_intarray *ia;
+
+       STATISTICS(jniinvokation());
 
-    if (len < 0) {
-               *exceptionptr = new_exception(string_java_lang_NegativeArraySizeException);
+       if (len < 0) {
+               exceptions_throw_negativearraysizeexception();
                return NULL;
-    }
+       }
 
-    j = builtin_newarray_int(len);
+       ia = builtin_newarray_int(len);
 
-    return j;
+       return (jintArray) NewLocalRef(env, (jobject) ia);
 }
 
 
 jlongArray NewLongArray(JNIEnv *env, jsize len)
 {
-       java_longarray *j;
-       STATS(jniinvokation();)
+       java_longarray *la;
+
+       STATISTICS(jniinvokation());
 
-    if (len < 0) {
-               *exceptionptr = new_exception(string_java_lang_NegativeArraySizeException);
+       if (len < 0) {
+               exceptions_throw_negativearraysizeexception();
                return NULL;
-    }
+       }
 
-    j = builtin_newarray_long(len);
+       la = builtin_newarray_long(len);
 
-    return j;
+       return (jlongArray) NewLocalRef(env, (jobject) la);
 }
 
 
 jfloatArray NewFloatArray(JNIEnv *env, jsize len)
 {
-       java_floatarray *j;
-       STATS(jniinvokation();)
+       java_floatarray *fa;
 
-    if (len < 0) {
-               *exceptionptr = new_exception(string_java_lang_NegativeArraySizeException);
+       STATISTICS(jniinvokation());
+
+       if (len < 0) {
+               exceptions_throw_negativearraysizeexception();
                return NULL;
-    }
+       }
 
-    j = builtin_newarray_float(len);
+       fa = builtin_newarray_float(len);
 
-    return j;
+       return (jfloatArray) NewLocalRef(env, (jobject) fa);
 }
 
 
 jdoubleArray NewDoubleArray(JNIEnv *env, jsize len)
 {
-       java_doublearray *j;
-       STATS(jniinvokation();)
+       java_doublearray *da;
 
-    if (len < 0) {
-               *exceptionptr = new_exception(string_java_lang_NegativeArraySizeException);
+       STATISTICS(jniinvokation());
+
+       if (len < 0) {
+               exceptions_throw_negativearraysizeexception();
                return NULL;
-    }
+       }
 
-    j = builtin_newarray_double(len);
+       da = builtin_newarray_double(len);
 
-    return j;
+       return (jdoubleArray) NewLocalRef(env, (jobject) da);
 }
 
 
-jboolean * GetBooleanArrayElements (JNIEnv *env, jbooleanArray array, jboolean *isCopy)
+/* Get<PrimitiveType>ArrayElements *********************************************
+
+   A family of functions that returns the body of the primitive array.
+
+*******************************************************************************/
+
+jboolean *GetBooleanArrayElements(JNIEnv *env, jbooleanArray array,
+                                                                 jboolean *isCopy)
 {
-       STATS(jniinvokation();)
-    if (isCopy) *isCopy = JNI_FALSE;
+       STATISTICS(jniinvokation());
+
+    if (isCopy)
+               *isCopy = JNI_FALSE;
+
     return array->data;
 }
 
 
-jbyte * GetByteArrayElements (JNIEnv *env, jbyteArray array, jboolean *isCopy)
+jbyte *GetByteArrayElements(JNIEnv *env, jbyteArray array, jboolean *isCopy)
 {
-       STATS(jniinvokation();)
-    if (isCopy) *isCopy = JNI_FALSE;
+       STATISTICS(jniinvokation());
+
+    if (isCopy)
+               *isCopy = JNI_FALSE;
+
     return array->data;
 }
 
 
-jchar * GetCharArrayElements (JNIEnv *env, jcharArray array, jboolean *isCopy)
+jchar *GetCharArrayElements(JNIEnv *env, jcharArray array, jboolean *isCopy)
 {
-       STATS(jniinvokation();)
-    if (isCopy) *isCopy = JNI_FALSE;
+       STATISTICS(jniinvokation());
+
+    if (isCopy)
+               *isCopy = JNI_FALSE;
+
     return array->data;
 }
 
 
-jshort * GetShortArrayElements (JNIEnv *env, jshortArray array, jboolean *isCopy)
+jshort *GetShortArrayElements(JNIEnv *env, jshortArray array, jboolean *isCopy)
 {
-       STATS(jniinvokation();)
-    if (isCopy) *isCopy = JNI_FALSE;
+       STATISTICS(jniinvokation());
+
+    if (isCopy)
+               *isCopy = JNI_FALSE;
+
     return array->data;
 }
 
 
-jint * GetIntArrayElements (JNIEnv *env, jintArray array, jboolean *isCopy)
+jint *GetIntArrayElements(JNIEnv *env, jintArray array, jboolean *isCopy)
 {
-       STATS(jniinvokation();)
-    if (isCopy) *isCopy = JNI_FALSE;
+       STATISTICS(jniinvokation());
+
+    if (isCopy)
+               *isCopy = JNI_FALSE;
+
     return array->data;
 }
 
 
-jlong * GetLongArrayElements (JNIEnv *env, jlongArray array, jboolean *isCopy)
+jlong *GetLongArrayElements(JNIEnv *env, jlongArray array, jboolean *isCopy)
 {
-       STATS(jniinvokation();)
-    if (isCopy) *isCopy = JNI_FALSE;
+       STATISTICS(jniinvokation());
+
+    if (isCopy)
+               *isCopy = JNI_FALSE;
+
     return array->data;
 }
 
 
-jfloat * GetFloatArrayElements (JNIEnv *env, jfloatArray array, jboolean *isCopy)
+jfloat *GetFloatArrayElements(JNIEnv *env, jfloatArray array, jboolean *isCopy)
 {
-       STATS(jniinvokation();)
-    if (isCopy) *isCopy = JNI_FALSE;
+       STATISTICS(jniinvokation());
+
+    if (isCopy)
+               *isCopy = JNI_FALSE;
+
     return array->data;
 }
 
 
-jdouble * GetDoubleArrayElements (JNIEnv *env, jdoubleArray array, jboolean *isCopy)
+jdouble *GetDoubleArrayElements(JNIEnv *env, jdoubleArray array,
+                                                               jboolean *isCopy)
 {
-       STATS(jniinvokation();)
-    if (isCopy) *isCopy = JNI_FALSE;
+       STATISTICS(jniinvokation());
+
+    if (isCopy)
+               *isCopy = JNI_FALSE;
+
     return array->data;
 }
 
 
+/* 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 ReleaseBooleanArrayElements (JNIEnv *env, jbooleanArray array, jboolean *elems, jint mode)
+*******************************************************************************/
+
+void ReleaseBooleanArrayElements(JNIEnv *env, jbooleanArray array,
+                                                                jboolean *elems, jint mode)
 {
-       STATS(jniinvokation();)
-    /* empty */
+       STATISTICS(jniinvokation());
+
+       if (elems != array->data) {
+               switch (mode) {
+               case JNI_COMMIT:
+                       MCOPY(array->data, elems, jboolean, array->header.size);
+                       break;
+               case 0:
+                       MCOPY(array->data, elems, jboolean, array->header.size);
+                       /* XXX TWISTI how should it be freed? */
+                       break;
+               case JNI_ABORT:
+                       /* XXX TWISTI how should it be freed? */
+                       break;
+               }
+       }
 }
 
 
-void ReleaseByteArrayElements (JNIEnv *env, jbyteArray array, jbyte *elems, jint mode)
+void ReleaseByteArrayElements(JNIEnv *env, jbyteArray array, jbyte *elems,
+                                                         jint mode)
 {
-       STATS(jniinvokation();)
-    /* empty */
+       STATISTICS(jniinvokation());
+
+       if (elems != array->data) {
+               switch (mode) {
+               case JNI_COMMIT:
+                       MCOPY(array->data, elems, jboolean, array->header.size);
+                       break;
+               case 0:
+                       MCOPY(array->data, elems, jboolean, array->header.size);
+                       /* XXX TWISTI how should it be freed? */
+                       break;
+               case JNI_ABORT:
+                       /* XXX TWISTI how should it be freed? */
+                       break;
+               }
+       }
 }
 
 
-void ReleaseCharArrayElements (JNIEnv *env, jcharArray array, jchar *elems, jint mode)
+void ReleaseCharArrayElements(JNIEnv *env, jcharArray array, jchar *elems,
+                                                         jint mode)
 {
-    /* empty */
+       STATISTICS(jniinvokation());
+
+       if (elems != array->data) {
+               switch (mode) {
+               case JNI_COMMIT:
+                       MCOPY(array->data, elems, jboolean, array->header.size);
+                       break;
+               case 0:
+                       MCOPY(array->data, elems, jboolean, array->header.size);
+                       /* XXX TWISTI how should it be freed? */
+                       break;
+               case JNI_ABORT:
+                       /* XXX TWISTI how should it be freed? */
+                       break;
+               }
+       }
 }
 
 
-void ReleaseShortArrayElements (JNIEnv *env, jshortArray array, jshort *elems, jint mode)
+void ReleaseShortArrayElements(JNIEnv *env, jshortArray array, jshort *elems,
+                                                          jint mode)
 {
-       STATS(jniinvokation();)
-    /* empty */
+       STATISTICS(jniinvokation());
+
+       if (elems != array->data) {
+               switch (mode) {
+               case JNI_COMMIT:
+                       MCOPY(array->data, elems, jboolean, array->header.size);
+                       break;
+               case 0:
+                       MCOPY(array->data, elems, jboolean, array->header.size);
+                       /* XXX TWISTI how should it be freed? */
+                       break;
+               case JNI_ABORT:
+                       /* XXX TWISTI how should it be freed? */
+                       break;
+               }
+       }
 }
 
 
-void ReleaseIntArrayElements (JNIEnv *env, jintArray array, jint *elems, jint mode)
+void ReleaseIntArrayElements(JNIEnv *env, jintArray array, jint *elems,
+                                                        jint mode)
 {
-       STATS(jniinvokation();)
-    /* empty */
+       STATISTICS(jniinvokation());
+
+       if (elems != array->data) {
+               switch (mode) {
+               case JNI_COMMIT:
+                       MCOPY(array->data, elems, jboolean, array->header.size);
+                       break;
+               case 0:
+                       MCOPY(array->data, elems, jboolean, array->header.size);
+                       /* XXX TWISTI how should it be freed? */
+                       break;
+               case JNI_ABORT:
+                       /* XXX TWISTI how should it be freed? */
+                       break;
+               }
+       }
 }
 
 
-void ReleaseLongArrayElements (JNIEnv *env, jlongArray array, jlong *elems, jint mode)
+void ReleaseLongArrayElements(JNIEnv *env, jlongArray array, jlong *elems,
+                                                         jint mode)
 {
-       STATS(jniinvokation();)
-    /* empty */
+       STATISTICS(jniinvokation());
+
+       if (elems != array->data) {
+               switch (mode) {
+               case JNI_COMMIT:
+                       MCOPY(array->data, elems, jboolean, array->header.size);
+                       break;
+               case 0:
+                       MCOPY(array->data, elems, jboolean, array->header.size);
+                       /* XXX TWISTI how should it be freed? */
+                       break;
+               case JNI_ABORT:
+                       /* XXX TWISTI how should it be freed? */
+                       break;
+               }
+       }
 }
 
 
-void ReleaseFloatArrayElements (JNIEnv *env, jfloatArray array, jfloat *elems, jint mode)
+void ReleaseFloatArrayElements(JNIEnv *env, jfloatArray array, jfloat *elems,
+                                                          jint mode)
 {
-       STATS(jniinvokation();)
-    /* empty */
+       STATISTICS(jniinvokation());
+
+       if (elems != array->data) {
+               switch (mode) {
+               case JNI_COMMIT:
+                       MCOPY(array->data, elems, jboolean, array->header.size);
+                       break;
+               case 0:
+                       MCOPY(array->data, elems, jboolean, array->header.size);
+                       /* XXX TWISTI how should it be freed? */
+                       break;
+               case JNI_ABORT:
+                       /* XXX TWISTI how should it be freed? */
+                       break;
+               }
+       }
 }
 
 
-void ReleaseDoubleArrayElements (JNIEnv *env, jdoubleArray array, jdouble *elems, jint mode)
+void ReleaseDoubleArrayElements(JNIEnv *env, jdoubleArray array,
+                                                               jdouble *elems, jint mode)
 {
-       STATS(jniinvokation();)
-    /* empty */
+       STATISTICS(jniinvokation());
+
+       if (elems != array->data) {
+               switch (mode) {
+               case JNI_COMMIT:
+                       MCOPY(array->data, elems, jboolean, array->header.size);
+                       break;
+               case 0:
+                       MCOPY(array->data, elems, jboolean, array->header.size);
+                       /* XXX TWISTI how should it be freed? */
+                       break;
+               case JNI_ABORT:
+                       /* XXX TWISTI how should it be freed? */
+                       break;
+               }
+       }
 }
 
 
-void GetBooleanArrayRegion(JNIEnv* env, jbooleanArray array, jsize start, jsize len, jboolean *buf)
+/*  Get<PrimitiveType>ArrayRegion **********************************************
+
+       A family of functions that copies a region of a primitive array
+       into a buffer.
+
+*******************************************************************************/
+
+void GetBooleanArrayRegion(JNIEnv *env, jbooleanArray array, jsize start,
+                                                  jsize len, jboolean *buf)
 {
-       STATS(jniinvokation();)
-    if (start < 0 || len < 0 || start + len > array->header.size)
-               *exceptionptr = new_exception(string_java_lang_ArrayIndexOutOfBoundsException);
+       STATISTICS(jniinvokation());
 
+    if (start < 0 || len < 0 || start + len > array->header.size)
+               exceptions_throw_arrayindexoutofboundsexception();
     else
-               memcpy(buf, &array->data[start], len * sizeof(array->data[0]));
+               MCOPY(buf, &array->data[start], jboolean, len);
 }
 
 
-void GetByteArrayRegion(JNIEnv* env, jbyteArray array, jsize start, jsize len, jbyte *buf)
+void GetByteArrayRegion(JNIEnv *env, jbyteArray array, jsize start, jsize len,
+                                               jbyte *buf)
 {
-       STATS(jniinvokation();)
-    if (start < 0 || len < 0 || start + len > array->header.size) 
-               *exceptionptr = new_exception(string_java_lang_ArrayIndexOutOfBoundsException);
+       STATISTICS(jniinvokation());
 
+    if (start < 0 || len < 0 || start + len > array->header.size) 
+               exceptions_throw_arrayindexoutofboundsexception();
     else
-               memcpy(buf, &array->data[start], len * sizeof(array->data[0]));
+               MCOPY(buf, &array->data[start], jbyte, len);
 }
 
 
-void GetCharArrayRegion(JNIEnv* env, jcharArray array, jsize start, jsize len, jchar *buf)
+void GetCharArrayRegion(JNIEnv *env, jcharArray array, jsize start, jsize len,
+                                               jchar *buf)
 {
-       STATS(jniinvokation();)
-    if (start < 0 || len < 0 || start + len > array->header.size)
-               *exceptionptr = new_exception(string_java_lang_ArrayIndexOutOfBoundsException);
+       STATISTICS(jniinvokation());
 
+    if (start < 0 || len < 0 || start + len > array->header.size)
+               exceptions_throw_arrayindexoutofboundsexception();
     else
-               memcpy(buf, &array->data[start], len * sizeof(array->data[0]));
+               MCOPY(buf, &array->data[start], jchar, len);
 }
 
 
-void GetShortArrayRegion(JNIEnv* env, jshortArray array, jsize start, jsize len, jshort *buf)
+void GetShortArrayRegion(JNIEnv *env, jshortArray array, jsize start,
+                                                jsize len, jshort *buf)
 {
-       STATS(jniinvokation();)
-    if (start < 0 || len < 0 || start + len > array->header.size)
-               *exceptionptr = new_exception(string_java_lang_ArrayIndexOutOfBoundsException);
+       STATISTICS(jniinvokation());
 
+    if (start < 0 || len < 0 || start + len > array->header.size)
+               exceptions_throw_arrayindexoutofboundsexception();
     else       
-               memcpy(buf, &array->data[start], len * sizeof(array->data[0]));
+               MCOPY(buf, &array->data[start], jshort, len);
 }
 
 
-void GetIntArrayRegion(JNIEnv* env, jintArray array, jsize start, jsize len, jint *buf)
+void GetIntArrayRegion(JNIEnv *env, jintArray array, jsize start, jsize len,
+                                          jint *buf)
 {
-       STATS(jniinvokation();)
-    if (start < 0 || len < 0 || start + len > array->header.size)
-               *exceptionptr = new_exception(string_java_lang_ArrayIndexOutOfBoundsException);
+       STATISTICS(jniinvokation());
 
+    if (start < 0 || len < 0 || start + len > array->header.size)
+               exceptions_throw_arrayindexoutofboundsexception();
     else
-               memcpy(buf, &array->data[start], len * sizeof(array->data[0]));
+               MCOPY(buf, &array->data[start], jint, len);
 }
 
 
-void GetLongArrayRegion(JNIEnv* env, jlongArray array, jsize start, jsize len, jlong *buf)
+void GetLongArrayRegion(JNIEnv *env, jlongArray array, jsize start, jsize len,
+                                               jlong *buf)
 {
-       STATS(jniinvokation();)
-    if (start < 0 || len < 0 || start + len > array->header.size)
-               *exceptionptr = new_exception(string_java_lang_ArrayIndexOutOfBoundsException);
+       STATISTICS(jniinvokation());
 
+    if (start < 0 || len < 0 || start + len > array->header.size)
+               exceptions_throw_arrayindexoutofboundsexception();
     else
-               memcpy(buf, &array->data[start], len * sizeof(array->data[0]));
+               MCOPY(buf, &array->data[start], jlong, len);
 }
 
 
-void GetFloatArrayRegion(JNIEnv* env, jfloatArray array, jsize start, jsize len, jfloat *buf)
+void GetFloatArrayRegion(JNIEnv *env, jfloatArray array, jsize start,
+                                                jsize len, jfloat *buf)
 {
-       STATS(jniinvokation();)
-    if (start < 0 || len < 0 || start + len > array->header.size)
-               *exceptionptr = new_exception(string_java_lang_ArrayIndexOutOfBoundsException);
+       STATISTICS(jniinvokation());
 
+    if (start < 0 || len < 0 || start + len > array->header.size)
+               exceptions_throw_arrayindexoutofboundsexception();
     else
-               memcpy(buf, &array->data[start], len * sizeof(array->data[0]));
+               MCOPY(buf, &array->data[start], jfloat, len);
 }
 
 
-void GetDoubleArrayRegion(JNIEnv* env, jdoubleArray array, jsize start, jsize len, jdouble *buf)
+void GetDoubleArrayRegion(JNIEnv *env, jdoubleArray array, jsize start,
+                                                 jsize len, jdouble *buf)
 {
-       STATS(jniinvokation();)
-    if (start < 0 || len < 0 || start+len>array->header.size)
-               *exceptionptr = new_exception(string_java_lang_ArrayIndexOutOfBoundsException);
+       STATISTICS(jniinvokation());
 
+    if (start < 0 || len < 0 || start+len>array->header.size)
+               exceptions_throw_arrayindexoutofboundsexception();
     else
-               memcpy(buf, &array->data[start], len * sizeof(array->data[0]));
+               MCOPY(buf, &array->data[start], jdouble, len);
 }
 
 
-void SetBooleanArrayRegion(JNIEnv* env, jbooleanArray array, jsize start, jsize len, jboolean *buf)
+/*  Set<PrimitiveType>ArrayRegion **********************************************
+
+       A family of functions that copies back a region of a primitive
+       array from a buffer.
+
+*******************************************************************************/
+
+void SetBooleanArrayRegion(JNIEnv *env, jbooleanArray array, jsize start,
+                                                  jsize len, jboolean *buf)
 {
-       STATS(jniinvokation();)
-    if (start < 0 || len < 0 || start + len > array->header.size)
-               *exceptionptr = new_exception(string_java_lang_ArrayIndexOutOfBoundsException);
+       STATISTICS(jniinvokation());
 
+    if (start < 0 || len < 0 || start + len > array->header.size)
+               exceptions_throw_arrayindexoutofboundsexception();
     else
-               memcpy(&array->data[start], buf, len * sizeof(array->data[0]));
+               MCOPY(&array->data[start], buf, jboolean, len);
 }
 
 
-void SetByteArrayRegion(JNIEnv* env, jbyteArray array, jsize start, jsize len, jbyte *buf)
+void SetByteArrayRegion(JNIEnv *env, jbyteArray array, jsize start, jsize len,
+                                               jbyte *buf)
 {
-       STATS(jniinvokation();)
-    if (start < 0 || len < 0 || start + len > array->header.size)
-               *exceptionptr = new_exception(string_java_lang_ArrayIndexOutOfBoundsException);
+       STATISTICS(jniinvokation());
 
+    if (start < 0 || len < 0 || start + len > array->header.size)
+               exceptions_throw_arrayindexoutofboundsexception();
     else
-               memcpy(&array->data[start], buf, len * sizeof(array->data[0]));
+               MCOPY(&array->data[start], buf, jbyte, len);
 }
 
 
-void SetCharArrayRegion(JNIEnv* env, jcharArray array, jsize start, jsize len, jchar *buf)
+void SetCharArrayRegion(JNIEnv *env, jcharArray array, jsize start, jsize len,
+                                               jchar *buf)
 {
-       STATS(jniinvokation();)
-    if (start < 0 || len < 0 || start + len > array->header.size)
-               *exceptionptr = new_exception(string_java_lang_ArrayIndexOutOfBoundsException);
+       STATISTICS(jniinvokation());
 
+    if (start < 0 || len < 0 || start + len > array->header.size)
+               exceptions_throw_arrayindexoutofboundsexception();
     else
-               memcpy(&array->data[start], buf, len * sizeof(array->data[0]));
-
+               MCOPY(&array->data[start], buf, jchar, len);
 }
 
 
-void SetShortArrayRegion(JNIEnv* env, jshortArray array, jsize start, jsize len, jshort *buf)
+void SetShortArrayRegion(JNIEnv *env, jshortArray array, jsize start,
+                                                jsize len, jshort *buf)
 {
-       STATS(jniinvokation();)
-    if (start < 0 || len < 0 || start + len > array->header.size)
-               *exceptionptr = new_exception(string_java_lang_ArrayIndexOutOfBoundsException);
+       STATISTICS(jniinvokation());
 
+    if (start < 0 || len < 0 || start + len > array->header.size)
+               exceptions_throw_arrayindexoutofboundsexception();
     else
-               memcpy(&array->data[start], buf, len * sizeof(array->data[0]));
+               MCOPY(&array->data[start], buf, jshort, len);
 }
 
 
-void SetIntArrayRegion(JNIEnv* env, jintArray array, jsize start, jsize len, jint *buf)
+void SetIntArrayRegion(JNIEnv *env, jintArray array, jsize start, jsize len,
+                                          jint *buf)
 {
-       STATS(jniinvokation();)
-    if (start < 0 || len < 0 || start + len > array->header.size)
-               *exceptionptr = new_exception(string_java_lang_ArrayIndexOutOfBoundsException);
+       STATISTICS(jniinvokation());
 
+    if (start < 0 || len < 0 || start + len > array->header.size)
+               exceptions_throw_arrayindexoutofboundsexception();
     else
-               memcpy(&array->data[start], buf, len * sizeof(array->data[0]));
-
+               MCOPY(&array->data[start], buf, jint, len);
 }
 
 
-void SetLongArrayRegion(JNIEnv* env, jlongArray array, jsize start, jsize len, jlong *buf)
+void SetLongArrayRegion(JNIEnv* env, jlongArray array, jsize start, jsize len,
+                                               jlong *buf)
 {
-       STATS(jniinvokation();)
-    if (start < 0 || len < 0 || start + len > array->header.size)
-               *exceptionptr = new_exception(string_java_lang_ArrayIndexOutOfBoundsException);
+       STATISTICS(jniinvokation());
 
+    if (start < 0 || len < 0 || start + len > array->header.size)
+               exceptions_throw_arrayindexoutofboundsexception();
     else
-               memcpy(&array->data[start], buf, len * sizeof(array->data[0]));
-
+               MCOPY(&array->data[start], buf, jlong, len);
 }
 
 
-void SetFloatArrayRegion(JNIEnv* env, jfloatArray array, jsize start, jsize len, jfloat *buf)
+void SetFloatArrayRegion(JNIEnv *env, jfloatArray array, jsize start,
+                                                jsize len, jfloat *buf)
 {
-       STATS(jniinvokation();)
-    if (start < 0 || len < 0 || start + len > array->header.size)
-               *exceptionptr = new_exception(string_java_lang_ArrayIndexOutOfBoundsException);
+       STATISTICS(jniinvokation());
 
+    if (start < 0 || len < 0 || start + len > array->header.size)
+               exceptions_throw_arrayindexoutofboundsexception();
     else
-               memcpy(&array->data[start], buf, len * sizeof(array->data[0]));
-
+               MCOPY(&array->data[start], buf, jfloat, len);
 }
 
 
-void SetDoubleArrayRegion(JNIEnv* env, jdoubleArray array, jsize start, jsize len, jdouble *buf)
+void SetDoubleArrayRegion(JNIEnv *env, jdoubleArray array, jsize start,
+                                                 jsize len, jdouble *buf)
 {
-       STATS(jniinvokation();)
-    if (start < 0 || len < 0 || start + len > array->header.size)
-               *exceptionptr = new_exception(string_java_lang_ArrayIndexOutOfBoundsException);
+       STATISTICS(jniinvokation());
 
+    if (start < 0 || len < 0 || start + len > array->header.size)
+               exceptions_throw_arrayindexoutofboundsexception();
     else
-               memcpy(&array->data[start], buf, len * sizeof(array->data[0]));
+               MCOPY(&array->data[start], buf, jdouble, len);
 }
 
 
-jint RegisterNatives (JNIEnv* env, jclass clazz, const JNINativeMethod *methods, jint nMethods)
+/* 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.
+
+*******************************************************************************/
+
+jint RegisterNatives(JNIEnv *env, jclass clazz, const JNINativeMethod *methods,
+                                        jint nMethods)
 {
-       STATS(jniinvokation();)
-    log_text("JNI-Call: RegisterNatives");
+       STATISTICS(jniinvokation());
+
+    log_text("JNI-Call: RegisterNatives: IMPLEMENT ME!!!");
+
     return 0;
 }
 
 
-jint UnregisterNatives (JNIEnv* env, jclass clazz)
+/* UnregisterNatives ***********************************************************
+
+   Unregisters native methods of a class. The class goes back to the
+   state before it was linked or registered with its native method
+   functions.
+
+   This function should not be used in normal native code. Instead, it
+   provides special programs a way to reload and relink native
+   libraries.
+
+*******************************************************************************/
+
+jint UnregisterNatives(JNIEnv *env, jclass clazz)
 {
-       STATS(jniinvokation();)
-    log_text("JNI-Call: UnregisterNatives");
+       STATISTICS(jniinvokation());
+
+       /* XXX TWISTI hmm, maybe we should not support that (like kaffe) */
+
+    log_text("JNI-Call: UnregisterNatives: IMPLEMENT ME!!!");
+
     return 0;
 }
 
@@ -3338,9 +4032,10 @@ jint UnregisterNatives (JNIEnv* env, jclass clazz)
 
 jint MonitorEnter(JNIEnv *env, jobject obj)
 {
-       STATS(jniinvokation();)
+       STATISTICS(jniinvokation());
+
        if (!obj) {
-               *exceptionptr = new_nullpointerexception();
+               exceptions_throw_nullpointerexception();
                return JNI_ERR;
        }
 
@@ -3364,9 +4059,10 @@ jint MonitorEnter(JNIEnv *env, jobject obj)
 
 jint MonitorExit(JNIEnv *env, jobject obj)
 {
-       STATS(jniinvokation();)
+       STATISTICS(jniinvokation());
+
        if (!obj) {
-               *exceptionptr = new_nullpointerexception();
+               exceptions_throw_nullpointerexception();
                return JNI_ERR;
        }
 
@@ -3390,150 +4086,201 @@ jint MonitorExit(JNIEnv *env, jobject obj)
 
 jint GetJavaVM(JNIEnv *env, JavaVM **vm)
 {
-       STATS(jniinvokation();)
+       STATISTICS(jniinvokation());
+
     *vm = &ptr_jvm;
 
        return 0;
 }
 
 
-void GetStringRegion (JNIEnv* env, jstring str, jsize start, jsize len, jchar *buf)
+void GetStringRegion(JNIEnv* env, jstring str, jsize start, jsize len, jchar *buf)
 {
-       STATS(jniinvokation();)
-       log_text("JNI-Call: GetStringRegion");
+       STATISTICS(jniinvokation());
+
+       log_text("JNI-Call: GetStringRegion: IMPLEMENT ME!");
 }
 
 
 void GetStringUTFRegion (JNIEnv* env, jstring str, jsize start, jsize len, char *buf)
 {
-       STATS(jniinvokation();)
-       log_text("JNI-Call: GetStringUTFRegion");
+       STATISTICS(jniinvokation());
+
+       log_text("JNI-Call: GetStringUTFRegion: IMPLEMENT ME!");
 }
 
 
-/************** obtain direct pointer to array elements ***********************/
+/* GetPrimitiveArrayCritical ***************************************************
 
-void * GetPrimitiveArrayCritical (JNIEnv* env, jarray array, jboolean *isCopy)
+   Obtain a direct pointer to array elements.
+
+*******************************************************************************/
+
+void *GetPrimitiveArrayCritical(JNIEnv *env, jarray array, jboolean *isCopy)
 {
-       java_objectheader *s = (java_objectheader*) array;
-       arraydescriptor *desc = s->vftbl->arraydesc;
+       java_bytearray *ba;
+       jbyte          *bp;
+
+       ba = (java_bytearray *) array;
 
-       STATS(jniinvokation();)
+       /* do the same as Kaffe does */
 
-       if (!desc) return NULL;
+       bp = GetByteArrayElements(env, ba, isCopy);
 
-       return ((u1*)s) + desc->dataoffset;
+       return (void *) bp;
 }
 
 
-void ReleasePrimitiveArrayCritical (JNIEnv* env, jarray array, void *carray, jint mode)
+/* ReleasePrimitiveArrayCritical ***********************************************
+
+   No specific documentation.
+
+*******************************************************************************/
+
+void ReleasePrimitiveArrayCritical(JNIEnv *env, jarray array, void *carray,
+                                                                  jint mode)
 {
-       STATS(jniinvokation();)
-       log_text("JNI-Call: ReleasePrimitiveArrayCritical");
+       STATISTICS(jniinvokation());
+
+       /* do the same as Kaffe does */
 
-       /* empty */
+       ReleaseByteArrayElements(env, (jbyteArray) array, (jbyte *) carray, mode);
 }
 
-/**** returns a pointer to an array of Unicode characters of the string *******/
 
-const jchar * GetStringCritical (JNIEnv* env, jstring string, jboolean *isCopy)
+/* GetStringCritical ***********************************************************
+
+   The semantics of these two functions are similar to the existing
+   Get/ReleaseStringChars functions.
+
+*******************************************************************************/
+
+const jchar *GetStringCritical(JNIEnv *env, jstring string, jboolean *isCopy)
 {
-       STATS(jniinvokation();)
-       log_text("JNI-Call: GetStringCritical");
+       STATISTICS(jniinvokation());
 
-       return GetStringChars(env,string,isCopy);
+       return GetStringChars(env, string, isCopy);
 }
 
-/*********** native code no longer needs access to chars **********************/
 
-void ReleaseStringCritical (JNIEnv* env, jstring string, const jchar *cstring)
+void ReleaseStringCritical(JNIEnv *env, jstring string, const jchar *cstring)
 {
-       STATS(jniinvokation();)
-       log_text("JNI-Call: ReleaseStringCritical");
+       STATISTICS(jniinvokation());
 
-       ReleaseStringChars(env,string,cstring);
+       ReleaseStringChars(env, string, cstring);
 }
 
 
-jweak NewWeakGlobalRef (JNIEnv* env, jobject obj)
+jweak NewWeakGlobalRef(JNIEnv* env, jobject obj)
 {
-       STATS(jniinvokation();)
-       log_text("JNI-Call: NewWeakGlobalRef");
+       STATISTICS(jniinvokation());
+
+       log_text("JNI-Call: NewWeakGlobalRef: IMPLEMENT ME!");
 
        return obj;
 }
 
 
-void DeleteWeakGlobalRef (JNIEnv* env, jweak ref)
+void DeleteWeakGlobalRef(JNIEnv* env, jweak ref)
 {
-       STATS(jniinvokation();)
-       log_text("JNI-Call: DeleteWeakGlobalRef");
+       STATISTICS(jniinvokation());
 
-       /* empty */
+       log_text("JNI-Call: DeleteWeakGlobalRef: IMPLEMENT ME");
 }
 
 
-/** Creates a new global reference to the object referred to by the obj argument **/
+/* NewGlobalRef ****************************************************************
+
+   Creates a new global reference to the object referred to by the obj
+   argument.
+
+*******************************************************************************/
     
 jobject NewGlobalRef(JNIEnv* env, jobject lobj)
 {
-       jobject refcount;
-       jint val;
-       jobject newval;
-       STATS(jniinvokation();)
+       java_lang_Integer *refcount;
+       java_objectheader *newval;
+
+       STATISTICS(jniinvokation());
 
-       MonitorEnter(env, *global_ref_table);
+#if defined(USE_THREADS)
+       builtin_monitorenter(*global_ref_table);
+#endif
        
-       refcount = CallObjectMethod(env, *global_ref_table, getmid, lobj);
-       val = (refcount == NULL) ? 0 : CallIntMethod(env, refcount, intvalue);
-       newval = NewObject(env, intclass, newint, val + 1);
+       refcount = (java_lang_Integer *)
+               asm_calljavafunction(getmid, *global_ref_table, lobj, NULL, NULL);
+
+       if (refcount == NULL) {
+               newval = native_new_and_init_int(class_java_lang_Integer, 1);
+
+               if (newval == NULL) {
+#if defined(USE_THREADS)
+                       builtin_monitorexit(*global_ref_table);
+#endif
+                       return NULL;
+               }
 
-       if (newval != NULL) {
-               CallObjectMethod(env, *global_ref_table, putmid, lobj, newval);
-               MonitorExit(env, *global_ref_table);
-               return lobj;
+               asm_calljavafunction(putmid, *global_ref_table, lobj, newval, NULL);
 
        } else {
-               log_text("JNI-NewGlobalRef: unable to create new java.lang.Integer");
-               MonitorExit(env, *global_ref_table);
-               return NULL;
+               /* we can access the object itself, as we are in a
+           synchronized section */
+
+               refcount->value++;
        }
+
+#if defined(USE_THREADS)
+       builtin_monitorexit(*global_ref_table);
+#endif
+
+       return lobj;
 }
 
-/*************  Deletes the global reference pointed to by globalRef **************/
 
-void DeleteGlobalRef(JNIEnv* env, jobject gref)
+/* DeleteGlobalRef *************************************************************
+
+   Deletes the global reference pointed to by globalRef.
+
+*******************************************************************************/
+
+void DeleteGlobalRef(JNIEnv* env, jobject globalRef)
 {
-       jobject refcount;
-       jint val;
-       STATS(jniinvokation();)
+       java_lang_Integer *refcount;
+       s4                 val;
 
-       MonitorEnter(env, *global_ref_table);
-       refcount = CallObjectMethod(env, *global_ref_table, getmid, gref);
+       STATISTICS(jniinvokation());
+
+#if defined(USE_THREADS)
+       builtin_monitorenter(*global_ref_table);
+#endif
+
+       refcount = (java_lang_Integer *)
+               asm_calljavafunction(getmid, *global_ref_table, globalRef, NULL, NULL);
 
        if (refcount == NULL) {
                log_text("JNI-DeleteGlobalRef: unable to find global reference");
                return;
        }
 
-       val = CallIntMethod(env, refcount, intvalue);
-       val--;
+       /* we can access the object itself, as we are in a synchronized
+          section */
+
+       val = refcount->value - 1;
 
        if (val == 0) {
-               CallObjectMethod(env, *global_ref_table, removemid,refcount);
+               asm_calljavafunction(removemid, *global_ref_table, refcount, NULL,
+                                                        NULL);
 
        } else {
-               jobject newval = NewObject(env, intclass, newint, val);
+               /* we do not create a new object, but set the new value into
+           the old one */
 
-               if (newval != NULL) {
-                       CallObjectMethod(env,*global_ref_table, putmid,newval);
-
-               } else {
-                       log_text("JNI-DeleteGlobalRef: unable to create new java.lang.Integer");
-               }
+               refcount->value = val;
        }
 
-       MonitorExit(env,*global_ref_table);
+#if defined(USE_THREADS)
+       builtin_monitorexit(*global_ref_table);
+#endif
 }
 
 
@@ -3546,7 +4293,8 @@ void DeleteGlobalRef(JNIEnv* env, jobject gref)
 
 jboolean ExceptionCheck(JNIEnv *env)
 {
-       STATS(jniinvokation();)
+       STATISTICS(jniinvokation());
+
        return *exceptionptr ? JNI_TRUE : JNI_FALSE;
 }
 
@@ -3563,10 +4311,56 @@ jboolean ExceptionCheck(JNIEnv *env)
 
 jobject NewDirectByteBuffer(JNIEnv *env, void *address, jlong capacity)
 {
-       STATS(jniinvokation();)
-       log_text("NewDirectByteBuffer: IMPLEMENT ME!");
+       java_objectheader *nbuf;
+#if SIZEOF_VOID_P == 8
+       gnu_classpath_Pointer64 *paddress;
+#else
+       gnu_classpath_Pointer32 *paddress;
+#endif
 
-       return NULL;
+       STATISTICS(jniinvokation());
+
+       log_text("JNI-NewDirectByteBuffer: called");
+
+#if 0
+       /* allocate a java.nio.DirectByteBufferImpl$ReadWrite object */
+
+       if (!(nbuf = (java_nio_DirectByteBufferImpl$ReadWrite *)
+                 builtin_new(class_java_nio_DirectByteBufferImpl_ReadWrite)))
+               return NULL;
+#endif
+
+       /* alocate a gnu.classpath.Pointer{32,64} object */
+
+#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 */
+
+       paddress->data = (ptrint) address;
+
+#if 0
+       /* fill java.nio.Buffer object */
+
+       nbuf->cap     = (s4) capacity;
+       nbuf->limit   = (s4) capacity;
+       nbuf->pos     = 0;
+       nbuf->address = (gnu_classpath_Pointer *) paddress;
+#endif
+
+       nbuf = (*env)->NewObject(env, class_java_nio_DirectByteBufferImpl_ReadWrite,
+                                                        dbbirw_init, NULL, paddress,
+                                                        (jint) capacity, (jint) capacity, (jint) 0);
+
+       /* add local reference and return the value */
+
+       return NewLocalRef(env, nbuf);
 }
 
 
@@ -3579,10 +4373,29 @@ jobject NewDirectByteBuffer(JNIEnv *env, void *address, jlong capacity)
 
 void *GetDirectBufferAddress(JNIEnv *env, jobject buf)
 {
-       STATS(jniinvokation();)
-       log_text("GetDirectBufferAddress: IMPLEMENT ME!");
+       java_nio_DirectByteBufferImpl *nbuf;
+#if SIZEOF_VOID_P == 8
+       gnu_classpath_Pointer64       *address;
+#else
+       gnu_classpath_Pointer32       *address;
+#endif
 
-       return NULL;
+       STATISTICS(jniinvokation());
+
+#if 0
+       if (!builtin_instanceof(buf, class_java_nio_DirectByteBufferImpl))
+               return NULL;
+#endif
+
+       nbuf = (java_nio_DirectByteBufferImpl *) buf;
+
+#if SIZEOF_VOID_P == 8
+       address = (gnu_classpath_Pointer64 *) nbuf->address;
+#else
+       address = (gnu_classpath_Pointer32 *) nbuf->address;
+#endif
+
+       return (void *) address->data;
 }
 
 
@@ -3595,17 +4408,24 @@ void *GetDirectBufferAddress(JNIEnv *env, jobject buf)
 
 jlong GetDirectBufferCapacity(JNIEnv* env, jobject buf)
 {
-       STATS(jniinvokation();)
-       log_text("GetDirectBufferCapacity: IMPLEMENT ME!");
+       java_nio_Buffer *nbuf;
 
-       return 0;
+       STATISTICS(jniinvokation());
+
+       if (buf == NULL)
+               return -1;
+
+       nbuf = (java_nio_Buffer *) buf;
+
+       return (jlong) nbuf->cap;
 }
 
 
 jint DestroyJavaVM(JavaVM *vm)
 {
-       STATS(jniinvokation();)
-       log_text("DestroyJavaVM called");
+       STATISTICS(jniinvokation());
+
+       log_text("JNI-Call: DestroyJavaVM: IMPLEMENT ME!");
 
        return 0;
 }
@@ -3627,8 +4447,9 @@ jint DestroyJavaVM(JavaVM *vm)
 
 jint AttachCurrentThread(JavaVM *vm, void **env, void *thr_args)
 {
-       STATS(jniinvokation();)
-       log_text("AttachCurrentThread called");
+       STATISTICS(jniinvokation());
+
+       log_text("JNI-Call: AttachCurrentThread: IMPLEMENT ME!");
 
 #if !defined(HAVE___THREAD)
 /*     cacao_thread_attach();*/
@@ -3644,146 +4465,65 @@ jint AttachCurrentThread(JavaVM *vm, void **env, void *thr_args)
 
 jint DetachCurrentThread(JavaVM *vm)
 {
-       STATS(jniinvokation();)
-       log_text("DetachCurrentThread called");
+       STATISTICS(jniinvokation());
+
+       log_text("JNI-Call: DetachCurrentThread: IMPLEMENT ME!");
 
        return 0;
 }
 
 
-jint GetEnv(JavaVM *vm, void **env, jint version)
-{
-       STATS(jniinvokation();)
-       if ((version != JNI_VERSION_1_1) && (version != JNI_VERSION_1_2) &&
-               (version != JNI_VERSION_1_4)) {
-               *env = NULL;
-               return JNI_EVERSION;
-       }
-
-       /*
-         TODO: If the current thread is not attached to the VM...
-       if (0) {
-               *env = NULL;
-               return JNI_EDETACHED;
-       }
-       */
+/* GetEnv **********************************************************************
 
-       *env = &ptr_env;
-
-       return JNI_OK;
-}
+   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 AttachCurrentThreadAsDaemon(JavaVM *vm, void **par1, void *par2)
+jint GetEnv(JavaVM *vm, void **env, jint version)
 {
-       STATS(jniinvokation();)
-       log_text("AttachCurrentThreadAsDaemon called");
-
-       return 0;
-}
+       STATISTICS(jniinvokation());
 
-/************* JNI Initialization ****************************************************/
+#if defined(USE_THREADS) && defined(NATIVE_THREADS)
+       if (thread_getself() == NULL) {
+               *env = NULL;
 
-jobject jni_init1(JNIEnv* env, jobject lobj) {
-#if defined(USE_THREADS)
-       while (initrunning) {yieldThread();} /* wait until init is done */
-#endif
-       if (global_ref_table == NULL) {
-               jni_init();
-       } 
-#if defined(USE_THREADS)
-       else {
-               /* wait until jni_init is done */
-               MonitorEnter(env, *global_ref_table) ;
-               MonitorExit(env, *global_ref_table);
-       }
-#endif
-       return NewGlobalRef(env, lobj); 
-}
-void jni_init2(JNIEnv* env, jobject gref) {
-       log_text("DeleteGlobalref called before NewGlobalref");
-#if defined(USE_THREADS)
-       while (initrunning) {yieldThread();} /* wait until init is done */
-#endif
-       if (global_ref_table == NULL) {
-               jni_init();
-       } 
-#if defined(USE_THREADS)
-       else {
-               /* wait until jni_init is done */
-               MonitorEnter(env, *global_ref_table) ;
-               MonitorExit(env, *global_ref_table);
+               return JNI_EDETACHED;
        }
 #endif
-       DeleteGlobalRef(env, gref); 
-}
-
-void jni_init(){
-       jmethodID mid;
-
-       initrunning = true;
-       log_text("JNI-Init: initialize global_ref_table");
-       /* initalize global reference table */
-       ihmclass = FindClass(NULL, "java/util/IdentityHashMap");
-       
-       if (ihmclass == NULL) {
-               log_text("JNI-Init: unable to find java.util.IdentityHashMap");
-       }
-
-       mid = GetMethodID(NULL, ihmclass, "<init>","()V");
-       if (mid == NULL) {
-               log_text("JNI-Init: unable to find constructor in java.util.IdentityHashMap");
-       }
-       
-       global_ref_table = (jobject*)heap_allocate(sizeof(jobject),true,NULL);
 
-       *global_ref_table = NewObject(NULL,ihmclass,mid);
+       if ((version == JNI_VERSION_1_1) || (version == JNI_VERSION_1_2) ||
+               (version == JNI_VERSION_1_4)) {
+               *env = &ptr_env;
 
-       if (*global_ref_table == NULL) {
-               log_text("JNI-Init: unable to create new global_ref_table");
+               return JNI_OK;
        }
 
-       initrunning = false;
+#if defined(ENABLE_JVMTI)
+       if (version == JVMTI_VERSION_1_0) {
+               *env = (void *) new_jvmtienv();
 
-       getmid = GetMethodID(NULL, ihmclass, "get","(Ljava/lang/Object;)Ljava/lang/Object;");
-       if (mid == NULL) {
-               log_text("JNI-Init: unable to find method \"get\" in java.util.IdentityHashMap");
+               if (env != NULL)
+                       return JNI_OK;
        }
+#endif
+       
+       *env = NULL;
 
-       getmid = GetMethodID(NULL ,ihmclass, "get","(Ljava/lang/Object;)Ljava/lang/Object;");
-       if (getmid == NULL) {
-               log_text("JNI-Init: unable to find method \"get\" in java.util.IdentityHashMap");
-       }
+       return JNI_EVERSION;
+}
 
-       putmid = GetMethodID(NULL, ihmclass, "put","(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
-       if (putmid == NULL) {
-               log_text("JNI-Init: unable to find method \"put\" in java.util.IdentityHashMap");
-       }
 
-       intclass = FindClass(NULL, "java/lang/Integer");
-       if (intclass == NULL) {
-               log_text("JNI-Init: unable to find java.lang.Integer");
-       }
 
-       newint = GetMethodID(NULL, intclass, "<init>","(I)V");
-       if (newint == NULL) {
-               log_text("JNI-Init: unable to find constructor in java.lang.Integer");
-       }
+jint AttachCurrentThreadAsDaemon(JavaVM *vm, void **par1, void *par2)
+{
+       STATISTICS(jniinvokation());
 
-       intvalue = GetMethodID(NULL, intclass, "intValue","()I");
-       if (intvalue == NULL) {
-               log_text("JNI-Init: unable to find method \"intValue\" in java.lang.Integer");
-       }
+       log_text("JNI-Call: AttachCurrentThreadAsDaemon: IMPLEMENT ME!");
 
-       removemid = GetMethodID(NULL, ihmclass, "remove","(Ljava/lang/Object;)Ljava/lang/Object;");
-       if (removemid == NULL) {
-               log_text("JNI-DeleteGlobalRef: unable to find method \"remove\" in java.lang.Object");
-       }
-       
-       /* set NewGlobalRef, DeleteGlobalRef envTable entry to real implementation */
-
-       JNI_JNIEnvTable.NewGlobalRef = &NewGlobalRef;
-       JNI_JNIEnvTable.DeleteGlobalRef = &DeleteGlobalRef;
+       return 0;
 }
 
 
@@ -3829,8 +4569,8 @@ struct JNINativeInterface JNI_JNIEnvTable = {
        &PushLocalFrame,
        &PopLocalFrame,
 
-       &jni_init1, /* &NewGlobalRef,    initialize Global_Ref_Table*/
-       &jni_init2, /* &DeleteGlobalRef,*/
+       &NewGlobalRef,
+       &DeleteGlobalRef,
        &DeleteLocalRef,
        &IsSameObject,
        &NewLocalRef,
@@ -4121,8 +4861,14 @@ jint JNI_GetCreatedJavaVMs(JavaVM **vmBuf, jsize bufLen, jsize *nVMs)
 
 jint JNI_CreateJavaVM(JavaVM **p_vm, JNIEnv **p_env, void *vm_args)
 {
-       *p_vm = (JavaVM *) &JNI_JavaVMTable;
-       *p_env = (JNIEnv *) &JNI_JNIEnvTable;
+       const struct JNIInvokeInterface *vm;
+       struct JNINativeInterface *env;
+
+       vm = &JNI_JavaVMTable;
+       env = &JNI_JNIEnvTable;
+
+       *p_vm = (JavaVM *) vm;
+       *p_env = (JNIEnv *) env;
 
        return 0;
 }
@@ -4134,6 +4880,7 @@ jobject *jni_method_invokeNativeHelper(JNIEnv *env, methodinfo *methodID,
        jni_callblock *blk;
        jobject        o;
        s4             argcount;
+       s4             paramcount;
 
        if (methodID == 0) {
                *exceptionptr = new_exception(string_java_lang_NoSuchMethodError); 
@@ -4141,11 +4888,12 @@ jobject *jni_method_invokeNativeHelper(JNIEnv *env, methodinfo *methodID,
        }
 
        argcount = methodID->parseddesc->paramcount;
+       paramcount = argcount;
 
        /* if method is non-static, remove the `this' pointer */
 
        if (!(methodID->flags & ACC_STATIC))
-               argcount--;
+               paramcount--;
 
        /* the method is an instance method the obj has to be an instance of the 
           class the method belongs to. For static methods the obj parameter
@@ -4159,17 +4907,8 @@ jobject *jni_method_invokeNativeHelper(JNIEnv *env, methodinfo *methodID,
                return NULL;
        }
 
-
-#ifdef arglimit
-       if (argcount > 3) {
-               *exceptionptr = new_exception(string_java_lang_IllegalArgumentException);
-               log_text("Too many arguments. invokeNativeHelper does not support that");
-               return NULL;
-       }
-#endif
-
-       if (((params == NULL) && (argcount != 0)) ||
-               (params && (params->header.size != argcount))) {
+       if (((params == NULL) && (paramcount != 0)) ||
+               (params && (params->header.size != paramcount))) {
                *exceptionptr =
                        new_exception(string_java_lang_IllegalArgumentException);
                return NULL;
@@ -4193,7 +4932,7 @@ jobject *jni_method_invokeNativeHelper(JNIEnv *env, methodinfo *methodID,
                }
        }
 
-       blk = MNEW(jni_callblock, /*4 */argcount + 2);
+       blk = MNEW(jni_callblock, argcount);
 
        if (!fill_callblock_from_objectarray(obj, methodID->parseddesc, blk,
                                                                                 params))
@@ -4201,16 +4940,16 @@ jobject *jni_method_invokeNativeHelper(JNIEnv *env, methodinfo *methodID,
 
        switch (methodID->parseddesc->returntype.decltype) {
        case TYPE_VOID:
-               (void) asm_calljavafunction2(methodID, argcount + 1,
-                                                                        (argcount + 1) * sizeof(jni_callblock),
+               (void) asm_calljavafunction2(methodID, argcount,
+                                                                        argcount * sizeof(jni_callblock),
                                                                         blk);
                o = NULL; /*native_new_and_init(loader_load(utf_new_char("java/lang/Void")));*/
                break;
 
        case PRIMITIVETYPE_INT: {
                s4 i;
-               i = asm_calljavafunction2int(methodID, argcount + 1,
-                                                                        (argcount + 1) * sizeof(jni_callblock),
+               i = asm_calljavafunction2int(methodID, argcount,
+                                                                        argcount * sizeof(jni_callblock),
                                                                         blk);
 
                o = native_new_and_init_int(class_java_lang_Integer, i);
@@ -4219,8 +4958,8 @@ jobject *jni_method_invokeNativeHelper(JNIEnv *env, methodinfo *methodID,
 
        case PRIMITIVETYPE_BYTE: {
                s4 i;
-               i = asm_calljavafunction2int(methodID, argcount + 1,
-                                                                        (argcount + 1) * sizeof(jni_callblock),
+               i = asm_calljavafunction2int(methodID, argcount,
+                                                                        argcount * sizeof(jni_callblock),
                                                                         blk);
 
 /*             o = native_new_and_init_int(class_java_lang_Byte, i); */
@@ -4237,8 +4976,8 @@ jobject *jni_method_invokeNativeHelper(JNIEnv *env, methodinfo *methodID,
        case PRIMITIVETYPE_CHAR: {
                s4 intVal;
                intVal = asm_calljavafunction2int(methodID,
-                                                                                 argcount + 1,
-                                                                                 (argcount + 1) * sizeof(jni_callblock),
+                                                                                 argcount,
+                                                                                 argcount * sizeof(jni_callblock),
                                                                                  blk);
                o = builtin_new(class_java_lang_Character);
                CallVoidMethod(env,
@@ -4253,8 +4992,8 @@ jobject *jni_method_invokeNativeHelper(JNIEnv *env, methodinfo *methodID,
        case PRIMITIVETYPE_SHORT: {
                s4 intVal;
                intVal = asm_calljavafunction2int(methodID,
-                                                                                 argcount + 1,
-                                                                                 (argcount + 1) * sizeof(jni_callblock),
+                                                                                 argcount,
+                                                                                 argcount * sizeof(jni_callblock),
                                                                                  blk);
                o = builtin_new(class_java_lang_Short);
                CallVoidMethod(env,
@@ -4269,8 +5008,8 @@ jobject *jni_method_invokeNativeHelper(JNIEnv *env, methodinfo *methodID,
        case PRIMITIVETYPE_BOOLEAN: {
                s4 intVal;
                intVal = asm_calljavafunction2int(methodID,
-                                                                                 argcount + 1,
-                                                                                 (argcount + 1) * sizeof(jni_callblock),
+                                                                                 argcount,
+                                                                                 argcount * sizeof(jni_callblock),
                                                                                  blk);
                o = builtin_new(class_java_lang_Boolean);
                CallVoidMethod(env,
@@ -4282,11 +5021,11 @@ jobject *jni_method_invokeNativeHelper(JNIEnv *env, methodinfo *methodID,
        }
        break;
 
-       case 'J': {
+       case PRIMITIVETYPE_LONG: {
                jlong longVal;
                longVal = asm_calljavafunction2long(methodID,
-                                                                                       argcount + 1,
-                                                                                       (argcount + 1) * sizeof(jni_callblock),
+                                                                                       argcount,
+                                                                                       argcount * sizeof(jni_callblock),
                                                                                        blk);
                o = builtin_new(class_java_lang_Long);
                CallVoidMethod(env,
@@ -4301,8 +5040,8 @@ jobject *jni_method_invokeNativeHelper(JNIEnv *env, methodinfo *methodID,
        case PRIMITIVETYPE_FLOAT: {
                jdouble floatVal;       
                floatVal = asm_calljavafunction2float(methodID,
-                                                                                         argcount + 1,
-                                                                                         (argcount + 1) * sizeof(jni_callblock),
+                                                                                         argcount,
+                                                                                         argcount * sizeof(jni_callblock),
                                                                                          blk);
                o = builtin_new(class_java_lang_Float);
                CallVoidMethod(env,
@@ -4317,8 +5056,8 @@ jobject *jni_method_invokeNativeHelper(JNIEnv *env, methodinfo *methodID,
        case PRIMITIVETYPE_DOUBLE: {
                jdouble doubleVal;
                doubleVal = asm_calljavafunction2double(methodID,
-                                                                                               argcount + 1,
-                                                                                               (argcount + 1) * sizeof(jni_callblock),
+                                                                                               argcount,
+                                                                                               argcount * sizeof(jni_callblock),
                                                                                                blk);
                o = builtin_new(class_java_lang_Double);
                CallVoidMethod(env,
@@ -4331,19 +5070,19 @@ jobject *jni_method_invokeNativeHelper(JNIEnv *env, methodinfo *methodID,
        break;
 
        case TYPE_ADR:
-               o = asm_calljavafunction2(methodID, argcount + 1,
-                                                                 (argcount + 1) * sizeof(jni_callblock), blk);
+               o = asm_calljavafunction2(methodID, argcount,
+                                                                 argcount * sizeof(jni_callblock), blk);
                break;
 
        default:
                /* if this happens the exception has already been set by              */
                /* fill_callblock_from_objectarray                                    */
 
-               MFREE(blk, jni_callblock, /*4 */ argcount+2);
+               MFREE(blk, jni_callblock, argcount);
                return (jobject *) 0;
        }
 
-       MFREE(blk, jni_callblock, /* 4 */ argcount+2);
+       MFREE(blk, jni_callblock, argcount);
 
        if (*exceptionptr) {
                java_objectheader *cause;