1 /*
2  * Copyright (c) 2014, 2020, 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 package compiler.profiling.spectrapredefineclass_classloaders;
25 
26 import com.sun.tools.attach.VirtualMachine;
27 import jdk.test.lib.Utils;
28 
29 import java.lang.instrument.ClassFileTransformer;
30 import java.lang.instrument.Instrumentation;
31 import java.lang.reflect.Method;
32 import java.net.MalformedURLException;
33 import java.net.URL;
34 import java.net.URLClassLoader;
35 import java.nio.file.Path;
36 import java.nio.file.Paths;
37 import java.security.ProtectionDomain;
38 
39 public class Agent implements ClassFileTransformer {
40     public static final String AGENT_JAR = Paths.get(Utils.TEST_CLASSES, "agent.jar").toString();
newClassLoader()41     public static ClassLoader newClassLoader() {
42         try {
43             return new URLClassLoader(new URL[] {
44                     Paths.get(Utils.TEST_CLASSES).toUri().toURL(),
45             }, null);
46         } catch (MalformedURLException e){
47             throw new RuntimeException("Unexpected URL conversion failure", e);
48         }
49     }
50 
51     static public Class Test_class;
52 
main(String[] args)53     static public void main(String[] args) throws Exception {
54 
55         // loader2 must be first on the list so loader 1 must be used first
56         ClassLoader loader1 = newClassLoader();
57         String packageName = Agent.class.getPackage().getName();
58         Class dummy = loader1.loadClass(packageName + ".Test");
59 
60         ClassLoader loader2 = newClassLoader();
61 
62         Test_class = loader2.loadClass(packageName + ".Test");
63         Method m3 = Test_class.getMethod("m3", ClassLoader.class);
64         // Add speculative trap in m2() (loaded by loader1) that
65         // references m4() (loaded by loader2).
66         m3.invoke(Test_class.newInstance(), loader1);
67 
68         String pid = Long.toString(ProcessHandle.current().pid());
69 
70         // Make the nmethod go away
71         for (int i = 0; i < 10; i++) {
72             System.gc();
73         }
74 
75         // Redefine class Test loaded by loader2
76         for (int i = 0; i < 2; i++) {
77             try {
78                 VirtualMachine vm = VirtualMachine.attach(pid);
79                 vm.loadAgent(AGENT_JAR, "");
80                 vm.detach();
81             } catch (Exception e) {
82                 throw new RuntimeException(e);
83             }
84         }
85         // Will process loader2 first, find m4() is redefined and
86         // needs to be freed then process loader1, check the
87         // speculative trap in m2() and try to access m4() which was
88         // freed already.
89         for (int i = 0; i < 10; i++) {
90             System.gc();
91         }
92     }
93 
transform(final ClassLoader classLoader, final String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer)94     public synchronized byte[] transform(final ClassLoader classLoader,
95                                          final String className,
96                                          Class<?> classBeingRedefined,
97                                          ProtectionDomain protectionDomain,
98                                          byte[] classfileBuffer) {
99         System.out.println("Transforming class " + className + " "+ classLoader);
100         return classfileBuffer;
101     }
102 
redefine(String agentArgs, Instrumentation instrumentation, Class to_redefine)103     public static void redefine(String agentArgs, Instrumentation instrumentation, Class to_redefine) {
104 
105         try {
106             instrumentation.retransformClasses(to_redefine);
107         } catch (Exception e) {
108             e.printStackTrace();
109         }
110 
111     }
112 
agentmain(String agentArgs, Instrumentation instrumentation)113     public static void agentmain(String agentArgs, Instrumentation instrumentation) throws Exception {
114         Agent transformer = new Agent();
115         instrumentation.addTransformer(transformer, true);
116 
117         redefine(agentArgs, instrumentation, Test_class);
118     }
119 }
120