1 /*
   2  * Copyright (c) 2019, 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  * @test
  26  * @bug 8181171 8210457
  27  * @summary Break ResolvedMethodTable with redefined nest class.
  28  * @library /test/lib
  29  * @modules java.base/jdk.internal.misc
  30  * @modules java.compiler
  31  *          java.instrument
  32  *          jdk.jartool/sun.tools.jar
  33  * @compile ../../NamedBuffer.java
  34  * @compile redef/Xost.java
  35  * @run main RedefineClassHelper
  36  * @run main/othervm -javaagent:redefineagent.jar -Xlog:redefine+class+update*=debug,membername+table=debug MethodHandleDeletedMethod
  37  */
  38 
  39 import java.io.File;
  40 import java.io.FileInputStream;
  41 import java.lang.invoke.*;
  42 
  43 class Host {
  44     static MethodHandle fooMH;
  45 
  46     static class A {
  47         private static void foo() { System.out.println("OLD foo called"); }
  48     }
  49     static void bar() throws NoSuchMethodError {
  50         A.foo();
  51     }
  52     static void barMH() throws Throwable {
  53         fooMH.invokeExact();
  54     }
  55 
  56     public static void reresolve() throws Throwable {
  57         fooMH = MethodHandles.lookup().findStatic(A.class, "foo", MethodType.methodType(void.class));
  58     }
  59 
  60     static {
  61         try {
  62           fooMH = MethodHandles.lookup().findStatic(A.class, "foo", MethodType.methodType(void.class));
  63         } catch (ReflectiveOperationException ex) {
  64         }
  65     }
  66 }
  67 
  68 public class MethodHandleDeletedMethod {
  69 
  70     static final String DEST = System.getProperty("test.classes");
  71     static final boolean VERBOSE = false;
  72 
  73     private static byte[] bytesForHostClass(char replace) throws Throwable {
  74         return NamedBuffer.bytesForHostClass(replace, "Host$A");
  75     }
  76 
  77     public static void main(java.lang.String[] unused) throws Throwable {
  78         Host h = new Host();
  79         h.bar();
  80         h.barMH();
  81         byte[] buf = bytesForHostClass('X');
  82         RedefineClassHelper.redefineClass(Host.A.class, buf);
  83         try {
  84             h.bar();    // call deleted Method directly
  85             throw new RuntimeException("Failed, expected NSME");
  86         } catch (NoSuchMethodError nsme) {
  87             System.out.println("Received expected NSME");
  88         }
  89         try {
  90             h.barMH();  // call through MethodHandle for deleted Method
  91             throw new RuntimeException("Failed, expected NSME");
  92         } catch (NoSuchMethodError nsme) {
  93             System.out.println("Received expected NSME");
  94         }
  95         System.out.println("Passed.");
  96     }
  97 }