8087342: Crash in klassItable::initialize_itable_for_interface
Summary: Fix method searches to handle static, private instance and overpass
Reviewed-by: lfoltan, dholmes, hseigel
--- a/hotspot/src/share/vm/interpreter/linkResolver.cpp Thu Aug 06 16:00:55 2015 +0200
+++ b/hotspot/src/share/vm/interpreter/linkResolver.cpp Thu Aug 06 13:02:15 2015 -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,
--- a/hotspot/src/share/vm/oops/instanceKlass.cpp Thu Aug 06 16:00:55 2015 +0200
+++ b/hotspot/src/share/vm/oops/instanceKlass.cpp Thu Aug 06 13:02:15 2015 -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<Method*>* 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<Method*>* 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<Method*>* 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<Method*>* methods, Symbol* name, Symbol* signature, OverpassLookupMode overpass_mode, StaticLookupMode static_mode) {
- int hit = find_method_index(methods, name, signature, overpass_mode, static_mode);
+ Array<Method*>* 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<Method*>* methods, Symbol* name, Symbol* signature, OverpassLookupMode overpass_mode, StaticLookupMode static_mode) {
+ Array<Method*>* 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<InstanceKlass*>(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;
}
--- a/hotspot/src/share/vm/oops/instanceKlass.hpp Thu Aug 06 16:00:55 2015 +0200
+++ b/hotspot/src/share/vm/oops/instanceKlass.hpp Thu Aug 06 13:02:15 2015 -0400
@@ -503,12 +503,28 @@
Method* find_instance_method(Symbol* name, Symbol* signature);
static Method* find_instance_method(Array<Method*>* methods, Symbol* name, Symbol* signature);
- // 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);
+ // 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 index in default_methods (returns -1 if not found)
- static int find_method_index(Array<Method*>* methods, Symbol* name, Symbol* signature,
- OverpassLookupMode overpass_mode, StaticLookupMode static_mode);
+ // find a local method from given methods array (returns NULL if not found)
+ static Method* find_local_method(Array<Method*>* 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, bool skipping_private);
+
+ // find a local method index in methods or default_methods (returns -1 if not found)
+ static int find_method_index(Array<Method*>* 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<Method*>* 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<Method*>* methods,
+ Symbol* name, Symbol* signature,
+ OverpassLookupMode overpass_mode,
+ StaticLookupMode static_mode,
+ PrivateLookupMode private_mode);
// Free CHeap allocated fields.
void release_C_heap_structures();
--- a/hotspot/src/share/vm/oops/klass.hpp Thu Aug 06 16:00:55 2015 +0200
+++ b/hotspot/src/share/vm/oops/klass.hpp Thu Aug 06 13:02:15 2015 -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; }
--- a/hotspot/src/share/vm/oops/klassVtable.cpp Thu Aug 06 16:00:55 2015 +0200
+++ b/hotspot/src/share/vm/oops/klassVtable.cpp Thu Aug 06 13:02:15 2015 -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,57 @@
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.
+// The goal of pass 2 is to walk through the superinterfaces to see if any of
+// the superinterface methods (which were all abstract pre-default methods)
+// need to be added to the vtable.
+// With the addition of default methods, we have three new challenges:
+// overpasses, static interface methods and private interface methods.
+// Static and private interface methods do not get added to the vtable and
+// are not seen by the method resolution process, so we skip those.
+// Overpass methods are already in the vtable, so vtable lookup will
+// find them and we don't need to add a miranda method to the end of
+// the vtable. So we look for overpass methods and if they are found we
+// return false. Note that we inherit our superclasses vtable, so
+// the superclass' search also needs to use find_overpass so that if
+// one is found we return false.
+// False means - we don't need a miranda method added to the vtable.
+//
// 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<Method*>* class_methods,
Array<Method*>* default_methods, Klass* super) {
if (m->is_static() || m->is_private() || m->is_overpass()) {
@@ -717,44 +748,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 Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/lambda-features/TestStaticandInstance.java Thu Aug 06 13:02:15 2015 -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 m() { return 1;} // javac with "n()" and patch to "m()"
+ private int m() { return 2;} // javac with public and patch to private
+}
+
+public class D {
+ public static int CallStatic() {
+ int staticret = C.m(); // javac with "C.n" and patch to "C.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, "<init>", "()V", null, null);
+ mv.visitCode();
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()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, "<init>", "()V", null, null);
+ mv.visitCode();
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()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", "<init>", "()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", "<init>", "()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();
+ }
+}