OSDN Git Service

PR target/27599
[pf3gnuchains/gcc-fork.git] / libjava / link.cc
index 26bf898..4f01cb5 100644 (file)
@@ -15,8 +15,18 @@ details.  */
 
 #include <stdio.h>
 
+#ifdef USE_LIBFFI
+#include <ffi.h>
+#endif
+
 #include <java-interp.h>
 
+// Set GC_DEBUG before including gc.h!
+#ifdef LIBGCJ_GC_DEBUG
+# define GC_DEBUG
+#endif
+#include <gc.h>
+
 #include <jvm.h>
 #include <gcj/cni.h>
 #include <string.h>
@@ -142,10 +152,10 @@ _Jv_Linker::find_field_helper (jclass search, _Jv_Utf8Const *name,
          // pass in the descriptor and check that way, because when
          // the field is already resolved there is no easy way to
          // find its descriptor again.
-         if ( (field->isResolved () ? 
-                _Jv_equalUtf8Classnames (type_name, field->type->name) :
-                _Jv_equalUtf8Classnames (
-                  type_name, (_Jv_Utf8Const *) field->type)) )
+         if ((field->isResolved ()
+               ? _Jv_equalUtf8Classnames (type_name, field->type->name)
+               : _Jv_equalUtf8Classnames (type_name,
+                                          (_Jv_Utf8Const *) field->type)))
            {
              *declarer = search;
              return field;
@@ -261,6 +271,21 @@ _Jv_Linker::resolve_pool_entry (jclass klass, int index, bool lazy)
 {
   using namespace java::lang::reflect;
 
+  if (GC_base (klass) && klass->constants.data
+      && ! GC_base (klass->constants.data))
+    {
+      jsize count = klass->constants.size;
+      if (count)
+       {
+         _Jv_word* constants
+           = (_Jv_word*) _Jv_AllocRawObj (count * sizeof (_Jv_word));
+         memcpy ((void*)constants,
+                 (void*)klass->constants.data,
+                 count * sizeof (_Jv_word));
+         klass->constants.data = constants;
+       }
+    }
+
   _Jv_Constants *pool = &klass->constants;
 
   if ((pool->tags[index] & JV_CONSTANT_ResolvedFlag) != 0)
@@ -471,16 +496,11 @@ _Jv_Linker::resolve_pool_entry (jclass klass, int index, bool lazy)
            throw new java::lang::NoSuchMethodError (sb->toString());
          }
       
-       int vtable_index = -1;
-       if (pool->tags[index] != JV_CONSTANT_InterfaceMethodref)
-         vtable_index = (jshort)the_method->index;
-
        pool->data[index].rmethod
          = klass->engine->resolve_method(the_method,
                                          found_class,
                                          ((the_method->accflags
-                                           & Modifier::STATIC) != 0),
-                                         vtable_index);
+                                           & Modifier::STATIC) != 0));
        pool->tags[index] |= JV_CONSTANT_ResolvedFlag;
       }
       break;
@@ -552,7 +572,7 @@ _Jv_Linker::search_method_in_class (jclass cls, jclass klass,
 #define INITIAL_IOFFSETS_LEN 4
 #define INITIAL_IFACES_LEN 4
 
-static _Jv_IDispatchTable null_idt = { {SHRT_MAX, 0, NULL} };
+static _Jv_IDispatchTable null_idt = {SHRT_MAX, 0, {}};
 
 // Generate tables for constant-time assignment testing and interface
 // method lookup. This implements the technique described by Per Bothner
@@ -611,9 +631,6 @@ _Jv_Linker::prepare_constant_time_tables (jclass klass)
       return;
     }
 
-  klass->idt = 
-    (_Jv_IDispatchTable *) _Jv_AllocRawObj (sizeof (_Jv_IDispatchTable));
-
   _Jv_ifaces ifaces;
   ifaces.count = 0;
   ifaces.len = INITIAL_IFACES_LEN;
@@ -625,9 +642,10 @@ _Jv_Linker::prepare_constant_time_tables (jclass klass)
     {
       // The classes pointed to by the itable will always be reachable
       // via other paths.
-      klass->idt->cls.itable = 
-       (void **) _Jv_AllocBytes (itable_size * sizeof (void *));
-      klass->idt->cls.itable_length = itable_size;
+      int idt_bytes = sizeof (_Jv_IDispatchTable) + (itable_size 
+                                                    * sizeof (void *));
+      klass->idt = (_Jv_IDispatchTable *) _Jv_AllocBytes (idt_bytes);
+      klass->idt->itable_length = itable_size;
 
       jshort *itable_offsets = 
        (jshort *) _Jv_Malloc (ifaces.count * sizeof (jshort));
@@ -639,18 +657,17 @@ _Jv_Linker::prepare_constant_time_tables (jclass klass)
 
       for (int i = 0; i < ifaces.count; i++)
        {
-         ifaces.list[i]->idt->iface.ioffsets[cls_iindex] =
-           itable_offsets[i];
+         ifaces.list[i]->ioffsets[cls_iindex] = itable_offsets[i];
        }
 
-      klass->idt->cls.iindex = cls_iindex;         
+      klass->idt->iindex = cls_iindex;     
 
       _Jv_Free (ifaces.list);
       _Jv_Free (itable_offsets);
     }
   else 
     {
-      klass->idt->cls.iindex = SHRT_MAX;
+      klass->idt->iindex = SHRT_MAX;
     }
 }
 
@@ -698,9 +715,18 @@ _Jv_Linker::get_interfaces (jclass klass, _Jv_ifaces *ifaces)
          result += get_interfaces (klass->interfaces[i], ifaces);
        }
     }
-    
+
   if (klass->isInterface())
-    result += klass->method_count + 1;
+    {
+      // We want to add 1 plus the number of interface methods here.
+      // But, we take special care to skip <clinit>.
+      ++result;
+      for (int i = 0; i < klass->method_count; ++i)
+       {
+         if (klass->methods[i].name->first() != '<')
+           ++result;
+       }
+    }
   else if (klass->superclass)
     result += get_interfaces (klass->superclass, ifaces);
   return result;
@@ -713,7 +739,7 @@ void
 _Jv_Linker::generate_itable (jclass klass, _Jv_ifaces *ifaces,
                               jshort *itable_offsets)
 {
-  void **itable = klass->idt->cls.itable;
+  void **itable = klass->idt->itable;
   jshort itable_pos = 0;
 
   for (int i = 0; i < ifaces->count; i++)
@@ -722,12 +748,9 @@ _Jv_Linker::generate_itable (jclass klass, _Jv_ifaces *ifaces,
       itable_offsets[i] = itable_pos;
       itable_pos = append_partial_itable (klass, iface, itable, itable_pos);
 
-      /* Create interface dispatch table for iface */
-      if (iface->idt == NULL)
+      /* Create ioffsets table for iface */
+      if (iface->ioffsets == NULL)
        {
-         iface->idt
-           = (_Jv_IDispatchTable *) _Jv_AllocRawObj (sizeof (_Jv_IDispatchTable));
-
          // The first element of ioffsets is its length (itself included).
          jshort *ioffsets = (jshort *) _Jv_AllocBytes (INITIAL_IOFFSETS_LEN
                                                        * sizeof (jshort));
@@ -735,7 +758,7 @@ _Jv_Linker::generate_itable (jclass klass, _Jv_ifaces *ifaces,
          for (int i = 1; i < INITIAL_IOFFSETS_LEN; i++)
            ioffsets[i] = -1;
 
-         iface->idt->iface.ioffsets = ioffsets;            
+         iface->ioffsets = ioffsets;
        }
     }
 }
@@ -777,7 +800,7 @@ _Jv_ThrowNoClassDefFoundErrorTrampoline(ffi_cif *,
                                         void *data)
 {
   throw new java::lang::NoClassDefFoundError(
-    _Jv_NewStringUtf8Const( (_Jv_Utf8Const *) data));
+    _Jv_NewStringUtf8Const((_Jv_Utf8Const *) data));
 }
 #else
 // A variant of the NoClassDefFoundError throwing method that can
@@ -819,7 +842,7 @@ _Jv_ThrowAbstractMethodError ()
 // Returns the offset at which the next partial ITable should be appended.
 jshort
 _Jv_Linker::append_partial_itable (jclass klass, jclass iface,
-                                    void **itable, jshort pos)
+                                  void **itable, jshort pos)
 {
   using namespace java::lang::reflect;
 
@@ -828,6 +851,10 @@ _Jv_Linker::append_partial_itable (jclass klass, jclass iface,
   
   for (int j=0; j < iface->method_count; j++)
     {
+      // Skip '<clinit>' here.
+      if (iface->methods[j].name->first() == '<')
+       continue;
+
       meth = NULL;
       for (jclass cl = klass; cl; cl = cl->getSuperclass())
         {
@@ -838,12 +865,7 @@ _Jv_Linker::append_partial_itable (jclass klass, jclass iface,
            break;
        }
 
-      if (meth && (meth->name->first() == '<'))
-       {
-         // leave a placeholder in the itable for hidden init methods.
-          itable[pos] = NULL;  
-       }
-      else if (meth)
+      if (meth)
         {
          if ((meth->accflags & Modifier::STATIC) != 0)
            throw new java::lang::IncompatibleClassChangeError
@@ -881,8 +903,8 @@ static bool iindex_mutex_initialized = false;
 // Interface Dispatch Table, we just compare the first element to see if it 
 // matches the desired interface. So how can we find the correct offset?  
 // Our solution is to keep a vector of candiate offsets in each interface 
-// (idt->iface.ioffsets), and in each class we have an index 
-// (idt->cls.iindex) used to select the correct offset from ioffsets.
+// (ioffsets), and in each class we have an index (idt->iindex) used to
+// select the correct offset from ioffsets.
 //
 // Calculate and return iindex for a new class. 
 // ifaces is a vector of num interfaces that the class implements.
@@ -913,9 +935,9 @@ _Jv_Linker::find_iindex (jclass *ifaces, jshort *offsets, jshort num)
         {
          if (j >= num)
            goto found;
-         if (i >= ifaces[j]->idt->iface.ioffsets[0])
+         if (i >= ifaces[j]->ioffsets[0])
            continue;
-         int ioffset = ifaces[j]->idt->iface.ioffsets[i];
+         int ioffset = ifaces[j]->ioffsets[i];
          /* We can potentially share this position with another class. */
          if (ioffset >= 0 && ioffset != offsets[j])
            break; /* Nope. Try next i. */        
@@ -924,14 +946,15 @@ _Jv_Linker::find_iindex (jclass *ifaces, jshort *offsets, jshort num)
   found:
   for (j = 0; j < num; j++)
     {
-      int len = ifaces[j]->idt->iface.ioffsets[0];
+      int len = ifaces[j]->ioffsets[0];
       if (i >= len) 
        {
          // Resize ioffsets.
          int newlen = 2 * len;
          if (i >= newlen)
            newlen = i + 3;
-         jshort *old_ioffsets = ifaces[j]->idt->iface.ioffsets;
+
+         jshort *old_ioffsets = ifaces[j]->ioffsets;
          jshort *new_ioffsets = (jshort *) _Jv_AllocBytes (newlen
                                                            * sizeof(jshort));
          memcpy (&new_ioffsets[1], &old_ioffsets[1],
@@ -941,9 +964,9 @@ _Jv_Linker::find_iindex (jclass *ifaces, jshort *offsets, jshort num)
          while (len < newlen)
            new_ioffsets[len++] = -1;
          
-         ifaces[j]->idt->iface.ioffsets = new_ioffsets;
+         ifaces[j]->ioffsets = new_ioffsets;
        }
-      ifaces[j]->idt->iface.ioffsets[i] = offsets[j];
+      ifaces[j]->ioffsets[i] = offsets[j];
     }
 
   _Jv_MutexUnlock (&iindex_mutex);
@@ -952,7 +975,6 @@ _Jv_Linker::find_iindex (jclass *ifaces, jshort *offsets, jshort num)
 }
 
 #ifdef USE_LIBFFI
-
 // We use a structure of this type to store the closure that
 // represents a missing method.
 struct method_closure
@@ -965,12 +987,9 @@ struct method_closure
   ffi_type *arg_types[1];
 };
 
-#endif // USE_LIBFFI
-
 void *
 _Jv_Linker::create_error_method (_Jv_Utf8Const *class_name)
 {
-#ifdef USE_LIBFFI
   method_closure *closure
     = (method_closure *) _Jv_AllocBytes(sizeof (method_closure));
 
@@ -979,9 +998,13 @@ _Jv_Linker::create_error_method (_Jv_Utf8Const *class_name)
   // Initializes the cif and the closure.  If that worked the closure
   // is returned and can be used as a function pointer in a class'
   // atable.
-  if (ffi_prep_cif (&closure->cif, FFI_DEFAULT_ABI, 1, &ffi_type_void,
-                   closure->arg_types) == FFI_OK
-      && ffi_prep_closure (&closure->closure, &closure->cif,
+  if (   ffi_prep_cif (&closure->cif,
+                       FFI_DEFAULT_ABI,
+                       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;
@@ -994,13 +1017,17 @@ _Jv_Linker::create_error_method (_Jv_Utf8Const *class_name)
       buffer->append (_Jv_NewStringUtf8Const(class_name));
       throw new java::lang::InternalError(buffer->toString());
     }
+}
 #else
+void *
+_Jv_Linker::create_error_method (_Jv_Utf8Const *)
+{
   // Codepath for platforms which do not support (or want) libffi.
   // You have to accept that it is impossible to provide the name
   // of the missing class then.
   return (void *) _Jv_ThrowNoClassDefFoundError;
-#endif
 }
+#endif // USE_LIBFFI
 
 // Functions for indirect dispatch (symbolic virtual binding) support.
 
@@ -1218,7 +1245,7 @@ _Jv_Linker::link_symbol_table (jclass klass)
        }
 
       // Try fields only if the target class exists.
-      if ( target_class != NULL )
+      if (target_class != NULL)
       {
        wait_for_state(target_class, JV_STATE_PREPARED);
        jclass found_class;
@@ -1500,6 +1527,8 @@ _Jv_Linker::ensure_fields_laid_out (jclass klass)
   else
     instance_size = java::lang::Object::class$.size();
 
+  klass->engine->allocate_field_initializers (klass); 
+
   for (int i = 0; i < klass->field_count; i++)
     {
       int field_size;
@@ -1512,7 +1541,6 @@ _Jv_Linker::ensure_fields_laid_out (jclass klass)
          // It is safe to resolve the field here, since it's a
          // primitive class, which does not cause loading to happen.
          resolve_field (field, klass->loader);
-
          field_size = field->type->size ();
          field_align = get_alignment_from_class (field->type);
        }
@@ -1602,21 +1630,6 @@ _Jv_Linker::ensure_class_linked (jclass klass)
            }
        }
 
-#if 0  // Should be redundant now
-      // If superclass looks like a constant pool entry,
-      // resolve it now.
-      if ((uaddr) klass->superclass < (uaddr) pool->size)
-       klass->superclass = pool->data[(uaddr) klass->superclass].clazz;
-
-      // Likewise for interfaces.
-      for (int i = 0; i < klass->interface_count; i++)
-       {
-         if ((uaddr) klass->interfaces[i] < (uaddr) pool->size)
-           klass->interfaces[i]
-             = pool->data[(uaddr) klass->interfaces[i]].clazz;
-       }
-#endif
-
       // Resolve the remaining constant pool entries.
       for (int index = 1; index < pool->size; ++index)
        {
@@ -1848,9 +1861,9 @@ _Jv_Linker::print_class_loaded (jclass klass)
        }
     }
   if (codesource == NULL)
-    codesource = "<no code source>";
+    codesource = (char *) "<no code source>";
 
-  char *abi;
+  const char *abi;
   if (_Jv_IsInterpretedClass (klass))
     abi = "bytecode";
   else if (_Jv_IsBinaryCompatibilityABI (klass))
@@ -1882,6 +1895,21 @@ _Jv_Linker::wait_for_state (jclass klass, int state)
   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
   // pre-compiled cases here.