BZ #72: CACAO and gcc don't agree on calling conventions

Status fields:

creation_ts:2008-05-23 15:17
component:jit
version:unspecified
rep_platform:i386
op_sys:Linux
bug_status:RESOLVED
resolution:FIXED
reporter:stefan@complang.tuwien.ac.at
After updating to Fedora 9 (and getting rid of the mmap problem I posted to the mailing
list), I noticed that dacapo had stopped working in a very peculiar way - it could not
create files during unzipping because of the non-existent directory "scratch/antlr"
which it should have created with File.mkdir(). But it had not.

After lots of poking around, I found out that gcc 4.3 only uses 8 bits (al) to return a
boolean value. But cacao expects the whole register to be set. The following line
appeared in a +TraceJavaCalls output.

java.io.File.exists()Z->135257088 (0x080fdc00)

It means that the file does not exist (the lower 8 bits are zero). CACAO, however,
interprets it as non-zero and thus doesn't execute the subsequent mkdir, causing the
file extraction to fail.

I don't know what the official ABI says, and I couldn't find an obvious easy way to fix
it, so I'm reporting it here.

On x86_64, in contrast, I didn't have this problem. Maybe the calling convention is
different there, maybe gcc didn't change its behavior or maybe it was just bad luck...

Comment #1 by stefan@complang.tuwien.ac.at on 2008-05-23 15:29:00

Is there even such a thing as an official ABI? If there is, it's not easily
discoverable...

Comment #2 by stefan@complang.tuwien.ac.at on 2008-05-23 16:21:46

Found it: http://www.sco.com/developers/devspecs/abi386-4.pdf

Not very helpful though - "A function that returns an integral or pointer value places
its result in register %eax."

This can mean anything, although I would probably interpret it the way CACAO does.

Comment #3 by twisti@complang.tuwien.ac.at on 2008-05-31 08:49:57

Stefan, I assign this bug to you.

Comment #4 by stefan@complang.tuwien.ac.at on 2008-06-09 18:38:29

Created an attachment (id=41)
hg export of fix

This should fix it (for i386). I cannot commit (thank you Debian), so I'm posting it
here.

I'm not sure about x86_64 anymore. Theoretically, it should be affected too. Maybe I
haven't noticed because I haven't rebuilt classpath yet...

Comment #5 by stefan@complang.tuwien.ac.at on 2008-06-09 18:40:04

twisti, what's with that "XXX does not work, because of nibbles" comment?

It works fine for <REG_RESULT, REG_RESULT> at least...

Comment #6 by twisti@complang.tuwien.ac.at on 2008-06-10 10:20:37

Yes, it works for register number 0 (EAX == AX == AL), but not for others.  So enabling
this one is not a good idea.

Comment #7 by twisti@complang.tuwien.ac.at on 2008-06-11 08:29:30

With what optimization are you compiling?  Have you tried to change that?

Comment #8 by stefan@complang.tuwien.ac.at on 2008-06-11 08:41:26

(In reply to comment #7)
> With what optimization are you compiling?  Have you tried to change that?
>

Yeah, it doesn't make a difference.

The function "exists" compiles to the code shown below (I used -fomit-frame-pointer for
brevity)

char exists(int a)
{
        return a > 0;
}

0000007d <exists>:
  7d:   83 7c 24 04 00          cmpl   $0x0,0x4(%esp)
  82:   0f 9f c0                setg   %al
  85:   c3                      ret

Comment #9 by twisti@complang.tuwien.ac.at on 2008-06-11 09:31:51

Yes, you're right.  I just tried it on my Debian box:

$ gcc-4.2 -S -m32 -fomit-frame-pointer -O2 test.c
$ cat test.s
<snip>
exists:
        xorl    %eax, %eax
        cmpl    $0, 4(%esp)
        setg    %al
        ret

$ gcc-4.3 -S -m32 -fomit-frame-pointer -O2 test.c
$ cat test.s
<snip>
exists:
        movl    4(%esp), %eax
        testl   %eax, %eax
        setg    %al
        ret

See the missing register clear?  Same applies to x86_64:

$ gcc-4.2 -S -m64 -fomit-frame-pointer -O2 test.c
$ cat test.s
<snip>
exists:
.LFB2:
        xorl    %eax, %eax
        testl   %edi, %edi
        setg    %al
        ret

$ gcc-4.3 -S -m64 -fomit-frame-pointer -O2 test.c
$ cat test.s
<snip>
exists:
.LFB2:
        testl   %edi, %edi
        setg    %al
        ret

I don't know if this is indented or a bug.

Comment #10 by stefan@complang.tuwien.ac.at on 2008-06-11 10:24:16

I cannot imagine this being a bug. I think I remember a somewhat similar change a few
years ago when gcc changed the point in time at which it forced (C++) bools to 0/1.
Before, bools always contained only 0/1, so a cast to char was a nop. They changed it so
that bools can contain any value, and only upon casting to a numeric value is it
interpreted as false/true and set to 0/1 resp. The change might have been the other way
round but I'm sure it happened at some time.

Comment #11 by twisti@complang.tuwien.ac.at on 2008-06-11 12:24:22

I just tried Sun Studio compiler and it produces the same code as GCC 4.2.  Should we
ask the GCC list?

Comment #12 by stefan@complang.tuwien.ac.at on 2008-06-11 16:52:33

Intel 10.0 does the same (like GCC 4.2).

It happened somewhere between the gcc-4.3-20070707 and gcc-4.3-20070713 snapshots. No
idea which changeset exactly.

It does interoperate well with older code, however, because apparently, compiled code
has never assumed the upper part of the register to contain anything useful.

Comment #13 by stefan@complang.tuwien.ac.at on 2008-06-11 19:28:07

See http://gcc.gnu.org/ml/gcc/2008-01/msg00052.html (and followups)

Comment #14 by twisti@complang.tuwien.ac.at on 2008-06-11 21:36:09

Hmm, OK.  So it seems we have to add a "workaround".

Comment #15 by stefan@complang.tuwien.ac.at on 2008-06-11 22:21:30

Interestingly, Visual C++ 2003 (the only version I tried) produces code like gcc 4.3.

In a way, I like the change. Before, the expansion has always been done twice - once
before returning and once when interpreting the return value. Now that redundancy is
gone. And this is a good thing. It's very similar to that whole cld issue
<http://lwn.net/Articles/272048/>, except that the ABI specification is crystal clear
for the direction flag, something which cannot be said about the return value issue.

Comment #16 by stefan@complang.tuwien.ac.at on 2008-06-11 23:21:03

Created an attachment (id=43)
pr72-i386

First part (i386). Now I know what you meant with that nibbles comment...

Comment #17 by stefan@complang.tuwien.ac.at on 2008-06-11 23:34:54

Created an attachment (id=44)
pr72-x86_64

This should do it for x86_64...

Comment #18 by stefan@complang.tuwien.ac.at on 2008-06-11 23:43:48

Committed.

Comment #19 by twisti@complang.tuwien.ac.at on 2008-06-12 10:04:03

Thanks for fixing this one.

Attachment id=41

date:2008-06-09 18:38
desc:hg export of fix
type:text/plain
download:bug72

Attachment id=43

date:2008-06-11 23:21
desc:pr72-i386
type:text/plain
download:pr72

Attachment id=44

date:2008-06-11 23:34
desc:pr72-x86_64
type:text/plain
download:pr72-x86_64