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]

BC ABI: handling volatile


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...

Andrew.


http://www.cs.umd.edu/~pugh/java/memoryModel/


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