Thu, 21 Apr 2016 21:53:15 +0530
8141551: C2 can not handle returns with inccompatible interface arrays
Reviewed-by: kvn
1.1 --- a/src/share/vm/opto/cfgnode.cpp Fri Apr 15 12:02:37 2016 +0530 1.2 +++ b/src/share/vm/opto/cfgnode.cpp Thu Apr 21 21:53:15 2016 +0530 1.3 @@ -973,7 +973,7 @@ 1.4 #ifdef ASSERT 1.5 // The following logic has been moved into TypeOopPtr::filter. 1.6 const Type* jt = t->join_speculative(_type); 1.7 - if( jt->empty() ) { // Emptied out??? 1.8 + if (jt->empty()) { // Emptied out??? 1.9 1.10 // Check for evil case of 't' being a class and '_type' expecting an 1.11 // interface. This can happen because the bytecodes do not contain 1.12 @@ -984,14 +984,21 @@ 1.13 // be 'I' or 'j/l/O'. Thus we'll pick 'j/l/O'. If this then flows 1.14 // into a Phi which "knows" it's an Interface type we'll have to 1.15 // uplift the type. 1.16 - if( !t->empty() && ttip && ttip->is_loaded() && ttip->klass()->is_interface() ) 1.17 - { assert(ft == _type, ""); } // Uplift to interface 1.18 - else if( !t->empty() && ttkp && ttkp->is_loaded() && ttkp->klass()->is_interface() ) 1.19 - { assert(ft == _type, ""); } // Uplift to interface 1.20 - // Otherwise it's something stupid like non-overlapping int ranges 1.21 - // found on dying counted loops. 1.22 - else 1.23 - { assert(ft == Type::TOP, ""); } // Canonical empty value 1.24 + if (!t->empty() && ttip && ttip->is_loaded() && ttip->klass()->is_interface()) { 1.25 + assert(ft == _type, ""); // Uplift to interface 1.26 + } else if (!t->empty() && ttkp && ttkp->is_loaded() && ttkp->klass()->is_interface()) { 1.27 + assert(ft == _type, ""); // Uplift to interface 1.28 + } else { 1.29 + // We also have to handle 'evil cases' of interface- vs. class-arrays 1.30 + Type::get_arrays_base_elements(jt, _type, NULL, &ttip); 1.31 + if (!t->empty() && ttip != NULL && ttip->is_loaded() && ttip->klass()->is_interface()) { 1.32 + assert(ft == _type, ""); // Uplift to array of interface 1.33 + } else { 1.34 + // Otherwise it's something stupid like non-overlapping int ranges 1.35 + // found on dying counted loops. 1.36 + assert(ft == Type::TOP, ""); // Canonical empty value 1.37 + } 1.38 + } 1.39 } 1.40 1.41 else {
2.1 --- a/src/share/vm/opto/parse1.cpp Fri Apr 15 12:02:37 2016 +0530 2.2 +++ b/src/share/vm/opto/parse1.cpp Thu Apr 21 21:53:15 2016 +0530 2.3 @@ -962,13 +962,18 @@ 2.4 // In case of concurrent class loading, the type we set for the 2.5 // ret_phi in build_exits() may have been too optimistic and the 2.6 // ret_phi may be top now. 2.7 -#ifdef ASSERT 2.8 + // Otherwise, we've encountered an error and have to mark the method as 2.9 + // not compilable. Just using an assertion instead would be dangerous 2.10 + // as this could lead to an infinite compile loop in non-debug builds. 2.11 { 2.12 MutexLockerEx ml(Compile_lock, Mutex::_no_safepoint_check_flag); 2.13 - assert(ret_type->isa_ptr() && C->env()->system_dictionary_modification_counter_changed(), "return value must be well defined"); 2.14 + if (C->env()->system_dictionary_modification_counter_changed()) { 2.15 + C->record_failure(C2Compiler::retry_class_loading_during_parsing()); 2.16 + } else { 2.17 + C->record_method_not_compilable("Can't determine return type."); 2.18 + } 2.19 } 2.20 -#endif 2.21 - C->record_failure(C2Compiler::retry_class_loading_during_parsing()); 2.22 + return; 2.23 } 2.24 _exits.push_node(ret_type->basic_type(), ret_phi); 2.25 } 2.26 @@ -2093,15 +2098,24 @@ 2.27 // here. 2.28 Node* phi = _exits.argument(0); 2.29 const TypeInstPtr *tr = phi->bottom_type()->isa_instptr(); 2.30 - if( tr && tr->klass()->is_loaded() && 2.31 - tr->klass()->is_interface() ) { 2.32 + if (tr && tr->klass()->is_loaded() && 2.33 + tr->klass()->is_interface()) { 2.34 const TypeInstPtr *tp = value->bottom_type()->isa_instptr(); 2.35 if (tp && tp->klass()->is_loaded() && 2.36 !tp->klass()->is_interface()) { 2.37 // sharpen the type eagerly; this eases certain assert checking 2.38 if (tp->higher_equal(TypeInstPtr::NOTNULL)) 2.39 tr = tr->join_speculative(TypeInstPtr::NOTNULL)->is_instptr(); 2.40 - value = _gvn.transform(new (C) CheckCastPPNode(0,value,tr)); 2.41 + value = _gvn.transform(new (C) CheckCastPPNode(0, value, tr)); 2.42 + } 2.43 + } else { 2.44 + // Also handle returns of oop-arrays to an arrays-of-interface return 2.45 + const TypeInstPtr* phi_tip; 2.46 + const TypeInstPtr* val_tip; 2.47 + Type::get_arrays_base_elements(phi->bottom_type(), value->bottom_type(), &phi_tip, &val_tip); 2.48 + if (phi_tip != NULL && phi_tip->is_loaded() && phi_tip->klass()->is_interface() && 2.49 + val_tip != NULL && val_tip->is_loaded() && !val_tip->klass()->is_interface()) { 2.50 + value = _gvn.transform(new (C) CheckCastPPNode(0, value, phi->bottom_type())); 2.51 } 2.52 } 2.53 phi->add_req(value);
3.1 --- a/src/share/vm/opto/type.cpp Fri Apr 15 12:02:37 2016 +0530 3.2 +++ b/src/share/vm/opto/type.cpp Thu Apr 21 21:53:15 2016 +0530 3.3 @@ -149,6 +149,33 @@ 3.4 return bt; 3.5 } 3.6 3.7 +// For two instance arrays of same dimension, return the base element types. 3.8 +// Otherwise or if the arrays have different dimensions, return NULL. 3.9 +void Type::get_arrays_base_elements(const Type *a1, const Type *a2, 3.10 + const TypeInstPtr **e1, const TypeInstPtr **e2) { 3.11 + 3.12 + if (e1) *e1 = NULL; 3.13 + if (e2) *e2 = NULL; 3.14 + const TypeAryPtr* a1tap = (a1 == NULL) ? NULL : a1->isa_aryptr(); 3.15 + const TypeAryPtr* a2tap = (a2 == NULL) ? NULL : a2->isa_aryptr(); 3.16 + 3.17 + if (a1tap != NULL && a2tap != NULL) { 3.18 + // Handle multidimensional arrays 3.19 + const TypePtr* a1tp = a1tap->elem()->make_ptr(); 3.20 + const TypePtr* a2tp = a2tap->elem()->make_ptr(); 3.21 + while (a1tp && a1tp->isa_aryptr() && a2tp && a2tp->isa_aryptr()) { 3.22 + a1tap = a1tp->is_aryptr(); 3.23 + a2tap = a2tp->is_aryptr(); 3.24 + a1tp = a1tap->elem()->make_ptr(); 3.25 + a2tp = a2tap->elem()->make_ptr(); 3.26 + } 3.27 + if (a1tp && a1tp->isa_instptr() && a2tp && a2tp->isa_instptr()) { 3.28 + if (e1) *e1 = a1tp->is_instptr(); 3.29 + if (e2) *e2 = a2tp->is_instptr(); 3.30 + } 3.31 + } 3.32 +} 3.33 + 3.34 //---------------------------get_typeflow_type--------------------------------- 3.35 // Import a type produced by ciTypeFlow. 3.36 const Type* Type::get_typeflow_type(ciType* type) { 3.37 @@ -1982,7 +2009,11 @@ 3.38 bool TypeAry::interface_vs_oop(const Type *t) const { 3.39 const TypeAry* t_ary = t->is_ary(); 3.40 if (t_ary) { 3.41 - return _elem->interface_vs_oop(t_ary->_elem); 3.42 + const TypePtr* this_ptr = _elem->make_ptr(); // In case we have narrow_oops 3.43 + const TypePtr* t_ptr = t_ary->_elem->make_ptr(); 3.44 + if(this_ptr != NULL && t_ptr != NULL) { 3.45 + return this_ptr->interface_vs_oop(t_ptr); 3.46 + } 3.47 } 3.48 return false; 3.49 } 3.50 @@ -2834,8 +2865,17 @@ 3.51 // be 'I' or 'j/l/O'. Thus we'll pick 'j/l/O'. If this then flows 3.52 // into a Phi which "knows" it's an Interface type we'll have to 3.53 // uplift the type. 3.54 - if (!empty() && ktip != NULL && ktip->is_loaded() && ktip->klass()->is_interface()) 3.55 - return kills; // Uplift to interface 3.56 + if (!empty()) { 3.57 + if (ktip != NULL && ktip->is_loaded() && ktip->klass()->is_interface()) { 3.58 + return kills; // Uplift to interface 3.59 + } 3.60 + // Also check for evil cases of 'this' being a class array 3.61 + // and 'kills' expecting an array of interfaces. 3.62 + Type::get_arrays_base_elements(ft, kills, NULL, &ktip); 3.63 + if (ktip != NULL && ktip->is_loaded() && ktip->klass()->is_interface()) { 3.64 + return kills; // Uplift to array of interface 3.65 + } 3.66 + } 3.67 3.68 return Type::TOP; // Canonical empty value 3.69 }
4.1 --- a/src/share/vm/opto/type.hpp Fri Apr 15 12:02:37 2016 +0530 4.2 +++ b/src/share/vm/opto/type.hpp Thu Apr 21 21:53:15 2016 +0530 4.3 @@ -367,6 +367,11 @@ 4.4 return _const_basic_type[type]; 4.5 } 4.6 4.7 + // For two instance arrays of same dimension, return the base element types. 4.8 + // Otherwise or if the arrays have different dimensions, return NULL. 4.9 + static void get_arrays_base_elements(const Type *a1, const Type *a2, 4.10 + const TypeInstPtr **e1, const TypeInstPtr **e2); 4.11 + 4.12 // Mapping to the array element's basic type. 4.13 BasicType array_element_basic_type() const; 4.14
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 5.2 +++ b/test/compiler/types/TestMeetIncompatibleInterfaceArrays.java Thu Apr 21 21:53:15 2016 +0530 5.3 @@ -0,0 +1,351 @@ 5.4 +/* 5.5 + * Copyright 2015 SAP AG. All Rights Reserved. 5.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5.7 + * 5.8 + * This code is free software; you can redistribute it and/or modify it 5.9 + * under the terms of the GNU General Public License version 2 only, as 5.10 + * published by the Free Software Foundation. 5.11 + * 5.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 5.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 5.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 5.15 + * version 2 for more details (a copy is included in the LICENSE file that 5.16 + * accompanied this code). 5.17 + * 5.18 + * You should have received a copy of the GNU General Public License version 5.19 + * 2 along with this work; if not, write to the Free Software Foundation, 5.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 5.21 + * 5.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 5.23 + * or visit www.oracle.com if you need additional information or have any 5.24 + * questions. 5.25 + */ 5.26 + 5.27 +/* 5.28 + * @test 5.29 + * @bug 8141551 5.30 + * @summary C2 can not handle returns with inccompatible interface arrays 5.31 + * @library /testlibrary /testlibrary/whitebox/ 5.32 + * @build sun.hotspot.WhiteBox 5.33 + * @run main ClassFileInstaller sun.hotspot.WhiteBox 5.34 + * sun.hotspot.WhiteBox$WhiteBoxPermission 5.35 + * @run main/othervm 5.36 + * -Xbootclasspath/a:. 5.37 + * -XX:+UnlockDiagnosticVMOptions 5.38 + * -XX:+WhiteBoxAPI 5.39 + * -Xbatch 5.40 + * -XX:CompileThreshold=1 5.41 + * -XX:-TieredCompilation 5.42 + * -XX:CICompilerCount=1 5.43 + * -XX:+PrintCompilation 5.44 + * -XX:+PrintInlining 5.45 + * -XX:CompileCommand=compileonly,MeetIncompatibleInterfaceArrays*.run 5.46 + * -XX:CompileCommand=dontinline,TestMeetIncompatibleInterfaceArrays$Helper.createI2* 5.47 + * -XX:CompileCommand=quiet 5.48 + * TestMeetIncompatibleInterfaceArrays 0 5.49 + * @run main/othervm 5.50 + * -Xbootclasspath/a:. 5.51 + * -XX:+UnlockDiagnosticVMOptions 5.52 + * -XX:+WhiteBoxAPI 5.53 + * -Xbatch 5.54 + * -XX:CompileThreshold=1 5.55 + * -XX:-TieredCompilation 5.56 + * -XX:CICompilerCount=1 5.57 + * -XX:+PrintCompilation 5.58 + * -XX:+PrintInlining 5.59 + * -XX:CompileCommand=compileonly,MeetIncompatibleInterfaceArrays*.run 5.60 + * -XX:CompileCommand=inline,TestMeetIncompatibleInterfaceArrays$Helper.createI2* 5.61 + * -XX:CompileCommand=quiet 5.62 + * TestMeetIncompatibleInterfaceArrays 1 5.63 + * @run main/othervm 5.64 + * -Xbootclasspath/a:. 5.65 + * -XX:+UnlockDiagnosticVMOptions 5.66 + * -XX:+WhiteBoxAPI 5.67 + * -Xbatch 5.68 + * -XX:CompileThreshold=1 5.69 + * -XX:Tier0InvokeNotifyFreqLog=0 -XX:Tier2InvokeNotifyFreqLog=0 -XX:Tier3InvokeNotifyFreqLog=0 -XX:Tier23InlineeNotifyFreqLog=0 5.70 + * -XX:Tier3InvocationThreshold=2 -XX:Tier3MinInvocationThreshold=2 -XX:Tier3CompileThreshold=2 5.71 + * -XX:Tier4InvocationThreshold=1 -XX:Tier4MinInvocationThreshold=1 -XX:Tier4CompileThreshold=1 5.72 + * -XX:+TieredCompilation 5.73 + * -XX:CICompilerCount=2 5.74 + * -XX:+PrintCompilation 5.75 + * -XX:+PrintInlining 5.76 + * -XX:CompileCommand=compileonly,MeetIncompatibleInterfaceArrays*.run 5.77 + * -XX:CompileCommand=compileonly,TestMeetIncompatibleInterfaceArrays$Helper.createI2* 5.78 + * -XX:CompileCommand=inline,TestMeetIncompatibleInterfaceArrays$Helper.createI2* 5.79 + * -XX:CompileCommand=quiet 5.80 + * TestMeetIncompatibleInterfaceArrays 2 5.81 + * 5.82 + * @author volker.simonis@gmail.com 5.83 + */ 5.84 + 5.85 +import java.io.FileOutputStream; 5.86 +import java.lang.reflect.InvocationTargetException; 5.87 +import java.lang.reflect.Method; 5.88 +import jdk.internal.org.objectweb.asm.ClassWriter; 5.89 +import jdk.internal.org.objectweb.asm.MethodVisitor; 5.90 +import static jdk.internal.org.objectweb.asm.Opcodes.*; 5.91 +import sun.hotspot.WhiteBox; 5.92 + 5.93 +public class TestMeetIncompatibleInterfaceArrays extends ClassLoader { 5.94 + 5.95 + private static final WhiteBox WB = WhiteBox.getWhiteBox(); 5.96 + 5.97 + public static interface I1 { public String getName(); } 5.98 + public static interface I2 { public String getName(); } 5.99 + public static class I2C implements I2 { public String getName() { return "I2";} } 5.100 + public static class I21C implements I2, I1 { public String getName() { return "I2 and I1";} } 5.101 + 5.102 + public static class Helper { 5.103 + public static I2 createI2Array0() { 5.104 + return new I2C(); 5.105 + } 5.106 + public static I2[] createI2Array1() { 5.107 + return new I2C[] { new I2C() }; 5.108 + } 5.109 + public static I2[][] createI2Array2() { 5.110 + return new I2C[][] { new I2C[] { new I2C() } }; 5.111 + } 5.112 + public static I2[][][] createI2Array3() { 5.113 + return new I2C[][][] { new I2C[][] { new I2C[] { new I2C() } } }; 5.114 + } 5.115 + public static I2[][][][] createI2Array4() { 5.116 + return new I2C[][][][] { new I2C[][][] { new I2C[][] { new I2C[] { new I2C() } } } }; 5.117 + } 5.118 + public static I2[][][][][] createI2Array5() { 5.119 + return new I2C[][][][][] { new I2C[][][][] { new I2C[][][] { new I2C[][] { new I2C[] { new I2C() } } } } }; 5.120 + } 5.121 + public static I2 createI21Array0() { 5.122 + return new I21C(); 5.123 + } 5.124 + public static I2[] createI21Array1() { 5.125 + return new I21C[] { new I21C() }; 5.126 + } 5.127 + public static I2[][] createI21Array2() { 5.128 + return new I21C[][] { new I21C[] { new I21C() } }; 5.129 + } 5.130 + public static I2[][][] createI21Array3() { 5.131 + return new I21C[][][] { new I21C[][] { new I21C[] { new I21C() } } }; 5.132 + } 5.133 + public static I2[][][][] createI21Array4() { 5.134 + return new I21C[][][][] { new I21C[][][] { new I21C[][] { new I21C[] { new I21C() } } } }; 5.135 + } 5.136 + public static I2[][][][][] createI21Array5() { 5.137 + return new I21C[][][][][] { new I21C[][][][] { new I21C[][][] { new I21C[][] { new I21C[] { new I21C() } } } } }; 5.138 + } 5.139 + } 5.140 + 5.141 + // Location for the generated class files 5.142 + public static final String PATH = System.getProperty("test.classes", ".") + java.io.File.separator; 5.143 + 5.144 + /* 5.145 + * With 'good == false' this helper method creates the following classes 5.146 + * (using the nested 'Helper' class and the nested interfaces 'I1' and 'I2'). 5.147 + * For brevity I omit the enclosing class 'TestMeetIncompatibleInterfaceArrays' in the 5.148 + * following examples: 5.149 + * 5.150 + * public class MeetIncompatibleInterfaceArrays0ASM { 5.151 + * public static I1 run() { 5.152 + * return Helper.createI2Array0(); // returns I2 5.153 + * } 5.154 + * public static void test() { 5.155 + * I1 i1 = run(); 5.156 + * System.out.println(i1.getName()); 5.157 + * } 5.158 + * } 5.159 + * public class MeetIncompatibleInterfaceArrays1ASM { 5.160 + * public static I1[] run() { 5.161 + * return Helper.createI2Array1(); // returns I2[] 5.162 + * } 5.163 + * public static void test() { 5.164 + * I1[] i1 = run(); 5.165 + * System.out.println(i1[0].getName()); 5.166 + * } 5.167 + * } 5.168 + * ... 5.169 + * // MeetIncompatibleInterfaceArrays4ASM is special because it creates 5.170 + * // an illegal class which will be rejected by the verifier. 5.171 + * public class MeetIncompatibleInterfaceArrays4ASM { 5.172 + * public static I1[][][][] run() { 5.173 + * return Helper.createI2Array3(); // returns I1[][][] which gives a verifier error because return expects I1[][][][] 5.174 + * } 5.175 + * public static void test() { 5.176 + * I1[][][][][] i1 = run(); 5.177 + * System.out.println(i1[0][0][0][0][0].getName()); 5.178 + * } 5.179 + * ... 5.180 + * public class MeetIncompatibleInterfaceArrays5ASM { 5.181 + * public static I1[][][][][] run() { 5.182 + * return Helper.createI2Array5(); // returns I2[][][][][] 5.183 + * } 5.184 + * public static void test() { 5.185 + * I1[][][][][] i1 = run(); 5.186 + * System.out.println(i1[0][0][0][0][0].getName()); 5.187 + * } 5.188 + * } 5.189 + * 5.190 + * Notice that this is not legal Java code. We would have to use a cast in "run()" to make it legal: 5.191 + * 5.192 + * public static I1[] run() { 5.193 + * return (I1[])Helper.createI2Array1(); // returns I2[] 5.194 + * } 5.195 + * 5.196 + * But in pure bytecode, the "run()" methods are perfectly legal: 5.197 + * 5.198 + * public static I1[] run(); 5.199 + * Code: 5.200 + * 0: invokestatic #16 // Method Helper.createI2Array1:()[LI2; 5.201 + * 3: areturn 5.202 + * 5.203 + * The "test()" method calls the "getName()" function from I1 on the objects returned by "run()". 5.204 + * This will epectedly fail with an "IncompatibleClassChangeError" because the objects returned 5.205 + * by "run()" (and by createI2Array()) are actually of type "I2C" and only implement "I2" but not "I1". 5.206 + * 5.207 + * 5.208 + * With 'good == true' this helper method will create the following classes: 5.209 + * 5.210 + * public class MeetIncompatibleInterfaceArraysGood0ASM { 5.211 + * public static I1 run() { 5.212 + * return Helper.createI21Array0(); // returns I2 5.213 + * } 5.214 + * public static void test() { 5.215 + * I1 i1 = run(); 5.216 + * System.out.println(i1.getName()); 5.217 + * } 5.218 + * } 5.219 + * 5.220 + * Calling "test()" on these objects will succeed and output "I2 and I1" because now the "run()" 5.221 + * method calls "createI21Array()" which actually return an object (or an array of objects) of 5.222 + * type "I21C" which implements both "I2" and "I1". 5.223 + * 5.224 + * Notice that at the bytecode level, the code for the "run()" and "test()" methods in 5.225 + * "MeetIncompatibleInterfaceArraysASM" and "MeetIncompatibleInterfaceArraysGoodASM" look exactly 5.226 + * the same. I.e. the verifier has no chance to verify if the I2 object returned by "createI1Array()" 5.227 + * or "createI21Array()" implements "I1" or not. That's actually the reason why both versions of 5.228 + * generated classes are legal from a verifier point of view. 5.229 + * 5.230 + */ 5.231 + static void generateTestClass(int dim, boolean good) throws Exception { 5.232 + String baseClassName = "MeetIncompatibleInterfaceArrays"; 5.233 + if (good) 5.234 + baseClassName += "Good"; 5.235 + String createName = "createI2" + (good ? "1" : "") + "Array"; 5.236 + String a = ""; 5.237 + for (int i = 0; i < dim; i++) 5.238 + a += "["; 5.239 + ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); 5.240 + cw.visit(V1_8, ACC_PUBLIC, baseClassName + dim + "ASM", null, "java/lang/Object", null); 5.241 + MethodVisitor constr = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); 5.242 + constr.visitCode(); 5.243 + constr.visitVarInsn(ALOAD, 0); 5.244 + constr.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false); 5.245 + constr.visitInsn(RETURN); 5.246 + constr.visitMaxs(0, 0); 5.247 + constr.visitEnd(); 5.248 + MethodVisitor run = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "run", 5.249 + "()" + a + "LTestMeetIncompatibleInterfaceArrays$I1;", null, null); 5.250 + run.visitCode(); 5.251 + if (dim == 4) { 5.252 + run.visitMethodInsn(INVOKESTATIC, "TestMeetIncompatibleInterfaceArrays$Helper", createName + 3, 5.253 + "()" + "[[[" + "LTestMeetIncompatibleInterfaceArrays$I2;", false); 5.254 + } else { 5.255 + run.visitMethodInsn(INVOKESTATIC, "TestMeetIncompatibleInterfaceArrays$Helper", createName + dim, 5.256 + "()" + a + "LTestMeetIncompatibleInterfaceArrays$I2;", false); 5.257 + } 5.258 + run.visitInsn(ARETURN); 5.259 + run.visitMaxs(0, 0); 5.260 + run.visitEnd(); 5.261 + MethodVisitor test = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "test", "()V", null, null); 5.262 + test.visitCode(); 5.263 + test.visitMethodInsn(INVOKESTATIC, baseClassName + dim + "ASM", "run", 5.264 + "()" + a + "LTestMeetIncompatibleInterfaceArrays$I1;", false); 5.265 + test.visitVarInsn(ASTORE, 0); 5.266 + if (dim > 0) { 5.267 + test.visitVarInsn(ALOAD, 0); 5.268 + for (int i = 1; i <= dim; i++) { 5.269 + test.visitInsn(ICONST_0); 5.270 + test.visitInsn(AALOAD); 5.271 + } 5.272 + test.visitVarInsn(ASTORE, 1); 5.273 + } 5.274 + test.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); 5.275 + test.visitVarInsn(ALOAD, dim > 0 ? 1 : 0); 5.276 + test.visitMethodInsn(INVOKEINTERFACE, "TestMeetIncompatibleInterfaceArrays$I1", "getName", 5.277 + "()Ljava/lang/String;", true); 5.278 + test.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/Object;)V", false); 5.279 + test.visitInsn(RETURN); 5.280 + test.visitMaxs(0, 0); 5.281 + test.visitEnd(); 5.282 + 5.283 + // Get the bytes of the class.. 5.284 + byte[] b = cw.toByteArray(); 5.285 + // ..and write them into a class file (for debugging) 5.286 + FileOutputStream fos = new FileOutputStream(PATH + baseClassName + dim + "ASM.class"); 5.287 + fos.write(b); 5.288 + fos.close(); 5.289 + 5.290 + } 5.291 + 5.292 + public static String[][] tier = { { "interpreted", "C2 (tier 4) without inlining", "C2 (tier4) without inlining" }, 5.293 + { "interpreted", "C2 (tier 4) with inlining", "C2 (tier4) with inlining" }, 5.294 + { "interpreted", "C1 (tier 3) with inlining", "C2 (tier4) with inlining" } }; 5.295 + 5.296 + public static void main(String[] args) throws Exception { 5.297 + final int pass = Integer.parseInt(args.length > 0 ? args[0] : "0"); 5.298 + 5.299 + // Load and initialize some classes required for compilation 5.300 + Class.forName("TestMeetIncompatibleInterfaceArrays$I1"); 5.301 + Class.forName("TestMeetIncompatibleInterfaceArrays$I2"); 5.302 + Class.forName("TestMeetIncompatibleInterfaceArrays$Helper"); 5.303 + 5.304 + for (int g = 0; g < 2; g++) { 5.305 + String baseClassName = "MeetIncompatibleInterfaceArrays"; 5.306 + boolean good = (g == 0) ? false : true; 5.307 + if (good) 5.308 + baseClassName += "Good"; 5.309 + for (int i = 0; i < 6; i++) { 5.310 + System.out.println(); 5.311 + System.out.println("Creating " + baseClassName + i + "ASM.class"); 5.312 + System.out.println("========================================" + "=" + "========="); 5.313 + // Create the "MeetIncompatibleInterfaceArrays<i>ASM" class 5.314 + generateTestClass(i, good); 5.315 + Class<?> c = null; 5.316 + try { 5.317 + c = Class.forName(baseClassName + i + "ASM"); 5.318 + } catch (VerifyError ve) { 5.319 + if (i == 4) { 5.320 + System.out.println("OK - must be (" + ve.getMessage() + ")."); 5.321 + } else { 5.322 + throw ve; 5.323 + } 5.324 + continue; 5.325 + } 5.326 + // Call MeetIncompatibleInterfaceArrays<i>ASM.test() 5.327 + Method m = c.getMethod("test"); 5.328 + Method r = c.getMethod("run"); 5.329 + for (int j = 0; j < 3; j++) { 5.330 + System.out.println((j + 1) + ". invokation of " + baseClassName + i + "ASM.test() [should be " 5.331 + + tier[pass][j] + "]"); 5.332 + try { 5.333 + m.invoke(null); 5.334 + } catch (InvocationTargetException ite) { 5.335 + if (good) { 5.336 + throw ite; 5.337 + } else { 5.338 + if (ite.getCause() instanceof IncompatibleClassChangeError) { 5.339 + System.out.println(" OK - catched InvocationTargetException(" 5.340 + + ite.getCause().getMessage() + ")."); 5.341 + } else { 5.342 + throw ite; 5.343 + } 5.344 + } 5.345 + } 5.346 + } 5.347 + System.out.println("Method " + r + (WB.isMethodCompiled(r) ? " has" : " has not") + " been compiled."); 5.348 + if (!WB.isMethodCompiled(r)) { 5.349 + throw new Exception("Method " + r + " must be compiled!"); 5.350 + } 5.351 + } 5.352 + } 5.353 + } 5.354 +}