#include <config.h>
#include <stdio.h>
#include <stddef.h>
#include <string.h>
#include <gcj/cni.h>
#include <jvm.h>
#include <java-assert.h>
#include <jni.h>
#ifdef ENABLE_JVMPI
#include <jvmpi.h>
#endif
#include <java/lang/Class.h>
#include <java/lang/ClassLoader.h>
#include <java/lang/Throwable.h>
#include <java/lang/ArrayIndexOutOfBoundsException.h>
#include <java/lang/StringIndexOutOfBoundsException.h>
#include <java/lang/StringBuffer.h>
#include <java/lang/UnsatisfiedLinkError.h>
#include <java/lang/InstantiationException.h>
#include <java/lang/NoSuchFieldError.h>
#include <java/lang/NoSuchMethodError.h>
#include <java/lang/reflect/Constructor.h>
#include <java/lang/reflect/Method.h>
#include <java/lang/reflect/Modifier.h>
#include <java/lang/OutOfMemoryError.h>
#include <java/lang/Integer.h>
#include <java/lang/ThreadGroup.h>
#include <java/lang/Thread.h>
#include <java/lang/IllegalAccessError.h>
#include <java/nio/DirectByteBufferImpl.h>
#include <java/util/IdentityHashMap.h>
#include <gnu/gcj/RawData.h>
#include <gcj/method.h>
#include <gcj/field.h>
#include <java-interp.h>
#include <java-threads.h>
using namespace gcj;
enum invocation_type
{
normal,
nonvirtual,
static_type,
constructor
};
extern struct JNINativeInterface _Jv_JNIFunctions;
extern struct JNIInvokeInterface _Jv_JNI_InvokeFunctions;
#define FRAME_SIZE 32
#define MARK_NONE 0
#define MARK_USER 1
#define MARK_SYSTEM 2
struct _Jv_JNI_LocalFrame
{
int marker : 2;
int size : 30;
_Jv_JNI_LocalFrame *next;
jobject vec[0];
};
static java::util::IdentityHashMap *local_ref_table;
static java::util::IdentityHashMap *global_ref_table;
static JavaVM *the_vm;
#ifdef ENABLE_JVMPI
static JVMPI_Interface _Jv_JVMPI_Interface;
static jint
jvmpiEnableEvent (jint event_type, void *)
{
switch (event_type)
{
case JVMPI_EVENT_OBJECT_ALLOC:
_Jv_JVMPI_Notify_OBJECT_ALLOC = _Jv_JVMPI_Interface.NotifyEvent;
break;
case JVMPI_EVENT_THREAD_START:
_Jv_JVMPI_Notify_THREAD_START = _Jv_JVMPI_Interface.NotifyEvent;
break;
case JVMPI_EVENT_THREAD_END:
_Jv_JVMPI_Notify_THREAD_END = _Jv_JVMPI_Interface.NotifyEvent;
break;
default:
return JVMPI_NOT_AVAILABLE;
}
return JVMPI_SUCCESS;
}
static jint
jvmpiDisableEvent (jint event_type, void *)
{
switch (event_type)
{
case JVMPI_EVENT_OBJECT_ALLOC:
_Jv_JVMPI_Notify_OBJECT_ALLOC = NULL;
break;
default:
return JVMPI_NOT_AVAILABLE;
}
return JVMPI_SUCCESS;
}
#endif
void
_Jv_JNI_Init (void)
{
local_ref_table = new java::util::IdentityHashMap;
global_ref_table = new java::util::IdentityHashMap;
#ifdef ENABLE_JVMPI
_Jv_JVMPI_Interface.version = 1;
_Jv_JVMPI_Interface.EnableEvent = &jvmpiEnableEvent;
_Jv_JVMPI_Interface.DisableEvent = &jvmpiDisableEvent;
_Jv_JVMPI_Interface.EnableGC = &_Jv_EnableGC;
_Jv_JVMPI_Interface.DisableGC = &_Jv_DisableGC;
_Jv_JVMPI_Interface.RunGC = &_Jv_RunGC;
#endif
}
static void
mark_for_gc (jobject obj, java::util::IdentityHashMap *ref_table)
{
JvSynchronize sync (ref_table);
using namespace java::lang;
Integer *refcount = (Integer *) ref_table->get (obj);
jint val = (refcount == NULL) ? 0 : refcount->intValue ();
ref_table->put (obj, new Integer (val + 1));
}
static void
unmark_for_gc (jobject obj, java::util::IdentityHashMap *ref_table)
{
JvSynchronize sync (ref_table);
using namespace java::lang;
Integer *refcount = (Integer *) ref_table->get (obj);
JvAssert (refcount);
jint val = refcount->intValue () - 1;
JvAssert (val >= 0);
if (val == 0)
ref_table->remove (obj);
else
ref_table->put (obj, new Integer (val));
}
template<typename T>
static T
unwrap (T val)
{
return val;
}
template<typename T>
static T *
unwrap (T *obj)
{
using namespace gnu::gcj::runtime;
if (obj == NULL || obj->getClass () != &JNIWeakRef::class$)
return obj;
JNIWeakRef *wr = reinterpret_cast<JNIWeakRef *> (obj);
return reinterpret_cast<T *> (wr->get ());
}
static jobject JNICALL
_Jv_JNI_NewGlobalRef (JNIEnv *, jobject obj)
{
obj = unwrap (obj);
mark_for_gc (obj, global_ref_table);
return obj;
}
static void JNICALL
_Jv_JNI_DeleteGlobalRef (JNIEnv *, jobject obj)
{
obj = unwrap (obj);
unmark_for_gc (obj, global_ref_table);
}
static void JNICALL
_Jv_JNI_DeleteLocalRef (JNIEnv *env, jobject obj)
{
_Jv_JNI_LocalFrame *frame;
obj = unwrap (obj);
for (frame = env->locals; frame != NULL; frame = frame->next)
{
for (int i = 0; i < frame->size; ++i)
{
if (frame->vec[i] == obj)
{
frame->vec[i] = NULL;
unmark_for_gc (obj, local_ref_table);
return;
}
}
JvAssert (frame->marker == MARK_NONE);
}
JvAssert (0);
}
static jint JNICALL
_Jv_JNI_EnsureLocalCapacity (JNIEnv *env, jint size)
{
_Jv_JNI_LocalFrame *frame;
try
{
frame = (_Jv_JNI_LocalFrame *) _Jv_Malloc (sizeof (_Jv_JNI_LocalFrame)
+ size * sizeof (jobject));
}
catch (jthrowable t)
{
env->ex = t;
return JNI_ERR;
}
frame->marker = MARK_NONE;
frame->size = size;
memset (&frame->vec[0], 0, size * sizeof (jobject));
frame->next = env->locals;
env->locals = frame;
return 0;
}
static jint JNICALL
_Jv_JNI_PushLocalFrame (JNIEnv *env, jint size)
{
jint r = _Jv_JNI_EnsureLocalCapacity (env, size);
if (r < 0)
return r;
env->locals->marker = MARK_USER;
return 0;
}
static jobject JNICALL
_Jv_JNI_NewLocalRef (JNIEnv *env, jobject obj)
{
obj = unwrap (obj);
_Jv_JNI_LocalFrame *frame = env->locals;
bool done = false, set = false;
for (; frame != NULL && ! done; frame = frame->next)
{
for (int i = 0; i < frame->size; ++i)
{
if (frame->vec[i] == NULL)
{
set = true;
done = true;
frame->vec[i] = obj;
break;
}
}
if (done || frame == NULL || frame->marker != MARK_NONE)
break;
}
if (! set)
{
_Jv_JNI_EnsureLocalCapacity (env, 16);
env->locals->vec[0] = obj;
}
mark_for_gc (obj, local_ref_table);
return obj;
}
static jobject JNICALL
_Jv_JNI_PopLocalFrame (JNIEnv *env, jobject result, int stop)
{
_Jv_JNI_LocalFrame *rf = env->locals;
bool done = false;
while (rf != NULL && ! done)
{
for (int i = 0; i < rf->size; ++i)
if (rf->vec[i] != NULL)
unmark_for_gc (rf->vec[i], local_ref_table);
done = (rf->marker == stop);
_Jv_JNI_LocalFrame *n = rf->next;
if (n == NULL)
{
memset (&rf->vec[0], 0, rf->size * sizeof (jobject));
break;
}
_Jv_Free (rf);
rf = n;
}
env->locals = rf;
return result == NULL ? NULL : _Jv_JNI_NewLocalRef (env, result);
}
static jobject JNICALL
_Jv_JNI_PopLocalFrame (JNIEnv *env, jobject result)
{
return _Jv_JNI_PopLocalFrame (env, result, MARK_USER);
}
template<typename T>
static bool
_Jv_JNI_check_types (JNIEnv *env, JArray<T> *array, jclass K)
{
jclass klass = array->getClass()->getComponentType();
if (__builtin_expect (klass != K, false))
{
env->ex = new java::lang::IllegalAccessError ();
return false;
}
else
return true;
}
extern "C" void
_Jv_JNI_PopSystemFrame (JNIEnv *env)
{
_Jv_JNI_PopLocalFrame (env, NULL, MARK_SYSTEM);
if (env->ex)
{
jthrowable t = env->ex;
env->ex = NULL;
throw t;
}
}
template<typename T> T extract_from_jvalue(jvalue const & t);
template<> jboolean extract_from_jvalue(jvalue const & jv) { return jv.z; }
template<> jbyte extract_from_jvalue(jvalue const & jv) { return jv.b; }
template<> jchar extract_from_jvalue(jvalue const & jv) { return jv.c; }
template<> jshort extract_from_jvalue(jvalue const & jv) { return jv.s; }
template<> jint extract_from_jvalue(jvalue const & jv) { return jv.i; }
template<> jlong extract_from_jvalue(jvalue const & jv) { return jv.j; }
template<> jfloat extract_from_jvalue(jvalue const & jv) { return jv.f; }
template<> jdouble extract_from_jvalue(jvalue const & jv) { return jv.d; }
template<> jobject extract_from_jvalue(jvalue const & jv) { return jv.l; }
template<typename T>
static T
wrap_value (JNIEnv *, T value)
{
return value;
}
template<typename R, typename T>
static T *
wrap_value (JNIEnv *env, T *value)
{
return (value == NULL
? value
: (T *) _Jv_JNI_NewLocalRef (env, (jobject) value));
}
static jint JNICALL
_Jv_JNI_GetVersion (JNIEnv *)
{
return JNI_VERSION_1_4;
}
static jclass JNICALL
_Jv_JNI_DefineClass (JNIEnv *env, const char *name, jobject loader,
const jbyte *buf, jsize bufLen)
{
try
{
loader = unwrap (loader);
jstring sname = JvNewStringUTF (name);
jbyteArray bytes = JvNewByteArray (bufLen);
jbyte *elts = elements (bytes);
memcpy (elts, buf, bufLen * sizeof (jbyte));
java::lang::ClassLoader *l
= reinterpret_cast<java::lang::ClassLoader *> (loader);
jclass result = l->defineClass (sname, bytes, 0, bufLen);
return (jclass) wrap_value (env, result);
}
catch (jthrowable t)
{
env->ex = t;
return NULL;
}
}
static jclass JNICALL
_Jv_JNI_FindClass (JNIEnv *env, const char *name)
{
int len = strlen (name);
char s[len + 1];
for (int i = 0; i <= len; ++i)
s[i] = (name[i] == '/') ? '.' : name[i];
jclass r = NULL;
try
{
jstring n = JvNewStringUTF (s);
java::lang::ClassLoader *loader = NULL;
if (env->klass != NULL)
loader = env->klass->getClassLoaderInternal ();
if (loader == NULL)
{
loader = java::lang::ClassLoader::getSystemClassLoader ();
}
r = loader->loadClass (n);
}
catch (jthrowable t)
{
env->ex = t;
}
return (jclass) wrap_value (env, r);
}
static jclass JNICALL
_Jv_JNI_GetSuperclass (JNIEnv *env, jclass clazz)
{
return (jclass) wrap_value (env, unwrap (clazz)->getSuperclass ());
}
static jboolean JNICALL
_Jv_JNI_IsAssignableFrom (JNIEnv *, jclass clazz1, jclass clazz2)
{
return unwrap (clazz1)->isAssignableFrom (unwrap (clazz2));
}
static jint JNICALL
_Jv_JNI_Throw (JNIEnv *env, jthrowable obj)
{
obj = unwrap (obj);
JvAssert (obj != NULL && java::lang::Throwable::class$.isInstance (obj));
env->ex = obj;
return 0;
}
static jint JNICALL
_Jv_JNI_ThrowNew (JNIEnv *env, jclass clazz, const char *message)
{
using namespace java::lang::reflect;
clazz = unwrap (clazz);
JvAssert (java::lang::Throwable::class$.isAssignableFrom (clazz));
int r = JNI_OK;
try
{
JArray<jclass> *argtypes
= (JArray<jclass> *) JvNewObjectArray (1, &java::lang::Class::class$,
NULL);
jclass *elts = elements (argtypes);
elts[0] = &StringClass;
Constructor *cons = clazz->getConstructor (argtypes);
jobjectArray values = JvNewObjectArray (1, &StringClass, NULL);
jobject *velts = elements (values);
velts[0] = JvNewStringUTF (message);
jobject obj = cons->newInstance (values);
env->ex = reinterpret_cast<jthrowable> (obj);
}
catch (jthrowable t)
{
env->ex = t;
r = JNI_ERR;
}
return r;
}
static jthrowable JNICALL
_Jv_JNI_ExceptionOccurred (JNIEnv *env)
{
return (jthrowable) wrap_value (env, env->ex);
}
static void JNICALL
_Jv_JNI_ExceptionDescribe (JNIEnv *env)
{
if (env->ex != NULL)
env->ex->printStackTrace();
}
static void JNICALL
_Jv_JNI_ExceptionClear (JNIEnv *env)
{
env->ex = NULL;
}
static jboolean JNICALL
_Jv_JNI_ExceptionCheck (JNIEnv *env)
{
return env->ex != NULL;
}
static void JNICALL
_Jv_JNI_FatalError (JNIEnv *, const char *message)
{
JvFail (message);
}
static jboolean JNICALL
_Jv_JNI_IsSameObject (JNIEnv *, jobject obj1, jobject obj2)
{
return unwrap (obj1) == unwrap (obj2);
}
static jobject JNICALL
_Jv_JNI_AllocObject (JNIEnv *env, jclass clazz)
{
jobject obj = NULL;
using namespace java::lang::reflect;
try
{
clazz = unwrap (clazz);
JvAssert (clazz && ! clazz->isArray ());
if (clazz->isInterface() || Modifier::isAbstract(clazz->getModifiers()))
env->ex = new java::lang::InstantiationException ();
else
obj = _Jv_AllocObject (clazz);
}
catch (jthrowable t)
{
env->ex = t;
}
return wrap_value (env, obj);
}
static jclass JNICALL
_Jv_JNI_GetObjectClass (JNIEnv *env, jobject obj)
{
obj = unwrap (obj);
JvAssert (obj);
return (jclass) wrap_value (env, obj->getClass());
}
static jboolean JNICALL
_Jv_JNI_IsInstanceOf (JNIEnv *, jobject obj, jclass clazz)
{
return unwrap (clazz)->isInstance(unwrap (obj));
}
template<jboolean is_static>
static jmethodID JNICALL
_Jv_JNI_GetAnyMethodID (JNIEnv *env, jclass clazz,
const char *name, const char *sig)
{
try
{
clazz = unwrap (clazz);
_Jv_InitClass (clazz);
_Jv_Utf8Const *name_u = _Jv_makeUtf8Const ((char *) name, -1);
int len = strlen (sig);
char s[len + 1];
for (int i = 0; i <= len; ++i)
s[i] = (sig[i] == '/') ? '.' : sig[i];
_Jv_Utf8Const *sig_u = _Jv_makeUtf8Const ((char *) s, -1);
JvAssert (! clazz->isPrimitive());
using namespace java::lang::reflect;
while (clazz != NULL)
{
jint count = JvNumMethods (clazz);
jmethodID meth = JvGetFirstMethod (clazz);
for (jint i = 0; i < count; ++i)
{
if (((is_static && Modifier::isStatic (meth->accflags))
|| (! is_static && ! Modifier::isStatic (meth->accflags)))
&& _Jv_equalUtf8Consts (meth->name, name_u)
&& _Jv_equalUtf8Consts (meth->signature, sig_u))
return meth;
meth = meth->getNextMethod();
}
clazz = clazz->getSuperclass ();
}
java::lang::StringBuffer *name_sig =
new java::lang::StringBuffer (JvNewStringUTF (name));
name_sig->append ((jchar) ' ')->append (JvNewStringUTF (s));
env->ex = new java::lang::NoSuchMethodError (name_sig->toString ());
}
catch (jthrowable t)
{
env->ex = t;
}
return NULL;
}
static void
array_from_valist (jvalue *values, JArray<jclass> *arg_types, va_list vargs)
{
jclass *arg_elts = elements (arg_types);
for (int i = 0; i < arg_types->length; ++i)
{
JvAssert (sizeof (int) >= sizeof (jint));
JvAssert (sizeof (jlong) >= sizeof (int));
JvAssert (sizeof (double) >= sizeof (jfloat));
JvAssert (sizeof (double) >= sizeof (jdouble));
if (arg_elts[i] == JvPrimClass (byte))
values[i].b = (jbyte) va_arg (vargs, int);
else if (arg_elts[i] == JvPrimClass (short))
values[i].s = (jshort) va_arg (vargs, int);
else if (arg_elts[i] == JvPrimClass (int))
values[i].i = (jint) va_arg (vargs, int);
else if (arg_elts[i] == JvPrimClass (long))
values[i].j = (jlong) va_arg (vargs, jlong);
else if (arg_elts[i] == JvPrimClass (float))
values[i].f = (jfloat) va_arg (vargs, double);
else if (arg_elts[i] == JvPrimClass (double))
values[i].d = (jdouble) va_arg (vargs, double);
else if (arg_elts[i] == JvPrimClass (boolean))
values[i].z = (jboolean) va_arg (vargs, int);
else if (arg_elts[i] == JvPrimClass (char))
values[i].c = (jchar) va_arg (vargs, int);
else
{
values[i].l = unwrap (va_arg (vargs, jobject));
}
}
}
template<typename T, invocation_type style>
static T JNICALL
_Jv_JNI_CallAnyMethodV (JNIEnv *env, jobject obj, jclass klass,
jmethodID id, va_list vargs)
{
obj = unwrap (obj);
klass = unwrap (klass);
jclass decl_class = klass ? klass : obj->getClass ();
JvAssert (decl_class != NULL);
jclass return_type;
JArray<jclass> *arg_types;
try
{
_Jv_GetTypesFromSignature (id, decl_class,
&arg_types, &return_type);
jvalue args[arg_types->length];
array_from_valist (args, arg_types, vargs);
if (style == constructor)
return_type = klass;
jvalue result;
_Jv_CallAnyMethodA (obj, return_type, id,
style == constructor,
style == normal,
arg_types, args, &result);
return wrap_value (env, extract_from_jvalue<T>(result));
}
catch (jthrowable t)
{
env->ex = t;
}
return wrap_value (env, (T) 0);
}
template<typename T, invocation_type style>
static T JNICALL
_Jv_JNI_CallAnyMethod (JNIEnv *env, jobject obj, jclass klass,
jmethodID method, ...)
{
va_list args;
T result;
va_start (args, method);
result = _Jv_JNI_CallAnyMethodV<T, style> (env, obj, klass, method, args);
va_end (args);
return result;
}
template<typename T, invocation_type style>
static T JNICALL
_Jv_JNI_CallAnyMethodA (JNIEnv *env, jobject obj, jclass klass,
jmethodID id, jvalue *args)
{
obj = unwrap (obj);
klass = unwrap (klass);
jclass decl_class = klass ? klass : obj->getClass ();
JvAssert (decl_class != NULL);
jclass return_type;
JArray<jclass> *arg_types;
try
{
_Jv_GetTypesFromSignature (id, decl_class,
&arg_types, &return_type);
if (style == constructor)
return_type = klass;
jclass *type_elts = elements (arg_types);
jvalue arg_copy[arg_types->length];
for (int i = 0; i < arg_types->length; ++i)
{
if (type_elts[i]->isPrimitive ())
arg_copy[i] = args[i];
else
arg_copy[i].l = unwrap (args[i].l);
}
jvalue result;
_Jv_CallAnyMethodA (obj, return_type, id,
style == constructor,
style == normal,
arg_types, arg_copy, &result);
return wrap_value (env, extract_from_jvalue<T>(result));
}
catch (jthrowable t)
{
env->ex = t;
}
return wrap_value (env, (T) 0);
}
template<invocation_type style>
static void JNICALL
_Jv_JNI_CallAnyVoidMethodV (JNIEnv *env, jobject obj, jclass klass,
jmethodID id, va_list vargs)
{
obj = unwrap (obj);
klass = unwrap (klass);
jclass decl_class = klass ? klass : obj->getClass ();
JvAssert (decl_class != NULL);
jclass return_type;
JArray<jclass> *arg_types;
try
{
_Jv_GetTypesFromSignature (id, decl_class,
&arg_types, &return_type);
jvalue args[arg_types->length];
array_from_valist (args, arg_types, vargs);
if (style == constructor)
return_type = klass;
_Jv_CallAnyMethodA (obj, return_type, id,
style == constructor,
style == normal,
arg_types, args, NULL);
}
catch (jthrowable t)
{
env->ex = t;
}
}
template<invocation_type style>
static void JNICALL
_Jv_JNI_CallAnyVoidMethod (JNIEnv *env, jobject obj, jclass klass,
jmethodID method, ...)
{
va_list args;
va_start (args, method);
_Jv_JNI_CallAnyVoidMethodV<style> (env, obj, klass, method, args);
va_end (args);
}
template<invocation_type style>
static void JNICALL
_Jv_JNI_CallAnyVoidMethodA (JNIEnv *env, jobject obj, jclass klass,
jmethodID id, jvalue *args)
{
jclass decl_class = klass ? klass : obj->getClass ();
JvAssert (decl_class != NULL);
jclass return_type;
JArray<jclass> *arg_types;
try
{
_Jv_GetTypesFromSignature (id, decl_class,
&arg_types, &return_type);
jclass *type_elts = elements (arg_types);
jvalue arg_copy[arg_types->length];
for (int i = 0; i < arg_types->length; ++i)
{
if (type_elts[i]->isPrimitive ())
arg_copy[i] = args[i];
else
arg_copy[i].l = unwrap (args[i].l);
}
_Jv_CallAnyMethodA (obj, return_type, id,
style == constructor,
style == normal,
arg_types, args, NULL);
}
catch (jthrowable t)
{
env->ex = t;
}
}
template<typename T>
static T JNICALL
_Jv_JNI_CallMethodV (JNIEnv *env, jobject obj,
jmethodID id, va_list args)
{
return _Jv_JNI_CallAnyMethodV<T, normal> (env, obj, NULL, id, args);
}
template<typename T>
static T JNICALL
_Jv_JNI_CallMethod (JNIEnv *env, jobject obj, jmethodID id, ...)
{
va_list args;
T result;
va_start (args, id);
result = _Jv_JNI_CallAnyMethodV<T, normal> (env, obj, NULL, id, args);
va_end (args);
return result;
}
template<typename T>
static T JNICALL
_Jv_JNI_CallMethodA (JNIEnv *env, jobject obj,
jmethodID id, jvalue *args)
{
return _Jv_JNI_CallAnyMethodA<T, normal> (env, obj, NULL, id, args);
}
static void JNICALL
_Jv_JNI_CallVoidMethodV (JNIEnv *env, jobject obj,
jmethodID id, va_list args)
{
_Jv_JNI_CallAnyVoidMethodV<normal> (env, obj, NULL, id, args);
}
static void JNICALL
_Jv_JNI_CallVoidMethod (JNIEnv *env, jobject obj, jmethodID id, ...)
{
va_list args;
va_start (args, id);
_Jv_JNI_CallAnyVoidMethodV<normal> (env, obj, NULL, id, args);
va_end (args);
}
static void JNICALL
_Jv_JNI_CallVoidMethodA (JNIEnv *env, jobject obj,
jmethodID id, jvalue *args)
{
_Jv_JNI_CallAnyVoidMethodA<normal> (env, obj, NULL, id, args);
}
template<typename T>
static T JNICALL
_Jv_JNI_CallStaticMethodV (JNIEnv *env, jclass klass,
jmethodID id, va_list args)
{
JvAssert (((id->accflags) & java::lang::reflect::Modifier::STATIC));
JvAssert (java::lang::Class::class$.isInstance (unwrap (klass)));
return _Jv_JNI_CallAnyMethodV<T, static_type> (env, NULL, klass, id, args);
}
template<typename T>
static T JNICALL
_Jv_JNI_CallStaticMethod (JNIEnv *env, jclass klass,
jmethodID id, ...)
{
va_list args;
T result;
JvAssert (((id->accflags) & java::lang::reflect::Modifier::STATIC));
JvAssert (java::lang::Class::class$.isInstance (unwrap (klass)));
va_start (args, id);
result = _Jv_JNI_CallAnyMethodV<T, static_type> (env, NULL, klass,
id, args);
va_end (args);
return result;
}
template<typename T>
static T JNICALL
_Jv_JNI_CallStaticMethodA (JNIEnv *env, jclass klass, jmethodID id,
jvalue *args)
{
JvAssert (((id->accflags) & java::lang::reflect::Modifier::STATIC));
JvAssert (java::lang::Class::class$.isInstance (unwrap (klass)));
return _Jv_JNI_CallAnyMethodA<T, static_type> (env, NULL, klass, id, args);
}
static void JNICALL
_Jv_JNI_CallStaticVoidMethodV (JNIEnv *env, jclass klass,
jmethodID id, va_list args)
{
_Jv_JNI_CallAnyVoidMethodV<static_type> (env, NULL, klass, id, args);
}
static void JNICALL
_Jv_JNI_CallStaticVoidMethod (JNIEnv *env, jclass klass,
jmethodID id, ...)
{
va_list args;
va_start (args, id);
_Jv_JNI_CallAnyVoidMethodV<static_type> (env, NULL, klass, id, args);
va_end (args);
}
static void JNICALL
_Jv_JNI_CallStaticVoidMethodA (JNIEnv *env, jclass klass,
jmethodID id, jvalue *args)
{
_Jv_JNI_CallAnyVoidMethodA<static_type> (env, NULL, klass, id, args);
}
static jobject JNICALL
_Jv_JNI_NewObjectV (JNIEnv *env, jclass klass,
jmethodID id, va_list args)
{
JvAssert (klass && ! klass->isArray ());
JvAssert (! strcmp (id->name->data, "<init>")
&& id->signature->length > 2
&& id->signature->data[0] == '('
&& ! strcmp (&id->signature->data[id->signature->length - 2],
")V"));
return _Jv_JNI_CallAnyMethodV<jobject, constructor> (env, NULL, klass,
id, args);
}
static jobject JNICALL
_Jv_JNI_NewObject (JNIEnv *env, jclass klass, jmethodID id, ...)
{
JvAssert (klass && ! klass->isArray ());
JvAssert (! strcmp (id->name->data, "<init>")
&& id->signature->length > 2
&& id->signature->data[0] == '('
&& ! strcmp (&id->signature->data[id->signature->length - 2],
")V"));
va_list args;
jobject result;
va_start (args, id);
result = _Jv_JNI_CallAnyMethodV<jobject, constructor> (env, NULL, klass,
id, args);
va_end (args);
return result;
}
static jobject JNICALL
_Jv_JNI_NewObjectA (JNIEnv *env, jclass klass, jmethodID id,
jvalue *args)
{
JvAssert (klass && ! klass->isArray ());
JvAssert (! strcmp (id->name->data, "<init>")
&& id->signature->length > 2
&& id->signature->data[0] == '('
&& ! strcmp (&id->signature->data[id->signature->length - 2],
")V"));
return _Jv_JNI_CallAnyMethodA<jobject, constructor> (env, NULL, klass,
id, args);
}
template<typename T>
static T JNICALL
_Jv_JNI_GetField (JNIEnv *env, jobject obj, jfieldID field)
{
obj = unwrap (obj);
JvAssert (obj);
T *ptr = (T *) ((char *) obj + field->getOffset ());
return wrap_value (env, *ptr);
}
template<typename T>
static void JNICALL
_Jv_JNI_SetField (JNIEnv *, jobject obj, jfieldID field, T value)
{
obj = unwrap (obj);
value = unwrap (value);
JvAssert (obj);
T *ptr = (T *) ((char *) obj + field->getOffset ());
*ptr = value;
}
template<jboolean is_static>
static jfieldID JNICALL
_Jv_JNI_GetAnyFieldID (JNIEnv *env, jclass clazz,
const char *name, const char *sig)
{
try
{
clazz = unwrap (clazz);
_Jv_InitClass (clazz);
_Jv_Utf8Const *a_name = _Jv_makeUtf8Const ((char *) name, -1);
int len = strlen (sig);
char s[len + 1];
for (int i = 0; i <= len; ++i)
s[i] = (sig[i] == '/') ? '.' : sig[i];
jclass field_class = _Jv_FindClassFromSignature ((char *) s, NULL);
java::lang::ClassLoader *loader = clazz->getClassLoaderInternal ();
while (clazz != NULL)
{
JvSynchronize sync (clazz);
jint count = (is_static
? JvNumStaticFields (clazz)
: JvNumInstanceFields (clazz));
jfieldID field = (is_static
? JvGetFirstStaticField (clazz)
: JvGetFirstInstanceField (clazz));
for (jint i = 0; i < count; ++i)
{
_Jv_Utf8Const *f_name = field->getNameUtf8Const(clazz);
_Jv_ResolveField (field, loader);
if (_Jv_equalUtf8Consts (f_name, a_name)
&& field->getClass() == field_class)
return field;
field = field->getNextField ();
}
clazz = clazz->getSuperclass ();
}
env->ex = new java::lang::NoSuchFieldError ();
}
catch (jthrowable t)
{
env->ex = t;
}
return NULL;
}
template<typename T>
static T JNICALL
_Jv_JNI_GetStaticField (JNIEnv *env, jclass, jfieldID field)
{
T *ptr = (T *) field->u.addr;
return wrap_value (env, *ptr);
}
template<typename T>
static void JNICALL
_Jv_JNI_SetStaticField (JNIEnv *, jclass, jfieldID field, T value)
{
value = unwrap (value);
T *ptr = (T *) field->u.addr;
*ptr = value;
}
static jstring JNICALL
_Jv_JNI_NewString (JNIEnv *env, const jchar *unichars, jsize len)
{
try
{
jstring r = _Jv_NewString (unichars, len);
return (jstring) wrap_value (env, r);
}
catch (jthrowable t)
{
env->ex = t;
return NULL;
}
}
static jsize JNICALL
_Jv_JNI_GetStringLength (JNIEnv *, jstring string)
{
return unwrap (string)->length();
}
static const jchar * JNICALL
_Jv_JNI_GetStringChars (JNIEnv *, jstring string, jboolean *isCopy)
{
string = unwrap (string);
jchar *result = _Jv_GetStringChars (string);
mark_for_gc (string, global_ref_table);
if (isCopy)
*isCopy = false;
return (const jchar *) result;
}
static void JNICALL
_Jv_JNI_ReleaseStringChars (JNIEnv *, jstring string, const jchar *)
{
unmark_for_gc (unwrap (string), global_ref_table);
}
static jstring JNICALL
_Jv_JNI_NewStringUTF (JNIEnv *env, const char *bytes)
{
try
{
jstring result = JvNewStringUTF (bytes);
return (jstring) wrap_value (env, result);
}
catch (jthrowable t)
{
env->ex = t;
return NULL;
}
}
static jsize JNICALL
_Jv_JNI_GetStringUTFLength (JNIEnv *, jstring string)
{
return JvGetStringUTFLength (unwrap (string));
}
static const char * JNICALL
_Jv_JNI_GetStringUTFChars (JNIEnv *env, jstring string,
jboolean *isCopy)
{
try
{
string = unwrap (string);
if (string == NULL)
return NULL;
jsize len = JvGetStringUTFLength (string);
char *r = (char *) _Jv_Malloc (len + 1);
JvGetStringUTFRegion (string, 0, string->length(), r);
r[len] = '\0';
if (isCopy)
*isCopy = true;
return (const char *) r;
}
catch (jthrowable t)
{
env->ex = t;
return NULL;
}
}
static void JNICALL
_Jv_JNI_ReleaseStringUTFChars (JNIEnv *, jstring, const char *utf)
{
_Jv_Free ((void *) utf);
}
static void JNICALL
_Jv_JNI_GetStringRegion (JNIEnv *env, jstring string, jsize start,
jsize len, jchar *buf)
{
string = unwrap (string);
jchar *result = _Jv_GetStringChars (string);
if (start < 0 || start > string->length ()
|| len < 0 || start + len > string->length ())
{
try
{
env->ex = new java::lang::StringIndexOutOfBoundsException ();
}
catch (jthrowable t)
{
env->ex = t;
}
}
else
memcpy (buf, &result[start], len * sizeof (jchar));
}
static void JNICALL
_Jv_JNI_GetStringUTFRegion (JNIEnv *env, jstring str, jsize start,
jsize len, char *buf)
{
str = unwrap (str);
if (start < 0 || start > str->length ()
|| len < 0 || start + len > str->length ())
{
try
{
env->ex = new java::lang::StringIndexOutOfBoundsException ();
}
catch (jthrowable t)
{
env->ex = t;
}
}
else
_Jv_GetStringUTFRegion (str, start, len, buf);
}
static const jchar * JNICALL
_Jv_JNI_GetStringCritical (JNIEnv *, jstring str, jboolean *isCopy)
{
jchar *result = _Jv_GetStringChars (unwrap (str));
if (isCopy)
*isCopy = false;
return result;
}
static void JNICALL
_Jv_JNI_ReleaseStringCritical (JNIEnv *, jstring, const jchar *)
{
}
static jsize JNICALL
_Jv_JNI_GetArrayLength (JNIEnv *, jarray array)
{
return unwrap (array)->length;
}
static jarray JNICALL
_Jv_JNI_NewObjectArray (JNIEnv *env, jsize length,
jclass elementClass, jobject init)
{
try
{
elementClass = unwrap (elementClass);
init = unwrap (init);
_Jv_CheckCast (elementClass, init);
jarray result = JvNewObjectArray (length, elementClass, init);
return (jarray) wrap_value (env, result);
}
catch (jthrowable t)
{
env->ex = t;
return NULL;
}
}
static jobject JNICALL
_Jv_JNI_GetObjectArrayElement (JNIEnv *env, jobjectArray array,
jsize index)
{
if ((unsigned) index >= (unsigned) array->length)
_Jv_ThrowBadArrayIndex (index);
jobject *elts = elements (unwrap (array));
return wrap_value (env, elts[index]);
}
static void JNICALL
_Jv_JNI_SetObjectArrayElement (JNIEnv *env, jobjectArray array,
jsize index, jobject value)
{
try
{
array = unwrap (array);
value = unwrap (value);
_Jv_CheckArrayStore (array, value);
if ((unsigned) index >= (unsigned) array->length)
_Jv_ThrowBadArrayIndex (index);
jobject *elts = elements (array);
elts[index] = value;
}
catch (jthrowable t)
{
env->ex = t;
}
}
template<typename T, jclass K>
static JArray<T> * JNICALL
_Jv_JNI_NewPrimitiveArray (JNIEnv *env, jsize length)
{
try
{
return (JArray<T> *) wrap_value (env, _Jv_NewPrimArray (K, length));
}
catch (jthrowable t)
{
env->ex = t;
return NULL;
}
}
template<typename T, jclass K>
static T * JNICALL
_Jv_JNI_GetPrimitiveArrayElements (JNIEnv *env, JArray<T> *array,
jboolean *isCopy)
{
array = unwrap (array);
if (! _Jv_JNI_check_types (env, array, K))
return NULL;
T *elts = elements (array);
if (isCopy)
{
*isCopy = false;
}
mark_for_gc (array, global_ref_table);
return elts;
}
template<typename T, jclass K>
static void JNICALL
_Jv_JNI_ReleasePrimitiveArrayElements (JNIEnv *env, JArray<T> *array,
T *, jint )
{
array = unwrap (array);
_Jv_JNI_check_types (env, array, K);
unmark_for_gc (array, global_ref_table);
}
template<typename T, jclass K>
static void JNICALL
_Jv_JNI_GetPrimitiveArrayRegion (JNIEnv *env, JArray<T> *array,
jsize start, jsize len,
T *buf)
{
array = unwrap (array);
if (! _Jv_JNI_check_types (env, array, K))
return;
if (start < 0 || len < 0
|| (unsigned long) (start + len) > (unsigned long) array->length)
{
try
{
env->ex = new java::lang::ArrayIndexOutOfBoundsException ();
}
catch (jthrowable t)
{
env->ex = t;
}
}
else
{
T *elts = elements (array) + start;
memcpy (buf, elts, len * sizeof (T));
}
}
template<typename T, jclass K>
static void JNICALL
_Jv_JNI_SetPrimitiveArrayRegion (JNIEnv *env, JArray<T> *array,
jsize start, jsize len, T *buf)
{
array = unwrap (array);
if (! _Jv_JNI_check_types (env, array, K))
return;
if (start < 0 || len < 0
|| (unsigned long) (start + len) > (unsigned long) array->length)
{
try
{
env->ex = new java::lang::ArrayIndexOutOfBoundsException ();
}
catch (jthrowable t)
{
env->ex = t;
}
}
else
{
T *elts = elements (array) + start;
memcpy (elts, buf, len * sizeof (T));
}
}
static void * JNICALL
_Jv_JNI_GetPrimitiveArrayCritical (JNIEnv *, jarray array,
jboolean *isCopy)
{
array = unwrap (array);
jclass klass = array->getClass()->getComponentType();
JvAssert (klass->isPrimitive ());
char *r = _Jv_GetArrayElementFromElementType (array, klass);
if (isCopy)
*isCopy = false;
return r;
}
static void JNICALL
_Jv_JNI_ReleasePrimitiveArrayCritical (JNIEnv *, jarray, void *, jint)
{
}
static jint JNICALL
_Jv_JNI_MonitorEnter (JNIEnv *env, jobject obj)
{
try
{
_Jv_MonitorEnter (unwrap (obj));
return 0;
}
catch (jthrowable t)
{
env->ex = t;
}
return JNI_ERR;
}
static jint JNICALL
_Jv_JNI_MonitorExit (JNIEnv *env, jobject obj)
{
try
{
_Jv_MonitorExit (unwrap (obj));
return 0;
}
catch (jthrowable t)
{
env->ex = t;
}
return JNI_ERR;
}
jobject JNICALL
_Jv_JNI_ToReflectedField (JNIEnv *env, jclass cls, jfieldID fieldID,
jboolean)
{
try
{
cls = unwrap (cls);
java::lang::reflect::Field *field = new java::lang::reflect::Field();
field->declaringClass = cls;
field->offset = (char*) fieldID - (char *) cls->fields;
field->name = _Jv_NewStringUtf8Const (fieldID->getNameUtf8Const (cls));
return wrap_value (env, field);
}
catch (jthrowable t)
{
env->ex = t;
}
return NULL;
}
static jfieldID JNICALL
_Jv_JNI_FromReflectedField (JNIEnv *, jobject f)
{
using namespace java::lang::reflect;
f = unwrap (f);
Field *field = reinterpret_cast<Field *> (f);
return _Jv_FromReflectedField (field);
}
jobject JNICALL
_Jv_JNI_ToReflectedMethod (JNIEnv *env, jclass klass, jmethodID id,
jboolean)
{
using namespace java::lang::reflect;
jobject result = NULL;
klass = unwrap (klass);
try
{
if (_Jv_equalUtf8Consts (id->name, init_name))
{
Constructor *cons = new Constructor ();
cons->offset = (char *) id - (char *) &klass->methods;
cons->declaringClass = klass;
result = cons;
}
else
{
Method *meth = new Method ();
meth->offset = (char *) id - (char *) &klass->methods;
meth->declaringClass = klass;
result = meth;
}
}
catch (jthrowable t)
{
env->ex = t;
}
return wrap_value (env, result);
}
static jmethodID JNICALL
_Jv_JNI_FromReflectedMethod (JNIEnv *, jobject method)
{
using namespace java::lang::reflect;
method = unwrap (method);
if (Method::class$.isInstance (method))
return _Jv_FromReflectedMethod (reinterpret_cast<Method *> (method));
return
_Jv_FromReflectedConstructor (reinterpret_cast<Constructor *> (method));
}
jweak JNICALL
_Jv_JNI_NewWeakGlobalRef (JNIEnv *env, jobject obj)
{
using namespace gnu::gcj::runtime;
JNIWeakRef *ref = NULL;
try
{
obj = unwrap (obj);
ref = new JNIWeakRef (obj);
mark_for_gc (ref, global_ref_table);
}
catch (jthrowable t)
{
env->ex = t;
}
return reinterpret_cast<jweak> (ref);
}
void JNICALL
_Jv_JNI_DeleteWeakGlobalRef (JNIEnv *, jweak obj)
{
using namespace gnu::gcj::runtime;
JNIWeakRef *ref = reinterpret_cast<JNIWeakRef *> (obj);
unmark_for_gc (ref, global_ref_table);
ref->clear ();
}
static jobject JNICALL
_Jv_JNI_NewDirectByteBuffer (JNIEnv *, void *address, jlong length)
{
using namespace gnu::gcj;
using namespace java::nio;
return new DirectByteBufferImpl (reinterpret_cast<RawData *> (address),
length);
}
static void * JNICALL
_Jv_JNI_GetDirectBufferAddress (JNIEnv *, jobject buffer)
{
using namespace java::nio;
DirectByteBufferImpl* bb = static_cast<DirectByteBufferImpl *> (buffer);
return reinterpret_cast<void *> (bb->address);
}
static jlong JNICALL
_Jv_JNI_GetDirectBufferCapacity (JNIEnv *, jobject buffer)
{
using namespace java::nio;
DirectByteBufferImpl* bb = static_cast<DirectByteBufferImpl *> (buffer);
return bb->capacity();
}
static JNINativeMethod *nathash;
static int nathash_count = 0;
static int nathash_size = 0;
#define DELETED_ENTRY ((char *) (~0))
static int
hash (const JNINativeMethod *method)
{
char *ptr;
int hash = 0;
ptr = method->name;
while (*ptr)
hash = (31 * hash) + *ptr++;
ptr = method->signature;
while (*ptr)
hash = (31 * hash) + *ptr++;
return hash;
}
static JNINativeMethod *
nathash_find_slot (const JNINativeMethod *method)
{
jint h = hash (method);
int step = (h ^ (h >> 16)) | 1;
int w = h & (nathash_size - 1);
int del = -1;
for (;;)
{
JNINativeMethod *slotp = &nathash[w];
if (slotp->name == NULL)
{
if (del >= 0)
return &nathash[del];
else
return slotp;
}
else if (slotp->name == DELETED_ENTRY)
del = w;
else if (! strcmp (slotp->name, method->name)
&& ! strcmp (slotp->signature, method->signature))
return slotp;
w = (w + step) & (nathash_size - 1);
}
}
static void *
nathash_find (JNINativeMethod *method)
{
if (nathash == NULL)
return NULL;
JNINativeMethod *slot = nathash_find_slot (method);
if (slot->name == NULL || slot->name == DELETED_ENTRY)
return NULL;
return slot->fnPtr;
}
static void
natrehash ()
{
if (nathash == NULL)
{
nathash_size = 1024;
nathash =
(JNINativeMethod *) _Jv_AllocBytes (nathash_size
* sizeof (JNINativeMethod));
memset (nathash, 0, nathash_size * sizeof (JNINativeMethod));
}
else
{
int savesize = nathash_size;
JNINativeMethod *savehash = nathash;
nathash_size *= 2;
nathash =
(JNINativeMethod *) _Jv_AllocBytes (nathash_size
* sizeof (JNINativeMethod));
memset (nathash, 0, nathash_size * sizeof (JNINativeMethod));
for (int i = 0; i < savesize; ++i)
{
if (savehash[i].name != NULL && savehash[i].name != DELETED_ENTRY)
{
JNINativeMethod *slot = nathash_find_slot (&savehash[i]);
*slot = savehash[i];
}
}
}
}
static void
nathash_add (const JNINativeMethod *method)
{
if (3 * nathash_count >= 2 * nathash_size)
natrehash ();
JNINativeMethod *slot = nathash_find_slot (method);
if (slot->name != NULL && slot->name != DELETED_ENTRY)
return;
slot->name = strdup (method->name);
slot->signature = strdup (method->signature);
slot->fnPtr = method->fnPtr;
}
static jint JNICALL
_Jv_JNI_RegisterNatives (JNIEnv *env, jclass klass,
const JNINativeMethod *methods,
jint nMethods)
{
JvSynchronize sync (global_ref_table);
for (int j = 0; j < nMethods; ++j)
{
bool found = false;
_Jv_Method *imeths = JvGetFirstMethod (klass);
for (int i = 0; i < JvNumMethods (klass); ++i)
{
_Jv_Method *self = &imeths[i];
if (! strcmp (self->name->chars (), methods[j].name)
&& ! strcmp (self->signature->chars (), methods[j].signature))
{
if (! (self->accflags & java::lang::reflect::Modifier::NATIVE))
break;
found = true;
nathash_add (&methods[j]);
break;
}
}
if (! found)
{
jstring m = JvNewStringUTF (methods[j].name);
try
{
env->ex = new java::lang::NoSuchMethodError (m);
}
catch (jthrowable t)
{
env->ex = t;
}
return JNI_ERR;
}
}
return JNI_OK;
}
static jint JNICALL
_Jv_JNI_UnregisterNatives (JNIEnv *, jclass)
{
return JNI_ERR;
}
static void
add_char (char *buf, jchar c, int *here)
{
if (c == '_')
{
buf[(*here)++] = '_';
buf[(*here)++] = '1';
}
else if (c == ';')
{
buf[(*here)++] = '_';
buf[(*here)++] = '2';
}
else if (c == '[')
{
buf[(*here)++] = '_';
buf[(*here)++] = '3';
}
else if (c == '/' || c == '.')
buf[(*here)++] = '_';
else if ((c >= '0' && c <= '9')
|| (c >= 'a' && c <= 'z')
|| (c >= 'A' && c <= 'Z'))
buf[(*here)++] = (char) c;
else
{
buf[(*here)++] = '_';
buf[(*here)++] = '0';
for (int i = 0; i < 4; ++i)
{
int val = c & 0x0f;
buf[(*here) + 3 - i] = (val > 10) ? ('a' + val - 10) : ('0' + val);
c >>= 4;
}
*here += 4;
}
}
static void
mangled_name (jclass klass, _Jv_Utf8Const *func_name,
_Jv_Utf8Const *signature, char *buf, int *long_start)
{
strcpy (buf, "Java_");
int here = 5;
jchar *chars = _Jv_GetStringChars (klass->getName ());
jint len = klass->getName ()->length ();
for (int i = 0; i < len; ++i)
add_char (buf, chars[i], &here);
buf[here++] = '_';
const unsigned char *fn = (const unsigned char *) func_name->chars ();
const unsigned char *limit = fn + func_name->len ();
for (int i = 0; ; ++i)
{
int ch = UTF8_GET (fn, limit);
if (ch < 0)
break;
add_char (buf, ch, &here);
}
*long_start = here;
buf[here++] = '_';
buf[here++] = '_';
const unsigned char *sig = (const unsigned char *) signature->chars ();
limit = sig + signature->len ();
JvAssert (sig[0] == '(');
++sig;
while (1)
{
int ch = UTF8_GET (sig, limit);
if (ch == ')' || ch < 0)
break;
add_char (buf, ch, &here);
}
buf[here] = '\0';
}
extern "C" JNIEnv *
_Jv_GetJNIEnvNewFrame (jclass klass)
{
JNIEnv *env = _Jv_GetCurrentJNIEnv ();
if (env == NULL)
{
env = (JNIEnv *) _Jv_MallocUnchecked (sizeof (JNIEnv));
env->p = &_Jv_JNIFunctions;
env->klass = klass;
env->locals = NULL;
_Jv_SetCurrentJNIEnv (env);
}
_Jv_JNI_LocalFrame *frame
= (_Jv_JNI_LocalFrame *) _Jv_MallocUnchecked (sizeof (_Jv_JNI_LocalFrame)
+ (FRAME_SIZE
* sizeof (jobject)));
frame->marker = MARK_SYSTEM;
frame->size = FRAME_SIZE;
frame->next = env->locals;
for (int i = 0; i < frame->size; ++i)
frame->vec[i] = NULL;
env->locals = frame;
env->ex = NULL;
return env;
}
extern "C" void *
_Jv_LookupJNIMethod (jclass klass, _Jv_Utf8Const *name,
_Jv_Utf8Const *signature, MAYBE_UNUSED int args_size)
{
int name_length = name->len();
int sig_length = signature->len();
char buf[10 + 6 * (name_length + sig_length) + 12];
int long_start;
void *function;
JvSynchronize sync (global_ref_table);
strncpy (buf, name->chars (), name_length);
buf[name_length] = '\0';
strncpy (buf + name_length + 1, signature->chars (), sig_length);
buf[name_length + sig_length + 1] = '\0';
JNINativeMethod meth;
meth.name = buf;
meth.signature = buf + name_length + 1;
function = nathash_find (&meth);
if (function != NULL)
return function;
buf[0] = '_';
mangled_name (klass, name, signature, buf + 1, &long_start);
char c = buf[long_start + 1];
buf[long_start + 1] = '\0';
function = _Jv_FindSymbolInExecutable (buf + 1);
#ifdef WIN32
char asz_buf[12];
char long_nm_sv[11];
if (function == NULL)
{
memcpy (long_nm_sv, (buf + long_start + 1 + 1), sizeof (long_nm_sv));
sprintf (asz_buf, "@%d", args_size);
strcat (buf, asz_buf);
function = _Jv_FindSymbolInExecutable (buf);
if (function == NULL)
{
function = _Jv_FindSymbolInExecutable (buf + 1);
}
}
#endif
if (function == NULL)
{
buf[long_start + 1] = c;
#ifdef WIN32
memcpy ((buf + long_start + 1 + 1), long_nm_sv, sizeof (long_nm_sv));
#endif
function = _Jv_FindSymbolInExecutable (buf + 1);
if (function == NULL)
{
#ifdef WIN32
strcat (buf, asz_buf);
function = _Jv_FindSymbolInExecutable (buf);
if (function == NULL)
function = _Jv_FindSymbolInExecutable (buf + 1);
if (function == NULL)
#endif
{
jstring str = JvNewStringUTF (name->chars ());
throw new java::lang::UnsatisfiedLinkError (str);
}
}
}
return function;
}
#ifdef INTERPRETER
void
_Jv_JNIMethod::call (ffi_cif *, void *ret, ffi_raw *args, void *__this)
{
_Jv_JNIMethod* _this = (_Jv_JNIMethod *) __this;
JNIEnv *env = _Jv_GetJNIEnvNewFrame (_this->defining_class);
{
JvSynchronize sync (global_ref_table);
if (_this->function == NULL)
{
int args_size = sizeof (JNIEnv *) + _this->args_raw_size;
if (_this->self->accflags & java::lang::reflect::Modifier::STATIC)
args_size += sizeof (_this->defining_class);
_this->function = _Jv_LookupJNIMethod (_this->defining_class,
_this->self->name,
_this->self->signature,
args_size);
}
}
JvAssert (_this->args_raw_size % sizeof (ffi_raw) == 0);
ffi_raw real_args[2 + _this->args_raw_size / sizeof (ffi_raw)];
int offset = 0;
real_args[offset++].ptr = env;
if ((_this->self->accflags & java::lang::reflect::Modifier::STATIC))
real_args[offset++].ptr = _this->defining_class;
jobject sync = NULL;
if ((_this->self->accflags & java::lang::reflect::Modifier::SYNCHRONIZED))
{
if ((_this->self->accflags & java::lang::reflect::Modifier::STATIC))
sync = _this->defining_class;
else
sync = (jobject) args[0].ptr;
_Jv_MonitorEnter (sync);
}
memcpy (&real_args[offset], args, _this->args_raw_size);
#if FFI_NATIVE_RAW_API
ffi_raw_call (&_this->jni_cif, (void (*)()) _this->function,
ret, real_args);
#else
ffi_java_raw_call (&_this->jni_cif, (void (*)()) _this->function,
ret, real_args);
#endif
if (sync != NULL)
_Jv_MonitorExit (sync);
_Jv_JNI_PopSystemFrame (env);
}
#endif
static jint
_Jv_JNI_AttachCurrentThread (JavaVM *, jstring name, void **penv,
void *args, jboolean is_daemon)
{
JavaVMAttachArgs *attach = reinterpret_cast<JavaVMAttachArgs *> (args);
java::lang::ThreadGroup *group = NULL;
if (attach)
{
if (attach->version != JNI_VERSION_1_4
&& attach->version != JNI_VERSION_1_2
&& attach->version != JNI_VERSION_1_1)
return JNI_EVERSION;
JvAssert (java::lang::ThreadGroup::class$.isInstance (attach->group));
group = reinterpret_cast<java::lang::ThreadGroup *> (attach->group);
}
if (_Jv_GetCurrentJNIEnv () != NULL)
return 0;
JNIEnv *env = (JNIEnv *) _Jv_MallocUnchecked (sizeof (JNIEnv));
if (env == NULL)
return JNI_ERR;
env->p = &_Jv_JNIFunctions;
env->ex = NULL;
env->klass = NULL;
env->locals
= (_Jv_JNI_LocalFrame *) _Jv_MallocUnchecked (sizeof (_Jv_JNI_LocalFrame)
+ (FRAME_SIZE
* sizeof (jobject)));
if (env->locals == NULL)
{
_Jv_Free (env);
return JNI_ERR;
}
env->locals->marker = MARK_SYSTEM;
env->locals->size = FRAME_SIZE;
env->locals->next = NULL;
for (int i = 0; i < env->locals->size; ++i)
env->locals->vec[i] = NULL;
*penv = reinterpret_cast<void *> (env);
if (_Jv_ThreadCurrent () == NULL)
{
try
{
if (is_daemon)
_Jv_AttachCurrentThreadAsDaemon (name, group);
else
_Jv_AttachCurrentThread (name, group);
}
catch (jthrowable t)
{
return JNI_ERR;
}
}
_Jv_SetCurrentJNIEnv (env);
return 0;
}
static jint JNICALL
_Jv_JNI_AttachCurrentThread (JavaVM *vm, void **penv, void *args)
{
return _Jv_JNI_AttachCurrentThread (vm, NULL, penv, args, false);
}
static jint JNICALL
_Jv_JNI_AttachCurrentThreadAsDaemon (JavaVM *vm, void **penv,
void *args)
{
return _Jv_JNI_AttachCurrentThread (vm, NULL, penv, args, true);
}
static jint JNICALL
_Jv_JNI_DestroyJavaVM (JavaVM *vm)
{
JvAssert (the_vm && vm == the_vm);
JNIEnv *env;
if (_Jv_ThreadCurrent () != NULL)
{
jstring main_name;
try
{
main_name = JvNewStringLatin1 ("main");
}
catch (jthrowable t)
{
return JNI_ERR;
}
jint r = _Jv_JNI_AttachCurrentThread (vm, main_name,
reinterpret_cast<void **> (&env),
NULL, false);
if (r < 0)
return r;
}
else
env = _Jv_GetCurrentJNIEnv ();
_Jv_ThreadWait ();
return JNI_ERR;
}
jint JNICALL
_Jv_JNI_DetachCurrentThread (JavaVM *)
{
jint code = _Jv_DetachCurrentThread ();
return code ? JNI_EDETACHED : 0;
}
static jint JNICALL
_Jv_JNI_GetEnv (JavaVM *, void **penv, jint version)
{
if (_Jv_ThreadCurrent () == NULL)
{
*penv = NULL;
return JNI_EDETACHED;
}
#ifdef ENABLE_JVMPI
if (version == JVMPI_VERSION_1)
{
*penv = (void *) &_Jv_JVMPI_Interface;
return 0;
}
#endif
if (version != JNI_VERSION_1_4 && version != JNI_VERSION_1_2
&& version != JNI_VERSION_1_1)
{
*penv = NULL;
return JNI_EVERSION;
}
*penv = (void *) _Jv_GetCurrentJNIEnv ();
return 0;
}
jint JNICALL
JNI_GetDefaultJavaVMInitArgs (void *args)
{
jint version = * (jint *) args;
if (version != JNI_VERSION_1_2 && version != JNI_VERSION_1_4)
return JNI_EVERSION;
JavaVMInitArgs *ia = reinterpret_cast<JavaVMInitArgs *> (args);
ia->version = JNI_VERSION_1_4;
ia->nOptions = 0;
ia->options = NULL;
ia->ignoreUnrecognized = true;
return 0;
}
jint JNICALL
JNI_CreateJavaVM (JavaVM **vm, void **penv, void *args)
{
JvAssert (! the_vm);
_Jv_CreateJavaVM (NULL);
JavaVM *nvm = (JavaVM *) _Jv_MallocUnchecked (sizeof (JavaVM));
if (nvm == NULL)
return JNI_ERR;
nvm->functions = &_Jv_JNI_InvokeFunctions;
if (args != NULL)
{
jint version = * (jint *) args;
if (version != JNI_VERSION_1_2 && version != JNI_VERSION_1_4)
return JNI_EVERSION;
JavaVMInitArgs *ia = reinterpret_cast<JavaVMInitArgs *> (args);
for (int i = 0; i < ia->nOptions; ++i)
{
if (! strcmp (ia->options[i].optionString, "vfprintf")
|| ! strcmp (ia->options[i].optionString, "exit")
|| ! strcmp (ia->options[i].optionString, "abort"))
{
continue;
}
else if (! strncmp (ia->options[i].optionString,
"-verbose", sizeof ("-verbose") - 1))
{
continue;
}
else if (! strncmp (ia->options[i].optionString, "-D", 2))
{
continue;
}
else if (ia->ignoreUnrecognized)
{
if (ia->options[i].optionString[0] == '_'
|| ! strncmp (ia->options[i].optionString, "-X", 2))
continue;
}
return JNI_ERR;
}
}
jint r =_Jv_JNI_AttachCurrentThread (nvm, penv, NULL);
if (r < 0)
return r;
the_vm = nvm;
*vm = the_vm;
return 0;
}
jint JNICALL
JNI_GetCreatedJavaVMs (JavaVM **vm_buffer, jsize buf_len, jsize *n_vms)
{
if (buf_len <= 0)
return JNI_ERR;
if (the_vm != NULL)
{
vm_buffer[0] = the_vm;
*n_vms = 1;
}
else
*n_vms = 0;
return 0;
}
JavaVM *
_Jv_GetJavaVM ()
{
if (! the_vm)
{
JavaVM *nvm = (JavaVM *) _Jv_MallocUnchecked (sizeof (JavaVM));
if (nvm != NULL)
nvm->functions = &_Jv_JNI_InvokeFunctions;
the_vm = nvm;
}
if (_Jv_ThreadCurrent () != NULL)
{
void *ignore;
_Jv_JNI_AttachCurrentThread (the_vm, &ignore, NULL);
}
return the_vm;
}
static jint JNICALL
_Jv_JNI_GetJavaVM (JNIEnv *, JavaVM **vm)
{
*vm = _Jv_GetJavaVM ();
return *vm == NULL ? JNI_ERR : JNI_OK;
}
#define RESERVED NULL
struct JNINativeInterface _Jv_JNIFunctions =
{
RESERVED,
RESERVED,
RESERVED,
RESERVED,
_Jv_JNI_GetVersion, _Jv_JNI_DefineClass, _Jv_JNI_FindClass, _Jv_JNI_FromReflectedMethod, _Jv_JNI_FromReflectedField, _Jv_JNI_ToReflectedMethod, _Jv_JNI_GetSuperclass, _Jv_JNI_IsAssignableFrom, _Jv_JNI_ToReflectedField, _Jv_JNI_Throw, _Jv_JNI_ThrowNew, _Jv_JNI_ExceptionOccurred, _Jv_JNI_ExceptionDescribe, _Jv_JNI_ExceptionClear, _Jv_JNI_FatalError,
_Jv_JNI_PushLocalFrame, _Jv_JNI_PopLocalFrame, _Jv_JNI_NewGlobalRef, _Jv_JNI_DeleteGlobalRef, _Jv_JNI_DeleteLocalRef,
_Jv_JNI_IsSameObject,
_Jv_JNI_NewLocalRef, _Jv_JNI_EnsureLocalCapacity,
_Jv_JNI_AllocObject, _Jv_JNI_NewObject, _Jv_JNI_NewObjectV, _Jv_JNI_NewObjectA, _Jv_JNI_GetObjectClass, _Jv_JNI_IsInstanceOf, _Jv_JNI_GetAnyMethodID<false>,
_Jv_JNI_CallMethod<jobject>, _Jv_JNI_CallMethodV<jobject>, _Jv_JNI_CallMethodA<jobject>, _Jv_JNI_CallMethod<jboolean>, _Jv_JNI_CallMethodV<jboolean>, _Jv_JNI_CallMethodA<jboolean>, _Jv_JNI_CallMethod<jbyte>, _Jv_JNI_CallMethodV<jbyte>, _Jv_JNI_CallMethodA<jbyte>, _Jv_JNI_CallMethod<jchar>, _Jv_JNI_CallMethodV<jchar>, _Jv_JNI_CallMethodA<jchar>, _Jv_JNI_CallMethod<jshort>, _Jv_JNI_CallMethodV<jshort>, _Jv_JNI_CallMethodA<jshort>, _Jv_JNI_CallMethod<jint>, _Jv_JNI_CallMethodV<jint>, _Jv_JNI_CallMethodA<jint>, _Jv_JNI_CallMethod<jlong>, _Jv_JNI_CallMethodV<jlong>, _Jv_JNI_CallMethodA<jlong>, _Jv_JNI_CallMethod<jfloat>, _Jv_JNI_CallMethodV<jfloat>, _Jv_JNI_CallMethodA<jfloat>, _Jv_JNI_CallMethod<jdouble>, _Jv_JNI_CallMethodV<jdouble>, _Jv_JNI_CallMethodA<jdouble>, _Jv_JNI_CallVoidMethod, _Jv_JNI_CallVoidMethodV, _Jv_JNI_CallVoidMethodA,
_Jv_JNI_CallAnyMethod<jobject, nonvirtual>, _Jv_JNI_CallAnyMethodV<jobject, nonvirtual>, _Jv_JNI_CallAnyMethodA<jobject, nonvirtual>, _Jv_JNI_CallAnyMethod<jboolean, nonvirtual>, _Jv_JNI_CallAnyMethodV<jboolean, nonvirtual>, _Jv_JNI_CallAnyMethodA<jboolean, nonvirtual>, _Jv_JNI_CallAnyMethod<jbyte, nonvirtual>, _Jv_JNI_CallAnyMethodV<jbyte, nonvirtual>, _Jv_JNI_CallAnyMethodA<jbyte, nonvirtual>, _Jv_JNI_CallAnyMethod<jchar, nonvirtual>, _Jv_JNI_CallAnyMethodV<jchar, nonvirtual>, _Jv_JNI_CallAnyMethodA<jchar, nonvirtual>, _Jv_JNI_CallAnyMethod<jshort, nonvirtual>, _Jv_JNI_CallAnyMethodV<jshort, nonvirtual>, _Jv_JNI_CallAnyMethodA<jshort, nonvirtual>, _Jv_JNI_CallAnyMethod<jint, nonvirtual>, _Jv_JNI_CallAnyMethodV<jint, nonvirtual>, _Jv_JNI_CallAnyMethodA<jint, nonvirtual>, _Jv_JNI_CallAnyMethod<jlong, nonvirtual>, _Jv_JNI_CallAnyMethodV<jlong, nonvirtual>, _Jv_JNI_CallAnyMethodA<jlong, nonvirtual>, _Jv_JNI_CallAnyMethod<jfloat, nonvirtual>, _Jv_JNI_CallAnyMethodV<jfloat, nonvirtual>, _Jv_JNI_CallAnyMethodA<jfloat, nonvirtual>, _Jv_JNI_CallAnyMethod<jdouble, nonvirtual>, _Jv_JNI_CallAnyMethodV<jdouble, nonvirtual>, _Jv_JNI_CallAnyMethodA<jdouble, nonvirtual>, _Jv_JNI_CallAnyVoidMethod<nonvirtual>, _Jv_JNI_CallAnyVoidMethodV<nonvirtual>, _Jv_JNI_CallAnyVoidMethodA<nonvirtual>,
_Jv_JNI_GetAnyFieldID<false>, _Jv_JNI_GetField<jobject>, _Jv_JNI_GetField<jboolean>, _Jv_JNI_GetField<jbyte>, _Jv_JNI_GetField<jchar>, _Jv_JNI_GetField<jshort>, _Jv_JNI_GetField<jint>, _Jv_JNI_GetField<jlong>, _Jv_JNI_GetField<jfloat>, _Jv_JNI_GetField<jdouble>, _Jv_JNI_SetField, _Jv_JNI_SetField, _Jv_JNI_SetField, _Jv_JNI_SetField, _Jv_JNI_SetField, _Jv_JNI_SetField, _Jv_JNI_SetField, _Jv_JNI_SetField, _Jv_JNI_SetField, _Jv_JNI_GetAnyMethodID<true>,
_Jv_JNI_CallStaticMethod<jobject>, _Jv_JNI_CallStaticMethodV<jobject>, _Jv_JNI_CallStaticMethodA<jobject>, _Jv_JNI_CallStaticMethod<jboolean>, _Jv_JNI_CallStaticMethodV<jboolean>, _Jv_JNI_CallStaticMethodA<jboolean>, _Jv_JNI_CallStaticMethod<jbyte>, _Jv_JNI_CallStaticMethodV<jbyte>, _Jv_JNI_CallStaticMethodA<jbyte>, _Jv_JNI_CallStaticMethod<jchar>, _Jv_JNI_CallStaticMethodV<jchar>, _Jv_JNI_CallStaticMethodA<jchar>, _Jv_JNI_CallStaticMethod<jshort>, _Jv_JNI_CallStaticMethodV<jshort>, _Jv_JNI_CallStaticMethodA<jshort>, _Jv_JNI_CallStaticMethod<jint>, _Jv_JNI_CallStaticMethodV<jint>, _Jv_JNI_CallStaticMethodA<jint>, _Jv_JNI_CallStaticMethod<jlong>, _Jv_JNI_CallStaticMethodV<jlong>, _Jv_JNI_CallStaticMethodA<jlong>, _Jv_JNI_CallStaticMethod<jfloat>, _Jv_JNI_CallStaticMethodV<jfloat>, _Jv_JNI_CallStaticMethodA<jfloat>, _Jv_JNI_CallStaticMethod<jdouble>, _Jv_JNI_CallStaticMethodV<jdouble>, _Jv_JNI_CallStaticMethodA<jdouble>, _Jv_JNI_CallStaticVoidMethod, _Jv_JNI_CallStaticVoidMethodV, _Jv_JNI_CallStaticVoidMethodA,
_Jv_JNI_GetAnyFieldID<true>, _Jv_JNI_GetStaticField<jobject>, _Jv_JNI_GetStaticField<jboolean>, _Jv_JNI_GetStaticField<jbyte>, _Jv_JNI_GetStaticField<jchar>, _Jv_JNI_GetStaticField<jshort>, _Jv_JNI_GetStaticField<jint>, _Jv_JNI_GetStaticField<jlong>, _Jv_JNI_GetStaticField<jfloat>, _Jv_JNI_GetStaticField<jdouble>, _Jv_JNI_SetStaticField, _Jv_JNI_SetStaticField, _Jv_JNI_SetStaticField, _Jv_JNI_SetStaticField, _Jv_JNI_SetStaticField, _Jv_JNI_SetStaticField, _Jv_JNI_SetStaticField, _Jv_JNI_SetStaticField, _Jv_JNI_SetStaticField, _Jv_JNI_NewString, _Jv_JNI_GetStringLength, _Jv_JNI_GetStringChars, _Jv_JNI_ReleaseStringChars, _Jv_JNI_NewStringUTF, _Jv_JNI_GetStringUTFLength, _Jv_JNI_GetStringUTFChars, _Jv_JNI_ReleaseStringUTFChars, _Jv_JNI_GetArrayLength, _Jv_JNI_NewObjectArray, _Jv_JNI_GetObjectArrayElement, _Jv_JNI_SetObjectArrayElement, _Jv_JNI_NewPrimitiveArray<jboolean, JvPrimClass (boolean)>,
_Jv_JNI_NewPrimitiveArray<jbyte, JvPrimClass (byte)>, _Jv_JNI_NewPrimitiveArray<jchar, JvPrimClass (char)>, _Jv_JNI_NewPrimitiveArray<jshort, JvPrimClass (short)>, _Jv_JNI_NewPrimitiveArray<jint, JvPrimClass (int)>, _Jv_JNI_NewPrimitiveArray<jlong, JvPrimClass (long)>, _Jv_JNI_NewPrimitiveArray<jfloat, JvPrimClass (float)>, _Jv_JNI_NewPrimitiveArray<jdouble, JvPrimClass (double)>, _Jv_JNI_GetPrimitiveArrayElements<jboolean, JvPrimClass (boolean)>,
_Jv_JNI_GetPrimitiveArrayElements<jbyte, JvPrimClass (byte)>,
_Jv_JNI_GetPrimitiveArrayElements<jchar, JvPrimClass (char)>,
_Jv_JNI_GetPrimitiveArrayElements<jshort, JvPrimClass (short)>,
_Jv_JNI_GetPrimitiveArrayElements<jint, JvPrimClass (int)>,
_Jv_JNI_GetPrimitiveArrayElements<jlong, JvPrimClass (long)>,
_Jv_JNI_GetPrimitiveArrayElements<jfloat, JvPrimClass (float)>,
_Jv_JNI_GetPrimitiveArrayElements<jdouble, JvPrimClass (double)>,
_Jv_JNI_ReleasePrimitiveArrayElements<jboolean, JvPrimClass (boolean)>,
_Jv_JNI_ReleasePrimitiveArrayElements<jbyte, JvPrimClass (byte)>,
_Jv_JNI_ReleasePrimitiveArrayElements<jchar, JvPrimClass (char)>,
_Jv_JNI_ReleasePrimitiveArrayElements<jshort, JvPrimClass (short)>,
_Jv_JNI_ReleasePrimitiveArrayElements<jint, JvPrimClass (int)>,
_Jv_JNI_ReleasePrimitiveArrayElements<jlong, JvPrimClass (long)>,
_Jv_JNI_ReleasePrimitiveArrayElements<jfloat, JvPrimClass (float)>,
_Jv_JNI_ReleasePrimitiveArrayElements<jdouble, JvPrimClass (double)>,
_Jv_JNI_GetPrimitiveArrayRegion<jboolean, JvPrimClass (boolean)>,
_Jv_JNI_GetPrimitiveArrayRegion<jbyte, JvPrimClass (byte)>,
_Jv_JNI_GetPrimitiveArrayRegion<jchar, JvPrimClass (char)>,
_Jv_JNI_GetPrimitiveArrayRegion<jshort, JvPrimClass (short)>,
_Jv_JNI_GetPrimitiveArrayRegion<jint, JvPrimClass (int)>,
_Jv_JNI_GetPrimitiveArrayRegion<jlong, JvPrimClass (long)>,
_Jv_JNI_GetPrimitiveArrayRegion<jfloat, JvPrimClass (float)>,
_Jv_JNI_GetPrimitiveArrayRegion<jdouble, JvPrimClass (double)>,
_Jv_JNI_SetPrimitiveArrayRegion<jboolean, JvPrimClass (boolean)>,
_Jv_JNI_SetPrimitiveArrayRegion<jbyte, JvPrimClass (byte)>,
_Jv_JNI_SetPrimitiveArrayRegion<jchar, JvPrimClass (char)>,
_Jv_JNI_SetPrimitiveArrayRegion<jshort, JvPrimClass (short)>,
_Jv_JNI_SetPrimitiveArrayRegion<jint, JvPrimClass (int)>,
_Jv_JNI_SetPrimitiveArrayRegion<jlong, JvPrimClass (long)>,
_Jv_JNI_SetPrimitiveArrayRegion<jfloat, JvPrimClass (float)>,
_Jv_JNI_SetPrimitiveArrayRegion<jdouble, JvPrimClass (double)>,
_Jv_JNI_RegisterNatives, _Jv_JNI_UnregisterNatives, _Jv_JNI_MonitorEnter, _Jv_JNI_MonitorExit, _Jv_JNI_GetJavaVM,
_Jv_JNI_GetStringRegion, _Jv_JNI_GetStringUTFRegion, _Jv_JNI_GetPrimitiveArrayCritical, _Jv_JNI_ReleasePrimitiveArrayCritical, _Jv_JNI_GetStringCritical, _Jv_JNI_ReleaseStringCritical,
_Jv_JNI_NewWeakGlobalRef, _Jv_JNI_DeleteWeakGlobalRef,
_Jv_JNI_ExceptionCheck,
_Jv_JNI_NewDirectByteBuffer, _Jv_JNI_GetDirectBufferAddress, _Jv_JNI_GetDirectBufferCapacity };
struct JNIInvokeInterface _Jv_JNI_InvokeFunctions =
{
RESERVED,
RESERVED,
RESERVED,
_Jv_JNI_DestroyJavaVM,
_Jv_JNI_AttachCurrentThread,
_Jv_JNI_DetachCurrentThread,
_Jv_JNI_GetEnv,
_Jv_JNI_AttachCurrentThreadAsDaemon
};