Finding the declaring class of a _Jv_Field

Mark Wielaard mark@klomp.org
Mon Oct 30 14:46:00 GMT 2000


Hi,

On Sun, Oct 29, 2000 at 06:59:56PM -0500, Jeff Sturm wrote:
> Mark Wielaard wrote:
> > If I read the JVM spec right then a final field can actually be assigned
> > a value multiple times if it is done in the class that declares the field.
> > But you can never change the value of a final field from another class.
> > The JLS says that you cannot assign a final field a value twice, but
> > the JVM spec has no such restriction for byte code. Strange but true!
> > Try compiling the following with gcj -C (which current has a bug that it
> > does generate code to change the final field twice) and try running it
> > with any java interpreter. I haven't found any that would not just print
> > 1 and 2.
> 
> Interesting.  TestFinal does seem to pass the bytecode verifier, perhaps
> because it processes one method at a time... the putstatic insn would be
> legal in either <clinit> or main, but not both.
> 
> Microsoft's VM (which is pickier than most) detects this at runtime:
> 
> [jsturm@CC42593-A ~]$ jview TestFinal
> 1
> java.lang.IllegalAccessError: TestFinal: field i is final
>         at TestFinal.main
> 
> ERROR: java.lang.IllegalAccessError: TestFinal: field i is final

The JVMs that I tried (kaffe, IBM 1.1.8 and 1.3.0) didn't throw
such an error. Now the question is which JVM implementation is right.

I read some more in the JVM specification and found the following
references to the final field flag.

The section Field Modifiers (2.9.1) says:
"A field can be declared final, in which case its declarator must include
a variable initializer. Both class and instance variables (static and
non-static fields) may be declared final. Once a final field has been
initialized, it always contains the same value. If a final field holds a
reference to an object, then the state of the object may be changed by
operations on the object, but the field will always refer to the same
object."

The field access flags table lists:
ACC_FINAL 0x0010 Declared final; no further assignment after initialization. 

The part about the (byte code) verification process does not really say
anything specific about changing fields just that:
"The first time an instruction invokes a method, or accesses or modifies
a field, the executing instruction does the following:
 - Ensures that the referenced method or field exists in the given class.
 - Checks that the referenced method or field has the indicated descriptor.
 - Checks that the currently executing method has access to the referenced
   method or field."
But does not specify 'has access to'.

The description of putfield and putstatic say:
"If the field is final, it should be declared in the current class.
Otherwise, an IllegalAccessError is thrown." (This is a Linking Exception)

The section on Access Control (5.4.4) does not mention final fields at all!

In the appendix that describes the changes between the first and second
edition:
"The descriptions of the instructions putfield and putstatic now include
a specification of their behavior when a field is final. This documents
the behavior of existing implementations."

So while the description of putfield and putstatic seem to indicate that
you only have to check that the field is set in the same class as the
the field is declared some of the other text seems to imply that a final
field may only be set once in the <cinit> (when static) or in the
<init> (when not static) methods. I would conclude that the description
of putfield and putstatic is not strict enough but that almost all JVMs
currently implement what it says and that the Microsoft VM is (the only)
correct JVM when it throws the IllegalAccessError.

It is interesting to know if that is indeed how one should interpret
the spec because it makes it easier to implement final field checking
in gij and it indicates that one may do some optimalisations on final
fields because they really are not suppost to change ever.

What do people think? (I ask because I cannot believe that almost all
current JVMs get this wrong. And I thought it was kind of cool that
final in the VM actually meant local modifiable but pulic readable.)

Cheers,

Mark


More information about the Java mailing list