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 }