BZ #159: Yeti crashes CACAO

Status fields:

creation_ts:2011-07-22 03:23
version:default branch
Using cacao from Debian Squeeze, easily reproducible - just get and try running it with -e argument to evaluate

predator:~/yeti$ java -cacao -jar yeti-icast.jar -e 42
LOG: [0x00007f6dea83e700] We received a SIGSEGV and tried to handle it, but we were
LOG: [0x00007f707d7ba700] unable to find a Java method at:
LOG: [0x00007f707d7ba700]
LOG: [0x00007f707d7ba700] PC=0x00007f707c770425
LOG: [0x00007f707d7ba700]
LOG: [0x00007f707d7ba700] Dumping the current stacktrace:
        at yeti.lang.compiler.eval$evaluateYetiCode$._0(Lyeti/lang/compiler/YetiEval;Lye
        at yeti.lang.compiler.eval$evaluateYetiCode$.apply(Ljava/lang/Object;Ljava/lang/
        at yeti.lang.Fun2_.apply(Ljava/lang/Object;)Ljava/lang/Object;(NULL:0)
        at yeti.lang.compiler.yeti.main([Ljava/lang/String;)V(yeti.yeti:189)
LOG: [0x00007f707d7ba700] Exiting...

There is another problem also - differently from OpenJDK the Cacao expects that
INVOKEINTERFACE object argument is statically determined to be instance of the interface
that is invoked. For example, the following bytecode is fine with OpenJDK:

public final java.lang.Object apply(java.lang.Object);
   0:   aload_1
   1:   aconst_null
   2:   astore_1
   3:   ldc     #13; //String a
   5:   invokeinterface #19,  2; //InterfaceMethod
   10:  areturn

While Cacao gives the error that Exception in thread "main" java.lang.LinkageError:
subtype constraint violated (java.lang.Object is not a subclass of yeti/lang/Struct).

It seems to expect a explicit checkcast of the object reference (I'm not sure, it may be
right about that according to the VM specification). The compiler currently omits those
casts by default, because there would be really many of those and OpenJDK (nor
Sun/Oracle JVM based on it or JRockit) doesn't seem to require it.

This could be tested with

Comment #1 by on 2011-07-22 10:40:47

Interesting. The INVOKEINTERFACE problem is known as bug 82.

The crash also happens with a current version of CACAO.

Comment #2 by on 2011-08-05 23:14:06

After a lot of head scratching, I've found the problem, and it doesn't look pretty. It's
some weird register allocation stuff going on, of the kind that comes back from the dead
to haunt you. And I guarantee you, nobody really understands the CACAO register
allocator :(.

Method yeti.lang.compiler.eval$evaluateYetiCode$._1
   84:  aconst_null
   85:  astore  5
   87:  aconst_null
   88:  astore  7
   90:  aload   4
   92:  aload_0
   93:  invokevirtual   #213; //Method
   96:  aload   7
   98:  ifnonnull       104
   101: aload   5
   103: areturn
   104: aload   7
   106: athrow

There is a basic block boundary between 87 and 88, because 88 is an exception handler
target; the code for 85-88 looks like this:
0x00002aaaabb79f72:   4c 89 7c 24 28                   mov    %r15,0x28(%rsp)
0x00002aaaabb79f77:   4d 31 ff                         xor    %r15,%r15
== BB Boundary
0x00002aaaabb79f7a:   49 89 c7                         mov    %rax,%r15
0x00002aaaabb79f7d:   4c 89 7c 24 38                   mov    %r15,0x38(%rsp)

It should store NULL to local variable 7, but it does in fact store whatever happens to
be in register rax.

Comment #3 by on 2011-08-08 19:50:47

Comment #4 by on 2011-08-08 21:16:11

Out of curiosity: which compiler was used to produce that bytecode?

Comment #5 by on 2011-08-09 02:00:23

It was created by Yeti compiler (which is actually inside that jar).