JDK-8270928 : Unresolved dynamic constant disables code compilation
  • Type: Bug
  • Component: hotspot
  • Sub-Component: compiler
  • Affected Version: 16.0.1,18
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • OS: generic
  • CPU: generic
  • Submitted: 2021-05-24
  • Updated: 2022-01-25
  • Resolved: 2022-01-24
Related Reports
Duplicate :  
Description
A DESCRIPTION OF THE PROBLEM :
This pertains to a comment in c1_GraphBuilder.cpp:

void GraphBuilder::load_constant() {
  ciConstant con = stream()->get_constant();
  if (con.basic_type() == T_ILLEGAL) {
    // FIXME: an unresolved Dynamic constant can get here,
    // and that should not terminate the whole compilation.
    BAILOUT("could not resolve a constant");

The code I'm generating utilizes dynamic constants, but the code which references them isn't always reached. This leads to terrible performance because HotSpot never compiles the code, and instead it's only interpreted. 


STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
To reproduce, generate a method which doesn't reach a dynamic constant. Run with -XX:+PrintCompilation and observe the message, "could not resolve a constant".

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
I expect the code to compile even when the dynamic constant wasn't reached.
ACTUAL -
org.cojen.maker.ClassMaker-0::test (10 bytes)   COMPILE SKIPPED: could not resolve a constant (retry at different tier)

---------- BEGIN SOURCE ----------
This test depends on the open source Cojen/Maker project, because it's much easier for generating Java bytecode than anything else.

import org.cojen.maker.*;

public class Condy {
    public static void main(String[] args) throws Exception {
        Object a = new Object();
        Object b = new Object();

        var cm = ClassMaker.begin().public_();
        var mm = cm.addMethod(Object.class, "test", int.class).public_().static_();

        Label other = mm.label();
        mm.param(0).ifNe(0, other);
        mm.return_(mm.var(Object.class).setExact(a)); 
        other.here();
        // Never reached, and so the dynamic constant which yields 'b' never resolves. 
        mm.return_(mm.var(Object.class).setExact(b));

        var method = cm.finish().getMethod("test", int.class);

        while (true) {
            var result = method.invoke(null, 0); // pass 0 to never reach the 'b' case
            if (result == a) {
                x++;
            }
        }
    }

    static volatile int x;
}

---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Forcibly resolve all dynamic constants in a static initializer and then only reference them via private static final fields. This effectively defeats the entire purpose of the dynamic constant feature, because the constants aren't dynamically generated.

FREQUENCY : always



Comments
Kudos on the excellent bug report! And spot on the root cause! Unfortunately, it landed at hotspot/compiler too late, so I wasn't aware about it when filing JDK-8280473. I reclassified JDK-8280473 as a bug and will work on the fix there.
25-01-2022

This sounds like a dup of JDK-8280473. I'm closing this issue.
24-01-2022

Additional information received from submitter: ============================================================ The current version of the project has a workaround, so I created a special branch that disables it. It also has a test to reproduce the problem, although it's the same as I provided earlier. https://urldefense.com/v3/__https://github.com/cojen/Maker/tree/incident-9163726__;!!ACWV5N9M2RV99hQ!ZWARG9CYpCLna0uLPScVIPbMREjpcopbZjTFjPbBo8BHnO7-dl0fhPk_YJ8bWqOLwUk$ I'm having a problem sending the attachment via gmail, so I tried renaming it. It this doesn't work, run "mvn install" to built it. If there's a better way of sending you the jar file, let me know. The test: https://urldefense.com/v3/__https://github.com/cojen/Maker/blob/incident-9163726/example/main/java/org/cojen/example/Incident_9163726.java__;!!ACWV5N9M2RV99hQ!ZWARG9CYpCLna0uLPScVIPbMREjpcopbZjTFjPbBo8BHnO7-dl0fhPk_YJ8bTG2YYHM$ There's only one jar dependency, and so the test can be run with just the jar in the classpath, from a directory that has the test. java -cp <path>/cojen-maker-0.9163726.jar -XX:+PrintCompilation Incident_9163726.java The output shows messages like these: compilation bailout: could not resolve a constant COMPILE SKIPPED: could not resolve a constant (retry at different tier) COMPILE SKIPPED: cannot parse method (retry at different tier) To access the generated class, add -Dorg.cojen.maker.ClassMaker.DEBUG=true to the command line. It writes a file to the temp directory and outputs a message like this: "ClassMaker writing to...". The disassembled class shows two "ldc" instructions, but the test only allows one of them to ever be reached. javap -c "org.cojen.maker.ClassMaker-4(0).class" public class org.cojen.maker.ClassMaker-4 { public static java.lang.Object test(int); Code: 0: iload_0 1: ifne 7 4: ldc #17 // Dynamic #0:_:Ljava/lang/Object; 6: areturn 7: ldc #19 // Dynamic #1:_:Ljava/lang/Object; 9: areturn } The latest version of Cojen/Maker has a workaround which eagerly resolves dynamic constants in a static initializer, defeating the on-demand aspect of the feature. =========================================================================
20-07-2021