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: