array out of memory fixlet, InvocationTargetException handling, less debug output...
[cacao.git] / jni.c
diff --git a/jni.c b/jni.c
index ab99dfe3d3df70a6c301d290104f46cf0acee518..d4e66641bd81da68f2923bce2a3e95a0b400eb0f 100644 (file)
--- a/jni.c
+++ b/jni.c
@@ -1,10 +1,39 @@
-/********************************** jni.c *****************************************
+/* jni.c - implementation of the Java Native Interface functions
 
-       implementation of the Java Native Interface functions                             
-       which are used in the JNI function table                                         
+   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
+   R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser,
+   M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck,
+   P. Tomsich, J. Wenninger
 
-***********************************************************************************/
+   This file is part of CACAO.
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2, or (at
+   your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+   02111-1307, USA.
+
+   Contact: cacao@complang.tuwien.ac.at
+
+   Authors: ?
+
+   Changes: Joseph Wenninger
+
+   $Id: jni.c 718 2003-12-08 13:03:43Z jowenn $
+
+*/
 
+
+#include <string.h>
 #include "jni.h"
 #include "global.h"
 #include "loader.h"
@@ -12,6 +41,8 @@
 #include "native.h"
 #include "builtin.h"
 #include "threads/thread.h"
+#include "toolbox/loging.h"
+#include "toolbox/memory.h"
 #include "nat/java_lang_Byte.h"
 #include "nat/java_lang_Character.h"
 #include "nat/java_lang_Short.h"
 #define JNI_VERSION       0x00010002
 
 
-static utf* utf_char=0;
-static utf* utf_bool=0;
-static utf* utf_byte=0;
-static utf* utf_short=0;
-static utf* utf_int=0;
-static utf* utf_long=0;
-static utf* utf_float=0;
-static utf* utf_double=0;
+static utf* utf_char = 0;
+static utf* utf_bool = 0;
+static utf* utf_byte  =0;
+static utf* utf_short = 0;
+static utf* utf_int = 0;
+static utf* utf_long = 0;
+static utf* utf_float = 0;
+static utf* utf_double = 0;
+
 
 /********************* accessing instance-fields **********************************/
 
@@ -217,6 +249,10 @@ char fill_callblock_objA(void *obj, utf *descr, jni_callblock blk[], java_object
                switch (utf_nextu2(utf_ptr)) {
                case 'B':       
                                param=params->data[cnts];
+                               if (param==0) {
+                                       exceptionptr=native_new_and_init(loader_load(utf_new_char("java/lang/IllegalArgumentException")));
+                                       return 0;
+                               }
                                if (param->vftbl->class->name==utf_byte) {
                                        blk[cnt].itemtype=TYPE_INT;
                                        blk[cnt].item = (u8) ((struct java_lang_Byte * )param)->value;
@@ -227,6 +263,10 @@ char fill_callblock_objA(void *obj, utf *descr, jni_callblock blk[], java_object
                                break;
                case 'C':
                                param=params->data[cnts];
+                               if (param==0) {
+                                       exceptionptr=native_new_and_init(loader_load(utf_new_char("java/lang/IllegalArgumentException")));
+                                       return 0;
+                               }
                                if (param->vftbl->class->name==utf_char) {
                                        blk[cnt].itemtype=TYPE_INT;
                                        blk[cnt].item = (u8) ((struct java_lang_Character * )param)->value;
@@ -238,6 +278,10 @@ char fill_callblock_objA(void *obj, utf *descr, jni_callblock blk[], java_object
 
                case 'S': 
                                param=params->data[cnts];
+                               if (param==0) {
+                                       exceptionptr=native_new_and_init(loader_load(utf_new_char("java/lang/IllegalArgumentException")));
+                                       return 0;
+                               }
                                if (param->vftbl->class->name==utf_short) {
                                        blk[cnt].itemtype=TYPE_INT;
                                        blk[cnt].item = (u8) ((struct java_lang_Short* )param)->value;
@@ -254,6 +298,10 @@ char fill_callblock_objA(void *obj, utf *descr, jni_callblock blk[], java_object
 
                case 'Z':
                                param=params->data[cnts];
+                               if (param==0) {
+                                       exceptionptr=native_new_and_init(loader_load(utf_new_char("java/lang/IllegalArgumentException")));
+                                       return 0;
+                               }
                                if (param->vftbl->class->name==utf_bool) {
                                        blk[cnt].itemtype=TYPE_INT;
                                        blk[cnt].item = (u8) ((struct java_lang_Boolean * )param)->value;
@@ -264,8 +312,12 @@ char fill_callblock_objA(void *obj, utf *descr, jni_callblock blk[], java_object
                                break;
 
                case 'I':
-                               log_text("fill_callblock_objA: param 'I'");
+                               /*log_text("fill_callblock_objA: param 'I'");*/
                                param=params->data[cnts];
+                               if (param==0) {
+                                       exceptionptr=native_new_and_init(loader_load(utf_new_char("java/lang/IllegalArgumentException")));
+                                       return 0;
+                               }
                                if (param->vftbl->class->name==utf_int) {
                                        blk[cnt].itemtype=TYPE_INT;
                                        blk[cnt].item = (u8) ((struct java_lang_Integer * )param)->value;
@@ -288,6 +340,10 @@ char fill_callblock_objA(void *obj, utf *descr, jni_callblock blk[], java_object
                                break;
                case 'J':
                                param=params->data[cnts];
+                               if (param==0) {
+                                       exceptionptr=native_new_and_init(loader_load(utf_new_char("java/lang/IllegalArgumentException")));
+                                       return 0;
+                               }
                                if (param->vftbl->class->name==utf_long) {
                                        blk[cnt].itemtype=TYPE_LNG;
                                        blk[cnt].item = (u8) ((struct java_lang_Long * )param)->value;
@@ -315,6 +371,11 @@ char fill_callblock_objA(void *obj, utf *descr, jni_callblock blk[], java_object
 
                case 'F' : 
                                param=params->data[cnts];
+                               if (param==0) {
+                                       exceptionptr=native_new_and_init(loader_load(utf_new_char("java/lang/IllegalArgumentException")));
+                                       return 0;
+                               }
+
                                if (param->vftbl->class->name==utf_float) {
                                        blk[cnt].itemtype=TYPE_FLT;
                                        *((jfloat*)(&blk[cnt].item))=(jfloat) ((struct java_lang_Float*)param)->value;
@@ -325,6 +386,11 @@ char fill_callblock_objA(void *obj, utf *descr, jni_callblock blk[], java_object
                                break;
                case 'D' : 
                                param=params->data[cnts];
+                               if (param==0) {
+                                       exceptionptr=native_new_and_init(loader_load(utf_new_char("java/lang/IllegalArgumentException")));
+                                       return 0;
+                               }
+
                                if (param->vftbl->class->name==utf_double) {
                                        blk[cnt].itemtype=TYPE_DBL;
                                        *((jdouble*)(&blk[cnt].item))=(jdouble) ((struct java_lang_Float*)param)->value;
@@ -432,36 +498,41 @@ jobject callObjectMethod (jobject obj, jmethodID methodID, va_list args)
          printf("\n");
        */
 
-       if (methodID==0) {
+       if (methodID == 0) {
                exceptionptr = native_new_and_init(class_java_lang_NoSuchMethodError); 
                return 0;
        }
-        argcount=get_parametercount(methodID);
 
-       if (!( ((methodID->flags & ACC_STATIC) && (obj==0)) ||
-               ((!(methodID->flags & ACC_STATIC)) && (obj!=0)) )) {
+       argcount = get_parametercount(methodID);
+
+       if (!( ((methodID->flags & ACC_STATIC) && (obj == 0)) ||
+               ((!(methodID->flags & ACC_STATIC)) && (obj != 0)) )) {
                exceptionptr = native_new_and_init(class_java_lang_NoSuchMethodError);
                return 0;
        }
        
-       if (obj && (! builtin_instanceof(obj,methodID->class))) {
+       if (obj && !builtin_instanceof(obj, methodID->class)) {
                exceptionptr = native_new_and_init(class_java_lang_NoSuchMethodError);
                return 0;
        }
 
-       if  (argcount>3) {
-               exceptionptr=native_new_and_init(loader_load(utf_new_char("java/lang/IllegalArgumentException")));
+       if (argcount > 3) {
+               exceptionptr = native_new_and_init(loader_load(utf_new_char("java/lang/IllegalArgumentException")));
                log_text("Too many arguments. CallObjectMethod does not support that");
                return 0;
        }
 
        blk = MNEW(jni_callblock, 4 /*argcount+2*/);
 
-       fill_callblock(obj,methodID->descriptor,blk,args,'O');
+       fill_callblock(obj, methodID->descriptor, blk, args, 'O');
 
        /*      printf("parameter: obj: %p",blk[0].item); */
-       ret=asm_calljavafunction2(methodID,argcount+1,(argcount+1)*sizeof(jni_callblock),blk);
-       MFREE(blk,jni_callblock,argcount+1);
+       ret = asm_calljavafunction2(methodID,
+                                                               argcount + 1,
+                                                               (argcount + 1) * sizeof(jni_callblock),
+                                                               blk);
+
+       MFREE(blk, jni_callblock, argcount + 1);
        /*      printf("(CallObjectMethodV)-->%p\n",ret); */
        return ret;
 }
@@ -494,20 +565,20 @@ jint callIntegerMethod(jobject obj, jmethodID methodID, char retType, va_list ar
         
        argcount = get_parametercount(methodID);
 
-       if (!( ((methodID->flags & ACC_STATIC) && (obj==0)) ||
-               ((!(methodID->flags & ACC_STATIC)) && (obj!=0)) )) {
+       if (!( ((methodID->flags & ACC_STATIC) && (obj == 0)) ||
+               ((!(methodID->flags & ACC_STATIC)) && (obj != 0)) )) {
                exceptionptr = native_new_and_init(class_java_lang_NoSuchMethodError);
                return 0;
        }
 
-       if (obj && (! builtin_instanceof(obj,methodID->class))) {
+       if (obj && !builtin_instanceof(obj, methodID->class)) {
                exceptionptr = native_new_and_init(class_java_lang_NoSuchMethodError);
                return 0;
        }
 
 
-       if  (argcount>3) {
-               exceptionptr=native_new_and_init(loader_load(utf_new_char("java/lang/IllegalArgumentException")));
+       if (argcount > 3) {
+               exceptionptr = native_new_and_init(loader_load(utf_new_char("java/lang/IllegalArgumentException")));
                log_text("Too many arguments. CallObjectMethod does not support that");
                return 0;
        }
@@ -544,37 +615,42 @@ jlong callLongMethod(jobject obj, jmethodID methodID, va_list args)
         utf_display(obj->vftbl->class->name);
         printf("\n");
         */
-       if (methodID==0) {
+       if (methodID == 0) {
                exceptionptr = native_new_and_init(class_java_lang_NoSuchMethodError); 
                return 0;
        }
-       argcount=get_parametercount(methodID);
 
-       if (!( ((methodID->flags & ACC_STATIC) && (obj==0)) ||
+       argcount = get_parametercount(methodID);
+
+       if (!( ((methodID->flags & ACC_STATIC) && (obj == 0)) ||
                   ((!(methodID->flags & ACC_STATIC)) && (obj!=0)) )) {
                exceptionptr = native_new_and_init(class_java_lang_NoSuchMethodError);
                return 0;
        }
 
-       if (obj && (! builtin_instanceof(obj,methodID->class))) {
+       if (obj && !builtin_instanceof(obj,methodID->class)) {
                exceptionptr = native_new_and_init(class_java_lang_NoSuchMethodError);
                return 0;
        }
 
 
-       if  (argcount>3) {
-               exceptionptr=native_new_and_init(loader_load(utf_new_char("java/lang/IllegalArgumentException")));
+       if (argcount > 3) {
+               exceptionptr = native_new_and_init(loader_load(utf_new_char("java/lang/IllegalArgumentException")));
                log_text("Too many arguments. CallObjectMethod does not support that");
                return 0;
        }
 
        blk = MNEW(jni_callblock, 4 /*argcount+2*/);
 
-       fill_callblock(obj,methodID->descriptor,blk,args,'L');
+       fill_callblock(obj, methodID->descriptor, blk, args, 'L');
 
        /*      printf("parameter: obj: %p",blk[0].item); */
-       ret=asm_calljavafunction2long(methodID,argcount+1,(argcount+1)*sizeof(jni_callblock),blk);
-       MFREE(blk,jni_callblock,argcount+1);
+       ret = asm_calljavafunction2long(methodID,
+                                                                       argcount + 1,
+                                                                       (argcount + 1) * sizeof(jni_callblock),
+                                                                       blk);
+
+       MFREE(blk, jni_callblock, argcount + 1);
        /*      printf("(CallObjectMethodV)-->%p\n",ret); */
 
        return ret;
@@ -582,9 +658,9 @@ jlong callLongMethod(jobject obj, jmethodID methodID, va_list args)
 
 
 /*core function for float class methods (float,double)*/
-jdouble callFloatMethod (jobject obj, jmethodID methodID, va_list args,char retType)
+jdouble callFloatMethod(jobject obj, jmethodID methodID, va_list args,char retType)
 {
-       int argcount=get_parametercount(methodID);
+       int argcount = get_parametercount(methodID);
        jni_callblock *blk;
        jdouble ret;
 
@@ -596,19 +672,24 @@ jdouble callFloatMethod (jobject obj, jmethodID methodID, va_list args,char retT
         utf_display(obj->vftbl->class->name);
         printf("\n");
         */
-       if  (argcount>3) {
-               exceptionptr=native_new_and_init(loader_load(utf_new_char("java/lang/IllegalArgumentException")));
+
+       if (argcount > 3) {
+               exceptionptr = native_new_and_init(loader_load(utf_new_char("java/lang/IllegalArgumentException")));
                log_text("Too many arguments. CallObjectMethod does not support that");
                return 0;
        }
 
        blk = MNEW(jni_callblock, 4 /*argcount+2*/);
 
-       fill_callblock(obj,methodID->descriptor,blk,args,retType);
+       fill_callblock(obj, methodID->descriptor, blk, args, retType);
 
        /*      printf("parameter: obj: %p",blk[0].item); */
-       ret=asm_calljavafunction2double(methodID,argcount+1,(argcount+1)*sizeof(jni_callblock),blk);
-       MFREE(blk,jni_callblock,argcount+1);
+       ret = asm_calljavafunction2double(methodID,
+                                                                         argcount + 1,
+                                                                         (argcount + 1) * sizeof(jni_callblock),
+                                                                         blk);
+
+       MFREE(blk, jni_callblock, argcount + 1);
        /*      printf("(CallObjectMethodV)-->%p\n",ret); */
 
        return ret;
@@ -952,8 +1033,11 @@ jobject NewObjectA(JNIEnv* env, jclass clazz, jmethodID methodID, jvalue *args)
 jclass GetObjectClass(JNIEnv* env, jobject obj)
 {
        classinfo *c = obj->vftbl->class;
+/*     log_text("GetObjectClass");
+       utf_display(obj->vftbl->class->name);*/
        use_class_as_object(c);
 
+       /*printf("\nPointer: %p\n",c);*/
        return c;
 }
 
@@ -2329,11 +2413,12 @@ jsize GetArrayLength (JNIEnv *env, jarray array)
 
 jobjectArray NewObjectArray (JNIEnv *env, jsize len, jclass clazz, jobject init)
 {
+       java_objectarray *j;
     if (len<0) {
                exceptionptr=proto_java_lang_NegativeArraySizeException;
                return NULL;
     }
-    java_objectarray *j = builtin_anewarray (len, clazz);
+    j = builtin_anewarray (len, clazz);
     if (!j) exceptionptr = proto_java_lang_OutOfMemoryError;
     return j;
 }
@@ -2369,11 +2454,12 @@ void SetObjectArrayElement (JNIEnv *env, jobjectArray array, jsize index, jobjec
 
 jbooleanArray NewBooleanArray (JNIEnv *env, jsize len)
 {
+       java_booleanarray *j;
     if (len<0) {
                exceptionptr=proto_java_lang_NegativeArraySizeException;
                return NULL;
     }
-    java_booleanarray *j = builtin_newarray_boolean(len);
+    j = builtin_newarray_boolean(len);
     if (!j) exceptionptr = proto_java_lang_OutOfMemoryError;
     return j;
 }
@@ -2381,11 +2467,12 @@ jbooleanArray NewBooleanArray (JNIEnv *env, jsize len)
 
 jbyteArray NewByteArray (JNIEnv *env, jsize len)
 {
+       java_bytearray *j;
     if (len<0) {
                exceptionptr=proto_java_lang_NegativeArraySizeException;
                return NULL;
     }
-    java_bytearray *j = builtin_newarray_byte(len);
+    j = builtin_newarray_byte(len);
     if (!j) exceptionptr = proto_java_lang_OutOfMemoryError;
     return j;
 }
@@ -2393,11 +2480,12 @@ jbyteArray NewByteArray (JNIEnv *env, jsize len)
 
 jcharArray NewCharArray (JNIEnv *env, jsize len)
 {
+       java_chararray *j;
     if (len<0) {
                exceptionptr=proto_java_lang_NegativeArraySizeException;
                return NULL;
     }
-    java_chararray *j = builtin_newarray_char(len);
+    j = builtin_newarray_char(len);
     if (!j) exceptionptr = proto_java_lang_OutOfMemoryError;
     return j;
 }
@@ -2405,11 +2493,12 @@ jcharArray NewCharArray (JNIEnv *env, jsize len)
 
 jshortArray NewShortArray (JNIEnv *env, jsize len)
 {
+       java_shortarray *j;
     if (len<0) {
                exceptionptr=proto_java_lang_NegativeArraySizeException;
                return NULL;
     }
-    java_shortarray *j = builtin_newarray_short(len);   
+    j = builtin_newarray_short(len);   
     if (!j) exceptionptr = proto_java_lang_OutOfMemoryError;
     return j;
 }
@@ -2417,11 +2506,12 @@ jshortArray NewShortArray (JNIEnv *env, jsize len)
 
 jintArray NewIntArray (JNIEnv *env, jsize len)
 {
+       java_intarray *j;
     if (len<0) {
                exceptionptr=proto_java_lang_NegativeArraySizeException;
                return NULL;
     }
-    java_intarray *j = builtin_newarray_int(len);
+    j = builtin_newarray_int(len);
     if (!j) exceptionptr = proto_java_lang_OutOfMemoryError;
     return j;
 }
@@ -2429,11 +2519,12 @@ jintArray NewIntArray (JNIEnv *env, jsize len)
 
 jlongArray NewLongArray (JNIEnv *env, jsize len)
 {
+       java_longarray *j;
     if (len<0) {
                exceptionptr=proto_java_lang_NegativeArraySizeException;
                return NULL;
     }
-    java_longarray *j = builtin_newarray_long(len);
+    j = builtin_newarray_long(len);
     if (!j) exceptionptr = proto_java_lang_OutOfMemoryError;
     return j;
 }
@@ -2441,11 +2532,12 @@ jlongArray NewLongArray (JNIEnv *env, jsize len)
 
 jfloatArray NewFloatArray (JNIEnv *env, jsize len)
 {
+       java_floatarray *j;
     if (len<0) {
                exceptionptr=proto_java_lang_NegativeArraySizeException;
                return NULL;
     }
-    java_floatarray *j = builtin_newarray_float(len);
+    j = builtin_newarray_float(len);
     if (!j) exceptionptr = proto_java_lang_OutOfMemoryError;
     return j;
 }
@@ -2453,11 +2545,12 @@ jfloatArray NewFloatArray (JNIEnv *env, jsize len)
 
 jdoubleArray NewDoubleArray (JNIEnv *env, jsize len)
 {
+       java_doublearray *j;
     if (len<0) {
                exceptionptr=proto_java_lang_NegativeArraySizeException;
                return NULL;
     }
-    java_doublearray *j = builtin_newarray_double(len);
+    j = builtin_newarray_double(len);
     if (!j) exceptionptr = proto_java_lang_OutOfMemoryError;
     return j;
 }
@@ -3155,10 +3248,13 @@ jobject *jni_method_invokeNativeHelper(JNIEnv *env,struct methodinfo *methodID,j
        }
         argcount=get_parametercount(methodID);
 
-       if (obj && (! builtin_instanceof((java_objectheader*)obj,methodID->class))) {
-               exceptionptr = native_new_and_init(class_java_lang_NoSuchMethodError);
-               return 0;
-       }
+       if (obj && (!builtin_instanceof((java_objectheader*)obj,methodID->class))) {
+               (*env)->ThrowNew(env,loader_load(utf_new_char("java/lang/IllegalArgumentException")),
+                       "Object parameter of wrong type in Java_java_lang_reflect_Method_invokeNative");
+               return 0;
+       }
+
+
 
        if  (argcount>3) {
                exceptionptr=native_new_and_init(loader_load(utf_new_char("java/lang/IllegalArgumentException")));
@@ -3173,13 +3269,22 @@ jobject *jni_method_invokeNativeHelper(JNIEnv *env,struct methodinfo *methodID,j
                return 0;
        }
 
+
+         if (!(methodID->flags & ACC_STATIC) && (!obj))  {
+               (*env)->ThrowNew(env,loader_load(utf_new_char("java/lang/NullPointerException")),
+                       "Static mismatch in Java_java_lang_reflect_Method_invokeNative");
+               return 0;
+       }
+
+       if ((methodID->flags & ACC_STATIC) && (obj)) obj=0;
+
        blk = MNEW(jni_callblock, 4 /*argcount+2*/);
 
        retT=fill_callblock_objA(obj,methodID->descriptor,blk,params);
 
        switch (retT) {
                case 'V':       (void)asm_calljavafunction2(methodID,argcount+1,(argcount+1)*sizeof(jni_callblock),blk);
-                               retVal=native_new_and_init(loader_load(utf_new_char("java/lang/Void")));
+                               retVal=NULL; /*native_new_and_init(loader_load(utf_new_char("java/lang/Void")));*/
                                break;
                case 'I':       {
                                        s4 intVal;      
@@ -3273,8 +3378,14 @@ jobject *jni_method_invokeNativeHelper(JNIEnv *env,struct methodinfo *methodID,j
        }
        MFREE(blk, jni_callblock, 4 /*argcount+2*/);
 
-       if (exceptionptr)
-               exceptionptr=native_new_and_init(loader_load("java/lang/reflect/InvocationTargetException"));
+       if (exceptionptr) {
+               java_objectheader *exceptionToWrap=exceptionptr;
+               classinfo *ivtec=loader_load(utf_new_char("java/lang/reflect/InvocationTargetException"));
+               java_objectheader* ivte=builtin_new(ivtec);
+               if (asm_calljavamethod(class_resolvemethod(ivtec,utf_new_char("<init>"),utf_new_char("(Ljava/lang/Throwable;)V")),
+                       ivte,exceptionToWrap,0,0)!=NULL) panic("jni.c: error while creating InvocationTargetException wrapper");
+               exceptionptr=ivte;
+       }
        return retVal;  
 
 }