// link.cc - Code for linking and resolving classes and pool entries.
-/* Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation
+/* Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation
This file is part of libgcj.
#include <limits.h>
#include <java-cpool.h>
#include <execution.h>
+#ifdef INTERPRETER
+#include <jvmti.h>
+#include "jvmti-int.h"
+#endif
#include <java/lang/Class.h>
#include <java/lang/String.h>
#include <java/lang/StringBuffer.h>
end_of_method_search:
-
- // FIXME: if (cls->loader != klass->loader), then we
- // must actually check that the types of arguments
- // correspond. That is, for each argument type, and
- // the return type, doing _Jv_FindClassFromSignature
- // with either loader should produce the same result,
- // i.e., exactly the same jclass object. JVMS 5.4.3.3
-
if (the_method == 0)
{
java::lang::StringBuffer *sb = new java::lang::StringBuffer();
throw new java::lang::NoSuchMethodError (sb->toString());
}
+ // if (found_class->loader != klass->loader), then we
+ // must actually check that the types of arguments
+ // correspond. That is, for each argument type, and
+ // the return type, doing _Jv_FindClassFromSignature
+ // with either loader should produce the same result,
+ // i.e., exactly the same jclass object. JVMS 5.4.3.3
+ if (found_class->loader != klass->loader)
+ {
+ JArray<jclass> *found_args, *klass_args;
+ jclass found_return, klass_return;
+
+ _Jv_GetTypesFromSignature (the_method,
+ found_class,
+ &found_args,
+ &found_return);
+ _Jv_GetTypesFromSignature (the_method,
+ klass,
+ &klass_args,
+ &klass_return);
+
+ jclass *found_arg = elements (found_args);
+ jclass *klass_arg = elements (klass_args);
+
+ for (int i = 0; i < found_args->length; i++)
+ {
+ if (*(found_arg++) != *(klass_arg++))
+ throw new java::lang::LinkageError (JvNewStringLatin1
+ ("argument type mismatch with different loaders"));
+ }
+ if (found_return != klass_return)
+ throw new java::lang::LinkageError (JvNewStringLatin1
+ ("return type mismatch with different loaders"));
+ }
+
return the_method;
}
// with it should just throw a NoClassDefFoundError with the class'
// name.
if (! found)
- if (lazy)
- {
- found = _Jv_NewClass(name, NULL, NULL);
- found->state = JV_STATE_PHANTOM;
- pool->tags[index] |= JV_CONSTANT_ResolvedFlag;
- pool->data[index].clazz = found;
- break;
- }
- else
- throw new java::lang::NoClassDefFoundError (name->toString());
+ {
+ if (lazy)
+ {
+ found = _Jv_NewClass(name, NULL, NULL);
+ found->state = JV_STATE_PHANTOM;
+ pool->tags[index] |= JV_CONSTANT_ResolvedFlag;
+ pool->data[index].clazz = found;
+ break;
+ }
+ else
+ throw new java::lang::NoClassDefFoundError (name->toString());
+ }
// Check accessibility, but first strip array types as
// _Jv_ClassNameSamePackage can't handle arrays.
throw new java::lang::NoSuchMethodError;
}
-#if defined USE_LIBFFI && FFI_CLOSURES
+#if defined USE_LIBFFI && FFI_CLOSURES && defined(INTERPRETER)
// A function whose invocation is prepared using libffi. It gets called
// whenever a static method of a missing class is invoked. The data argument
// holds a reference to a String denoting the missing class.
return i;
}
-#if defined USE_LIBFFI && FFI_CLOSURES
+#if defined USE_LIBFFI && FFI_CLOSURES && defined(INTERPRETER)
// We use a structure of this type to store the closure that
// represents a missing method.
struct method_closure
// be the same as the address of the overall structure. This is due
// to disabling interior pointers in the GC.
ffi_closure closure;
+ _Jv_ClosureList list;
ffi_cif cif;
ffi_type *arg_types[1];
};
void *
-_Jv_Linker::create_error_method (_Jv_Utf8Const *class_name)
+_Jv_Linker::create_error_method (_Jv_Utf8Const *class_name, jclass klass)
{
+ void *code;
method_closure *closure
- = (method_closure *) _Jv_AllocBytes(sizeof (method_closure));
+ = (method_closure *)ffi_closure_alloc (sizeof (method_closure), &code);
closure->arg_types[0] = &ffi_type_void;
1,
&ffi_type_void,
closure->arg_types) == FFI_OK
- && ffi_prep_closure (&closure->closure,
- &closure->cif,
- _Jv_ThrowNoClassDefFoundErrorTrampoline,
- class_name) == FFI_OK)
- return &closure->closure;
+ && ffi_prep_closure_loc (&closure->closure,
+ &closure->cif,
+ _Jv_ThrowNoClassDefFoundErrorTrampoline,
+ class_name,
+ code) == FFI_OK)
+ {
+ closure->list.registerClosure (klass, closure);
+ return code;
+ }
else
{
+ ffi_closure_free (closure);
java::lang::StringBuffer *buffer = new java::lang::StringBuffer();
buffer->append(JvNewStringLatin1("Error setting up FFI closure"
" for static method of"
}
#else
void *
-_Jv_Linker::create_error_method (_Jv_Utf8Const *)
+_Jv_Linker::create_error_method (_Jv_Utf8Const *, jclass)
{
// Codepath for platforms which do not support (or want) libffi.
// You have to accept that it is impossible to provide the name
// at the corresponding position in the virtual method offset table
// (klass->otable).
-// The same otable and atable may be shared by many classes.
-
// This must be called while holding the class lock.
void
// NullPointerException
klass->atable->addresses[index] = NULL;
+ bool use_error_method = false;
+
// If the target class is missing we prepare a function call
// that throws a NoClassDefFoundError and store the address of
// that newly prepared method in the atable. The user can run
// code in classes where the missing class is part of the
// execution environment as long as it is never referenced.
if (target_class == NULL)
- klass->atable->addresses[index] = create_error_method(sym.class_name);
+ use_error_method = true;
// We're looking for a static field or a static method, and we
// can tell which is needed by looking at the signature.
else if (signature->first() == '(' && signature->len() >= 2)
}
}
else
+ use_error_method = true;
+
+ if (use_error_method)
klass->atable->addresses[index]
- = create_error_method(sym.class_name);
+ = create_error_method(sym.class_name, klass);
continue;
}
+
// Try fields only if the target class exists.
if (target_class != NULL)
{
if (klass->state >= state)
return;
- JvSynchronize sync (klass);
-
- // This is similar to the strategy for class initialization. If we
- // already hold the lock, just leave.
java::lang::Thread *self = java::lang::Thread::currentThread();
- while (klass->state <= state
- && klass->thread
- && klass->thread != self)
- klass->wait ();
- java::lang::Thread *save = klass->thread;
- klass->thread = self;
+ {
+ JvSynchronize sync (klass);
- // Allocate memory for static fields and constants.
- if (GC_base (klass) && klass->fields && ! GC_base (klass->fields))
- {
- jsize count = klass->field_count;
- if (count)
- {
- _Jv_Field* fields
- = (_Jv_Field*) _Jv_AllocRawObj (count * sizeof (_Jv_Field));
- memcpy ((void*)fields,
- (void*)klass->fields,
- count * sizeof (_Jv_Field));
- klass->fields = fields;
- }
- }
+ // This is similar to the strategy for class initialization. If we
+ // already hold the lock, just leave.
+ while (klass->state <= state
+ && klass->thread
+ && klass->thread != self)
+ klass->wait ();
+
+ java::lang::Thread *save = klass->thread;
+ klass->thread = self;
+
+ // Allocate memory for static fields and constants.
+ if (GC_base (klass) && klass->fields && ! GC_base (klass->fields))
+ {
+ jsize count = klass->field_count;
+ if (count)
+ {
+ _Jv_Field* fields
+ = (_Jv_Field*) _Jv_AllocRawObj (count * sizeof (_Jv_Field));
+ memcpy ((void*)fields,
+ (void*)klass->fields,
+ count * sizeof (_Jv_Field));
+ klass->fields = fields;
+ }
+ }
// Print some debugging info if requested. Interpreted classes are
// handled in defineclass, so we only need to handle the two
++gcj::loadedClasses;
}
- try
- {
- if (state >= JV_STATE_LOADING && klass->state < JV_STATE_LOADING)
- {
- ensure_supers_installed (klass);
- klass->set_state(JV_STATE_LOADING);
- }
+ try
+ {
+ if (state >= JV_STATE_LOADING && klass->state < JV_STATE_LOADING)
+ {
+ ensure_supers_installed (klass);
+ klass->set_state(JV_STATE_LOADING);
+ }
- if (state >= JV_STATE_LOADED && klass->state < JV_STATE_LOADED)
- {
- ensure_method_table_complete (klass);
- klass->set_state(JV_STATE_LOADED);
- }
+ if (state >= JV_STATE_LOADED && klass->state < JV_STATE_LOADED)
+ {
+ ensure_method_table_complete (klass);
+ klass->set_state(JV_STATE_LOADED);
+ }
- if (state >= JV_STATE_PREPARED && klass->state < JV_STATE_PREPARED)
- {
- ensure_fields_laid_out (klass);
- make_vtable (klass);
- layout_interface_methods (klass);
- prepare_constant_time_tables (klass);
- klass->set_state(JV_STATE_PREPARED);
- }
+ if (state >= JV_STATE_PREPARED && klass->state < JV_STATE_PREPARED)
+ {
+ ensure_fields_laid_out (klass);
+ make_vtable (klass);
+ layout_interface_methods (klass);
+ prepare_constant_time_tables (klass);
+ klass->set_state(JV_STATE_PREPARED);
+ }
- if (state >= JV_STATE_LINKED && klass->state < JV_STATE_LINKED)
- {
- if (gcj::verifyClasses)
- verify_class (klass);
+ if (state >= JV_STATE_LINKED && klass->state < JV_STATE_LINKED)
+ {
+ if (gcj::verifyClasses)
+ verify_class (klass);
- ensure_class_linked (klass);
- link_exception_table (klass);
- link_symbol_table (klass);
- klass->set_state(JV_STATE_LINKED);
- }
- }
- catch (java::lang::Throwable *exc)
- {
- klass->thread = save;
- klass->set_state(JV_STATE_ERROR);
- throw exc;
- }
+ ensure_class_linked (klass);
+ link_exception_table (klass);
+ link_symbol_table (klass);
+ klass->set_state(JV_STATE_LINKED);
+ }
+ }
+ catch (java::lang::Throwable *exc)
+ {
+ klass->thread = save;
+ klass->set_state(JV_STATE_ERROR);
+ throw exc;
+ }
+
+ klass->thread = save;
- klass->thread = save;
+ if (klass->state == JV_STATE_ERROR)
+ throw new java::lang::LinkageError;
+ }
- if (klass->state == JV_STATE_ERROR)
- throw new java::lang::LinkageError;
+#ifdef INTERPRETER
+ if (__builtin_expect (klass->state == JV_STATE_LINKED, false)
+ && state >= JV_STATE_LINKED
+ && JVMTI_REQUESTED_EVENT (ClassPrepare))
+ {
+ JNIEnv *jni_env = _Jv_GetCurrentJNIEnv ();
+ _Jv_JVMTI_PostEvent (JVMTI_EVENT_CLASS_PREPARE, self, jni_env,
+ klass);
+ }
+#endif
}