//java -XX:CompileCommand=compileonly,Test.foo -XX:CompileCommand=dontinline,Test.black -Xbatch -XX:+PrintEliminateAllocations -XX:+PrintEscapeAnalysis -XX:+TraceDeoptimization -XX:+PrintDeoptimizationDetails Test
//test-2
//java -XX:CompileCommand=compileonly,Test.bar -XX:CompileCommand=dontinline,Test.black -Xbatch -XX:+PrintEliminateAllocations -XX:+PrintEscapeAnalysis -XX:+TraceDeoptimization -XX:+PrintDeoptimizationDetails Test
public class Test {
    // custom value object
    static class MyValue {
      public int value;
      public static final MyValue zero = new MyValue(0);

      MyValue(int x) { this.value = x; }
      int intValue() { return this.value; }

      // merge a global final object and a newly allocated object.
      public static MyValue valueOf(int x) {
        return x != 0 ? new MyValue(x) : zero;
      }
    }

    public static void main(String[] args) throws Exception {
        // testcase 1 
        //
        // warmup
        // hit cached object 10% possibility. 
        //
        // so Integer.valueOf(value) in foo() will yield a phi node, which merges both cached object and new object.
        // see 112 Phi
        //
        // c2 actually treats boxing valueOf specially. int x = Integer.valueOf(a), 
        // LoadNode::Ideal will simplify memory chain int x = a and call Integer.valueOf() will ditch because nobody consumes its result.
        // we use global field value to make sure valueOf is called.
        // 
        // ======== Connection graph for  Test::foo
        // invocation #0: 2 iterations and 0.000011 sec to build connection graph with 258 nodes and worklist size 16
        //
        // JavaObject(4) NoEscape(NoEscape) NSR [ 246F [ 183 188 112 ]]   171  Allocate  ===  135  6  7  8  1 ( 159  169  40  1  1  10  1  1  10 ) [[ 172  173  174  181  182  183 ]]  rawptr:NotNull ( int:>=0, java/lang/Object:NotNull *, bool, top, bool ) Integer::valueOf @ bci:23 (line 1074) Test::foo @ bci:1 (line 20) !jvms: Integer::valueOf @ bci:23 (line 1074) Test::foo @ bci:1 (line 20)
        // LocalVar(10) [ 171P [ 188 246b ]]   183  Proj  ===  171  [[ 184  188  246 ]] #5 !jvms: Integer::valueOf @ bci:23 (line 1074) Test::foo @ bci:1 (line 20)
        // LocalVar(12) [ 183 171P [ 112 ]]   188  CheckCastPP  ===  185  183  [[ 252  112 ]]  #java/lang/Integer:NotNull:exact *  Oop:java/lang/Integer:NotNull:exact * !jvms: Integer::valueOf @ bci:23 (line 1074) Test::foo @ bci:1 (line 20)
        // LocalVar(13) [ 168 188 1P 171P [ ]]   112  Phi  ===  108  168  188  [[ 50 ]]  #java/lang/Integer:NotNull:exact *  Oop:java/lang/Integer:NotNull:exact * !jvms: Test::foo @ bci:1 (line 20)
        // 
        for (int i=0; i<10000; ++i) {
            value += Integer.valueOf(1); 
        }

        // trigger compilation of foo with profile data value > 999.
        for(int i = 0; i < 100000; i++) {
           foo(1000 + (i % 1000));
        }

        // trigger deoptimization , see -XX:+TraceDeoptimization
        // bigger the cached values but <= 999
        foo(300);

        // testcase 2
        // trigger compilation of bar
        for(int i = 0; i < 100000; i++) {
           bar(i % 100, true);
        }
        // trigger deopt
        bar(300, false);
    }

    public static int foo(int value) {
        Integer ii = Integer.valueOf(value);
        int sum = 0;
        if (value > 999) {
            sum += ii.intValue();
        }
        return sum;
    }

// before: 
// ======== Connection graph for  Test::bar
// invocation #0: 2 iterations and 0.000009 sec to build connection graph with 154 nodes and worklist size 12
//
// JavaObject(4) NoEscape(NoEscape) NSR [ 108F 142F [ 57 62 122 ]]   45  Allocate  ===  37  6  7  8  1 ( 43  42  33  1  1  1  11  1  1  10 ) [[ 46  47  48  55  56  57 ]]  rawptr:NotNull ( int:>=0, java/lang/Object:NotNull *, bool, top, bool ) Test$MyValue::valueOf @ bci:4 (line 14) Test::bar @ bci:1 (line 71) !jvms: Test$MyValue::valueOf @ bci:4 (line 14) Test::bar @ bci:1 (line 71)
// LocalVar(9) [ 45P [ 62 108b ]]   57  Proj  ===  45  [[ 58  62  108 ]] #5 !jvms: Test$MyValue::valueOf @ bci:4 (line 14) Test::bar @ bci:1 (line 71)
// LocalVar(10) [ 57 45P [ 122 ]]   62  CheckCastPP  ===  59  57  [[ 122 ]]  #Test$MyValue:NotNull:exact *  Oop:Test$MyValue:NotNull:exact * !jvms: Test$MyValue::valueOf @ bci:4 (line 14) Test::bar @ bci:1 (line 71)
// LocalVar(5) [ 116P 62 45P [ 142b ]]   122  Phi  ===  114  116  62  [[ 142  142  137 ]]  #Test$MyValue:NotNull:exact *  Oop:Test$MyValue:NotNull:exact * !jvms: Test$MyValue::valueOf @ bci:18 (line 14) Test::bar @ bci:1 (line 71)
//
// After: 
// LocalVar(5) [ 116P 62 45P [ 142b ]]   122  Phi  ===  114  116  62  [[ 142  142 ]]  #Test$MyValue:NotNull:exact *  Oop:Test$MyValue:NotNull:exact * !jvms: Test$MyValue::valueOf @ bci:18 (line 14) Test::bar @ bci:1 (line 71)
// 
// removed 137 is the very common_trap. 
// so far, we still can't do scalar replacement of 45 because it's non-escaping/NSR. We are working on it. 
// 
    public static int bar(int value, boolean cond) {
        var ii = MyValue.valueOf(value);

        int sum = 0;
        if (cond) {
            sum += ii.value;
        }
        return sum;
    }
    
    public static Integer value = Integer.valueOf(0);
}
