X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=src%2Fnative%2Fjni.c;h=651649e9ff2e57833775844a1ddedfcc5f89b220;hb=43516f8504c8cbcff9965132cf8286972e373520;hp=4ad5e43d29574911aa5e1f51fd0db76995f485e8;hpb=fa75c8b02ac7e66f4091432385aec49cd78741d8;p=cacao.git diff --git a/src/native/jni.c b/src/native/jni.c index 4ad5e43d2..651649e9f 100644 --- a/src/native/jni.c +++ b/src/native/jni.c @@ -31,11 +31,12 @@ Martin Platter Christian Thalinger - $Id: jni.c 2424 2005-04-30 13:45:06Z jowenn $ + $Id: jni.c 3095 2005-07-21 13:51:36Z motse $ */ +#include #include #include "config.h" @@ -53,11 +54,18 @@ #include "native/include/java_lang_Float.h" #include "native/include/java_lang_Double.h" #include "native/include/java_lang_Throwable.h" +#include "native/include/java_lang_reflect_Method.h" +#include "native/include/java_lang_reflect_Constructor.h" +#include "native/include/java_lang_reflect_Field.h" #include "native/include/java_lang_Class.h" /* for java_lang_VMClass.h */ #include "native/include/java_lang_VMClass.h" #include "native/include/java_lang_VMClassLoader.h" +#if defined(ENABLE_JVMTI) +# include "native/jvmti/jvmti.h" +#endif + #if defined(USE_THREADS) # if defined(NATIVE_THREADS) # include "threads/native/threads.h" @@ -81,13 +89,16 @@ #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)) @@ -112,193 +123,224 @@ static jmethodID removemid = NULL; #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); +#define setfield_critical(clazz,obj,name,sig,jdatatype,val) \ + setField(obj, jdatatype, getFieldID_critical(env,clazz,name,sig), val); + -static void fill_callblock(void *obj, methoddesc *descr, jni_callblock blk[], va_list data, int rettype) +static void fill_callblock_from_vargs(void *obj, methoddesc *descr, + jni_callblock blk[], va_list data, + s4 rettype) { - int cnt; - u4 dummy; - int i; - typedesc *paramtype; + typedesc *paramtypes; + s4 i; + + paramtypes = descr->paramtypes; + + /* if method is non-static fill first block and skip `this' pointer */ + + i = 0; if (obj) { - /* the this pointer */ + /* the `this' pointer */ blk[0].itemtype = TYPE_ADR; blk[0].item = PTR_TO_ITEM(obj); - cnt = 1; + + paramtypes++; + i++; } - else - cnt = 0; - paramtype = descr->paramtypes; - for (i=0; iparamcount; ++i,++cnt,++paramtype) { - switch (paramtype->decltype) { - /* primitive types */ + for (; i < descr->paramcount; i++, paramtypes++) { + switch (paramtypes->decltype) { + /* primitive types */ case PRIMITIVETYPE_BYTE: case PRIMITIVETYPE_CHAR: case PRIMITIVETYPE_SHORT: case PRIMITIVETYPE_BOOLEAN: - blk[cnt].itemtype = TYPE_INT; - blk[cnt].item = (u8) va_arg(data, int); + blk[i].itemtype = TYPE_INT; + blk[i].item = (s8) va_arg(data, s4); break; case PRIMITIVETYPE_INT: - blk[cnt].itemtype = TYPE_INT; - dummy = va_arg(data, u4); - /*printf("fill_callblock: pos:%d, value:%d\n",cnt,dummy);*/ - blk[cnt].item = (u8) dummy; + blk[i].itemtype = TYPE_INT; + blk[i].item = (s8) va_arg(data, s4); break; case PRIMITIVETYPE_LONG: - blk[cnt].itemtype = TYPE_LNG; - blk[cnt].item = (u8) va_arg(data, jlong); + blk[i].itemtype = TYPE_LNG; + blk[i].item = (s8) va_arg(data, s8); break; case PRIMITIVETYPE_FLOAT: - blk[cnt].itemtype = TYPE_FLT; - *((jfloat *) (&blk[cnt].item)) = (jfloat) va_arg(data, jdouble); + 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: - blk[cnt].itemtype = TYPE_DBL; - *((jdouble *) (&blk[cnt].item)) = (jdouble) va_arg(data, jdouble); + blk[i].itemtype = TYPE_DBL; + *((jdouble *) (&blk[i].item)) = (jdouble) va_arg(data, jdouble); break; case TYPE_ADR: - blk[cnt].itemtype = TYPE_ADR; - blk[cnt].item = PTR_TO_ITEM(va_arg(data, void*)); + blk[i].itemtype = TYPE_ADR; + blk[i].item = PTR_TO_ITEM(va_arg(data, void*)); break; } } - /*the standard doesn't say anything about return value checking, but it appears to be usefull*/ + /* The standard doesn't say anything about return value checking, but it */ + /* appears to be useful. */ + if (rettype != descr->returntype.decltype) log_text("\n====\nWarning call*Method called for function with wrong return type\n===="); } + /* XXX it could be considered if we should do typechecking here in the future */ -static bool fill_callblock_objA(void *obj, methoddesc *descr, jni_callblock blk[], java_objectarray* params, - int *rettype) + +static bool fill_callblock_from_objectarray(void *obj, methoddesc *descr, + jni_callblock blk[], + java_objectarray *params) { - jobject param; - int cnt; - int cnts; - typedesc *paramtype; + jobject param; + s4 paramcount; + typedesc *paramtypes; + classinfo *c; + s4 i; + s4 j; + + paramcount = descr->paramcount; + paramtypes = descr->paramtypes; + + /* if method is non-static fill first block and skip `this' pointer */ + + i = 0; - /* determine number of parameters */ if (obj) { /* this pointer */ blk[0].itemtype = TYPE_ADR; blk[0].item = PTR_TO_ITEM(obj); - cnt=1; - } else { - cnt = 0; + + paramtypes++; + paramcount--; + i++; } - paramtype = descr->paramtypes; - for (cnts=0; cnts < descr->paramcount; ++cnts,++cnt,++paramtype) { - switch (paramtype->type) { - /* primitive types */ - case TYPE_INT: - case TYPE_LONG: - case TYPE_FLOAT: - case TYPE_DOUBLE: - - param = params->data[cnts]; - if (!param) + for (j = 0; j < paramcount; i++, j++, paramtypes++) { + switch (paramtypes->type) { + /* primitive types */ + case TYPE_INT: + case TYPE_LONG: + case TYPE_FLOAT: + case TYPE_DOUBLE: + param = params->data[j]; + if (!param) + goto illegal_arg; + + /* internally used data type */ + blk[i].itemtype = paramtypes->type; + + /* convert the value according to its declared type */ + + c = param->vftbl->class; + + switch (paramtypes->decltype) { + case PRIMITIVETYPE_BOOLEAN: + if (c == primitivetype_table[paramtypes->decltype].class_wrap) + blk[i].item = (s8) ((java_lang_Boolean *) param)->value; + else goto illegal_arg; + break; - /* internally used data type */ - blk[cnt].itemtype = paramtype->type; - - /* convert the value according to its declared type */ - switch (paramtype->decltype) { - case PRIMITIVETYPE_BOOLEAN: - if (param->vftbl->class == primitivetype_table[paramtype->decltype].class_wrap) - blk[cnt].item = (u8) ((java_lang_Boolean *) param)->value; - else - goto illegal_arg; - break; - case PRIMITIVETYPE_BYTE: - if (param->vftbl->class == primitivetype_table[paramtype->decltype].class_wrap) - blk[cnt].item = (u8) ((java_lang_Byte *) param)->value; - else - goto illegal_arg; - break; - case PRIMITIVETYPE_CHAR: - if (param->vftbl->class == primitivetype_table[paramtype->decltype].class_wrap) - blk[cnt].item = (u8) ((java_lang_Character *) param)->value; - else - goto illegal_arg; - break; - case PRIMITIVETYPE_SHORT: - if (param->vftbl->class == primitivetype_table[paramtype->decltype].class_wrap) - blk[cnt].item = (u8) ((java_lang_Short *) param)->value; - else if (param->vftbl->class == primitivetype_table[PRIMITIVETYPE_BYTE].class_wrap) - blk[cnt].item = (u8) ((java_lang_Byte *) param)->value; - else - goto illegal_arg; - break; - case PRIMITIVETYPE_INT: - if (param->vftbl->class == primitivetype_table[paramtype->decltype].class_wrap) - blk[cnt].item = (u8) ((java_lang_Integer *) param)->value; - else if (param->vftbl->class == primitivetype_table[PRIMITIVETYPE_SHORT].class_wrap) - blk[cnt].item = (u8) ((java_lang_Short *) param)->value; - else if (param->vftbl->class == primitivetype_table[PRIMITIVETYPE_BYTE].class_wrap) - blk[cnt].item = (u8) ((java_lang_Byte *) param)->value; - else - goto illegal_arg; - break; - case PRIMITIVETYPE_LONG: - if (param->vftbl->class == primitivetype_table[paramtype->decltype].class_wrap) - blk[cnt].item = (u8) ((java_lang_Long *) param)->value; - else if (param->vftbl->class == primitivetype_table[PRIMITIVETYPE_INT].class_wrap) - blk[cnt].item = (u8) ((java_lang_Integer *) param)->value; - else if (param->vftbl->class == primitivetype_table[PRIMITIVETYPE_SHORT].class_wrap) - blk[cnt].item = (u8) ((java_lang_Short *) param)->value; - else if (param->vftbl->class == primitivetype_table[PRIMITIVETYPE_BYTE].class_wrap) - blk[cnt].item = (u8) ((java_lang_Byte *) param)->value; - else - goto illegal_arg; - break; - case PRIMITIVETYPE_FLOAT: - if (param->vftbl->class == primitivetype_table[paramtype->decltype].class_wrap) - *((jfloat *) (&blk[cnt].item)) = (jfloat) ((java_lang_Float *) param)->value; - else - goto illegal_arg; - break; - case PRIMITIVETYPE_DOUBLE: - if (param->vftbl->class == primitivetype_table[paramtype->decltype].class_wrap) - *((jdouble *) (&blk[cnt].item)) = (jdouble) ((java_lang_Float *) param)->value; - else if (param->vftbl->class == primitivetype_table[PRIMITIVETYPE_FLOAT].class_wrap) - *((jfloat *) (&blk[cnt].item)) = (jfloat) ((java_lang_Float *) param)->value; - else - goto illegal_arg; - break; - default: - goto illegal_arg; - } /* end declared type switch */ + case PRIMITIVETYPE_BYTE: + if (c == primitivetype_table[paramtypes->decltype].class_wrap) + 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 = (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 = (s8) ((java_lang_Short *) param)->value; + else if (c == primitivetype_table[PRIMITIVETYPE_BYTE].class_wrap) + 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 = (s8) ((java_lang_Integer *) param)->value; + else if (c == primitivetype_table[PRIMITIVETYPE_SHORT].class_wrap) + blk[i].item = (s8) ((java_lang_Short *) param)->value; + else if (c == primitivetype_table[PRIMITIVETYPE_BYTE].class_wrap) + 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 = (s8) ((java_lang_Long *) param)->value; + else if (c == primitivetype_table[PRIMITIVETYPE_INT].class_wrap) + blk[i].item = (s8) ((java_lang_Integer *) param)->value; + else if (c == primitivetype_table[PRIMITIVETYPE_SHORT].class_wrap) + blk[i].item = (s8) ((java_lang_Short *) param)->value; + else if (c == primitivetype_table[PRIMITIVETYPE_BYTE].class_wrap) + blk[i].item = (s8) ((java_lang_Byte *) param)->value; + else + goto illegal_arg; + break; + + case PRIMITIVETYPE_FLOAT: + if (c == primitivetype_table[paramtypes->decltype].class_wrap) + *((jfloat *) (&blk[i].item)) = (jfloat) ((java_lang_Float *) param)->value; + else + goto illegal_arg; + break; + + case PRIMITIVETYPE_DOUBLE: + if (c == primitivetype_table[paramtypes->decltype].class_wrap) + *((jdouble *) (&blk[i].item)) = (jdouble) ((java_lang_Float *) param)->value; + else if (c == primitivetype_table[PRIMITIVETYPE_FLOAT].class_wrap) + *((jfloat *) (&blk[i].item)) = (jfloat) ((java_lang_Float *) param)->value; + else + goto illegal_arg; + break; + + default: + goto illegal_arg; + } /* end declared type switch */ + break; case TYPE_ADDRESS: - { - classinfo *cls; - - if (!resolve_class_from_typedesc(paramtype,true,&cls)) - return false; /* exception */ - if (params->data[cnts] != 0) { - if (paramtype->arraydim > 0) { - if (!builtin_arrayinstanceof(params->data[cnts], cls->vftbl)) - goto illegal_arg; - } - else { - if (!builtin_instanceof(params->data[cnts], cls)) - goto illegal_arg; - } + if (!resolve_class_from_typedesc(paramtypes, true, true, &c)) + return false; + + if (params->data[j] != 0) { + if (paramtypes->arraydim > 0) { + if (!builtin_arrayinstanceof(params->data[j], c->vftbl)) + goto illegal_arg; + + } else { + if (!builtin_instanceof(params->data[j], c)) + goto illegal_arg; } - blk[cnt].itemtype = TYPE_ADR; - blk[cnt].item = PTR_TO_ITEM(params->data[cnts]); } + blk[i].itemtype = TYPE_ADR; + blk[i].item = PTR_TO_ITEM(params->data[j]); break; default: @@ -307,8 +349,9 @@ static bool fill_callblock_objA(void *obj, methoddesc *descr, jni_callblock blk[ } /* end param loop */ - if (rettype) - *rettype = descr->returntype.decltype; +/* if (rettype) */ +/* *rettype = descr->returntype.decltype; */ + return true; illegal_arg: @@ -317,20 +360,27 @@ illegal_arg: } -static jmethodID get_virtual(jobject obj,jmethodID methodID) { - if (obj->vftbl->class==methodID->class) return methodID; - return class_resolvemethod (obj->vftbl->class, methodID->name, methodID->descriptor); +static jmethodID get_virtual(jobject obj, jmethodID methodID) +{ + if (obj->vftbl->class == methodID->class) + return methodID; + + return class_resolvemethod(obj->vftbl->class, methodID->name, + methodID->descriptor); } -static jmethodID get_nonvirtual(jclass clazz,jmethodID methodID) { - if (clazz==methodID->class) return methodID; -/*class_resolvemethod -> classfindmethod? (JOWENN)*/ - return class_resolvemethod (clazz, methodID->name, methodID->descriptor); +static jmethodID get_nonvirtual(jclass clazz, jmethodID methodID) +{ + if (clazz == methodID->class) + return methodID; + + /* class_resolvemethod -> classfindmethod? (JOWENN) */ + return class_resolvemethod(clazz, methodID->name, methodID->descriptor); } -static jobject callObjectMethod (jobject obj, jmethodID methodID, va_list args) +static jobject callObjectMethod(jobject obj, jmethodID methodID, va_list args) { int argcount; jni_callblock *blk; @@ -367,7 +417,7 @@ static jobject callObjectMethod (jobject obj, jmethodID methodID, va_list args) blk = MNEW(jni_callblock, /*4 */argcount+2); - fill_callblock(obj, methodID->parseddesc, blk, args, TYPE_ADR); + fill_callblock_from_vargs(obj, methodID->parseddesc, blk, args, TYPE_ADR); /* printf("parameter: obj: %p",blk[0].item); */ STATS(jnicallXmethodnvokation();) ret = asm_calljavafunction2(methodID, @@ -429,7 +479,7 @@ static jint callIntegerMethod(jobject obj, jmethodID methodID, int retType, va_l blk = MNEW(jni_callblock, /*4 */ argcount+2); - fill_callblock(obj, methodID->parseddesc, blk, args, retType); + fill_callblock_from_vargs(obj, methodID->parseddesc, blk, args, retType); /* printf("parameter: obj: %p",blk[0].item); */ STATS(jnicallXmethodnvokation();) @@ -490,7 +540,7 @@ static jlong callLongMethod(jobject obj, jmethodID methodID, va_list args) blk = MNEW(jni_callblock,/* 4 */argcount+2); - fill_callblock(obj, methodID->parseddesc, blk, args, TYPE_LNG); + fill_callblock_from_vargs(obj, methodID->parseddesc, blk, args, TYPE_LNG); /* printf("parameter: obj: %p",blk[0].item); */ STATS(jnicallXmethodnvokation();) @@ -534,7 +584,7 @@ static jdouble callFloatMethod(jobject obj, jmethodID methodID, va_list args,int blk = MNEW(jni_callblock, /*4 */ argcount+2); - fill_callblock(obj, methodID->parseddesc, blk, args, retType); + fill_callblock_from_vargs(obj, methodID->parseddesc, blk, args, retType); /* printf("parameter: obj: %p",blk[0].item); */ STATS(jnicallXmethodnvokation();) @@ -588,9 +638,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; + + /* just say we support JNI 1.4 */ + + return JNI_VERSION_1_4; } @@ -604,19 +656,22 @@ jint GetVersion(JNIEnv *env) *******************************************************************************/ -jclass DefineClass(JNIEnv *env, const char *name, jobject loader, const jbyte *buf, jsize bufLen) +jclass DefineClass(JNIEnv *env, const char *name, jobject loader, + const jbyte *buf, jsize bufLen) { - jclass c; + java_lang_ClassLoader *cl; + java_lang_String *s; + java_bytearray *ba; + jclass c; + STATS(jniinvokation();) - c = (jclass) Java_java_lang_VMClassLoader_defineClass(env, - NULL, - (java_lang_ClassLoader *) loader, - javastring_new_char(name), - (java_bytearray *) buf, - 0, - bufLen, - NULL); + cl = (java_lang_ClassLoader *) loader; + s = javastring_new_char(name); + ba = (java_bytearray *) buf; + + c = (jclass) Java_java_lang_VMClassLoader_defineClass(env, NULL, cl, s, ba, + 0, bufLen, NULL); return c; } @@ -632,12 +687,28 @@ jclass DefineClass(JNIEnv *env, const char *name, jobject loader, const jbyte *b jclass FindClass(JNIEnv *env, const char *name) { - classinfo *c = NULL; + utf *u; + classinfo *c; + java_objectheader *cl; + STATS(jniinvokation();) - - if (!load_class_bootstrap(utf_new_char_classname((char *) name),&c) || !link_class(c)) { + + 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__) + cl = cacao_currentClassLoader(); +#else + cl = NULL; +#endif + + if (!(c = load_class_from_classloader(u, cl))) + return NULL; + + if (!link_class(c)) return NULL; - } use_class_as_object(c); @@ -645,19 +716,51 @@ jclass FindClass(JNIEnv *env, const char *name) } -/******************************************************************************* +/* FromReflectedMethod ********************************************************* - converts java.lang.reflect.Method or - java.lang.reflect.Constructor object to a method ID + Converts java.lang.reflect.Method or java.lang.reflect.Constructor + object to a method ID. *******************************************************************************/ -jmethodID FromReflectedMethod(JNIEnv* env, jobject method) +jmethodID FromReflectedMethod(JNIEnv *env, jobject method) { - log_text("JNI-Call: FromReflectedMethod: IMPLEMENT ME!!!"); + methodinfo *mi; + classinfo *c; + s4 slot; + STATS(jniinvokation();) - return 0; + if (method == NULL) + return NULL; + + if (builtin_instanceof(method, class_java_lang_reflect_Method)) { + java_lang_reflect_Method *rm; + + rm = (java_lang_reflect_Method *) method; + c = (classinfo *) (rm->declaringClass); + slot = rm->slot; + + } else if (builtin_instanceof(method, class_java_lang_reflect_Constructor)) { + java_lang_reflect_Constructor *rc; + + rc = (java_lang_reflect_Constructor *) method; + c = (classinfo *) (rc->clazz); + slot = rc->slot; + + } else + return NULL; + + if ((slot < 0) || (slot >= c->methodscount)) { + /* this usually means a severe internal cacao error or somebody + tempered around with the reflected method */ + log_text("error illegal slot for method in class(FromReflectedMethod)"); + assert(0); + } + + mi = &(c->methods[slot]); + + return mi; } @@ -868,9 +971,9 @@ jobject PopLocalFrame(JNIEnv* env, jobject result) void DeleteLocalRef(JNIEnv *env, jobject localRef) { - log_text("JNI-Call: DeleteLocalRef: IMPLEMENT ME!"); STATS(jniinvokation();) + log_text("JNI-Call: DeleteLocalRef: IMPLEMENT ME!"); } @@ -1060,10 +1163,23 @@ jboolean IsInstanceOf(JNIEnv *env, jobject obj, jclass clazz) jfieldID FromReflectedField(JNIEnv* env, jobject field) { - log_text("JNI-Call: FromReflectedField"); - STATS(jniinvokation();) - - return 0; + java_lang_reflect_Field *f; + classinfo *c; + jfieldID fid; /* the JNI-fieldid of the wrapping object */ + STATS(jniinvokation();) + /*log_text("JNI-Call: FromReflectedField");*/ + + f=(java_lang_reflect_Field *)field; + if (f==0) return 0; + c=(classinfo*)(f->declaringClass); + if ( (f->slot<0) || (f->slot>=c->fieldscount)) { + /*this usually means a severe internal cacao error or somebody + tempered around with the reflected method*/ + log_text("error illegal slot for field in class(FromReflectedField)"); + assert(0); + } + fid=&(c->fields[f->slot]); + return fid; } @@ -1102,7 +1218,7 @@ jmethodID GetMethodID(JNIEnv* env, jclass clazz, const char *name, const char *s *exceptionptr = new_exception_message(string_java_lang_NoSuchMethodError, name); - return 0; + return NULL; } return m; @@ -1760,6 +1876,7 @@ void CallNonvirtualVoidMethodA (JNIEnv *env, jobject obj, jclass clazz, jmethodI jfieldID GetFieldID (JNIEnv *env, jclass clazz, const char *name, const char *sig) { jfieldID f; + STATS(jniinvokation();) /* log_text("========================= searching for:"); @@ -1794,7 +1911,8 @@ jfieldID getFieldID_critical(JNIEnv *env, jclass clazz, char *name, char *sig) log_text("sig:"); log_text(sig); - panic("setfield_critical failed"); + log_text("setfield_critical failed"); + assert(0); } return id; } @@ -2544,6 +2662,8 @@ void SetStaticDoubleField(JNIEnv *env, jclass clazz, jfieldID fieldID, jdouble v } +/* String Operations **********************************************************/ + /* NewString ******************************************************************* Create new java.lang.String object from an array of Unicode @@ -2556,6 +2676,7 @@ jstring NewString(JNIEnv *env, const jchar *buf, jsize len) java_lang_String *s; java_chararray *a; u4 i; + STATS(jniinvokation();) s = (java_lang_String *) builtin_new(class_java_lang_String); @@ -2577,66 +2698,104 @@ jstring NewString(JNIEnv *env, const jchar *buf, jsize len) } -static char emptyString[]=""; 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; + java_lang_String *s; + java_chararray *a; + u2 *stringbuffer; + u4 i; + STATS(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; icount; 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); + jchar *jc; + STATS(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); + + if (chars == emptyStringJ) + return; + + MFREE(((jchar *) chars), jchar, ((java_lang_String *) str)->count + 1); } @@ -2664,47 +2823,65 @@ jsize GetStringUTFLength (JNIEnv *env, jstring string) } -/************ converts a Javastring to an array of UTF-8 characters ****************/ +/* GetStringUTFChars *********************************************************** + + Returns a pointer to an array of UTF-8 characters of the + string. This array is valid until it is released by + ReleaseStringUTFChars(). -const char* GetStringUTFChars(JNIEnv *env, jstring string, jboolean *isCopy) +*******************************************************************************/ + +const char *GetStringUTFChars(JNIEnv *env, jstring string, jboolean *isCopy) { - utf *u; + utf *u; STATS(jniinvokation();) - u = javastring_toutf((java_lang_String *) string, false); + if (!string) + return ""; - if (isCopy) - *isCopy = JNI_FALSE; + if (isCopy) + *isCopy = JNI_TRUE; - if (u) + u = javastring_toutf((java_lang_String *) string, false); + + if (u) return u->text; - return emptyString; - + return ""; } -/***************** native code no longer needs access to utf ***********************/ +/* ReleaseStringUTFChars ******************************************************* + + 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 str, const char* chars) +*******************************************************************************/ + +void ReleaseStringUTFChars(JNIEnv *env, jstring string, const char *utf) { STATS(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();) - return array->size; + return array->size; } @@ -2900,318 +3077,574 @@ jdoubleArray NewDoubleArray(JNIEnv *env, jsize len) } -jboolean * GetBooleanArrayElements (JNIEnv *env, jbooleanArray array, jboolean *isCopy) +/* GetArrayElements ********************************************* + + 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; + + 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; + + 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; + + 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; + + 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; + + 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; + + 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; + + 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; + + if (isCopy) + *isCopy = JNI_FALSE; + return array->data; } +/* ReleaseArrayElements ***************************************** -void ReleaseBooleanArrayElements (JNIEnv *env, jbooleanArray array, jboolean *elems, jint mode) + 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 + GetArrayElements() 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) { STATS(jniinvokation();) - /* empty */ + + 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 */ + + 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 */ + STATS(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 */ + + 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 */ + + 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 */ + + 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 */ + + 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 */ + + 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) +/* GetArrayRegion ********************************************** + + 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); + *exceptionptr = + new_exception(string_java_lang_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); + *exceptionptr = + new_exception(string_java_lang_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); + *exceptionptr = + new_exception(string_java_lang_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); + *exceptionptr = + new_exception(string_java_lang_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); + *exceptionptr = + new_exception(string_java_lang_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); + *exceptionptr = + new_exception(string_java_lang_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); + *exceptionptr = + new_exception(string_java_lang_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); + *exceptionptr = + new_exception(string_java_lang_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) +/* SetArrayRegion ********************************************** + + 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); + *exceptionptr = + new_exception(string_java_lang_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); + *exceptionptr = + new_exception(string_java_lang_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); + *exceptionptr = + new_exception(string_java_lang_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); + *exceptionptr = + new_exception(string_java_lang_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); + *exceptionptr = + new_exception(string_java_lang_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); + *exceptionptr = + new_exception(string_java_lang_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); + *exceptionptr = + new_exception(string_java_lang_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); + *exceptionptr = + new_exception(string_java_lang_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"); + + 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"); + + /* XXX TWISTI hmm, maybe we should not support that (like kaffe) */ + + log_text("JNI-Call: UnregisterNatives: IMPLEMENT ME!!!"); + return 0; } @@ -3300,46 +3733,71 @@ void GetStringUTFRegion (JNIEnv* env, jstring str, jsize start, jsize len, char } -/************** obtain direct pointer to array elements ***********************/ +/* GetPrimitiveArrayCritical *************************************************** + + Obtain a direct pointer to array elements. -void * GetPrimitiveArrayCritical (JNIEnv* env, jarray array, jboolean *isCopy) +*******************************************************************************/ + +void *GetPrimitiveArrayCritical(JNIEnv *env, jarray array, jboolean *isCopy) { + java_objectheader *s; + arraydescriptor *desc; + STATS(jniinvokation();) - java_objectheader *s = (java_objectheader*) array; - arraydescriptor *desc = s->vftbl->arraydesc; - if (!desc) return NULL; + s = (java_objectheader *) array; + desc = s->vftbl->arraydesc; - return ((u1*)s) + desc->dataoffset; + if (!desc) + return NULL; + + if (isCopy) + *isCopy = JNI_FALSE; + + /* TODO add to global refs */ + + return ((u1 *) s) + desc->dataoffset; } -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"); - /* empty */ + log_text("JNI-Call: ReleasePrimitiveArrayCritical: IMPLEMENT ME!!!"); + + /* TODO remove from global refs */ } -/**** 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"); - 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"); - ReleaseStringChars(env,string,cstring); + ReleaseStringChars(env, string, cstring); } @@ -3414,7 +3872,7 @@ void DeleteGlobalRef(JNIEnv* env, jobject gref) jobject newval = NewObject(env, intclass, newint, val); if (newval != NULL) { - CallObjectMethod(env,*global_ref_table, putmid,newval); + CallObjectMethod(env,*global_ref_table, putmid, gref, newval); } else { log_text("JNI-DeleteGlobalRef: unable to create new java.lang.Integer"); @@ -3443,8 +3901,9 @@ jboolean ExceptionCheck(JNIEnv *env) /* NewDirectByteBuffer ********************************************************* - Allocates and returns a direct java.nio.ByteBuffer referring to the block of - memory starting at the memory address address and extending capacity bytes. + Allocates and returns a direct java.nio.ByteBuffer referring to the + block of memory starting at the memory address address and + extending capacity bytes. *******************************************************************************/ @@ -3459,8 +3918,8 @@ jobject NewDirectByteBuffer(JNIEnv *env, void *address, jlong capacity) /* GetDirectBufferAddress ****************************************************** - Fetches and returns the starting address of the memory region referenced by - the given direct java.nio.Buffer. + Fetches and returns the starting address of the memory region + referenced by the given direct java.nio.Buffer. *******************************************************************************/ @@ -3475,8 +3934,8 @@ void *GetDirectBufferAddress(JNIEnv *env, jobject buf) /* GetDirectBufferCapacity ***************************************************** - Fetches and returns the capacity in bytes of the memory region referenced by - the given direct java.nio.Buffer. + Fetches and returns the capacity in bytes of the memory region + referenced by the given direct java.nio.Buffer. *******************************************************************************/ @@ -3498,9 +3957,24 @@ jint DestroyJavaVM(JavaVM *vm) } +/* AttachCurrentThread ********************************************************* + + Attaches the current thread to a Java VM. Returns a JNI interface + pointer in the JNIEnv argument. + + Trying to attach a thread that is already attached is a no-op. + + A native thread cannot be attached simultaneously to two Java VMs. + + When a thread is attached to the VM, the context class loader is + the bootstrap loader. + +*******************************************************************************/ + jint AttachCurrentThread(JavaVM *vm, void **env, void *thr_args) { STATS(jniinvokation();) + log_text("AttachCurrentThread called"); #if !defined(HAVE___THREAD) @@ -3510,6 +3984,7 @@ jint AttachCurrentThread(JavaVM *vm, void **env, void *thr_args) #endif *env = &ptr_env; + return 0; } @@ -3523,29 +3998,50 @@ jint DetachCurrentThread(JavaVM *vm) } +/* GetEnv ********************************************************************** + + If the current thread is not attached to the VM, sets *env to NULL, + and returns JNI_EDETACHED. If the specified version is not + supported, sets *env to NULL, and returns JNI_EVERSION. Otherwise, + sets *env to the appropriate interface, and returns JNI_OK. + +*******************************************************************************/ + jint 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) { +#if defined(USE_THREADS) && defined(NATIVE_THREADS) + if (thread_getself() == NULL) { *env = NULL; + return JNI_EDETACHED; } - */ +#endif - *env = &ptr_env; + if ((version == JNI_VERSION_1_1) || (version == JNI_VERSION_1_2) || + (version == JNI_VERSION_1_4)) { + *env = &ptr_env; - return JNI_OK; + return JNI_OK; + } + +#if defined(ENABLE_JVMTI) + if (version == JVMTI_VERSION_1_0) { + *env = (void *) new_jvmtienv(); + + if (env != NULL) + return JNI_OK; + } +#endif + + *env = NULL; + + return JNI_EVERSION; } + jint AttachCurrentThreadAsDaemon(JavaVM *vm, void **par1, void *par2) { STATS(jniinvokation();) @@ -3590,11 +4086,13 @@ void jni_init2(JNIEnv* env, jobject gref) { DeleteGlobalRef(env, gref); } -void jni_init(){ + +void jni_init(void) +{ jmethodID mid; initrunning = true; - log_text("JNI-Init: initialize global_ref_table"); + /* initalize global reference table */ ihmclass = FindClass(NULL, "java/util/IdentityHashMap"); @@ -3993,19 +4491,25 @@ 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; } -jobject *jni_method_invokeNativeHelper(JNIEnv *env, struct methodinfo *methodID, jobject obj, java_objectarray *params) +jobject *jni_method_invokeNativeHelper(JNIEnv *env, methodinfo *methodID, + jobject obj, java_objectarray *params) { - int argcount; jni_callblock *blk; - int retT; - jobject retVal; + jobject o; + s4 argcount; if (methodID == 0) { *exceptionptr = new_exception(string_java_lang_NoSuchMethodError); @@ -4014,14 +4518,21 @@ jobject *jni_method_invokeNativeHelper(JNIEnv *env, struct methodinfo *methodID, argcount = methodID->parseddesc->paramcount; + /* if method is non-static, remove the `this' pointer */ + + if (!(methodID->flags & ACC_STATIC)) + argcount--; + /* 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 is ignored. */ + if (!(methodID->flags & ACC_STATIC) && obj && (!builtin_instanceof((java_objectheader *) obj, methodID->class))) { - *exceptionptr = new_exception_message(string_java_lang_IllegalArgumentException, + *exceptionptr = + new_exception_message(string_java_lang_IllegalArgumentException, "Object parameter of wrong type in Java_java_lang_reflect_Method_invokeNative"); - return 0; + return NULL; } @@ -4029,73 +4540,73 @@ jobject *jni_method_invokeNativeHelper(JNIEnv *env, struct methodinfo *methodID, if (argcount > 3) { *exceptionptr = new_exception(string_java_lang_IllegalArgumentException); log_text("Too many arguments. invokeNativeHelper does not support that"); - return 0; + return NULL; } #endif - if (((params==0) && (argcount != 0)) || (params && (params->header.size != argcount))) { - *exceptionptr = new_exception(string_java_lang_IllegalArgumentException); - return 0; + + if (((params == NULL) && (argcount != 0)) || + (params && (params->header.size != argcount))) { + *exceptionptr = + new_exception(string_java_lang_IllegalArgumentException); + return NULL; } - if (((methodID->flags & ACC_STATIC)==0) && (0==obj)) { + if (!(methodID->flags & ACC_STATIC) && !obj) { *exceptionptr = new_exception_message(string_java_lang_NullPointerException, "Static mismatch in Java_java_lang_reflect_Method_invokeNative"); - return 0; + return NULL; } - if ((methodID->flags & ACC_STATIC) && (obj)) obj = 0; + if ((methodID->flags & ACC_STATIC) && (obj)) + obj = NULL; if (obj) { - if ( (methodID->flags & ACC_ABSTRACT) || (methodID->class->flags & ACC_INTERFACE) ) { - methodID=get_virtual(obj,methodID); + if ((methodID->flags & ACC_ABSTRACT) || + (methodID->class->flags & ACC_INTERFACE)) { + methodID = get_virtual(obj, methodID); } } - blk = MNEW(jni_callblock, /*4 */argcount+2); + blk = MNEW(jni_callblock, /*4 */argcount + 2); - if (!fill_callblock_objA(obj, methodID->parseddesc, blk, params,&retT)) - return 0; /* exception */ + if (!fill_callblock_from_objectarray(obj, methodID->parseddesc, blk, + params)) + return NULL; - switch (retT) { + switch (methodID->parseddesc->returntype.decltype) { case TYPE_VOID: - (void) asm_calljavafunction2(methodID, - argcount + 1, + (void) asm_calljavafunction2(methodID, argcount + 1, (argcount + 1) * sizeof(jni_callblock), blk); - retVal = NULL; /*native_new_and_init(loader_load(utf_new_char("java/lang/Void")));*/ + o = NULL; /*native_new_and_init(loader_load(utf_new_char("java/lang/Void")));*/ break; case PRIMITIVETYPE_INT: { - s4 intVal; - intVal = asm_calljavafunction2int(methodID, - argcount + 1, - (argcount + 1) * sizeof(jni_callblock), - blk); - retVal = builtin_new(class_java_lang_Integer); - CallVoidMethod(env, - retVal, - class_resolvemethod(retVal->vftbl->class, - utf_init, - utf_int__void), - intVal); + s4 i; + i = asm_calljavafunction2int(methodID, argcount + 1, + (argcount + 1) * sizeof(jni_callblock), + blk); + + o = native_new_and_init_int(class_java_lang_Integer, i); } break; case PRIMITIVETYPE_BYTE: { - s4 intVal; - intVal = asm_calljavafunction2int(methodID, - argcount + 1, - (argcount + 1) * sizeof(jni_callblock), - blk); - retVal = builtin_new(class_java_lang_Byte); + s4 i; + i = asm_calljavafunction2int(methodID, argcount + 1, + (argcount + 1) * sizeof(jni_callblock), + blk); + +/* o = native_new_and_init_int(class_java_lang_Byte, i); */ + o = builtin_new(class_java_lang_Byte); CallVoidMethod(env, - retVal, - class_resolvemethod(retVal->vftbl->class, + o, + class_resolvemethod(o->vftbl->class, utf_init, utf_byte__void), - intVal); + i); } break; @@ -4105,10 +4616,10 @@ jobject *jni_method_invokeNativeHelper(JNIEnv *env, struct methodinfo *methodID, argcount + 1, (argcount + 1) * sizeof(jni_callblock), blk); - retVal = builtin_new(class_java_lang_Character); + o = builtin_new(class_java_lang_Character); CallVoidMethod(env, - retVal, - class_resolvemethod(retVal->vftbl->class, + o, + class_resolvemethod(o->vftbl->class, utf_init, utf_char__void), intVal); @@ -4121,10 +4632,10 @@ jobject *jni_method_invokeNativeHelper(JNIEnv *env, struct methodinfo *methodID, argcount + 1, (argcount + 1) * sizeof(jni_callblock), blk); - retVal = builtin_new(class_java_lang_Short); + o = builtin_new(class_java_lang_Short); CallVoidMethod(env, - retVal, - class_resolvemethod(retVal->vftbl->class, + o, + class_resolvemethod(o->vftbl->class, utf_init, utf_short__void), intVal); @@ -4137,10 +4648,10 @@ jobject *jni_method_invokeNativeHelper(JNIEnv *env, struct methodinfo *methodID, argcount + 1, (argcount + 1) * sizeof(jni_callblock), blk); - retVal = builtin_new(class_java_lang_Boolean); + o = builtin_new(class_java_lang_Boolean); CallVoidMethod(env, - retVal, - class_resolvemethod(retVal->vftbl->class, + o, + class_resolvemethod(o->vftbl->class, utf_init, utf_boolean__void), intVal); @@ -4153,10 +4664,10 @@ jobject *jni_method_invokeNativeHelper(JNIEnv *env, struct methodinfo *methodID, argcount + 1, (argcount + 1) * sizeof(jni_callblock), blk); - retVal = builtin_new(class_java_lang_Long); + o = builtin_new(class_java_lang_Long); CallVoidMethod(env, - retVal, - class_resolvemethod(retVal->vftbl->class, + o, + class_resolvemethod(o->vftbl->class, utf_init, utf_long__void), longVal); @@ -4169,10 +4680,10 @@ jobject *jni_method_invokeNativeHelper(JNIEnv *env, struct methodinfo *methodID, argcount + 1, (argcount + 1) * sizeof(jni_callblock), blk); - retVal = builtin_new(class_java_lang_Float); + o = builtin_new(class_java_lang_Float); CallVoidMethod(env, - retVal, - class_resolvemethod(retVal->vftbl->class, + o, + class_resolvemethod(o->vftbl->class, utf_init, utf_float__void), floatVal); @@ -4185,10 +4696,10 @@ jobject *jni_method_invokeNativeHelper(JNIEnv *env, struct methodinfo *methodID, argcount + 1, (argcount + 1) * sizeof(jni_callblock), blk); - retVal = builtin_new(class_java_lang_Double); + o = builtin_new(class_java_lang_Double); CallVoidMethod(env, - retVal, - class_resolvemethod(retVal->vftbl->class, + o, + class_resolvemethod(o->vftbl->class, utf_init, utf_double__void), doubleVal); @@ -4196,14 +4707,14 @@ jobject *jni_method_invokeNativeHelper(JNIEnv *env, struct methodinfo *methodID, break; case TYPE_ADR: - retVal = asm_calljavafunction2(methodID, - argcount + 1, - (argcount + 1) * sizeof(jni_callblock), - blk); + o = asm_calljavafunction2(methodID, argcount + 1, + (argcount + 1) * sizeof(jni_callblock), blk); break; default: - /* if this happens the acception has already been set by fill_callblock_objA*/ + /* if this happens the exception has already been set by */ + /* fill_callblock_from_objectarray */ + MFREE(blk, jni_callblock, /*4 */ argcount+2); return (jobject *) 0; } @@ -4211,36 +4722,23 @@ jobject *jni_method_invokeNativeHelper(JNIEnv *env, struct methodinfo *methodID, MFREE(blk, jni_callblock, /* 4 */ argcount+2); if (*exceptionptr) { - java_objectheader *exceptionToWrap = *exceptionptr; - classinfo *ivtec; - java_objectheader *ivte; + java_objectheader *cause; - *exceptionptr = NULL; - if (load_class_bootstrap(utf_new_char("java/lang/reflect/InvocationTargetException"), - &ivtec)) - { - ivte = builtin_new(ivtec); - asm_calljavafunction(class_resolvemethod(ivtec, - utf_new_char(""), - utf_new_char("(Ljava/lang/Throwable;)V")), - ivte, - exceptionToWrap, - 0, - 0); - } + cause = *exceptionptr; + + /* clear exception pointer, we are calling JIT code again */ - if (*exceptionptr != NULL) - panic("jni.c: error while creating InvocationTargetException wrapper"); + *exceptionptr = NULL; - *exceptionptr = ivte; + *exceptionptr = + new_exception_throwable(string_java_lang_reflect_InvocationTargetException, + (java_lang_Throwable *) cause); } - return (jobject *) retVal; + return (jobject *) o; } - - /* * These are local overrides for various environment variables in Emacs. * Please do not remove this and leave it at the end of the file, where