1 import java.io.*;
  2 
  3 class MergeAllVirts {
  4     int a;
  5     int b;
  6     int c = 100;
  7 
  8     public MergeAllVirts() {}
  9     public MergeAllVirts(boolean cond) {
 10         if (cond) {
 11             this.a = 1;
 12             this.b = 20;
 13             this.c = 300;
 14             blackhole(); // kill locals, so LV0 = this is dead here.
 15         } else {
 16             this.a = 100;
 17             this.b = 50;
 18             this.c = 7;
 19             blackhole(); // kill locals.
 20         }
 21         // merge 2 predecessors, but LV0 is not live here.
 22         // we need to merge allocation states, or wrong current allocation state is wrong.
 23     }
 24 
 25     public int sum() {
 26         return a + b + c;
 27     }
 28 
 29     public static int add(boolean cond) {
 30         MergeAllVirts obj = new MergeAllVirts();
 31         if (cond) {
 32             obj.a = 1;
 33         } else {
 34             obj.b = 2;
 35         }
 36         //obj3 = phi(obj1, obj2);
 37         return obj.sum();
 38     }
 39 
 40     public static MergeAllVirts cached;
 41     public static void escaped(boolean cond) {
 42         MergeAllVirts obj = new MergeAllVirts();
 43 
 44         if (cond) {
 45             obj.a = 1;
 46         } else {
 47             obj.b = 2;
 48         }
 49         // return obj;  we don't materialize at exit. if it's virtual, keep it virtual.
 50         cached = obj; // materialize here.
 51     }
 52 
 53     static void check_result(boolean cond, int sum) {
 54         if ((cond && sum != 101) || (!cond && sum != 102)) {
 55             throw new RuntimeException("wrong answer: " + sum);
 56         }
 57     }
 58     static void blackhole() {} // not inline this.
 59     static void blackhole(MergeAllVirts obj) {} // not inline this.
 60     static void blackhole(File file) throws IOException {}
 61     public static MergeAllVirts escaped2(boolean cond1, boolean cond2) {
 62         MergeAllVirts obj = new MergeAllVirts();
 63 
 64         if (cond1) {
 65             obj.a = 20;
 66         } else {
 67             obj.b = 30;
 68         }
 69         if (cond2) {
 70             blackhole(obj); // materialize obj here.
 71         }
 72         return obj;
 73     }
 74 
 75     static void check_result2(boolean cond1, int sum) {
 76         boolean okay = true;
 77 
 78         if (cond1) {
 79             okay = sum == 120;
 80         } else {
 81             okay = sum == 130;
 82         }
 83 
 84         if (!okay) {
 85             throw new RuntimeException("wrong answer: " + cond1 + " " + sum);
 86         }
 87     }
 88 
 89     public static MergeAllVirts escaped3(boolean cond1, boolean cond2) {
 90         MergeAllVirts obj = new MergeAllVirts();
 91 
 92         if (cond1) {
 93             obj.a = 20;
 94         } else {
 95             obj.b = 30;
 96         }
 97         if (cond2) {
 98             blackhole(obj); // materialize obj here.
 99             obj.a = 300;
100         }
101         return obj;
102     }
103 
104     static void check_result3(boolean cond1, boolean cond2, int sum) {
105         boolean okay = true;
106 
107         if (cond1) {
108             if (cond2)
109                 okay = sum == 400; // 300 + 0 + 100
110             else
111                 okay = sum == 120;
112         } else {
113             if (cond2)
114                 okay = sum == 430; // 300 + 30 + 100
115             else
116                 okay = sum == 130;
117         }
118 
119         if (!okay) {
120             throw new RuntimeException("wrong answer: " + cond1 + " "  + cond2 + " " + sum);
121         }
122     }
123     public static void escaped4(boolean cond) {
124         MergeAllVirts obj = new MergeAllVirts(cond);
125 
126         // return obj;  we don't materialize at exit. if it's virtual, keep it virtual.
127         cached = obj; // materialize here.
128     }
129 
130     static void check_result4(boolean cond, int sum) {
131         boolean okay;
132 
133         if (cond) {
134             okay = sum == 321;
135         } else {
136             okay = sum == 157;
137         }
138 
139         if (!okay) {
140             throw new RuntimeException("wrong answer: " + cond + " "  + sum);
141         }
142     }
143 
144     private static void fail(String msg, Object... args) {
145         throw new RuntimeException(msg);
146     }
147 
148     // JVM-1880: merge the same object but they have different aliases in its predecessors.
149     // one common reason is exception handler. C2 parse forces to generate a phi for them.
150     // inspired by sun.net.sdp.SdpProvider::<init>
151     public static Object merge_2virts(File file) {
152         MergeAllVirts obj = new MergeAllVirts();
153 
154         try {
155             blackhole(file);
156         } catch(IOException e) {
157             // create a phi node : n = phi(region, _, obj)
158             fail("Error reading %s: %s", file, e.getMessage());
159         }
160         // merge here: phi(r, m, n) and n is phi(region, _, obj)
161         // same object but different aliases!
162         return obj;
163     }
164 
165     public static MergeAllVirts merge_virts(boolean cond1, boolean cond2) {
166         MergeAllVirts obj = new MergeAllVirts();
167         if (cond1) {
168             if (cond2) {
169                 obj.a = 1;
170             } else {
171                 obj.a = 2;
172             }
173             blackhole(); // merge obj.a here.
174         } else {
175             obj.b = 20;  // merge both obj.a and obj.b
176         }
177         return obj;
178     }
179 
180     static void check_result_virts(boolean cond1, boolean cond2, int sum) {
181         boolean okay;
182         if (cond1) {
183             if (cond2) {
184                 okay = sum == 101;
185             } else {
186                 okay = sum == 102;
187             }
188         } else {
189             okay = sum == 120;
190         }
191 
192         if (!okay) {
193             throw new RuntimeException("wrong answer: " + cond1 + " " + cond2 + " "  + sum);
194         }
195     }
196 
197     public static void main(String[] args) {
198         long iterations = 0;
199         File file = new File("hello");
200         boolean cond2 = true;
201         try {
202             while (true) {
203                 boolean cond = 0 == (iterations & 0xf);
204                 int sum = MergeAllVirts.add(cond);
205                 check_result(cond, sum);
206 
207                 MergeAllVirts.escaped(cond);
208                 check_result(cond, cached.sum());
209 
210                 cond2 = cond2 ^ cond;
211                 sum = MergeAllVirts.escaped2(cond, cond2).sum();
212                 check_result2(cond, sum);
213 
214                 sum = MergeAllVirts.escaped3(cond, cond2).sum();
215                 check_result3(cond, cond2, sum);
216 
217                 MergeAllVirts.escaped4(cond);
218                 check_result4(cond, cached.sum());
219 
220                 MergeAllVirts.merge_2virts(file);
221 
222                 sum = MergeAllVirts.merge_virts(cond, cond2).sum();
223                 check_result_virts(cond, cond2, sum);
224                 iterations++;
225             }
226         } finally {
227             System.err.println("Epsilon Test: " + iterations);
228         }
229     }
230 }