In a comment added to
Here are John's comments on the issue:
"...there appears to be a hole in the JVM's logic which blocks non-<init> methods from running putfield on final fields. Probably you know about this, but I'll write it here just in case.
Suppose the interpreter executes a putfield on a final field in an <init> method, which causes a call to LinkResolver::resolve_field_access that succeeds. At that point, InterpreterRuntime::resolve_get_put updates the CP cache entry for the field reference.
Later on, with the CP cache initialized for "puts" to that field, a random method (not an <init> method) in the same class executes a putfield on that final field. The assembly code checks the CP cache and takes the fast path. The new logic in the changes for
The root issue is that the cached resolution information in the CP cache is shared between <init> and non-<init> methods.
BTW, I like the fact that, whatever happens with resolution, the rewriter has already scanned for malformed puts to finals, and has set a bit telling the JIT to distrust those fields. This means we shouldn't have mis-optimization even if I'm right about the above weakness in resolution checking.
Perhaps there is some way to have resolve_get_put refuse to "quicken" the CP cache for a put of a final field, *if* the "has_initialized_final_update" bit has been set by the rewriter. In that case, the slow path would get run all the time for resolution. However, I don't see a way to do this without significant changes to the assembly code."