Re: JavaMemoryModel: Final Means Different Things To VM and Java Language. Does That Impact JITs?

From: Bill Pugh (pugh@cs.umd.edu)
Date: Tue Sep 30 2003 - 16:12:17 EDT


The rules on final fields being set exactly once are part of the
JVM/classfile specification. A classfile in which a final field is
written to outside the constructor (or either zero or more than once
during construction) is an invalid classfile that should be rejected
by the JVM with a verification error.

So the example below would be rejected by the JVM if MyFieldJ was final.

Bill

At 3:12 PM -0400 9/30/03, Allan Kielstra wrote:
>My colleague Andrew Johnson has observed that:
> * the Java Language Specification ensures that final fields are only set
>once, in the constructor.
> * The byte code verifier just ensures that final fields are only set by
>methods in the defining class.
>
>Depending on how pedantic one wants to be, this may limit the flexibility
>of the Just-in-time compiler in making optimizations with final fields, as
>there is nothing prohibiting such fields changing. Given a program such
>as:
>/**
> * Test final fields
> */
>public class finalt1 {
> /** private final field */
> private final int MyFieldi;
> /** private field - modify to be final using debugger */
> private int MyFieldj;
> public int get() {
> return MyFieldi;
> }
> public int get1(int y) {
> if (y > 0) return get1(y-1);
> return MyFieldj;
> }
> /**
> * Sets MyFieldj to y
> */
> public int set1(int y, int y2) {
> if (y2 > 0) return set1(y, y2-1);
> return MyFieldj = y;
> }
> /**
> * constructs object and calls set1 to set MyFieldj
> */
> public finalt1(int z) {
> if (z == Integer.MIN_VALUE) {
> return;
> }
> MyFieldi = z;
> set1(z, 0);
> MyFieldj = 0;
> }
> public static void main(String[] args) {
> finalt1 q = new finalt1(args.length+Integer.MIN_VALUE);
> System.out.println("Object "+q+" MyFieldi "+q.get()+" MyFieldj
>"+q.get1(0));
> q.set1(2, 0);
> System.out.println("Object "+q+" MyFieldi "+q.get()+" MyFieldj
>"+q.get1(0));
> int ss = 0;
> for (int i = 0; i < 3000; ++i) {
> ss += q.r(i);
> }
> System.out.println(""+q+" MyFieldi "+q.get()+" MyFieldj
>"+q.get1(0)+" "+ss);
> }
> public int r(int t) {
> int y = 0;
> for (int i = 0; i < 100; ++i) {
> set1(t, 0);
> y += MyFieldj;
> }
> return y;
> }
>}
>
>If one were to use a binary editor to modify the resulting class file such
>that MyFieldj appears to be final, we get a case where the compiler assumes
>that the
> "y += MyFieldj"
>in the loop in method "r" can be statically computed (i.e., y +=
>100*MyFieldj) despite the fact that the method "set1" changes the value of
>the field.
>
>My feeling is that if you lie to the VM (by using a class file editor or
>other chicanery) you get what you get. That is, a JIT (or anything else)
>should be allowed to assume that you're telling the truth. Are there other
>opinions?
>
>Andrew has also noted that the jikes compiler (an open source Java compiler
>available here:
>http://oss.software.ibm.com/developerworks/opensource/jikes/) handles
>field initializers by putting all the code into a method called:
>private void this()
>which is then invoked at the start of each constructor.
>
>Unfortunately, one can re-run the "this" method at arbitrary program points
>using reflection:
>
>import java.lang.reflect.*
>class C {
> static int StaticGlobal = 0;
>
> private final int MyFinalField = ++StaticGlobal; // this statement
>will be placed in a method called "this"
>
> public void set() {
> Class z = getClass();
> try {
> /* invoke the private void this() method from Jikes */
> /* Cannot do it directly from java code */
> Method m = z.getDeclaredMethod("this", new Class[]{});
> m.invoke(this, new Object[0]);
> } catch (Exception e) {
> e.printStackTrace();
> }
> }
> }
>
>Given an object "c" of class "C", the invocation "c.set()" will cause
>"MyFinalField" to assume a new value. This is trickier because the cheat
>can be performed with Java source code (instead of a class file editor).
>In a slightly more perfect world, there would be a mechanism for a compiler
>to encode rules in the class file which the VM would use for prohibiting
>some operations that use reflection. In the meantime, I believe that this
>is a cheat and a JIT or VM is allowed to assume that it doesn't happen.
>Again, I am curious about other opinions. Are there any?
>
>
>Allan Kielstra
>IBM Canada Lab
>Phone: +1 (905) 413-3558 T/L 969-3558
>kielstra@ca.ibm.com
>
>-------------------------------
>JavaMemoryModel mailing list - http://www.cs.umd.edu/~pugh/java/memoryModel



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