JDK-8078629 : VM should constant fold Unsafe.get*() loads from final fields
  • Type: Enhancement
  • Component: hotspot
  • Sub-Component: compiler
  • Affected Version: 9
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2015-04-24
  • Updated: 2020-08-28
  • Resolved: 2015-07-14
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 9
9 b76Fixed
Related Reports
Blocks :  
Relates :  
Relates :  
Relates :  
Description
VM doesn't constant fold loads from final fields when field MethodHandles are used.

public class FieldAccess {
    static final int s1 = 123;

    static final MethodHandle f1;
    static {
        try {
            Class<?> THIS_CLASS = FieldAccess.class;
            MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
            f1 = LOOKUP.findStaticGetter(THIS_CLASS, "s1", int.class);
        } catch (Exception e) {
            throw new Error(e);
        }
    }

    static int testMH() throws Throwable {
        return (int)f1.invokeExact();
    }
    static int testDirect() throws Throwable {
        return s1;
    }

    public static void main(String[] args) throws Throwable {
        while (true) {
            testDirect();
            testMH();
        }
    }
}

$ java -XX:CompileCommand=dontinline,*::test* -XX:CompileCommand=print,*::test* FieldAccess
...
  # {method} {0x0000000118aca538} 'testDirect' '()I' in 'jsr292/FieldAccess'
...
  0x000000010be1716c: mov    $0x7b,%eax
...
  # {method} {0x0000000118aca498} 'testMH' '()I' in 'jsr292/FieldAccess'
...
  0x000000010be1f3ec: movabs $0x76abb2f48,%r10  ;   {oop(a 'java/lang/Class' = 'jsr292/FieldAccess')}
  0x000000010be1f3f6: mov    0x6c(%r10),%eax    ;*invokevirtual getInt
                                                ; - java.lang.invoke.LambdaForm$MH015/708049632::getIntStatic_001@23
                                                ; - java.lang.invoke.LambdaForm$MH013/991505714::invokeExact_000_MT@15
                                                ; - jsr292.FieldAccess::testMH@3 (line 24)
...
Comments
Thinking more about enhancing Unsafe.get*(Object, long offset) methods, my main concern is user expectations. Won���t constant folding surprise some users? It breaks ���Unsafe.putV(a, x, v); Unsafe.getV(a,x) == v��� invariant we have right now. Not sure how important it is though.
24-04-2015

One way to get this would be to customize field-access MethodHandles. I.e., if a field-access MH gets hot, replace its LF by a custom-built 'getfield' call. In the case of static final fields, the MH can simply be rendered by a MHs.constant combinator. An independent approach (later in the pipeline, more robust) is to align the library_call.cpp code for intrinsic expansion with parse3.cpp. The intrinsic expander "re-nominalizes" unsafe field references by recovering (if possible) the field metadata corresponding to a (constant-folded) unsafe data reference. Relevant logic is: http://hg.openjdk.java.net/jdk9/jdk9/hotspot/file/0e31ab6e8375/src/share/vm/opto/library_call.cpp#l2545 (where field metadata is queried) http://hg.openjdk.java.net/jdk9/jdk9/hotspot/file/0e31ab6e8375/src/share/vm/opto/compile.cpp#l1742 (where field metadata is recorded) http://hg.openjdk.java.net/jdk9/jdk9/hotspot/file/0e31ab6e8375/src/share/vm/opto/parse3.cpp#l150 (where the bytecode parser handles constants) There is no logic in library_call.cpp that corresponds to the field->is_constant() logic in parse3.cpp. There should be. Actually, this calls for better code-sharing between unsafe (but constant) field referencing code and the bytecode parser.
24-04-2015

VM can't constant fold Unsafe.getInt(). It seems a special LambdaForm should be used for constant foldable loads (from static final fields & instance final fields in java.lang.invoke package).
24-04-2015

f1.form: getIntStatic_000=Lambda(a0:L)=>{ t1:L=DirectMethodHandle.staticBase(a0:L); t2:J=DirectMethodHandle.staticOffset(a0:L); t3:I=Unsafe.getInt((sun.misc.Unsafe@41a4555e),t1:L,t2:J);t3:I} f1.member: jsr292.FieldAccess.s1/int/getStatic clazz = class jsr292.FieldAccess name = s1 type = int flags = 33816600 (REF_getStatic (2) + (STATIC | FINAL) (24) ) resolution = null
24-04-2015