-/* jni.c - implementation of the Java Native Interface functions
+/* native/jni.c - implementation of the Java Native Interface functions
- Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
- R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser,
- M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck,
- P. Tomsich, J. Wenninger
+ Copyright (C) 1996-2005 R. Grafl, A. Krall, C. Kruegel, C. Oates,
+ R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner,
+ C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger,
+ Institut f. Computersprachen - TU Wien
This file is part of CACAO.
Authors: ?
- Changes: Joseph Wenninger
+ Changes: Joseph Wenninger, Martin Platter
- $Id: jni.c 1067 2004-05-18 10:25:51Z stefan $
+ $Id: jni.c 1735 2004-12-07 14:33:27Z twisti $
*/
#include <string.h>
-#include "main.h"
-#include "jni.h"
-#include "global.h"
-#include "loader.h"
-#include "tables.h"
-#include "native.h"
-#include "builtin.h"
-#include "threads/thread.h"
+
+#include "mm/boehm.h"
+#include "mm/memory.h"
+#include "native/jni.h"
+#include "native/native.h"
+#include "native/include/java_lang_Byte.h"
+#include "native/include/java_lang_Character.h"
+#include "native/include/java_lang_Short.h"
+#include "native/include/java_lang_Integer.h"
+#include "native/include/java_lang_Boolean.h"
+#include "native/include/java_lang_Long.h"
+#include "native/include/java_lang_Float.h"
+#include "native/include/java_lang_Double.h"
+#include "native/include/java_lang_Throwable.h"
+
+#if defined(USE_THREADS)
+# if defined(NATIVE_THREADS)
+# include "threads/native/threads.h"
+# else
+# include "threads/green/threads.h"
+# endif
+#endif
+
#include "toolbox/logging.h"
-#include "toolbox/memory.h"
-#include "nat/java_lang_Byte.h"
-#include "nat/java_lang_Character.h"
-#include "nat/java_lang_Short.h"
-#include "nat/java_lang_Integer.h"
-#include "nat/java_lang_Boolean.h"
-#include "nat/java_lang_Long.h"
-#include "nat/java_lang_Float.h"
-#include "nat/java_lang_Double.h"
-#include "nat/java_lang_Throwable.h"
-#include "jit/jit.h"
-#include "asmpart.h"
+#include "vm/builtin.h"
+#include "vm/exceptions.h"
+#include "vm/global.h"
+#include "vm/loader.h"
+#include "vm/options.h"
+#include "vm/statistics.h"
+#include "vm/tables.h"
+#include "vm/jit/asmpart.h"
+#include "vm/jit/jit.h"
+
+
#define JNI_VERSION 0x00010002
static utf* utf_float = 0;
static utf* utf_double = 0;
+/* global reference table */
+static jobject *global_ref_table;
+static bool initrunning=false;
+
+/* 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;
+
/********************* accessing instance-fields **********************************/
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);
}
jni_callblock *blk;
jobject ret;
- /*
- log_text("JNI-Call: CallObjectMethodV");
- utf_display(methodID->name);
- utf_display(methodID->descriptor);
- printf("\nParmaeter count: %d\n",argcount);
- utf_display(obj->vftbl->class->name);
- printf("\n");
- */
+
if (methodID == 0) {
*exceptionptr = new_exception(string_java_lang_NoSuchMethodError);
*exceptionptr = new_exception(string_java_lang_NoSuchMethodError);
return 0;
}
-
+
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
- blk = MNEW(jni_callblock, 4 /*argcount+2*/);
+ blk = MNEW(jni_callblock, /*4 */argcount+2);
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);
/* printf("(CallObjectMethodV)-->%p\n",ret); */
+
return ret;
}
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
- blk = MNEW(jni_callblock, 4 /*argcount+2*/);
+ blk = MNEW(jni_callblock, /*4 */ argcount+2);
fill_callblock(obj, methodID->descriptor, blk, args, retType);
jni_callblock *blk;
jlong ret;
- /*
+/*
log_text("JNI-Call: CallObjectMethodV");
utf_display(methodID->name);
utf_display(methodID->descriptor);
printf("\nParmaeter count: %d\n",argcount);
utf_display(obj->vftbl->class->name);
printf("\n");
- */
+*/
if (methodID == 0) {
*exceptionptr = new_exception(string_java_lang_NoSuchMethodError);
return 0;
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
- blk = MNEW(jni_callblock, 4 /*argcount+2*/);
+ blk = MNEW(jni_callblock,/* 4 */argcount+2);
- fill_callblock(obj, methodID->descriptor, blk, args, 'L');
+ fill_callblock(obj, methodID->descriptor, blk, args, 'J');
/* printf("parameter: obj: %p",blk[0].item); */
ret = asm_calljavafunction2long(methodID,
printf("\n");
*/
+#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*/);
+ blk = MNEW(jni_callblock, /*4 */ argcount+2);
fill_callblock(obj, methodID->descriptor, blk, args, retType);
}
-/****************** loads a class from a buffer of raw class data *****************/
+/************** loads a class from a buffer of raw class data *****************/
jclass DefineClass(JNIEnv* env, const char *name, jobject loader, const jbyte *buf, jsize len)
{
- jclass clazz;
+ jclass c;
+ jclass r;
classbuffer *cb;
- s8 starttime;
- s8 stoptime;
-#if defined(USE_THREADS)
-#if defined(NATIVE_THREADS)
- compiler_lock();
- tables_lock();
-#else
- intsDisable();
-#endif
-#endif
+ c = class_new(utf_new_char_classname((char *) name));
+
+ /* enter a monitor on the class */
+
+ builtin_monitorenter((java_objectheader *) c);
/* measure time */
if (getloadingtime)
- starttime = getcputime();
-
- clazz = class_new(utf_new_char((char *) name));
+ loadingtime_start();
/* build a classbuffer with the given data */
cb = NEW(classbuffer);
- cb->class = clazz;
+ cb->class = c;
cb->size = len;
cb->data = (u1 *) buf;
cb->pos = cb->data - 1;
- class_load_intern(cb);
+ r = class_load_intern(cb);
+
+ /* if return value is NULL, we had a problem and the class is not loaded */
+ if (!r) {
+ c->loaded = false;
+
+ /* now free the allocated memory, otherwise we could ran into a DOS */
+ class_remove(c);
+ }
/* free memory */
FREE(cb, classbuffer);
/* measure time */
- if (getloadingtime) {
- stoptime = getcputime();
- loadingtime += (stoptime - starttime);
- }
+ if (getloadingtime)
+ loadingtime_stop();
-#if defined(USE_THREADS)
-#if defined(NATIVE_THREADS)
- tables_unlock();
- compiler_unlock();
-#else
- intsRestore();
-#endif
-#endif
+ /* leave the monitor */
- if (*exceptionptr)
- return NULL;
+ builtin_monitorexit((java_objectheader *) c);
/* XXX link the class here? */
- class_link(clazz);
+/* if (class_link(c)) */
+/* return NULL; */
- if (*exceptionptr)
- return NULL;
-
- if (clazz)
- clazz->classloader = loader;
+ if (r)
+ c->classloader = loader;
- return clazz;
+ return r;
}
-/*************** loads locally defined class with the specified name **************/
+/*********** loads locally defined class with the specified name **************/
jclass FindClass(JNIEnv* env, const char *name)
{
c = class_new(utf_new_char_classname((char *) name));
- class_load(c);
-
- if (*exceptionptr)
+ if (!class_load(c))
return NULL;
- class_link(c);
-
- if (*exceptionptr)
+ if (!class_link(c))
return NULL;
return c;
}
-/***********************************************************************************
+/*******************************************************************************
converts java.lang.reflect.Method or
java.lang.reflect.Constructor object to a method ID
- **********************************************************************************/
+*******************************************************************************/
jmethodID FromReflectedMethod(JNIEnv* env, jobject method)
{
jobject PopLocalFrame(JNIEnv* env, jobject result)
{
+ log_text("JNI-Call: PopLocalFrame");
/* empty */
return NULL;
}
-
-
-/** Creates a new global reference to the object referred to by the obj argument **/
-
-jobject NewGlobalRef(JNIEnv* env, jobject lobj)
-{
- return lobj;
-}
-
-/************* Deletes the global reference pointed to by globalRef **************/
-
-void DeleteGlobalRef (JNIEnv* env, jobject gref)
-{
- /* empty */
-}
/*************** Deletes the local reference pointed to by localRef ***************/
void DeleteLocalRef (JNIEnv* env, jobject localRef)
{
+/* log_text("JNI-Call: DeleteLocalRef");*/
/* empty */
}
/* log_text("JNI-Call: NewObject"); */
+#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
o = builtin_new (clazz); /* create object */
);
if (!m) *exceptionptr = new_exception(string_java_lang_NoSuchMethodError);
-
+ else if (m->flags & ACC_STATIC) {
+ m=0;
+ *exceptionptr = new_exception(string_java_lang_NoSuchMethodError);
+ }
return m;
}
jlong CallLongMethod(JNIEnv *env, jobject obj, jmethodID methodID, ...)
{
- log_text("JNI-Call: CallLongMethod");
+ jlong ret;
+ va_list vaargs;
+
+ va_start(vaargs,methodID);
+ ret = callLongMethod(obj,get_virtual(obj, methodID),vaargs);
+ va_end(vaargs);
- return 0;
+ return ret;
}
jlong CallLongMethodV(JNIEnv *env, jobject obj, jmethodID methodID, va_list args)
{
- log_text("JNI-Call: CallLongMethodV");
-
- return 0;
+ return callLongMethod(obj,get_virtual(obj, methodID),args);
}
);
if (!f) {
-/* utf_display(clazz->name);
+ utf_display(clazz->name);
log_text(name);
- log_text(sig);*/
+ log_text(sig);
*exceptionptr = new_exception(string_java_lang_NoSuchFieldError);
}
return f;
jobject GetObjectField (JNIEnv *env, jobject obj, jfieldID fieldID)
{
- return getField(obj,jobject,fieldID);
+ jobject dbg,dretval,*dpretval;
+ long int dli1, dli2, dli3;
+
+/* 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);*/
+
+ 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;
+
+ tmp = FindClass(env, "java/lang/Object");
+ mid = GetMethodID(env,tmp,"toString","()Ljava/lang/String;");
+ jstr = CallObjectMethod(env,dbg,mid);*/
+
+/* printf("GetObjectField(2): retval %p (obj: %#lx + offset: %#lx = %#lx (jobject*) %p (jobject) %p\n"
+ ,dbg, dli1, dli2, dli3,dpretval, dretval);*/
+
+
+ return dbg;
}
jboolean GetBooleanField (JNIEnv *env, jobject obj, jfieldID fieldID)
utf_new_char((char *) sig));
if (!m) *exceptionptr = new_exception(string_java_lang_NoSuchMethodError);
+ else if (!(m->flags & ACC_STATIC)) {
+ m=0;
+ *exceptionptr = new_exception(string_java_lang_NoSuchMethodError);
+ }
return m;
}
jobject CallStaticObjectMethod(JNIEnv *env, jclass clazz, jmethodID methodID, ...)
{
- log_text("JNI-Call: CallStaticObjectMethod");
+ jobject ret;
+ va_list vaargs;
- return NULL;
+ /* log_text("JNI-Call: CallStaticObjectMethod");*/
+
+ va_start(vaargs, methodID);
+ ret = callObjectMethod(0, methodID, vaargs);
+ va_end(vaargs);
+
+ return ret;
}
jobject CallStaticObjectMethodV(JNIEnv *env, jclass clazz, jmethodID methodID, va_list args)
{
- log_text("JNI-Call: CallStaticObjectMethodV");
-
- return NULL;
+ /* log_text("JNI-Call: CallStaticObjectMethodV"); */
+
+ return callObjectMethod(0,methodID,args);
}
}
+/** 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;
+
+ MonitorEnter(env, *global_ref_table);
+
+ refcount = CallObjectMethod(env, *global_ref_table, getmid, lobj);
+ val = (refcount == NULL) ? 0 : CallIntMethod(env, refcount, intvalue);
+ newval = NewObject(env, intclass, newint, val + 1);
+
+ if (newval != NULL) {
+ CallObjectMethod(env, *global_ref_table, putmid, lobj, newval);
+ MonitorExit(env, *global_ref_table);
+ return lobj;
+
+ } else {
+ log_text("JNI-NewGlobalRef: unable to create new java.lang.Integer");
+ MonitorExit(env, *global_ref_table);
+ return NULL;
+ }
+}
+
+/************* Deletes the global reference pointed to by globalRef **************/
+
+void DeleteGlobalRef(JNIEnv* env, jobject gref)
+{
+ jobject refcount;
+ jint val;
+
+ MonitorEnter(env, *global_ref_table);
+ refcount = CallObjectMethod(env, *global_ref_table, getmid, gref);
+
+ if (refcount == NULL) {
+ log_text("JNI-DeleteGlobalRef: unable to find global reference");
+ return;
+ }
+
+ val = CallIntMethod(env, refcount, intvalue);
+ val--;
+
+ if (val == 0) {
+ CallObjectMethod(env, *global_ref_table, removemid,refcount);
+
+ } else {
+ jobject newval = NewObject(env, intclass, newint, val);
+
+ if (newval != NULL) {
+ CallObjectMethod(env,*global_ref_table, putmid,newval);
+
+ } else {
+ log_text("JNI-DeleteGlobalRef: unable to create new java.lang.Integer");
+ }
+ }
+
+ MonitorExit(env,*global_ref_table);
+}
+
/******************************* check for pending exception ***********************/
return 0;
}
+/************* JNI Initialization ****************************************************/
+
+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);
+ }
+#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 (*global_ref_table == NULL) {
+ log_text("JNI-Init: unable to create new global_ref_table");
+ }
+
+ initrunning = false;
+
+ 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");
+ }
+
+ 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");
+ }
+
+ 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");
+ }
+
+ intvalue = GetMethodID(NULL, intclass, "intValue","()I");
+ if (intvalue == NULL) {
+ log_text("JNI-Init: unable to find method \"intValue\" in java.lang.Integer");
+ }
+
+ 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 */
+ envTable.NewGlobalRef = &NewGlobalRef;
+ envTable.DeleteGlobalRef = &DeleteGlobalRef;
+}
+
/********************************* JNI invocation table ******************************/
&FatalError,
&PushLocalFrame,
&PopLocalFrame,
- &NewGlobalRef,
- &DeleteGlobalRef,
+ &jni_init1, /* &NewGlobalRef, initialize Global_Ref_Table*/
+ &jni_init2, /* &DeleteGlobalRef,*/
&DeleteLocalRef,
&IsSameObject,
&NewLocalRef,
}
-
+#ifdef arglimit
if (argcount > 3) {
*exceptionptr = new_exception(string_java_lang_IllegalArgumentException);
log_text("Too many arguments. invokeNativeHelper does not support that");
return 0;
}
+#endif
if (((!params) && (argcount != 0)) || (params && (params->header.size != argcount))) {
*exceptionptr = new_exception(string_java_lang_IllegalArgumentException);
if (!(methodID->flags & ACC_STATIC) && (!obj)) {
- *exceptionptr = new_exception_message(string_java_lang_NullPointerException,
- "Static mismatch in Java_java_lang_reflect_Method_invokeNative");
+ *exceptionptr =
+ new_exception_message(string_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*/);
+ blk = MNEW(jni_callblock, /*4 */argcount+2);
retT = fill_callblock_objA(obj, methodID->descriptor, blk, params);
default:
/* if this happens the acception has already been set by fill_callblock_objA*/
- MFREE(blk, jni_callblock, 4 /*argcount+2*/);
+ MFREE(blk, jni_callblock, /*4 */ argcount+2);
return (jobject *) 0;
}
- MFREE(blk, jni_callblock, 4 /*argcount+2*/);
+ MFREE(blk, jni_callblock, /* 4 */ argcount+2);
if (*exceptionptr) {
java_objectheader *exceptionToWrap = *exceptionptr;
}
+
+
/*
* 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