blob: a4ad08846617dea7b8634f4e203e3c9607519e78 [file] [log] [blame]
stefank372a5b62013-01-22 13:53:53 +01001/*
2 * Copyright (c) 2013, 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
24import java.io.File;
25import java.io.FileInputStream;
26import java.io.InputStream;
27import java.lang.instrument.ClassDefinition;
28import java.lang.reflect.InvocationTargetException;
29import java.lang.reflect.Method;
30
31/**
32 * When an exception is thrown, the JVM collects just enough information
33 * about the stack trace to be able to create a full fledged stack trace
34 * (StackTraceElement[]). The backtrace contains this information and the
35 * JVM must make sure that the data in the backtrace is still usable after
36 * a class redefinition.
37 *
38 * After the PermGen removal there was a bug when the last reference to a Method
39 * was in the backtrace. The class of the method was kept alive, because of the
40 * mirror stored in the backtrace, but the old versions of the redefined method
41 * could be freed, since class redefinition didn't know about the backtraces.
42 */
43public class RedefineMethodInBacktraceApp {
44 public static void main(String args[]) throws Exception {
45 System.out.println("Hello from RedefineMethodInBacktraceApp!");
46
47 new RedefineMethodInBacktraceApp().doTest();
48
49 System.exit(0);
50 }
51
52 private void doTest() throws Exception {
53 doMethodInBacktraceTest();
54 }
55
56 private void doMethodInBacktraceTest() throws Exception {
57 Throwable t = getThrowableFromMethodToRedefine();
58
59 doRedefine(RedefineMethodInBacktraceTarget.class);
60
61 doClassUnloading();
62
63 touchRedefinedMethodInBacktrace(t);
64 }
65
66 private static Throwable getThrowableFromMethodToRedefine() throws Exception {
67 Class<RedefineMethodInBacktraceTarget> c =
68 RedefineMethodInBacktraceTarget.class;
69 Method method = c.getMethod("methodToRedefine");
70
71 Throwable thrownFromMethodToRedefine = null;
72 try {
73 method.invoke(null);
74 } catch (InvocationTargetException e) {
75 thrownFromMethodToRedefine = e.getCause();
76 if (!(thrownFromMethodToRedefine instanceof RuntimeException)) {
77 throw e;
78 }
79 }
80 method = null;
81 c = null;
82
83 return thrownFromMethodToRedefine;
84 }
85
86 private static void doClassUnloading() {
87 // This will clean out old, unused redefined methods.
88 System.gc();
89 }
90
91 private static void touchRedefinedMethodInBacktrace(Throwable throwable) {
92 // Make sure that we can convert the backtrace, which is referring to
93 // the redefined method, to a StrackTraceElement[] without crashing.
94 throwable.getStackTrace();
95 }
96
97 private static void doRedefine(Class<?> clazz) throws Exception {
98 // Load the second version of this class.
99 File f = new File(clazz.getName() + ".class");
100 System.out.println("Reading test class from " + f.getAbsolutePath());
101 InputStream redefineStream = new FileInputStream(f);
102
103 byte[] redefineBuffer = NamedBuffer.loadBufferFromStream(redefineStream);
104
105 ClassDefinition redefineParamBlock = new ClassDefinition(
106 clazz, redefineBuffer);
107
108 RedefineMethodInBacktraceAgent.getInstrumentation().redefineClasses(
109 new ClassDefinition[] {redefineParamBlock});
110 }
111}