// jni.cc - JNI implementation, including the jump table.
-/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004
+/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
Free Software Foundation
This file is part of libgcj.
#include <java/lang/ThreadGroup.h>
#include <java/lang/Thread.h>
#include <java/lang/IllegalAccessError.h>
+#include <java/nio/Buffer.h>
#include <java/nio/DirectByteBufferImpl.h>
+#include <java/nio/DirectByteBufferImpl$ReadWrite.h>
#include <java/util/IdentityHashMap.h>
#include <gnu/gcj/RawData.h>
+#include <java/lang/ClassNotFoundException.h>
#include <gcj/method.h>
#include <gcj/field.h>
// Number of slots in the default frame. The VM must allow at least
// 16.
-#define FRAME_SIZE 32
+#define FRAME_SIZE 16
// Mark value indicating this is an overflow frame.
#define MARK_NONE 0
{
// This is true if this frame object represents a pushed frame (eg
// from PushLocalFrame).
- int marker : 2;
+ int marker;
+
+ // Flag to indicate some locals were allocated.
+ int allocated_p;
// Number of elements in frame.
- int size : 30;
+ int size;
// Next frame in chain.
_Jv_JNI_LocalFrame *next;
return reinterpret_cast<T *> (wr->get ());
}
+jobject
+_Jv_UnwrapJNIweakReference (jobject obj)
+{
+ return unwrap (obj);
+}
+
\f
static jobject JNICALL
frame->marker = MARK_NONE;
frame->size = size;
+ frame->allocated_p = 0;
memset (&frame->vec[0], 0, size * sizeof (jobject));
frame->next = env->locals;
env->locals = frame;
set = true;
done = true;
frame->vec[i] = obj;
+ frame->allocated_p = 1;
break;
}
}
_Jv_JNI_EnsureLocalCapacity (env, 16);
// We know the first element of the new frame will be ok.
env->locals->vec[0] = obj;
+ env->locals->allocated_p = 1;
}
mark_for_gc (obj, local_ref_table);
done = (rf->marker == stop);
_Jv_JNI_LocalFrame *n = rf->next;
- // When N==NULL, we've reached the stack-allocated frame, and we
- // must not free it. However, we must be sure to clear all its
- // elements, since we might conceivably reuse it.
+ // When N==NULL, we've reached the reusable bottom_locals, and we must
+ // not free it. However, we must be sure to clear all its elements.
if (n == NULL)
{
- memset (&rf->vec[0], 0, rf->size * sizeof (jobject));
+ if (rf->allocated_p)
+ memset (&rf->vec[0], 0, rf->size * sizeof (jobject));
+ rf->allocated_p = 0;
+ rf = NULL;
break;
}
extern "C" void
_Jv_JNI_PopSystemFrame (JNIEnv *env)
{
- _Jv_JNI_PopLocalFrame (env, NULL, MARK_SYSTEM);
+ // Only enter slow path when we're not at the bottom, or there have been
+ // allocations. Usually this is false and we can just null out the locals
+ // field.
- if (env->ex)
+ if (__builtin_expect ((env->locals->next
+ || env->locals->allocated_p), false))
+ _Jv_JNI_PopLocalFrame (env, NULL, MARK_SYSTEM);
+ else
+ env->locals = NULL;
+
+ if (__builtin_expect (env->ex != NULL, false))
{
jthrowable t = env->ex;
env->ex = NULL;
static jboolean JNICALL
_Jv_JNI_IsAssignableFrom (JNIEnv *, jclass clazz1, jclass clazz2)
{
- return unwrap (clazz1)->isAssignableFrom (unwrap (clazz2));
+ return unwrap (clazz2)->isAssignableFrom (unwrap (clazz1));
}
static jint JNICALL
NULL);
jclass *elts = elements (argtypes);
- elts[0] = &StringClass;
+ elts[0] = &java::lang::String::class$;
Constructor *cons = clazz->getConstructor (argtypes);
- jobjectArray values = JvNewObjectArray (1, &StringClass, NULL);
+ jobjectArray values = JvNewObjectArray (1, &java::lang::String::class$,
+ NULL);
jobject *velts = elements (values);
velts[0] = JvNewStringUTF (message);
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],
+ JvAssert (! strcmp (id->name->chars(), "<init>")
+ && id->signature->len() > 2
+ && id->signature->chars()[0] == '('
+ && ! strcmp (&id->signature->chars()[id->signature->len() - 2],
")V"));
return _Jv_JNI_CallAnyMethodV<jobject, constructor> (env, NULL, klass,
_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],
+ JvAssert (! strcmp (id->name->chars(), "<init>")
+ && id->signature->len() > 2
+ && id->signature->chars()[0] == '('
+ && ! strcmp (&id->signature->chars()[id->signature->len() - 2],
")V"));
va_list args;
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],
+ JvAssert (! strcmp (id->name->chars(), "<init>")
+ && id->signature->len() > 2
+ && id->signature->chars()[0] == '('
+ && ! strcmp (&id->signature->chars()[id->signature->len() - 2],
")V"));
return _Jv_JNI_CallAnyMethodA<jobject, constructor> (env, NULL, klass,
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);
-
- // FIXME: what if field_class == NULL?
-
java::lang::ClassLoader *loader = clazz->getClassLoaderInternal ();
+ jclass field_class = _Jv_FindClassFromSignature ((char *) s, loader);
+ if (! field_class)
+ throw new java::lang::ClassNotFoundException(JvNewStringUTF(s));
+
while (clazz != NULL)
{
// We acquire the class lock so that fields aren't resolved
// The field might be resolved or it might not be. It
// is much simpler to always resolve it.
- _Jv_ResolveField (field, loader);
+ _Jv_Linker::resolve_field (field, loader);
if (_Jv_equalUtf8Consts (f_name, a_name)
&& field->getClass() == field_class)
return field;
return unwrap (array)->length;
}
-static jarray JNICALL
+static jobjectArray JNICALL
_Jv_JNI_NewObjectArray (JNIEnv *env, jsize length,
jclass elementClass, jobject init)
{
_Jv_CheckCast (elementClass, init);
jarray result = JvNewObjectArray (length, elementClass, init);
- return (jarray) wrap_value (env, result);
+ return (jobjectArray) wrap_value (env, result);
}
catch (jthrowable t)
{
{
using namespace gnu::gcj;
using namespace java::nio;
- return new DirectByteBufferImpl (reinterpret_cast<RawData *> (address),
- length);
+ return new DirectByteBufferImpl$ReadWrite
+ (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);
+ if (! _Jv_IsInstanceOf (buffer, &Buffer::class$))
+ return NULL;
+ Buffer *tmp = static_cast<Buffer *> (buffer);
+ return reinterpret_cast<void *> (tmp->address);
}
static jlong JNICALL
_Jv_JNI_GetDirectBufferCapacity (JNIEnv *, jobject buffer)
{
using namespace java::nio;
- DirectByteBufferImpl* bb = static_cast<DirectByteBufferImpl *> (buffer);
- return bb->capacity();
+ if (! _Jv_IsInstanceOf (buffer, &Buffer::class$))
+ return -1;
+ Buffer *tmp = static_cast<Buffer *> (buffer);
+ if (tmp->address == NULL)
+ return -1;
+ return tmp->capacity();
}
\f
nathash =
(JNINativeMethod *) _Jv_AllocBytes (nathash_size
* sizeof (JNINativeMethod));
- memset (nathash, 0, nathash_size * sizeof (JNINativeMethod));
}
else
{
nathash =
(JNINativeMethod *) _Jv_AllocBytes (nathash_size
* sizeof (JNINativeMethod));
- memset (nathash, 0, nathash_size * sizeof (JNINativeMethod));
for (int i = 0; i < savesize; ++i)
{
return;
// FIXME
slot->name = strdup (method->name);
- slot->signature = strdup (method->signature);
+ // This was already strduped in _Jv_JNI_RegisterNatives.
+ slot->signature = method->signature;
slot->fnPtr = method->fnPtr;
}
// the nathash table.
JvSynchronize sync (global_ref_table);
+ JNINativeMethod dottedMethod;
+
// Look at each descriptor given us, and find the corresponding
// method in the class.
for (int j = 0; j < nMethods; ++j)
{
_Jv_Method *self = &imeths[i];
- if (! strcmp (self->name->chars (), methods[j].name)
- && ! strcmp (self->signature->chars (), methods[j].signature))
+ // Copy this JNINativeMethod and do a slash to dot
+ // conversion on the signature.
+ dottedMethod.name = methods[j].name;
+ dottedMethod.signature = strdup (methods[j].signature);
+ dottedMethod.fnPtr = methods[j].fnPtr;
+ char *c = dottedMethod.signature;
+ while (*c)
+ {
+ if (*c == '/')
+ *c = '.';
+ c++;
+ }
+
+ if (! strcmp (self->name->chars (), dottedMethod.name)
+ && ! strcmp (self->signature->chars (), dottedMethod.signature))
{
- if (! (self->accflags
- & java::lang::reflect::Modifier::NATIVE))
+ if (! (self->accflags & java::lang::reflect::Modifier::NATIVE))
break;
// Found a match that is native.
found = true;
- nathash_add (&methods[j]);
+ nathash_add (&dottedMethod);
break;
}
jstring m = JvNewStringUTF (methods[j].name);
try
{
- env->ex =new java::lang::NoSuchMethodError (m);
+ env->ex = new java::lang::NoSuchMethodError (m);
}
catch (jthrowable t)
{
_Jv_GetJNIEnvNewFrame (jclass klass)
{
JNIEnv *env = _Jv_GetCurrentJNIEnv ();
- if (env == NULL)
+ if (__builtin_expect (env == NULL, false))
{
env = (JNIEnv *) _Jv_MallocUnchecked (sizeof (JNIEnv));
env->p = &_Jv_JNIFunctions;
env->locals = NULL;
// We set env->ex below.
+ // Set up the bottom, reusable frame.
+ env->bottom_locals = (_Jv_JNI_LocalFrame *)
+ _Jv_MallocUnchecked (sizeof (_Jv_JNI_LocalFrame)
+ + (FRAME_SIZE
+ * sizeof (jobject)));
+
+ env->bottom_locals->marker = MARK_SYSTEM;
+ env->bottom_locals->size = FRAME_SIZE;
+ env->bottom_locals->next = NULL;
+ env->bottom_locals->allocated_p = 0;
+ memset (&env->bottom_locals->vec[0], 0,
+ env->bottom_locals->size * sizeof (jobject));
+
_Jv_SetCurrentJNIEnv (env);
}
- _Jv_JNI_LocalFrame *frame
- = (_Jv_JNI_LocalFrame *) _Jv_MallocUnchecked (sizeof (_Jv_JNI_LocalFrame)
- + (FRAME_SIZE
- * sizeof (jobject)));
+ // If we're in a simple JNI call (non-nested), we can just reuse the
+ // locals frame we allocated many calls ago, back when the env was first
+ // built, above.
- frame->marker = MARK_SYSTEM;
- frame->size = FRAME_SIZE;
- frame->next = env->locals;
+ if (__builtin_expect (env->locals == NULL, true))
+ env->locals = env->bottom_locals;
+
+ else
+ {
+ // Alternatively, we might be re-entering JNI, in which case we can't
+ // reuse the bottom_locals frame, because it is already underneath
+ // us. So we need to make a new one.
- for (int i = 0; i < frame->size; ++i)
- frame->vec[i] = NULL;
+ _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->allocated_p = 0;
+ frame->next = env->locals;
+
+ memset (&frame->vec[0], 0,
+ frame->size * sizeof (jobject));
+
+ env->locals = frame;
+ }
- env->locals = frame;
env->ex = NULL;
return env;
}
+// Destroy the env's reusable resources. This is called from the thread
+// destructor "finalize_native" in natThread.cc
+void
+_Jv_FreeJNIEnv (_Jv_JNIEnv *env)
+{
+ if (env == NULL)
+ return;
+
+ if (env->bottom_locals != NULL)
+ _Jv_Free (env->bottom_locals);
+
+ _Jv_Free (env);
+}
+
// Return the function which implements a particular JNI method. If
// we can't find the function, we throw the appropriate exception.
// This is `extern "C"' because the compiler uses it.
memcpy (&real_args[offset], args, _this->args_raw_size);
// The actual call to the JNI function.
+#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
+
+ // We might need to unwrap a JNI weak reference here.
+ if (_this->jni_cif.rtype == &ffi_type_pointer)
+ {
+ _Jv_value *val = (_Jv_value *) ret;
+ val->object_value = unwrap (val->object_value);
+ }
if (sync != NULL)
_Jv_MonitorExit (sync);
}
// Attaching an already-attached thread is a no-op.
- if (_Jv_GetCurrentJNIEnv () != NULL)
- return 0;
+ JNIEnv *env = _Jv_GetCurrentJNIEnv ();
+ if (env != NULL)
+ {
+ *penv = reinterpret_cast<void *> (env);
+ return 0;
+ }
- JNIEnv *env = (JNIEnv *) _Jv_MallocUnchecked (sizeof (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
+ env->bottom_locals
= (_Jv_JNI_LocalFrame *) _Jv_MallocUnchecked (sizeof (_Jv_JNI_LocalFrame)
+ (FRAME_SIZE
* sizeof (jobject)));
+ env->locals = env->bottom_locals;
if (env->locals == NULL)
{
_Jv_Free (env);
return JNI_ERR;
}
+ env->locals->allocated_p = 0;
env->locals->marker = MARK_SYSTEM;
env->locals->size = FRAME_SIZE;
env->locals->next = NULL;
{
JvAssert (the_vm && vm == the_vm);
- JNIEnv *env;
+ union
+ {
+ JNIEnv *env;
+ void *env_p;
+ };
+
if (_Jv_ThreadCurrent () != NULL)
{
jstring main_name;
return JNI_ERR;
}
- jint r = _Jv_JNI_AttachCurrentThread (vm, main_name,
- reinterpret_cast<void **> (&env),
+ jint r = _Jv_JNI_AttachCurrentThread (vm, main_name, &env_p,
NULL, false);
if (r < 0)
return r;
{
JvAssert (! the_vm);
- _Jv_CreateJavaVM (NULL);
+ jint version = * (jint *) args;
+ // We only support 1.2 and 1.4.
+ if (version != JNI_VERSION_1_2 && version != JNI_VERSION_1_4)
+ return JNI_EVERSION;
+
+ JvVMInitArgs* vm_args = reinterpret_cast<JvVMInitArgs *> (args);
+
+ jint result = _Jv_CreateJavaVM (vm_args);
+ if (result)
+ return result;
// FIXME: synchronize
JavaVM *nvm = (JavaVM *) _Jv_MallocUnchecked (sizeof (JavaVM));
return JNI_ERR;
nvm->functions = &_Jv_JNI_InvokeFunctions;
- // Parse the arguments.
- if (args != NULL)
- {
- jint version = * (jint *) args;
- // We only support 1.2 and 1.4.
- 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"))
- {
- // We are required to recognize these, but for now we
- // don't handle them in any way. FIXME.
- continue;
- }
- else if (! strncmp (ia->options[i].optionString,
- "-verbose", sizeof ("-verbose") - 1))
- {
- // We don't do anything with this option either. We
- // might want to make sure the argument is valid, but we
- // don't really care all that much for now.
- continue;
- }
- else if (! strncmp (ia->options[i].optionString, "-D", 2))
- {
- // FIXME.
- 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;