Hi Andrew,

Good news.

Have these issues been filed as bugs? Are there going to be fixes committed to mainline Fedora?

Peter

On Wed, Jun 22, 2011 at 6:20 PM, Andrew Haley <aph@redhat.com> wrote:
I've found and fixed the bugs that were stopping gcj from working.


Firstly, there was the "libgcc is a symlink instead of a linker
script" bug that I've explained before.


Then there was the libgcj/sysdep/arm/locks.h problem that broke
locking.  I already described that.


Then I found a locking bug in the boehm garbage collector.
GC_clear(), which releases a lock, was simply

      inline static void GC_clear(volatile unsigned int *addr) {
        /* Try to discourage gcc from moving anything past this. */
        __asm__ __volatile__(" " : : : "memory");
        *(addr) = 0;
      }

but it needs a memory barrier instruction.  The easiest way to fix
this is to use a gcc builtin that generates the correct barrier:

       inline static void GC_clear(volatile unsigned int *addr) {
         __sync_lock_release(addr);
       }

I also replaced GC_test_and_set() with a gcc builtin, although this
isn't strictly necessary:

        inline static int GC_test_and_set(volatile unsigned int *addr) {
         return __sync_lock_test_and_set(addr, 1);
       }


There was also a problem in libffi when generating a closure.  The
code that generates a trampoline looks like this:

#define FFI_INIT_TRAMPOLINE(TRAMP,FUN,CTX)                              \
({ unsigned char *__tramp = (unsigned char*)(TRAMP);                    \
  unsigned int  __fun = (unsigned int)(FUN);                           \
  unsigned int  __ctx = (unsigned int)(CTX);                           \
  *(unsigned int*) &__tramp[0] = 0xe92d000f; /* stmfd sp!, {r0-r3} */  \
  *(unsigned int*) &__tramp[4] = 0xe59f0000; /* ldr r0, [pc] */        \
  *(unsigned int*) &__tramp[8] = 0xe59ff000; /* ldr pc, [pc] */        \
  *(unsigned int*) &__tramp[12] = __ctx;                               \
  *(unsigned int*) &__tramp[16] = __fun;                               \
  __clear_cache((&__tramp[0]), (&__tramp[19]));                        \
 })

Here, three instructions are laid down in memory, followed by some
data fields.  Once that has been done, __clear_cache() is called on
the block of memory.  Unfortunately, due to the requirement to placate
SELinux, the same block of memory is mapped twice, once with RW
mapping and once with RX mapping.  Therefore, there must be two calls
to __clear_cache(), one to flush the dcache, and one to flush the
icache.  Like this:

#define FFI_INIT_TRAMPOLINE(TRAMP,FUN,CTX)                              \
({ unsigned char *__tramp = (unsigned char*)(TRAMP);                    \
  unsigned int  __fun = (unsigned int)(FUN);                           \
  unsigned int  __ctx = (unsigned int)(CTX);                           \
  unsigned char *insns = (unsigned char *)(CTX);                       \
  *(unsigned int*) &__tramp[0] = 0xe92d000f; /* stmfd sp!, {r0-r3} */  \
  *(unsigned int*) &__tramp[4] = 0xe59f0000; /* ldr r0, [pc] */        \
  *(unsigned int*) &__tramp[8] = 0xe59ff000; /* ldr pc, [pc] */        \
  *(unsigned int*) &__tramp[12] = __ctx;                               \
  *(unsigned int*) &__tramp[16] = __fun;                               \
  __clear_cache((&__tramp[0]), (&__tramp[19])); /* Clear data mapping.  */ \
  __clear_cache(insns, insns + 3 * sizeof (unsigned int));             \
                                                /* Clear instruction   \
                                                   mapping.  */        \
 })


Finally, libjava was segfaulting when an array class was finalized.
This has apparently always happened, but on other platforms the
segfault is caught and turned into a NullPointerException.  All
finalizers are called from an exception region that traps all
exceptions and continues, so we never noticed.

Fixed thusly:

--- libjava/java/lang/natClass.cc       2010-06-11 05:09:01.000000000 -0400
+++ prev/libjava/java/lang/natClass.cc  2011-06-21 06:09:22.000000000 -0400
@@ -668,6 +668,8 @@
 void
 java::lang::Class::finalize (void)
 {
+  // Array classes don't have an engine, and don't need to be finalized.
+  if (engine)
  engine->unregister(this);
 }


After all this, gcj now seems to work.  I'm now building OpenJDK.

Andrew.
_______________________________________________
arm mailing list
arm@lists.fedoraproject.org
https://admin.fedoraproject.org/mailman/listinfo/arm