changeset 32189:5264b560ab1b

8087342: Crash in klassItable::initialize_itable_for_interface Summary: Fix method searches to handle static, private instance and overpass Reviewed-by: lfoltan, dholmes, hseigel
author acorn
date Thu, 06 Aug 2015 13:02:15 -0400
parents 2997b317d990
children acf684680d24
files hotspot/src/share/vm/interpreter/linkResolver.cpp hotspot/src/share/vm/oops/instanceKlass.cpp hotspot/src/share/vm/oops/instanceKlass.hpp hotspot/src/share/vm/oops/klass.hpp hotspot/src/share/vm/oops/klassVtable.cpp hotspot/test/runtime/lambda-features/TestStaticandInstance.java
diffstat 6 files changed, 434 insertions(+), 77 deletions(-) [+]
line wrap: on
line diff
--- 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);
 
+  // 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<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);
+  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<Method*>* 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<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();
+  }
+}