Bill,
I'm very pleased with this outcome.
As an implementor of custom RMI-IIOP serialization, I have been through
hell and back with the non-portable alternate mechanisms for setting
final fields.
In making this change, we have now permitted write-once, run-anywhere
for J2EE containers.
Thanks to everyone who helped bring this about (including Doug Lea).
> -----Original Message-----
> From: owner-javamemorymodel@cs.umd.edu
> [mailto:owner-javamemorymodel@cs.umd.edu]On Behalf Of Bill Pugh
> Sent: Wednesday, 12 May 2004 3:21 a.m.
> To: javamemorymodel-cs.umd.edu; JSR133
> Subject: JavaMemoryModel: Final fields and deserialization
> 
> 
> 
> Previously, we had made some fields final, such as fields of the String 
> and Integer classes,
> so that these classes would be truly immutable, even if references to 
> them were passed between
> threads via data races.
> 
> This turns out to have caused some critical applications to fail. These 
> applications
> were using their own deserialization mechanisms, and they were changing 
> fields via
> reflection. With the additional fields being final, the applications no 
> longer worked.
> 
> These applications in are the category of applications that must work 
> in order for
> Sun to consider the JVM acceptable.
> 
> So the solution that has been decided on is that if you call 
> setAccessible on
> a java.lang.reflect.Field object, this will allow you not only to 
> change private
> fields of other classes, but also to change final fields. Note that 
> special security
> permissions are required to call setAccessible, and if you have these 
> permissions you
> can also remove or change the SecurityManager, so there isn't a big new 
> security hole
> created by this.
> 
> At this point, it is about 99.99% certain that this is the solution 
> that will be used,
> although there is a slight chance it will make it into the release 
> candidate rather
> than beta2.
> 
> This is probably for the best. When people start using final fields 
> more widely,
> it was going to become impossible for people to writing deserialization 
> code without
> using special magic like Unsafe.
> 
> We are making some slight adjustments to the details of changing final 
> fields in
> the formal semantics, so that normally written deserialization code 
> will (almost always)
> just work. The semantics are only designed to handle the case where the 
> final fields
> are modified via reflection before the field is read. There is one case 
> that is
> problematic:
> 
> class A {
>    final int x;
>    A() {
>      x = 1;
>    }
>    int f() {
>      return d(this,this);
>    }
>    int d(A a1, A a2) {
>      int i = a1.x;
>      g(a1);
>      int j = a2.x;
>      return j - i;
>    }
>    static void g(A a) {
>      // uses reflection to change a.x to 2
>    }
> }
> 
> We want to allow compilers to reorder reads of final fields across 
> unknown method calls.
> Thus, the read of a1.x can be moved to after the call to g(a1), and the 
> read of a2.x can
> be moved above the call to g(a1). As a result, f() can return either 
> -1, 0 or 1.
> 
> To guarantee that this cannot happen, we allow a block of code to be 
> performed in a
> final field safe context (probably by giving a runnable to some static 
> executor method,
> or by using an annotation on a method).
> 
> The semantics of this are that if an object is initialized and then the 
> final field
> modified within the final field safe context, reads of the final field 
> that occur
> after the final field safe context are guaranteed to see the correct 
> value. More
> generally, reads of final fields may not be moved into or out of a 
> final field safe context,
> although they may be moved across it (thus, if g used a final field 
> safe context above,
> the anomalous behavior could still occur).
> 
> We can also use a final field safe context in something such as an 
> executor or thread pool,
> to ensure that if one runnable uses an incorrectly published reference 
> to an object,
> a subsequent runnable can use a correctly published reference and be 
> guaranteed to
> see the correct values for the final fields of the object.
> 
> Now, although the spec will describe it, the 1.5 Java API won't provide 
> any way to
> obtain a final field safe context. I believe we will get this 
> introduced in the 1.5.1
> API. Aggressive optimization of final fields probably won't come until 
> 1.5.1 anyway,
> so this should be OK.
> 
> Note also that changing a final field initialized to a compile time 
> constant
> is highly questionable, since the value is substituted for uses of the 
> field by
> the compiler. It is allowed, but any use is allowed to see the compile 
> time constant
> value.
> 
> So the decision to allow reflection to change final fields, assuming 
> the appropriate
> security permissions, is pretty much a done deal. There really wasn't 
> much time to
> debate it, sorry about that.
> 
> However, we are open to feedback on the formal semantics of doing so.
> 
> Previously we described a method realloc method that needed to be used 
> when
> modifying final fields. After thinking about it, we decided that this 
> was unlikely
> to be something that could be easily retrofitted to most 
> deserialization techniques.
> Instead, we are tweak the semantics so that deserialization code 
> written to handle
> non-final fields will also work for final fields, with a requirement
> for using this new "final field safe context" to absolutely guarantee 
> that the
> compiler won't reorder a read of a final field and a reflective change 
> to a final
> field within a thread.
> 
> 
> 
> Bill
> 
> -------------------------------
> JavaMemoryModel mailing list - 
http://www.cs.umd.edu/~pugh/java/memoryModel
-------------------------------
JavaMemoryModel mailing list - http://www.cs.umd.edu/~pugh/java/memoryModel
This archive was generated by hypermail 2b29 : Thu Oct 13 2005 - 07:01:06 EDT