# ProblemThe JVM JITs routinely optimize references to final fields as constantvalues, when a JIT can deduce a constant containing object. This is afundamental capability for producing good code.Currently, though, only a small number of "white listed" fields aretreated in this way, since vigorously optimizing _all_ final fields isthought to have unknown risky consequences. The white listing logicis defined using the function `trust_final_non_static_fields` andsimilar logic as part of changes like JDK-6912065 and JDK-8140483 # ProposalThe JVM should support an option `FoldConstantFields` which treatsbypasses the above "white list" and uses a "black list" instead asneeded. Initially this option should be turned off by default.Turning it on should, initially, also turn on a new option`VerifyConstantFields` which detects updates to final fields anddiagnoses them with some selectable mix of warnings or errors.(See below for discussion of how updates to final fields can occcur.The short summary is "reflection, JNI, or Unsafe". Each of theserequires a different remediation.)This feature will not solve the problem of full optimization ofconstant fields all at once, but will set the stage for finding andfixing problems caused by such optimizations.The support for `FoldConstantFields` should include (either initiallyor as follow-on work) the following functions:- Dependency recording in the JIT, whenever a final field value isused. At first this should be recorded per field declaration, notper individual field instance, on the assumption that invalidationwill be very rare. This assumption may need to be revised.- Updates to final fields via reflection must be trapped and musttrigger deoptimization of dependent JIT.- Updates to final fields via JNI must be trapped similarly.- Updates to final fields via other users of `Unsafe` must be trappedsimilarly. This addresses uses of `Unsafe` _that the JDK knowsabout and controls_.- Encourage other users of `Unsafe` to perform similar notifications,and document how to do so. Perhaps there are additional `Unsafe`API points to notify the JIT.- Placing the checking logic inside `Unsafe` is the wrong answer inmost cases, since it would penalize well-behaved users of `Unsafe`.Perhaps a separate flag `VerifyUnsafeUpdates` would be applicable,for stress tests where performance can be sacrificed.- Define an API for use by privileged frameworks (including those inthe JDK) for creating objects in a "larval" state, apart fromnormal constructor invocation. (Possibly `Unsafe.allocateInstance`is such an API point; see also JNI AllocObject.) These arereleased from the constraints on final field writing, including JITinvalidation. If a JIT encounters an object in the larval state,the JIT will simply refrain from constant-folding its fields.- Define an API for promoting larval objects to a normal "adult"state, at which point the normal JIT optimizations would apply. Ifthis isn't done, performance will be lost only regarding the larvalobjects created by old frameworks, so perhaps this isn't needed.- It seems likely that the larval and adult states would need to bereflected in a bit pattern in the object header. As anoptimization, normally constructed objects would probably not needto have this state change in their header bits, unless perhaps they"escape" during their constructor call.# DiscussionA final field can in some cases be assigned a new value. If a JIT hasalready observed the previous value of that final field, andincorporated it into object code as a constant, then (after theassignment of a new value to that field), the optimized object codewill execute wrongly. We call such wrongly executing code "invalid",and the JVM takes great care to avoid executing invalid code insimilar cases involving speculative optimizations, such asdevirtualized method calls or uncommon traps.The basic reason for this is that the Java Memory Model requires thatall fields (including changed final fields) must be read accurately.An accurate read yields a value that is appropriate to the currentthread, as defined by a web of "happens-before" relations. (It is notentirely wrong to think of these relations as a linear set, althoughconcurrency and races are also part of the JMM.)But final fields _must_ be changed when an object is initialized, and_may rarely_ change in other circumstances. There are a number ofways to change the current value of a final field:0. In a constructor, a final field may be changed from its currentvalue (typically initial default value) to a new (possiblynon-default) value. The JVM (per specification) allows this to occur_multiple times_ although most sources of bytecode are thought toavoid such behavior.1. When a field is reflected, and `setAccessible(true)` is called, thevalue may be set. This "hook" is intended for use by deserializersand other low-level facilities. It is thought to be used as asimulation of case #0 above, when an object's constructor cannot beconveniently invoked. In a real sense, holding this option open forserialization frameworks harms the optimization of the entireecosystem.2. JNI functions such as SetBooleanField can be used to smash newvalues into fields even if they are final.3. Good old `Unsafe.setInt` can be also be used to smash new valuesinto fields (or parts of fields or groups of fields) even if they arefinal.Although a debugger can forcibly change the value of a field fromoutside the JVM, via APIs in the `jdk.jdi` module, it appears to beimpossible to use those APIs to change final fields.It is unknown what libraries or bytecode spinners "in the wild" areusing any of the four options above in ways that would invalidateJIT-compiled code. Setting the JITs free to optimize fully requires aplan for mitigating the impact of final field changes both in knowncode (in the JDK) and in unknown "wild" code.## Side note on racesAlthough race conditions (on non-volatile fields) allow the JVM somelatitute to return "stale" values for field references, such latitudewould usually be quite narrow, since an execution of the invalidoptimized method is likely to occur downstream of the invalidatingfield update (as determined by the happens-before relation of theJMM). The JMM itself would have to be updated to either relaxhappens-before relations pertaining to final field updates, or elseallow special race conditions that allow the JIT to use stale valuesof final fields (in effect, loo king backward in time, past eventsvisible through the relevant happens-before events). There are noactive proposals to update the JMM in this way, and it seems easier totake the JMM as a given, or (at most) make very small changes to it tofurther specialize the treatment of final fields.