Java 5 has an extended class file format for annotations.  We have to
support that in gcj-compiled code too, and it requires an ABI change.

Tom Tromey, I'd appreciate it if you'd have a quick check of this one.

We should probably port the code that throws a ClassFormatError if
we're not ABI-compatible to the active branches.

Andrew.


2006-12-19  Andrew Haley  <[EMAIL PROTECTED]>

        * java/lang/natClassLoader.cc (_Jv_CheckABIVersion): Move here
        from include/jvm.h.
        Add BC ABI Version 1.
        Throw a ClassFormatError if we're not ABI-compatible.
        (_Jv_RegisterClasses): Throw a ClassFormatError if we're not
        ABI-compatible.
        (_Jv_RegisterClasses_Counted): Likewise.
        (_Jv_NewClassFromInitializer): Likewise.
        Call Class::initializerSize to get size of initializer struct.
        * include/jvm.h (_Jv_CheckABIVersion): Move to natClassLoader.cc.
        * java/lang/Class.h (Class::initializerSize): New function.

gIndex: gcc/java/decl.c
===================================================================
--- gcc/java/decl.c     (revision 120004)
+++ gcc/java/decl.c     (working copy)
@@ -75,9 +75,9 @@
                                          loader.  */
 
 /* If an ABI change is made within a GCC release series, rendering current
-   binaries incompatible with the old runtimes, this number can be set to
+   binaries incompatible with the old runtimes, this number must be set to
    enforce the compatibility rules. */
-#define MINOR_BINARYCOMPAT_ABI_VERSION 0
+#define MINOR_BINARYCOMPAT_ABI_VERSION 1
 
 /* The runtime may recognize a variety of BC ABIs (objects generated by 
    different version of gcj), but will probably always require strict 
Index: libjava/include/jvm.h
===================================================================
--- libjava/include/jvm.h       (revision 120004)
+++ libjava/include/jvm.h       (working copy)
@@ -658,30 +658,8 @@
 // New style version IDs used by GCJ 4.0.1 and later.
 #define GCJ_40_BC_ABI_VERSION (4 * 100000 + 0 * 1000)
 
-inline bool
-_Jv_CheckABIVersion (unsigned long value)
-{
-  // We are compatible with GCJ 4.0.0 BC-ABI classes. This release used a
-  // different format for the version ID string.
-   if (value == OLD_GCJ_40_BC_ABI_VERSION)
-     return true;
-     
-  // The 20 low-end bits are used for the version number.
-  unsigned long version = value & 0xfffff;
-
-  if (value & FLAG_BINARYCOMPAT_ABI)
-    {
-      int abi_rev = version % 100;
-      int abi_ver = version - abi_rev;
-      if (abi_ver == GCJ_40_BC_ABI_VERSION && abi_rev <= 0)
-        return true;
-    }
-  else
-    // C++ ABI
-    return version == GCJ_CXX_ABI_VERSION;
-  
-  return false;
-}
+void _Jv_CheckABIVersion (unsigned long value);
+
 
 inline bool
 _Jv_ClassForBootstrapLoader (unsigned long value)
Index: libjava/java/lang/natClassLoader.cc
===================================================================
--- libjava/java/lang/natClassLoader.cc (revision 120004)
+++ libjava/java/lang/natClassLoader.cc (working copy)
@@ -180,6 +180,41 @@
 // _Jv_RegisterNewClasses() are of Type 2.
 
 
+// Check that the file we're trying to load has been compiled with a
+// compatible version of gcj.  In previous versions of libgcj we
+// silently failed to register classes of an incompatible ABI version,
+// but this was totally bogus.
+void
+_Jv_CheckABIVersion (unsigned long value)
+{
+  // We are compatible with GCJ 4.0.0 BC-ABI classes. This release used a
+  // different format for the version ID string.
+   if (value == OLD_GCJ_40_BC_ABI_VERSION)
+     return;
+     
+  // The 20 low-end bits are used for the version number.
+  unsigned long version = value & 0xfffff;
+
+  if (value & FLAG_BINARYCOMPAT_ABI)
+    {
+      int abi_rev = version % 100;
+      int abi_ver = version - abi_rev;
+      // We are compatible with abi_rev 0 and 1.
+      if (abi_ver == GCJ_40_BC_ABI_VERSION && abi_rev <= 1)
+        return;
+    }
+  else
+    {
+      // C++ ABI
+      if (version == GCJ_CXX_ABI_VERSION)
+       return;
+    }
+
+  throw new ::java::lang::ClassFormatError
+    (JvNewStringLatin1 ("Library compiled with later ABI version than"
+                       " this version of libgcj supports"));
+}
+
 // 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 
@@ -194,14 +229,8 @@
     {
       jclass klass = *classes;
 
-      if (_Jv_CheckABIVersion ((unsigned long) klass->next_or_version))
-       (*_Jv_RegisterClassHook) (klass);
-      else
-       {
-         fprintf (stderr, "ABI mismatch: library is compiled with "
-                  "the wrong version of gcj\n");
-         abort ();
-       }
+      _Jv_CheckABIVersion ((unsigned long) klass->next_or_version);
+      (*_Jv_RegisterClassHook) (klass);
     }
 }
 
@@ -217,32 +246,37 @@
     {
       jclass klass = classes[i];
 
-      if (_Jv_CheckABIVersion ((unsigned long) klass->next_or_version))
-       (*_Jv_RegisterClassHook) (klass);
+      _Jv_CheckABIVersion ((unsigned long) klass->next_or_version);
+      (*_Jv_RegisterClassHook) (klass);
     }
 }
 
 // Create a class on the heap from an initializer struct.
-jclass
+inline jclass
 _Jv_NewClassFromInitializer (const char *class_initializer)
 {
+  const unsigned long version 
+    = ((unsigned long) 
+       ((::java::lang::Class *)class_initializer)->next_or_version);
+  _Jv_CheckABIVersion (version);
+  
   /* We create an instance of java::lang::Class and copy all of its
      fields except the first word (the vtable pointer) from
      CLASS_INITIALIZER.  This first word is pre-initialized by
      _Jv_AllocObj, and we don't want to overwrite it.  */
-
+  
   jclass new_class
-    = (jclass)_Jv_AllocObj (sizeof (java::lang::Class),
-                           &java::lang::Class::class$);
+    = (jclass)_Jv_AllocObj (sizeof (::java::lang::Class),
+                           &::java::lang::Class::class$);
   const char *src = class_initializer + sizeof (void*);
   char *dst = (char*)new_class + sizeof (void*);
-  size_t len = sizeof (*new_class) - sizeof (void*);
+  size_t len = (::java::lang::Class::initializerSize (version) 
+               - sizeof (void*));
   memcpy (dst, src, len);
-
+  
   new_class->engine = &_Jv_soleIndirectCompiledEngine;
-
-  if (_Jv_CheckABIVersion ((unsigned long) new_class->next_or_version))
-    (*_Jv_RegisterClassHook) (new_class);
+  
+  (*_Jv_RegisterClassHook) (new_class);
   
   return new_class;
 }
Index: libjava/java/lang/Class.h
===================================================================
--- libjava/java/lang/Class.h   (revision 120004)
+++ libjava/java/lang/Class.h   (working copy)
@@ -479,6 +479,20 @@
   // types. See prims.cc.
   Class ();
 
+  // Given the BC ABI version, return the size of an Class initializer.
+  static jlong initializerSize (jlong ABI)
+  {
+    unsigned long version = ABI & 0xfffff;
+    int abi_rev = version % 100;
+    
+    // The reflection_data field was added by abi_rev 1.
+    if (abi_rev == 0)
+      return ((char*)(&::java::lang::Class::class$.reflection_data)
+             - (char*)&::java::lang::Class::class$);
+    
+    return sizeof (::java::lang::Class);
+  }
+
   static java::lang::Class class$;
 
 private:   

Reply via email to