This is the mail archive of the java@gcc.gnu.org mailing list for the Java project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: BC ABI: handling volatile


Andrew Haley wrote:
We don't properly implement volatile when compiling BC, and as I see
it there's no way to do so without extending the ABI.

[I'm going to talk about non-static fields here, but the same argument
applies to static fields.]

When accessing fields in another class, we generate something like


D.678 = _otable_p[1]; if (D.678 == 0) { _Jv_ThrowNoSuchFieldError (1); } else { D.679 = _otable_p[1]; iftmp.2 = (<unnamed type>) D.679; } D.680 = iftmp.1 + iftmp.2; D.681 = *D.680;

which in turn generates code like

        movl    _otable_p+4, %eax       # _otable_p, D.705
        testl   %eax, %eax      # D.705
        je      .L11    #,
        movl    (%edx,%eax), %eax       #* D.705, tmp64

...

.L11:
        movl    $1, (%esp)      #,
        call    _Jv_ThrowNoSuchFieldError       #

This isn't all that bad, being only a single inline conditional
branch between the otable fetch and the load.


However, volatile present an additional problems: accessing a volatile
field has side efects.

We need to insert memory barriers when accessing volatiles (on x86
that's lfence after a load and mfence before a store.)  Also, at the
time of compilation we can't know whether a field is declared
volatile.  So, we could do something like this:

  D_678 = _otable_p[1];
  iftmp_2 = D_678;

if (D_678 <= 0)
{
if (D_678 == 0)
{
_Jv_ThrowNoSuchFieldError (1);
}
else
{
iftmp_2 = -iftmp_2;
int *D_680 = iftmp_1 + iftmp_2;
D_681 = *D_680;
__asm volatile ("lfence");
} }
else
{
int *D_680 = iftmp_1 + iftmp_2;
D_681 = *D_680;
}
which generates code like:


        movl    _otable_p+4, %eax
        cmpl    $0, %eax
        jle     .L9
        movl    (%eax,%eax,4), %ebx
.L6:
	...

.L9:
        je      .L10
        negl    %eax
        movl    (%eax,%eax,4), %ebx
        lfence
	...

.L10:
        movl    $1, (%esp)
        call    _Jv_ThrowNoSuchFieldError

In a way this isn't bad, because the commonly-executed path is no
longer than it is at the present time.  However, the additional code
bloat is quite substantial.

Compiler-generated get and put methods would present a cleaner way to do
this: it'd be

    D.701 = D.700->vtable;
    D.702 = _otable_p[1];
    D.704 = D.701 + D.702;
    D.707 = (*D.704) (D.699);

which generates code like
movl (%eax), %edx # <variable>.vtable, <variable>.vtable
movl %eax, (%esp) # D.700,
movl _otable_p+4, %eax # _otable_p, _otable_p
call *(%edx,%eax) #* _otable_p


which removes the need to test for ThrowNoSuchFieldError, volatile,
etc.

A fence instruction would be inserted into the accessor methods iff
the field was known to be volatile: the compiler has the advantage
that this is known at compile time at the point of declaration.
However, there would be the additional code bloat of the accessor
methods and their vtable entries.  Also, this changes the ABI in an
incompatible way.

There is one other idea that I am somewhat reluctant to contemplate:
always emit a fence when accessing volatiles declared outside the
current class.  This might not be so awful, because accessing fields
outside the current class is not much done in well-written
object-oriented code.  However, these fences can be quite slow on
some architectures.

Your opinion is welcomed...

How about a hybrid approach:


otable_entry e = _otable_p[i];
if (can_do_direct_access_p(e))
	target = *(other_object + e);
else
	target = (*e)();


At compile time you generate an accessor method if the volatile is accessible from outside of the class. Since most fields are not volatile, this should not be too much overhead.


At link time, fill in the otable entry with either the offset to the field (if not volatile), or a pointer to the accessor function. You also put a pointer to _Jv_ThrowNoSuchFieldError in the otable slots where it would be appropriate.

The trick is to have a very efficient can_do_direct_access_p(). A naive implementation might be:

boolean inline can_do_direct_access_p(void *x) { return x & ~0xffff;}

It might be possible to implement this as efficiently as the current otable accesses.

David Daney.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]