--- old/src/share/vm/interpreter/linkResolver.cpp 2015-07-31 13:27:29.133975782 -0400 +++ new/src/share/vm/interpreter/linkResolver.cpp 2015-07-31 13:27:29.017975786 -0400 @@ -379,7 +379,8 @@ if (!resolved_method->is_abstract() && (InstanceKlass::cast(klass())->default_methods() != NULL)) { int index = InstanceKlass::find_method_index(InstanceKlass::cast(klass())->default_methods(), - name, signature, Klass::find_overpass, Klass::find_static); + name, signature, Klass::find_overpass, + Klass::find_static, Klass::find_private); if (index >= 0 ) { vtable_index = InstanceKlass::cast(klass())->default_vtable_indices()->at(index); } @@ -1189,7 +1190,7 @@ assert(resolved_method->method_holder()->is_linked(), "must be linked"); // do lookup based on receiver klass using the vtable index - if (resolved_method->method_holder()->is_interface()) { // miranda method + if (resolved_method->method_holder()->is_interface()) { // default or miranda method vtable_index = vtable_index_of_interface_method(resolved_klass, resolved_method); assert(vtable_index >= 0 , "we should have valid vtable index at this point"); @@ -1198,7 +1199,7 @@ selected_method = methodHandle(THREAD, inst->method_at_vtable(vtable_index)); } else { // at this point we are sure that resolved_method is virtual and not - // a miranda method; therefore, it must have a valid vtable index. + // a default or miranda method; therefore, it must have a valid vtable index. assert(!resolved_method->has_itable_index(), ""); vtable_index = resolved_method->vtable_index(); // We could get a negative vtable_index for final methods, --- old/src/share/vm/oops/instanceKlass.cpp 2015-07-31 13:27:29.593975766 -0400 +++ new/src/share/vm/oops/instanceKlass.cpp 2015-07-31 13:27:29.477975770 -0400 @@ -1381,12 +1381,14 @@ // find_method looks up the name/signature in the local methods array Method* InstanceKlass::find_method(Symbol* name, Symbol* signature) const { - return find_method_impl(name, signature, find_overpass, find_static); + return find_method_impl(name, signature, find_overpass, find_static, find_private); } Method* InstanceKlass::find_method_impl(Symbol* name, Symbol* signature, - OverpassLookupMode overpass_mode, StaticLookupMode static_mode) const { - return InstanceKlass::find_method_impl(methods(), name, signature, overpass_mode, static_mode); + OverpassLookupMode overpass_mode, + StaticLookupMode static_mode, + PrivateLookupMode private_mode) const { + return InstanceKlass::find_method_impl(methods(), name, signature, overpass_mode, static_mode, private_mode); } // find_instance_method looks up the name/signature in the local methods array @@ -1394,7 +1396,7 @@ Method* InstanceKlass::find_instance_method( Array* methods, Symbol* name, Symbol* signature) { Method* meth = InstanceKlass::find_method_impl(methods, name, signature, - find_overpass, skip_static); + find_overpass, skip_static, find_private); assert(((meth == NULL) || !meth->is_static()), "find_instance_method should have skipped statics"); return meth; } @@ -1405,22 +1407,51 @@ return InstanceKlass::find_instance_method(methods(), name, signature); } +// Find looks up the name/signature in the local methods array +// and filters on the overpass, static and private flags +// This returns the first one found +// note that the local methods array can have up to one overpass, one static +// and one instance (private or not) with the same name/signature +Method* InstanceKlass::find_local_method(Symbol* name, Symbol* signature, + OverpassLookupMode overpass_mode, + StaticLookupMode static_mode, + PrivateLookupMode private_mode) const { + return InstanceKlass::find_method_impl(methods(), name, signature, overpass_mode, static_mode, private_mode); +} + +// Find looks up the name/signature in the local methods array +// and filters on the overpass, static and private flags +// This returns the first one found +// note that the local methods array can have up to one overpass, one static +// and one instance (private or not) with the same name/signature +Method* InstanceKlass::find_local_method(Array* methods, + Symbol* name, Symbol* signature, + OverpassLookupMode overpass_mode, + StaticLookupMode static_mode, + PrivateLookupMode private_mode) { + return InstanceKlass::find_method_impl(methods, name, signature, overpass_mode, static_mode, private_mode); +} + + // find_method looks up the name/signature in the local methods array Method* InstanceKlass::find_method( Array* methods, Symbol* name, Symbol* signature) { - return InstanceKlass::find_method_impl(methods, name, signature, find_overpass, find_static); + return InstanceKlass::find_method_impl(methods, name, signature, find_overpass, find_static, find_private); } Method* InstanceKlass::find_method_impl( - Array* methods, Symbol* name, Symbol* signature, OverpassLookupMode overpass_mode, StaticLookupMode static_mode) { - int hit = find_method_index(methods, name, signature, overpass_mode, static_mode); + Array* methods, Symbol* name, Symbol* signature, + OverpassLookupMode overpass_mode, StaticLookupMode static_mode, + PrivateLookupMode private_mode) { + int hit = find_method_index(methods, name, signature, overpass_mode, static_mode, private_mode); return hit >= 0 ? methods->at(hit): NULL; } -bool InstanceKlass::method_matches(Method* m, Symbol* signature, bool skipping_overpass, bool skipping_static) { - return (m->signature() == signature) && +bool InstanceKlass::method_matches(Method* m, Symbol* signature, bool skipping_overpass, bool skipping_static, bool skipping_private) { + return ((m->signature() == signature) && (!skipping_overpass || !m->is_overpass()) && - (!skipping_static || !m->is_static()); + (!skipping_static || !m->is_static()) && + (!skipping_private || !m->is_private())); } // Used directly for default_methods to find the index into the @@ -1430,17 +1461,25 @@ // the search continues to find a potential non-overpass match. This capability // is important during method resolution to prefer a static method, for example, // over an overpass method. +// There is the possibility in any _method's array to have the same name/signature +// for a static method, an overpass method and a local instance method +// To correctly catch a given method, the search criteria may need +// to explicitly skip the other two. For local instance methods, it +// is often necessary to skip private methods int InstanceKlass::find_method_index( - Array* methods, Symbol* name, Symbol* signature, OverpassLookupMode overpass_mode, StaticLookupMode static_mode) { + Array* methods, Symbol* name, Symbol* signature, + OverpassLookupMode overpass_mode, StaticLookupMode static_mode, + PrivateLookupMode private_mode) { bool skipping_overpass = (overpass_mode == skip_overpass); bool skipping_static = (static_mode == skip_static); + bool skipping_private = (private_mode == skip_private); int hit = binary_search(methods, name); if (hit != -1) { Method* m = methods->at(hit); // Do linear search to find matching signature. First, quick check // for common case, ignoring overpasses if requested. - if (method_matches(m, signature, skipping_overpass, skipping_static)) return hit; + if (method_matches(m, signature, skipping_overpass, skipping_static, skipping_private)) return hit; // search downwards through overloaded methods int i; @@ -1448,18 +1487,18 @@ Method* m = methods->at(i); assert(m->is_method(), "must be method"); if (m->name() != name) break; - if (method_matches(m, signature, skipping_overpass, skipping_static)) return i; + if (method_matches(m, signature, skipping_overpass, skipping_static, skipping_private)) return i; } // search upwards for (i = hit + 1; i < methods->length(); ++i) { Method* m = methods->at(i); assert(m->is_method(), "must be method"); if (m->name() != name) break; - if (method_matches(m, signature, skipping_overpass, skipping_static)) return i; + if (method_matches(m, signature, skipping_overpass, skipping_static, skipping_private)) return i; } // not found #ifdef ASSERT - int index = (skipping_overpass || skipping_static) ? -1 : linear_search(methods, name, signature); + int index = (skipping_overpass || skipping_static || skipping_private) ? -1 : linear_search(methods, name, signature); assert(index == -1, err_msg("binary search should have found entry %d", index)); #endif } @@ -1489,7 +1528,7 @@ OverpassLookupMode overpass_local_mode = overpass_mode; Klass* klass = const_cast(this); while (klass != NULL) { - Method* method = InstanceKlass::cast(klass)->find_method_impl(name, signature, overpass_local_mode, find_static); + Method* method = InstanceKlass::cast(klass)->find_method_impl(name, signature, overpass_local_mode, find_static, find_private); if (method != NULL) { return method; } --- old/src/share/vm/oops/instanceKlass.hpp 2015-07-31 13:27:30.073975749 -0400 +++ new/src/share/vm/oops/instanceKlass.hpp 2015-07-31 13:27:29.957975753 -0400 @@ -503,12 +503,28 @@ Method* find_instance_method(Symbol* name, Symbol* signature); static Method* find_instance_method(Array* methods, Symbol* name, Symbol* signature); + // find a local method (returns NULL if not found) + Method* find_local_method(Symbol* name, Symbol* signature, + OverpassLookupMode overpass_mode, + StaticLookupMode static_mode, + PrivateLookupMode private_mode) const; + + // find a local method from given methods array (returns NULL if not found) + static Method* find_local_method(Array* methods, + Symbol* name, Symbol* signature, + OverpassLookupMode overpass_mode, + StaticLookupMode static_mode, + PrivateLookupMode private_mode); + // true if method matches signature and conforms to skipping_X conditions. - static bool method_matches(Method* m, Symbol* signature, bool skipping_overpass, bool skipping_static); + static bool method_matches(Method* m, Symbol* signature, bool skipping_overpass, bool skipping_static, bool skipping_private); - // find a local method index in default_methods (returns -1 if not found) - static int find_method_index(Array* methods, Symbol* name, Symbol* signature, - OverpassLookupMode overpass_mode, StaticLookupMode static_mode); + // find a local method index in methods or default_methods (returns -1 if not found) + static int find_method_index(Array* methods, + Symbol* name, Symbol* signature, + OverpassLookupMode overpass_mode, + StaticLookupMode static_mode, + PrivateLookupMode private_mode); // lookup operation (returns NULL if not found) Method* uncached_lookup_method(Symbol* name, Symbol* signature, OverpassLookupMode overpass_mode) const; @@ -1153,9 +1169,14 @@ // find a local method (returns NULL if not found) Method* find_method_impl(Symbol* name, Symbol* signature, - OverpassLookupMode overpass_mode, StaticLookupMode static_mode) const; - static Method* find_method_impl(Array* methods, Symbol* name, Symbol* signature, - OverpassLookupMode overpass_mode, StaticLookupMode static_mode); + OverpassLookupMode overpass_mode, + StaticLookupMode static_mode, + PrivateLookupMode private_mode) const; + static Method* find_method_impl(Array* methods, + Symbol* name, Symbol* signature, + OverpassLookupMode overpass_mode, + StaticLookupMode static_mode, + PrivateLookupMode private_mode); // Free CHeap allocated fields. void release_C_heap_structures(); --- old/src/share/vm/oops/klass.hpp 2015-07-31 13:27:30.501975734 -0400 +++ new/src/share/vm/oops/klass.hpp 2015-07-31 13:27:30.385975738 -0400 @@ -161,6 +161,7 @@ enum DefaultsLookupMode { find_defaults, skip_defaults }; enum OverpassLookupMode { find_overpass, skip_overpass }; enum StaticLookupMode { find_static, skip_static }; + enum PrivateLookupMode { find_private, skip_private }; bool is_klass() const volatile { return true; } --- old/src/share/vm/oops/klassVtable.cpp 2015-07-31 13:27:30.921975719 -0400 +++ new/src/share/vm/oops/klassVtable.cpp 2015-07-31 13:27:30.805975723 -0400 @@ -683,7 +683,6 @@ if (mhk->is_interface()) { assert(m->is_public(), "should be public"); assert(ik()->implements_interface(method_holder) , "this class should implement the interface"); - // the search could find a miranda or a default method if (is_miranda(m, ik()->methods(), ik()->default_methods(), ik()->super())) { return true; } @@ -691,25 +690,42 @@ return false; } -// check if a method is a miranda method, given a class's methods table, -// its default_method table and its super -// Miranda methods are calculated twice: -// first: before vtable size calculation: including abstract and superinterface default +// Check if a method is a miranda method, given a class's methods array, +// its default_method table and its super class. +// "Miranda" means an abstract non-private method that would not be +// overridden for the local class. +// A "miranda" method should only include non-private interface +// instance methods, i.e. not private methods, not static methods, +// not default methods (concrete interface methods), not overpass methods. +// If a given class already has a local (including overpass) method, a +// default method, or any of its superclasses has the same which would have +// overridden an abstract method, then this is not a miranda method. +// +// Miranda methods are checked multiple times. +// Pass 1: during class load/class file parsing: before vtable size calculation: +// include superinterface abstract and default methods (non-private instance). // We include potential default methods to give them space in the vtable. -// During the first run, the default_methods list is empty -// This is seen by default method creation -// Second: recalculated during vtable initialization: only include abstract methods. +// During the first run, the current instanceKlass has not yet been +// created, the superclasses and superinterfaces do have instanceKlasses +// but may not have vtables, the default_methods list is empty, no overpasses. +// This is seen by default method creation. +// +// Pass 2: recalculated during vtable initialization: only include abstract methods. // During the second run, default_methods is set up, so concrete methods from // superinterfaces with matching names/signatures to default_methods are already // in the default_methods list and do not need to be appended to the vtable -// as mirandas -// This is seen by link resolution and selection. -// "miranda" means not static, not defined by this class. -// private methods in interfaces do not belong in the miranda list. -// the caller must make sure that the method belongs to an interface implemented by the class -// Miranda methods only include public interface instance methods -// Not private methods, not static methods, not default == concrete abstract -// Miranda methods also do not include overpass methods in interfaces +// as mirandas. Abstract methods may already have been handled via +// overpasses - either local or superclass overpasses, which may be +// in the vtable already. +// +// Pass 3: They are also checked by link resolution and selection, +// for invocation on a method (not interface method) reference that +// resolves to a method with an interface as its method_holder. +// Used as part of walking from the bottom of the vtable to find +// the vtable index for the miranda method. +// +// Part of the Miranda Rights in the US mean that if you do not have +// an attorney one will be appointed for you. bool klassVtable::is_miranda(Method* m, Array* class_methods, Array* default_methods, Klass* super) { if (m->is_static() || m->is_private() || m->is_overpass()) { @@ -717,44 +733,36 @@ } Symbol* name = m->name(); Symbol* signature = m->signature(); - Method* mo; - if ((mo = InstanceKlass::find_instance_method(class_methods, name, signature)) == NULL) { - // did not find it in the method table of the current class - if ((default_methods == NULL) || - InstanceKlass::find_method(default_methods, name, signature) == NULL) { - if (super == NULL) { - // super doesn't exist - return true; - } - - mo = InstanceKlass::cast(super)->lookup_method(name, signature); - while (mo != NULL && mo->access_flags().is_static() - && mo->method_holder() != NULL - && mo->method_holder()->super() != NULL) - { - mo = mo->method_holder()->super()->uncached_lookup_method(name, signature, Klass::find_overpass); - } - if (mo == NULL || mo->access_flags().is_private() ) { - // super class hierarchy does not implement it or protection is different - return true; - } - } - } else { - // if the local class has a private method, the miranda will not - // override it, so a vtable slot is needed - if (mo->access_flags().is_private()) { - - // Second round, weed out any superinterface methods that turned - // into default methods, i.e. were concrete not abstract in the end - if ((default_methods == NULL) || - InstanceKlass::find_method(default_methods, name, signature) == NULL) { - return true; - } - } + // First look in local methods to see if already covered + if (InstanceKlass::find_local_method(class_methods, name, signature, + Klass::find_overpass, Klass::skip_static, Klass::skip_private) != NULL) + { + return false; } - return false; + // Check local default methods + if ((default_methods != NULL) && + (InstanceKlass::find_method(default_methods, name, signature) != NULL)) + { + return false; + } + + InstanceKlass* cursuper; + // Iterate on all superclasses, which should have instanceKlasses + // Note that we explicitly look for overpasses at each level. + // Overpasses may or may not exist for supers for pass 1, + // they should have been created for pass 2 and later. + + for (cursuper = InstanceKlass::cast(super); cursuper != NULL; cursuper = (InstanceKlass*)cursuper->super()) + { + if (cursuper->find_local_method(name, signature, + Klass::find_overpass, Klass::skip_static, Klass::skip_private) != NULL) { + return false; + } + } + + return true; } // Scans current_interface_methods for miranda methods that do not --- /dev/null 2015-06-22 13:12:21.527631646 -0400 +++ new/test/runtime/lambda-features/TestStaticandInstance.java 2015-07-31 13:27:31.241975708 -0400 @@ -0,0 +1,272 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * @test + * @bug 8087342 + * @summary Test linkresolver search static, instance and overpass duplicates + * @run main/othervm -Xverify:none TestStaticandInstance + */ + + +import java.util.*; +import jdk.internal.org.objectweb.asm.*; +import static jdk.internal.org.objectweb.asm.Opcodes.*; + +public class TestStaticandInstance { + static final String stringC = "C"; + static final String stringD = "D"; + static final String stringI = "I"; + + public static void main(String args[]) throws Throwable { + ClassLoader cl = new ClassLoader() { + public Class loadClass(String name) throws ClassNotFoundException { + Class retClass; + if ((retClass = findLoadedClass(name)) != null) { + return retClass; + } + if (stringC.equals(name)) { + byte[] classFile=dumpC(); + return defineClass(stringC, classFile, 0, classFile.length); + } + if (stringD.equals(name)) { + byte[] classFile=dumpD(); + return defineClass(stringD, classFile, 0, classFile.length); + } + if (stringI.equals(name)) { + byte[] classFile=dumpI(); + return defineClass(stringI, classFile, 0, classFile.length); + } + return super.loadClass(name); + } + }; + + Class classC = cl.loadClass(stringC); + Class classI = cl.loadClass(stringI); + + try { + int staticret = (Integer)cl.loadClass(stringD).getDeclaredMethod("CallStatic").invoke(null); + if (staticret != 1) { + throw new RuntimeException("invokestatic failed to call correct method"); + } + System.out.println("staticret: " + staticret); // should be 1 + + int invokeinterfaceret = (Integer)cl.loadClass(stringD).getDeclaredMethod("CallInterface").invoke(null); + if (invokeinterfaceret != 0) { + throw new RuntimeException(String.format("Expected java.lang.AbstractMethodError, got %d", invokeinterfaceret)); + } + System.out.println("invokeinterfaceret: AbstractMethodError"); + + int invokevirtualret = (Integer)cl.loadClass(stringD).getDeclaredMethod("CallVirtual").invoke(null); + if (invokevirtualret != 0) { + throw new RuntimeException(String.format("Expected java.lang.IncompatibleClassChangeError, got %d", invokevirtualret)); + } + System.out.println("invokevirtualret: IncompatibleClassChangeError"); + } catch (java.lang.Throwable e) { + throw new RuntimeException("Unexpected exception: " + e.getMessage()); + } + } + +/* +interface I { + public int m(); // abstract + default int q() { return 3; } // trigger defmeth processing: C gets AME overpass +} + +// C gets static, private and AME overpass m()I with -Xverify:none +class C implements I { + static int n() { return 1;} // patch to m + public int m() { return 2;} // patch to private +} + +public class D { + public static int CallStatic() { + int staticret = C.n(); // patch to m + return staticret; + } + public static int CallInterface() throws AbstractMethodError{ + try { + I myI = new C(); + return myI.m(); + } catch (java.lang.AbstractMethodError e) { + return 0; // for success + } + } + public static int CallVirtual() { + try { + C myC = new C(); + return myC.m(); + } catch (java.lang.IncompatibleClassChangeError e) { + return 0; // for success + } + } +} +*/ + + public static byte[] dumpC() { + + ClassWriter cw = new ClassWriter(0); + FieldVisitor fv; + MethodVisitor mv; + AnnotationVisitor av0; + + cw.visit(52, ACC_SUPER, "C", null, "java/lang/Object", new String[] { "I" }); + + { + mv = cw.visitMethod(0, "", "()V", null, null); + mv.visitCode(); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); + mv.visitInsn(RETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + { + mv = cw.visitMethod(ACC_STATIC, "m", "()I", null, null); + mv.visitCode(); + mv.visitInsn(ICONST_1); + mv.visitInsn(IRETURN); + mv.visitMaxs(1, 0); + mv.visitEnd(); + } + { + mv = cw.visitMethod(ACC_PRIVATE, "m", "()I", null, null); + mv.visitCode(); + mv.visitInsn(ICONST_2); + mv.visitInsn(IRETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + cw.visitEnd(); + + return cw.toByteArray(); + } + + public static byte[] dumpD () { + + ClassWriter cw = new ClassWriter(0); + FieldVisitor fv; + MethodVisitor mv; + AnnotationVisitor av0; + + cw.visit(52, ACC_PUBLIC + ACC_SUPER, "D", null, "java/lang/Object", null); + + { + mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); + mv.visitCode(); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); + mv.visitInsn(RETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + { + mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "CallStatic", "()I", null, null); + mv.visitCode(); + mv.visitMethodInsn(INVOKESTATIC, "C", "m", "()I", false); + mv.visitVarInsn(ISTORE, 0); + mv.visitVarInsn(ILOAD, 0); + mv.visitInsn(IRETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + { + mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "CallInterface", "()I", null, new String[] { "java/lang/AbstractMethodError" }); + mv.visitCode(); + Label l0 = new Label(); + Label l1 = new Label(); + Label l2 = new Label(); + mv.visitTryCatchBlock(l0, l1, l2, "java/lang/AbstractMethodError"); + mv.visitLabel(l0); + mv.visitTypeInsn(NEW, "C"); + mv.visitInsn(DUP); + mv.visitMethodInsn(INVOKESPECIAL, "C", "", "()V", false); + mv.visitVarInsn(ASTORE, 0); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKEINTERFACE, "I", "m", "()I", true); + mv.visitLabel(l1); + mv.visitInsn(IRETURN); + mv.visitLabel(l2); + mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[] {"java/lang/AbstractMethodError"}); + mv.visitVarInsn(ASTORE, 0); + mv.visitInsn(ICONST_0); + mv.visitInsn(IRETURN); + mv.visitMaxs(2, 1); + mv.visitEnd(); + } + { + mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "CallVirtual", "()I", null, null); + mv.visitCode(); + Label l0 = new Label(); + Label l1 = new Label(); + Label l2 = new Label(); + mv.visitTryCatchBlock(l0, l1, l2, "java/lang/IncompatibleClassChangeError"); + mv.visitLabel(l0); + mv.visitTypeInsn(NEW, "C"); + mv.visitInsn(DUP); + mv.visitMethodInsn(INVOKESPECIAL, "C", "", "()V", false); + mv.visitVarInsn(ASTORE, 0); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKEVIRTUAL, "C", "m", "()I", false); + mv.visitLabel(l1); + mv.visitInsn(IRETURN); + mv.visitLabel(l2); + mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[] {"java/lang/IncompatibleClassChangeError"}); + mv.visitVarInsn(ASTORE, 0); + mv.visitInsn(ICONST_0); + mv.visitInsn(IRETURN); + mv.visitMaxs(2, 1); + mv.visitEnd(); + } + cw.visitEnd(); + + return cw.toByteArray(); + } + + public static byte[] dumpI() { + + ClassWriter cw = new ClassWriter(0); + FieldVisitor fv; + MethodVisitor mv; + AnnotationVisitor av0; + + cw.visit(52, ACC_ABSTRACT + ACC_INTERFACE, "I", null, "java/lang/Object", null); + + { + mv = cw.visitMethod(ACC_PUBLIC + ACC_ABSTRACT, "m", "()I", null, null); + mv.visitEnd(); + } + { + mv = cw.visitMethod(ACC_PUBLIC, "q", "()I", null, null); + mv.visitCode(); + mv.visitInsn(ICONST_3); + mv.visitInsn(IRETURN); + mv.visitMaxs(1, 1); + mv.visitEnd(); + } + cw.visitEnd(); + + return cw.toByteArray(); + } +}