1 /*
   2  * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  *
  23  */
  24 
  25 /**
  26  * @test
  27  * @bug 8025260 8016839
  28  * @summary Ensure that AbstractMethodError and IllegalAccessError are thrown appropriately, not NullPointerException
  29  * @modules java.base/jdk.internal.org.objectweb.asm
  30  * @library / .
  31  *
  32  * @build p.*
  33  * @run main/othervm compiler.jsr292.methodHandleExceptions.TestAMEnotNPE
  34  * @run main/othervm -Xint compiler.jsr292.methodHandleExceptions.TestAMEnotNPE
  35  * @run main/othervm -Xcomp compiler.jsr292.methodHandleExceptions.TestAMEnotNPE
  36  */
  37 
  38 package compiler.jsr292.methodHandleExceptions;
  39 
  40 import p.Dok;
  41 import jdk.internal.org.objectweb.asm.ClassWriter;
  42 import jdk.internal.org.objectweb.asm.Handle;
  43 import jdk.internal.org.objectweb.asm.MethodVisitor;
  44 import jdk.internal.org.objectweb.asm.Opcodes;
  45 
  46 import java.lang.reflect.InvocationTargetException;
  47 import java.lang.reflect.Method;
  48 import java.util.ArrayList;
  49 import java.util.List;
  50 
  51 import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PRIVATE;
  52 import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PUBLIC;
  53 import static jdk.internal.org.objectweb.asm.Opcodes.ACC_STATIC;
  54 import static jdk.internal.org.objectweb.asm.Opcodes.ACC_SUPER;
  55 import static jdk.internal.org.objectweb.asm.Opcodes.ALOAD;
  56 import static jdk.internal.org.objectweb.asm.Opcodes.ILOAD;
  57 import static jdk.internal.org.objectweb.asm.Opcodes.INVOKESPECIAL;
  58 import static jdk.internal.org.objectweb.asm.Opcodes.INVOKEVIRTUAL;
  59 import static jdk.internal.org.objectweb.asm.Opcodes.IRETURN;
  60 import static jdk.internal.org.objectweb.asm.Opcodes.LLOAD;
  61 import static jdk.internal.org.objectweb.asm.Opcodes.RETURN;
  62 import static jdk.internal.org.objectweb.asm.Opcodes.V1_8;
  63 
  64 public class TestAMEnotNPE {
  65 
  66     static boolean writeJarFiles = false;
  67     static boolean readJarFiles = false;
  68 
  69     /**
  70      * Optional command line parameter (any case-insensitive prefix of)
  71      * "writejarfiles" or "readjarfiles".
  72      *
  73      * "Writejarfiles" creates a jar file for each different set of tested classes.
  74      * "Readjarfiles" causes the classloader to use the copies of the classes
  75      * found in the corresponding jar files.
  76      *
  77      * Jarfilenames look something like pD_ext_pF (p.D extends p.F)
  78      * and qD_m_pp_imp_pI (q.D with package-private m implements p.I)
  79      *
  80      */
  81     public static void main(String args[]) throws Throwable {
  82         ArrayList<Throwable> lt = new ArrayList<Throwable>();
  83 
  84         if (args.length > 0) {
  85             String a0 = args[0].toLowerCase();
  86             if (a0.length() > 0) {
  87                 writeJarFiles = ("writejarfiles").startsWith(a0);
  88                 readJarFiles = ("readjarfiles").startsWith(a0);
  89             }
  90             if (!(writeJarFiles || readJarFiles)) {
  91                 throw new Error("Command line parameter (if any) should be prefix of writeJarFiles or readJarFiles");
  92             }
  93         }
  94 
  95         try {
  96             System.out.println("TRYING p.D.m PRIVATE interface-invoked as p.I.m, p.D extends p.F, p.F.m FINAL");
  97             tryAndCheckThrown(lt, bytesForDprivateSubWhat("p/F"),
  98                     "p.D extends p.F (p.F implements p.I, FINAL public m), private m",
  99                     IllegalAccessError.class, "pD_ext_pF");
 100             // We'll take either a VerifyError (pre 2013-11-30)
 101             // or an IllegalAccessError (post 2013-11-22)
 102         } catch (VerifyError ve) {
 103             System.out.println("Saw expected VerifyError " + ve);
 104         }
 105         System.out.println();
 106 
 107         System.out.println("TRYING p.D.m PRIVATE interface-invoked as p.I.m, p.D extends p.E");
 108         tryAndCheckThrown(lt, bytesForDprivateSubWhat("p/E"),
 109                 "p.D extends p.E (p.E implements p.I, public m), private m",
 110                 IllegalAccessError.class, "pD_ext_pE");
 111 
 112         System.out.println("TRYING p.D.m ABSTRACT interface-invoked as p.I.m");
 113         tryAndCheckThrown(lt, bytesForD(),
 114                 "D extends abstract C, no m",
 115                 AbstractMethodError.class, "pD_ext_pC");
 116 
 117         System.out.println("TRYING q.D.m PACKAGE interface-invoked as p.I.m");
 118         tryAndCheckThrown(lt, "q.D", bytesForDsomeAccess("q/D", 0),
 119                 "q.D implements p.I, protected m", IllegalAccessError.class,
 120                 "qD_m_pp_imp_pI");
 121 
 122         // Note jar file name is used in the plural-arg case.
 123         System.out.println("TRYING p.D.m PRIVATE interface-invoked as p.I.m");
 124         tryAndCheckThrown(lt, bytesForDsomeAccess("p/D", ACC_PRIVATE),
 125                 "p.D implements p.I, private m",
 126                 IllegalAccessError.class, "pD_m_pri_imp_pI");
 127 
 128         // Plural-arg test.
 129         System.out.println("TRYING p.D.m PRIVATE MANY ARG interface-invoked as p.I.m");
 130         tryAndCheckThrownMany(lt, bytesForDsomeAccess("p/D", ACC_PRIVATE),
 131                 "p.D implements p.I, private m", IllegalAccessError.class);
 132 
 133         if (lt.size() > 0) {
 134             System.out.flush();
 135             Thread.sleep(250); // This de-interleaves output and error in Netbeans, sigh.
 136             for (Throwable th : lt)
 137                 System.err.println(th);
 138             throw new Error("Test failed, there were " + lt.size() + " failures listed above");
 139         } else {
 140             System.out.println("ALL PASS, HOORAY!");
 141         }
 142     }
 143 
 144     /**
 145      * The bytes for D, a NOT abstract class extending abstract class C without
 146      * supplying an implementation for abstract method m. There is a default
 147      * method in the interface I, but it should lose to the abstract class.
 148      *
 149      * @return
 150      * @throws Exception
 151      */
 152     public static byte[] bytesForD() throws Exception {
 153 
 154         ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES
 155                 | ClassWriter.COMPUTE_MAXS);
 156         MethodVisitor mv;
 157 
 158         cw.visit(V1_8, ACC_PUBLIC + ACC_SUPER, "p/D", null, "p/C", null);
 159 
 160         {
 161             mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
 162             mv.visitCode();
 163             mv.visitVarInsn(ALOAD, 0);
 164             mv.visitMethodInsn(INVOKESPECIAL, "p/C", "<init>", "()V");
 165             mv.visitInsn(RETURN);
 166             mv.visitMaxs(0, 0);
 167             mv.visitEnd();
 168         }
 169         cw.visitEnd();
 170 
 171         return cw.toByteArray();
 172     }
 173 
 174     /**
 175      * The bytes for D, implements I, does not extend C, declares m()I with
 176      * access method_acc.
 177      *
 178      * @param d_name Name of class defined
 179      * @param method_acc Accessibility of that class's method m.
 180      * @return
 181      * @throws Exception
 182      */
 183     public static byte[] bytesForDsomeAccess(String d_name, int method_acc) throws Exception {
 184         return bytesForSomeDsubSomethingSomeAccess(d_name, "java/lang/Object", method_acc);
 185     }
 186 
 187     /**
 188      * The bytes for D implements I, extends some class, declares m()I as
 189      * private.
 190      *
 191      * Invokeinterface of I.m applied to this D should throw IllegalAccessError
 192      *
 193      * @param sub_what The name of the class that D will extend.
 194      * @return
 195      * @throws Exception
 196      */
 197     public static byte[] bytesForDprivateSubWhat(String sub_what) throws Exception {
 198         return bytesForSomeDsubSomethingSomeAccess("p/D", sub_what, ACC_PRIVATE);
 199     }
 200 
 201     /**
 202      * Returns the bytes for a class with name d_name (presumably "D" in some
 203      * package), extending some class with name sub_what, implementing p.I,
 204      * and defining two methods m() and m(11args) with access method_acc.
 205      *
 206      * @param d_name      Name of class that is defined
 207      * @param sub_what    Name of class that it extends
 208      * @param method_acc  Accessibility of method(s) m in defined class.
 209      * @return
 210      * @throws Exception
 211      */
 212     public static byte[] bytesForSomeDsubSomethingSomeAccess
 213     (String d_name, String sub_what, int method_acc)
 214             throws Exception {
 215 
 216         ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES
 217                 | ClassWriter.COMPUTE_MAXS);
 218         MethodVisitor mv;
 219         String[] interfaces = {"p/I"};
 220 
 221         cw.visit(V1_8, ACC_PUBLIC + ACC_SUPER, d_name, null, sub_what, interfaces);
 222         {
 223             mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
 224             mv.visitCode();
 225             mv.visitVarInsn(ALOAD, 0);
 226             mv.visitMethodInsn(INVOKESPECIAL, sub_what, "<init>", "()V");
 227             mv.visitInsn(RETURN);
 228             mv.visitMaxs(0, 0);
 229             mv.visitEnd();
 230         }
 231         // int m() {return 3;}
 232         {
 233             mv = cw.visitMethod(method_acc, "m", "()I", null, null);
 234             mv.visitCode();
 235             mv.visitLdcInsn(new Integer(3));
 236             mv.visitInsn(IRETURN);
 237             mv.visitMaxs(0, 0);
 238             mv.visitEnd();
 239         }
 240         // int m(11args) {return 3;}
 241         {
 242             mv = cw.visitMethod(method_acc, "m", "(BCSIJ"
 243                     + "Ljava/lang/Object;"
 244                     + "Ljava/lang/Object;"
 245                     + "Ljava/lang/Object;"
 246                     + "Ljava/lang/Object;"
 247                     + "Ljava/lang/Object;"
 248                     + "Ljava/lang/Object;"
 249                     + ")I", null, null);
 250             mv.visitCode();
 251             mv.visitLdcInsn(new Integer(3));
 252             mv.visitInsn(IRETURN);
 253             mv.visitMaxs(0, 0);
 254             mv.visitEnd();
 255         }
 256         cw.visitEnd();
 257         return cw.toByteArray();
 258     }
 259 
 260     /**
 261      * The bytecodes for a class p/T defining a methods test() and test(11args)
 262      * that contain an invokeExact of a particular methodHandle, I.m.
 263      *
 264      * Test will be passed values that may imperfectly implement I,
 265      * and thus may in turn throw exceptions.
 266      *
 267      * @return
 268      * @throws Exception
 269      */
 270     public static byte[] bytesForT() throws Exception {
 271 
 272         ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES
 273                 | ClassWriter.COMPUTE_MAXS);
 274         MethodVisitor mv;
 275 
 276         cw.visit(V1_8, ACC_PUBLIC + ACC_SUPER, "p/T", null, "java/lang/Object", null);
 277         {
 278             mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
 279             mv.visitCode();
 280             mv.visitVarInsn(ALOAD, 0);
 281             mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
 282             mv.visitInsn(RETURN);
 283             mv.visitMaxs(0, 0);
 284             mv.visitEnd();
 285         }
 286         // static int test(I)
 287         {
 288             mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "test", "(Lp/I;)I", null, null);
 289             mv.visitCode();
 290             mv.visitLdcInsn(new Handle(Opcodes.H_INVOKEINTERFACE, "p/I", "m", "()I"));
 291             mv.visitVarInsn(ALOAD, 0);
 292             mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle",
 293                     "invokeExact", "(Lp/I;)I");
 294             mv.visitInsn(IRETURN);
 295             mv.visitMaxs(0, 0);
 296             mv.visitEnd();
 297         }
 298         // static int test(I,11args)
 299         {
 300             mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "test", "(Lp/I;BCSIJLjava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)I", null, null);
 301             mv.visitCode();
 302             mv.visitLdcInsn(new Handle(Opcodes.H_INVOKEINTERFACE, "p/I", "m", "(BCSIJLjava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)I"));
 303             mv.visitVarInsn(ALOAD, 0);
 304             mv.visitVarInsn(ILOAD, 1);
 305             mv.visitVarInsn(ILOAD, 2);
 306             mv.visitVarInsn(ILOAD, 3);
 307             mv.visitVarInsn(ILOAD, 4);
 308             mv.visitVarInsn(LLOAD, 5);
 309             mv.visitVarInsn(ALOAD, 7);
 310             mv.visitVarInsn(ALOAD, 8);
 311             mv.visitVarInsn(ALOAD, 9);
 312             mv.visitVarInsn(ALOAD, 10);
 313             mv.visitVarInsn(ALOAD, 11);
 314             mv.visitVarInsn(ALOAD, 12);
 315             mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle",
 316                     "invokeExact", "(Lp/I;BCSIJLjava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)I");
 317             mv.visitInsn(IRETURN);
 318             mv.visitMaxs(0, 0);
 319             mv.visitEnd();
 320         }
 321         cw.visitEnd();
 322         return cw.toByteArray();
 323     }
 324 
 325     private static void tryAndCheckThrown(
 326             List<Throwable> lt, byte[] dBytes, String what, Class<?> expected, String jar_name)
 327             throws Throwable {
 328         tryAndCheckThrown(lt, "p.D", dBytes, what, expected, jar_name);
 329     }
 330 
 331     private static void tryAndCheckThrown(List<Throwable> lt, String d_name, byte[] dBytes, String what, Class<?> expected, String jar_name)
 332             throws Throwable {
 333 
 334         System.out.println("Methodhandle invokeExact I.m() for instance of " + what);
 335         ByteClassLoader bcl1 = new ByteClassLoader(jar_name, readJarFiles, writeJarFiles);
 336         try {
 337             Class<?> d1 = bcl1.loadBytes(d_name, dBytes);
 338             Class<?> t1 = bcl1.loadBytes("p.T", bytesForT());
 339             invokeTest(t1, d1, expected, lt);
 340         } finally {
 341             // Not necessary for others -- all class files are written in this call.
 342             // (unless the VM crashes first).
 343             bcl1.close();
 344         }
 345 
 346         System.out.println("Reflection invoke I.m() for instance of " + what);
 347         ByteClassLoader bcl3 = new ByteClassLoader(jar_name, readJarFiles, false);
 348         Class<?> d3 = bcl3.loadBytes(d_name, dBytes);
 349         Class<?> t3 = bcl3.loadClass("p.Treflect");
 350         invokeTest(t3, d3, expected, lt);
 351 
 352         System.out.println("Bytecode invokeInterface I.m() for instance of " + what);
 353         ByteClassLoader bcl2 = new ByteClassLoader(jar_name, readJarFiles, false);
 354         Class<?> d2 = bcl2.loadBytes(d_name, dBytes);
 355         Class<?> t2 = bcl2.loadClass("p.Tdirect");
 356         badGoodBadGood(t2, d2, expected, lt);
 357     }
 358 
 359     private static void invokeTest(Class<?> t, Class<?> d, Class<?> expected, List<Throwable> lt)
 360             throws Throwable {
 361         try {
 362             Method m = t.getMethod("test", p.I.class);
 363             Object o = d.newInstance();
 364             Object result = m.invoke(null, o);
 365             if (expected != null) {
 366                 System.out.println("FAIL, Expected " + expected.getName()
 367                         + " wrapped in InvocationTargetException, but nothing was thrown");
 368                 lt.add(new Error("Exception " + expected.getName() + " was not thrown"));
 369             } else {
 370                 System.out.println("PASS, saw expected return.");
 371             }
 372         } catch (InvocationTargetException e) {
 373             Throwable th = e.getCause();
 374             th.printStackTrace(System.out);
 375             if (expected != null) {
 376                 if (expected.isInstance(th)) {
 377                     System.out.println("PASS, saw expected exception (" + expected.getName() + ").");
 378                 } else {
 379                     System.out.println("FAIL, Expected " + expected.getName()
 380                             + " wrapped in InvocationTargetException, saw " + th);
 381                     lt.add(th);
 382                 }
 383             } else {
 384                 System.out.println("FAIL, expected no exception, saw " + th);
 385                 lt.add(th);
 386             }
 387         }
 388         System.out.println();
 389     }
 390 
 391     /* Many-arg versions of above */
 392     private static void tryAndCheckThrownMany(List<Throwable> lt, byte[] dBytes, String what, Class<?> expected)
 393             throws Throwable {
 394 
 395         System.out.println("Methodhandle invokeExact I.m(11params) for instance of " + what);
 396         ByteClassLoader bcl1 = new ByteClassLoader("p.D", readJarFiles, false);
 397         try {
 398             Class<?> d1 = bcl1.loadBytes("p.D", dBytes);
 399             Class<?> t1 = bcl1.loadBytes("p.T", bytesForT());
 400             invokeTestMany(t1, d1, expected, lt);
 401         } finally {
 402             bcl1.close(); // Not necessary for others -- all class files are written in this call.
 403         }
 404 
 405         {
 406             System.out.println("Bytecode invokeInterface I.m(11params) for instance of " + what);
 407             ByteClassLoader bcl2 = new ByteClassLoader("pD_m_pri_imp_pI", readJarFiles, false);
 408             Class<?> d2 = bcl2.loadBytes("p.D", dBytes);
 409             Class<?> t2 = bcl2.loadClass("p.Tdirect");
 410             badGoodBadGoodMany(t2, d2, expected, lt);
 411 
 412         }
 413         {
 414             System.out.println("Reflection invokeInterface I.m(11params) for instance of " + what);
 415             ByteClassLoader bcl2 = new ByteClassLoader("pD_m_pri_imp_pI", readJarFiles, false);
 416             Class<?> d2 = bcl2.loadBytes("p.D", dBytes);
 417             Class<?> t2 = bcl2.loadClass("p.Treflect");
 418             invokeTestMany(t2, d2, expected, lt);
 419         }
 420     }
 421 
 422     private static void invokeTestMany(Class<?> t, Class<?> d, Class<?> expected, List<Throwable> lt)
 423             throws Throwable {
 424         try {
 425             Method m = t.getMethod("test", p.I.class,
 426                     Byte.TYPE, Character.TYPE, Short.TYPE, Integer.TYPE, Long.TYPE,
 427                     Object.class, Object.class, Object.class,
 428                     Object.class, Object.class, Object.class);
 429             Object o = d.newInstance();
 430             Byte b = 1;
 431             Character c = 2;
 432             Short s = 3;
 433             Integer i = 4;
 434             Long j = 5L;
 435             Object o1 = b;
 436             Object o2 = c;
 437             Object o3 = s;
 438             Object o4 = i;
 439             Object o5 = j;
 440             Object o6 = "6";
 441 
 442             Object result = m.invoke(null, o, b, c, s, i, j,
 443                     o1, o2, o3, o4, o5, o6);
 444             if (expected != null) {
 445                 System.out.println("FAIL, Expected " + expected.getName()
 446                         + " wrapped in InvocationTargetException, but nothing was thrown");
 447                 lt.add(new Error("Exception " + expected.getName()
 448                         + " was not thrown"));
 449             } else {
 450                 System.out.println("PASS, saw expected return.");
 451             }
 452         } catch (InvocationTargetException e) {
 453             Throwable th = e.getCause();
 454             th.printStackTrace(System.out);
 455             if (expected != null) {
 456                 if (expected.isInstance(th)) {
 457                     System.out.println("PASS, saw expected exception ("
 458                             + expected.getName() + ").");
 459                 } else {
 460                     System.out.println("FAIL, Expected " + expected.getName()
 461                             + " wrapped in InvocationTargetException, saw " + th);
 462                     lt.add(th);
 463                 }
 464             } else {
 465                 System.out.println("FAIL, expected no exception, saw " + th);
 466                 lt.add(th);
 467             }
 468         }
 469         System.out.println();
 470     }
 471 
 472     /**
 473      * This tests a peculiar idiom for tickling the bug on older VMs that lack
 474      * methodhandles.  The bug (if not fixed) acts in the following way:
 475      *
 476      *  When a broken receiver is passed to the first execution of an invokeinterface
 477      * bytecode, the illegal access is detected before the effects of resolution are
 478      * cached for later use, and so repeated calls with a broken receiver will always
 479      * throw the correct error.
 480      *
 481      * If, however, a good receiver is passed to the invokeinterface, the effects of
 482      * resolution will be successfully cached.  A subsequent execution with a broken
 483      * receiver will reuse the cached information, skip the detailed resolution work,
 484      * and instead encounter a null pointer.  By convention, that is the encoding for a
 485      * missing abstract method, and an AbstractMethodError is thrown -- not the expected
 486      * IllegalAccessError.
 487      *
 488      * @param t2 Test invocation class
 489      * @param d2 Test receiver class
 490      * @param expected expected exception type
 491      * @param lt list of unexpected throwables seen
 492      */
 493     private static void badGoodBadGood(Class<?> t2, Class<?> d2, Class<?> expected, List<Throwable> lt)
 494             throws Throwable {
 495         System.out.println("  Error input 1st time");
 496         invokeTest(t2, d2, expected, lt);
 497         System.out.println("  Good input (instance of Dok)");
 498         invokeTest(t2, Dok.class, null, lt);
 499         System.out.println("  Error input 2nd time");
 500         invokeTest(t2, d2, expected, lt);
 501         System.out.println("  Good input (instance of Dok)");
 502         invokeTest(t2, Dok.class, null, lt);
 503     }
 504 
 505     private static void badGoodBadGoodMany(Class<?> t2, Class<?> d2, Class<?> expected, List<Throwable> lt)
 506             throws Throwable {
 507         System.out.println("  Error input 1st time");
 508         invokeTestMany(t2, d2, expected, lt);
 509         System.out.println("  Good input (instance of Dok)");
 510         invokeTestMany(t2, Dok.class, null, lt);
 511         System.out.println("  Error input 2nd time");
 512         invokeTestMany(t2, d2, expected, lt);
 513         System.out.println("  Good input (instance of Dok)");
 514         invokeTestMany(t2, Dok.class, null, lt);
 515     }
 516 }