Re: JavaMemoryModel: Finalization idioms

From: Jeremy Manson (jmanson@cs.umd.edu)
Date: Sun May 01 2005 - 23:30:17 EDT


Hans Boehm wrote:

> On rereading, I'm a little confused by the formal statement in the 3rd
> edition of the JLS, which is presuambly identical to the JSR133 document.
> The formal spec mentions a read as an active use, but the text doesn't. I
> somehow thought we had decided not to do that. I'm not sure what
> implications that has.

A read or write of an element of X is an active use of X. This only
means that all reads or writes of X that "come-after" the point at which
  an object is declared finalizable must occur in the finalizer or be as
a result of the finalizer causing the object to become reachable again.

For emphasis: This has nothing to do with visibility - "comes-before" is
_not_ "happens-before". "Comes-before" exists solely for the purposes
mentioned in the section on finalizer semantics.

> If I write to some other place outside the object,
> and then read a final field in the object, must the write be visible to
> the finalizer?

No.

> Even if the value of the final field is a compile-time
> constant?

Don't get me started on compile-time constants. Evil buggers. :)

David Holmes said:
>>
>> It is not sufficient that the resource manager be
>> reachable during execution of its own methods useA and useB, it must also be
>> seen to be reachable during executing of the client code someMethod,
>> otherwise the resource manager could be finalized in between the calls to
>> the resource manager methods:
>>
>> void someMethod() {
>> ResourceManager man = new ResourceManager();
>> // man could be finalized here
>> int result1 = man.useA();
>> // or here
>> int result2 = man.useB();
>> // or here
>> }

If, as Hans says, you put a synchronized (this){} at the end of useA()
and useB(), you can't finalize man until the end of someMethod().
Method calls, or lack thereof, are invisible to the semantics; the
compiler would have to look at the actual accesses to man regardless of
where they are accessed.

Along the same vein, you couldn't imagine a compiler optimization that
takes the following C code (apologies, I've been writing C all day):

g() {
   int w = 1;
   f(&w);
   int r1 = w;
}

f(int *w) {
   *w = 2;
}

and hoists the read of w above the call to f.

To David D. and Evan - You could finalize man in any of the places David
H. mentions if useA() and useB() don't access this, and are inlined by
the compiler. In such code, there would be no uses of man after its
initialization.

Hopefully, this was helpful.

                                        Jeremy
-------------------------------
JavaMemoryModel mailing list - http://www.cs.umd.edu/~pugh/java/memoryModel



This archive was generated by hypermail 2b29 : Thu Oct 13 2005 - 07:01:10 EDT