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