OSDN Git Service

2006-04-25 Andrew Haley <aph@redhat.com>
[pf3gnuchains/gcc-fork.git] / libjava / java / lang / natClassLoader.cc
index b05c1dd..87419c3 100644 (file)
@@ -1,6 +1,6 @@
 // natClassLoader.cc - Implementation of java.lang.ClassLoader native methods.
 
-/* Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005  Free Software Foundation
+/* Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006  Free Software Foundation
 
    This file is part of libgcj.
 
@@ -26,7 +26,6 @@ details.  */
 #include <java/lang/Character.h>
 #include <java/lang/Thread.h>
 #include <java/lang/ClassLoader.h>
-#include <gnu/gcj/runtime/VMClassLoader.h>
 #include <java/lang/InternalError.h>
 #include <java/lang/IllegalAccessError.h>
 #include <java/lang/LinkageError.h>
@@ -43,6 +42,8 @@ details.  */
 #include <java/io/Serializable.h>
 #include <java/lang/Cloneable.h>
 #include <java/util/HashMap.h>
+#include <gnu/gcj/runtime/BootClassLoader.h>
+#include <gnu/gcj/runtime/SystemClassLoader.h>
 
 // Size of local hash table.
 #define HASH_LEN 1013
@@ -50,6 +51,15 @@ details.  */
 // Hash function for Utf8Consts.
 #define HASH_UTF(Utf) ((Utf)->hash16() % HASH_LEN)
 
+// This records classes which will be registered with the system class
+// loader when it is initialized.
+static jclass system_class_list;
+
+// This is used as the value of system_class_list after we have
+// initialized the system class loader; it lets us know that we should
+// no longer pay attention to the system abi flag.
+#define SYSTEM_LOADER_INITIALIZED ((jclass) -1)
+
 static jclass loaded_classes[HASH_LEN];
 
 // This is the root of a linked list of classes
@@ -65,6 +75,20 @@ static int bootstrap_index;
 
 \f
 
+jclass
+java::lang::ClassLoader::loadClassFromSig(jstring name)
+{
+  int len = _Jv_GetStringUTFLength (name);
+  char sig[len + 1];
+  _Jv_GetStringUTFRegion (name, 0, name->length(), sig);
+  jclass result = _Jv_FindClassFromSignature(sig, this);
+  if (result == NULL)
+    throw new ClassNotFoundException(name);
+  return result;
+}
+
+\f
+
 // This tries to find a class in our built-in cache.  This cache is
 // used only for classes which are linked in to the executable or
 // loaded via dlopen().
@@ -75,7 +99,7 @@ _Jv_FindClassInCache (_Jv_Utf8Const *name)
   jint hash = HASH_UTF (name);
 
   jclass klass;
-  for (klass = loaded_classes[hash]; klass; klass = klass->next)
+  for (klass = loaded_classes[hash]; klass; klass = klass->next_or_version)
     {
       if (_Jv_equalUtf8Consts (name, klass->name))
        break;
@@ -87,15 +111,19 @@ _Jv_FindClassInCache (_Jv_Utf8Const *name)
 void
 _Jv_UnregisterClass (jclass the_class)
 {
+  // This can happen if the class could not be defined properly.
+  if (! the_class->name)
+    return;
+
   JvSynchronize sync (&java::lang::Class::class$);
   jint hash = HASH_UTF(the_class->name);
 
   jclass *klass = &(loaded_classes[hash]);
-  for ( ; *klass; klass = &((*klass)->next))
+  for ( ; *klass; klass = &((*klass)->next_or_version))
     {
       if (*klass == the_class)
        {
-         *klass = (*klass)->next;
+         *klass = (*klass)->next_or_version;
          break;
        }
     }
@@ -106,10 +134,28 @@ void
 _Jv_RegisterInitiatingLoader (jclass klass, java::lang::ClassLoader *loader)
 {
   if (! loader)
-    loader = java::lang::ClassLoader::getSystemClassLoader();
+    loader = java::lang::VMClassLoader::bootLoader;
+  if (! loader)
+    {
+      // Very early in the bootstrap process, the Bootstrap classloader may 
+      // not exist yet.
+      // FIXME: We could maintain a list of these and come back and register
+      // them later.
+      return;
+    }
   loader->loadedClasses->put(klass->name->toString(), klass);
 }
 
+// If we found an error while defining an interpreted class, we must
+// go back and unregister it.
+void
+_Jv_UnregisterInitiatingLoader (jclass klass, java::lang::ClassLoader *loader)
+{
+  if (! loader)
+    loader = java::lang::VMClassLoader::bootLoader;
+  loader->loadedClasses->remove(klass->name->toString());
+}
+
 // This function is called many times during startup, before main() is
 // run.  At that point in time we know for certain we are running 
 // single-threaded, so we don't need to lock when adding classes to the 
@@ -118,11 +164,14 @@ _Jv_RegisterInitiatingLoader (jclass klass, java::lang::ClassLoader *loader)
 void
 _Jv_RegisterClasses (const jclass *classes)
 {
+  _Jv_RegisterLibForGc (classes);
+
   for (; *classes; ++classes)
     {
       jclass klass = *classes;
 
-      (*_Jv_RegisterClassHook) (klass);
+      if (_Jv_CheckABIVersion ((unsigned long) klass->next_or_version))
+       (*_Jv_RegisterClassHook) (klass);
     }
 }
 
@@ -131,25 +180,78 @@ void
 _Jv_RegisterClasses_Counted (const jclass * classes, size_t count)
 {
   size_t i;
+
+  _Jv_RegisterLibForGc (classes);
+
   for (i = 0; i < count; i++)
     {
       jclass klass = classes[i];
 
-      (*_Jv_RegisterClassHook) (klass);
+      if (_Jv_CheckABIVersion ((unsigned long) klass->next_or_version))
+       (*_Jv_RegisterClassHook) (klass);
     }
 }
 
+// Create a class on the heap from an initializer struct.
+jclass
+_Jv_NewClassFromInitializer (const jclass class_initializer)
+{
+  jclass new_class = (jclass)_Jv_AllocObj (sizeof *new_class,
+                                          &java::lang::Class::class$);  
+  memcpy ((void*)new_class, (void*)class_initializer, sizeof *new_class);
+
+  if (_Jv_CheckABIVersion ((unsigned long) new_class->next_or_version))
+    (*_Jv_RegisterClassHook) (new_class);
+  
+  return new_class;
+}
+
+// Called by compiler-generated code at DSO initialization.  CLASSES
+// is an array of pairs: the first item of each pair is a pointer to
+// the initialized data that is a class initializer in a DSO, and the
+// second is a pointer to a class reference.
+// _Jv_NewClassFromInitializer() creates the new class (on the Java
+// heap) and we write the address of the new class into the address
+// pointed to by the second word.
+void
+_Jv_RegisterNewClasses (void **classes)
+{
+  _Jv_InitGC ();
+
+  jclass initializer;
+
+  while ((initializer = (jclass)*classes++))
+    {
+      jclass *class_ptr = (jclass *)*classes++;
+      *class_ptr = _Jv_NewClassFromInitializer (initializer);
+    }      
+}
+  
 void
 _Jv_RegisterClassHookDefault (jclass klass)
 {
+  // This is bogus, but there doesn't seem to be a better place to do
+  // it.
+  if (! klass->engine)
+    klass->engine = &_Jv_soleCompiledEngine;
+
+  if (system_class_list != SYSTEM_LOADER_INITIALIZED)
+    {
+      unsigned long abi = (unsigned long) klass->next_or_version;
+      if (! _Jv_ClassForBootstrapLoader (abi))
+       {
+         klass->next_or_version = system_class_list;
+         system_class_list = klass;
+         return;
+       }
+    }
+
   jint hash = HASH_UTF (klass->name);
 
-  // The BC ABI makes this check unnecessary: we always resolve all
-  // data references via the appropriate class loader, so the kludge
-  // that required this check has gone.
   // If the class is already registered, don't re-register it.
-  jclass check_class = klass->next;
-  while (check_class != NULL)
+  for (jclass check_class = loaded_classes[hash];
+       check_class != NULL;
+       check_class = check_class->next_or_version)
     {
       if (check_class == klass)
        {
@@ -170,14 +272,9 @@ _Jv_RegisterClassHookDefault (jclass klass)
              throw new java::lang::VirtualMachineError (str);
            }
        }
-
-      check_class = check_class->next;
     }
 
-  // FIXME: this is really bogus!
-  if (! klass->engine)
-    klass->engine = &_Jv_soleCompiledEngine;
-  klass->next = loaded_classes[hash];
+  klass->next_or_version = loaded_classes[hash];
   loaded_classes[hash] = klass;
 }
 
@@ -197,42 +294,82 @@ _Jv_RegisterClass (jclass klass)
   _Jv_RegisterClasses (classes);
 }
 
+// This is used during initialization to register all compiled-in
+// classes that are not part of the core with the system class loader.
+void
+_Jv_CopyClassesToSystemLoader (gnu::gcj::runtime::SystemClassLoader *loader)
+{
+  for (jclass klass = system_class_list;
+       klass;
+       klass = klass->next_or_version)
+    {
+      klass->loader = loader;
+      loader->addClass(klass);
+    }
+  system_class_list = SYSTEM_LOADER_INITIALIZED;
+}
+
+// An internal variant of _Jv_FindClass which simply swallows a
+// NoClassDefFoundError or a ClassNotFoundException. This gives the
+// caller a chance to evaluate the situation and behave accordingly.
+jclass
+_Jv_FindClassNoException (_Jv_Utf8Const *name, java::lang::ClassLoader *loader)
+{
+  jclass klass;
+
+  try
+    {
+      klass = _Jv_FindClass(name, loader);
+    }
+  catch ( java::lang::NoClassDefFoundError *ncdfe )
+    {
+      return NULL;
+    }
+  catch ( java::lang::ClassNotFoundException *cnfe )
+    {
+      return NULL;
+    }
+
+  return klass;
+}
+
 jclass
 _Jv_FindClass (_Jv_Utf8Const *name, java::lang::ClassLoader *loader)
 {
   // See if the class was already loaded by this loader.  This handles
   // initiating loader checks, as we register classes with their
   // initiating loaders.
-  java::lang::ClassLoader *sys
-    = java::lang::ClassLoader::getSystemClassLoader ();
+
+  java::lang::ClassLoader *boot = java::lang::VMClassLoader::bootLoader;
   java::lang::ClassLoader *real = loader;
   if (! real)
-    real = sys;
+    real = boot;
   jstring sname = name->toString();
   // We might still be bootstrapping the VM, in which case there
-  // won't be a system class loader yet.
+  // won't be a bootstrap class loader yet.
   jclass klass = real ? real->findLoadedClass (sname) : NULL;
 
   if (! klass)
     {
       if (loader)
        {
-         // Load using a user-defined loader, jvmspec 5.3.2
-         klass = loader->loadClass(sname, false);
+         // Load using a user-defined loader, jvmspec 5.3.2.
+         // Note that we explicitly must call the single-argument form.
+         klass = loader->loadClass(sname);
 
          // If "loader" delegated the loadClass operation to another
          // loader, explicitly register that it is also an initiating
          // loader of the given class.
-         java::lang::ClassLoader *delegate = (loader == sys
+         java::lang::ClassLoader *delegate = (loader == boot
                                               ? NULL
                                               : loader);
          if (klass && klass->getClassLoaderInternal () != delegate)
            _Jv_RegisterInitiatingLoader (klass, loader);
        }
-      else if (sys)
+      else if (boot)
        {
          // Load using the bootstrap loader jvmspec 5.3.1.
-         klass = sys->loadClass (sname, false); 
+         klass = java::lang::VMClassLoader::loadClass (sname, false); 
 
          // Register that we're an initiating loader.
          if (klass)
@@ -243,17 +380,26 @@ _Jv_FindClass (_Jv_Utf8Const *name, java::lang::ClassLoader *loader)
          // Not even a bootstrap loader, try the built-in cache.
          klass = _Jv_FindClassInCache (name);
 
-         if (bootstrap_index == BOOTSTRAP_CLASS_LIST_SIZE)
-           abort ();
-         bootstrap_class_list[bootstrap_index++] = klass;
+         if (klass)
+           {
+             bool found = false;
+             for (int i = 0; i < bootstrap_index; ++i)
+               {
+                 if (bootstrap_class_list[i] == klass)
+                   {
+                     found = true;
+                     break;
+                   }
+               }
+             if (! found)
+               {
+                 if (bootstrap_index == BOOTSTRAP_CLASS_LIST_SIZE)
+                   abort ();
+                 bootstrap_class_list[bootstrap_index++] = klass;
+               }
+           }
        }
     }
-  else
-    {
-      // we need classes to be in the hash while
-      // we're loading, so that they can refer to themselves. 
-      _Jv_Linker::wait_for_state (klass, JV_STATE_LOADED);
-    }
 
   return klass;
 }
@@ -274,7 +420,7 @@ _Jv_NewClass (_Jv_Utf8Const *name, jclass superclass,
   ret->superclass = superclass;
   ret->loader = loader;
 
-  _Jv_RegisterClass (ret);
+  _Jv_RegisterInitiatingLoader (ret, loader);
 
   return ret;
 }
@@ -283,6 +429,12 @@ static _Jv_IDispatchTable *array_idt = NULL;
 static jshort array_depth = 0;
 static jclass *array_ancestors = NULL;
 
+static jclass interfaces[] =
+{
+  &java::lang::Cloneable::class$,
+  &java::io::Serializable::class$
+};
+
 // Create a class representing an array of ELEMENT and store a pointer to it
 // in element->arrayclass. LOADER is the ClassLoader which _initiated_ the 
 // instantiation of this array. ARRAY_VTABLE is the vtable to use for the new 
@@ -337,8 +489,6 @@ _Jv_NewArrayClass (jclass element, java::lang::ClassLoader *loader,
 
   // Note that `vtable_method_count' doesn't include the initial
   // gc_descr slot.
-  JvAssert (java::lang::Object::class$.vtable_method_count
-           == NUM_OBJECT_METHODS);
   int dm_count = java::lang::Object::class$.vtable_method_count;
 
   // Create a new vtable by copying Object's vtable.
@@ -357,14 +507,9 @@ _Jv_NewArrayClass (jclass element, java::lang::ClassLoader *loader,
     = java::lang::Object::class$.vtable_method_count;
 
   // Stash the pointer to the element type.
-  array_class->methods = (_Jv_Method *) element;
+  array_class->element_type = element;
 
   // Register our interfaces.
-  static jclass interfaces[] =
-    {
-      &java::lang::Cloneable::class$,
-      &java::io::Serializable::class$
-    };
   array_class->interfaces = interfaces;
   array_class->interface_count = sizeof interfaces / sizeof interfaces[0];