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