BC ABI: handling volatile

Andrew Haley aph@redhat.com
Wed Jun 14 10:41:00 GMT 2006


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/


More information about the Java mailing list

AltStyle によって変換されたページ (->オリジナル) /