Sarita points out that I successfully obscured what was intended to be a simple point.
I was using C syntax, since it makes it easier to represent certain compiler transformations.
Restating the example in Java terms and a bit more precisely:
Assume we have the field access
j = p.f;
where p is in shared memory. Assume p is dead after this access in this thread, say because the
statement is followed by "p = null;". Assume we're on a machine on which memory
accesses cost no more than register accesses, on which a load instruction can't
add a displacement, and which is seriously short of memory. And assume that f is
not at offset zero in the object. (I believe all of these assumptions are individually
true somewhere.)
In that case the above needs to be compiled into an add instruction followed by a load
from the resulting address into j. Since p is dead, in a single-threaded program,
we can do the addition in place, so that p is replaced by the address of p.f. By
Jerry's argument this should be legal. I believe this would be OK if you were compiling C or C++,
though perhaps not desirable.
In the case of Java, this is type-unsafe. A second thread could observe the intermediate
value of p (an out-of-thin-air value) which really points to a field within p, and use
it to access memory outside the object.
This argues that a Java compiler can never completely ignore the fact that code
may be running in a multithreaded context. Type-safety requires some guarantees against
out-of-thin-air values, at least for object references. My understanding was that this
was a lot of the original motivation behind the effort to prevent these.
Another example of this is that an array subscript check must load the array length through the
same array pointer that is used to access the element; reloading the pointer to the array
is not safe in multithreaded code, though it would be fine in single-threaded code.
Hans
> -----Original Message-----
> From: Boehm, Hans
> Sent: Monday, July 28, 2003 1:52 PM
> To: 'Bill Pugh'; Jerry Schwarz; javamemorymodel@cs.umd.edu
> Subject: RE: JavaMemoryModel: Executions I find profoundly troubling
>
>
> > -----Original Message-----
> > From: Bill Pugh [mailto:pugh@cs.umd.edu]
> > At 10:11 AM -0700 7/28/03, Jerry Schwarz wrote:
> > >
> > >Put another way. If the code doesn't contain any threading
> > >constructs (volatile, synchronize, ...) then the compiler
> shouldn't
> > >be forced to treat the code is if it will be running in a
> > >multithreaded context.
> > >
> >
> > I've been thinking about this for several years actually. I
> think the
> > only limitation on compilers in synchronization-free code is that
> > they may not introduce additional reads or writes of shared
> variables
> > if the additional reads/writes could be detected. It turns out that
> > you can introduce additional writes if you know that all of the
> > writes will write the same value, because this can't be detected.
> >
> It seems to me that Jerry's view is very reasonable for
> C/C++, but I don't see how
> to make it work for Java.
>
> If we start out with (using C notation):
>
> j = p -> f;
>
> A C compiler may conceivably compile this as:
>
> p = &(p -> f);
> j = *p;
>
> In Java that clearly violates type safety if p is in shared
> memory; an observer thread
> may use the intermediate value of p to access parts of memory
> it shouldn't have
> access to.
>
> You could still allow this for non-reference fields in Java.
> But there is a strong
> argument that would also be removing guarantees from the
> existing spec, and it would
> almost certainly break security for some existing code. And
> the spec would now
> have to treat the two cases separately.
>
> Hans
>
-------------------------------
JavaMemoryModel mailing list - http://www.cs.umd.edu/~pugh/java/memoryModel
This archive was generated by hypermail 2b29 : Thu Oct 13 2005 - 07:00:47 EDT