1 /*
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
24 import com.sun.management.DiagnosticCommandMBean;
25 import java.io.File;
26 import java.io.FileInputStream;
27 import java.io.InputStream;
28 import java.lang.instrument.ClassDefinition;
29 import java.lang.management.ManagementFactory;
30 import java.lang.management.ThreadInfo;
31 import java.lang.reflect.InvocationTargetException;
32 import java.lang.reflect.Method;
33 import java.util.concurrent.CountDownLatch;
34 import sun.management.ManagementFactoryHelper;
35
36 /**
37 * When an exception is thrown, the JVM collects just enough information
38 * about the stack trace to be able to create a full fledged stack trace
39 * (StackTraceElement[]). The backtrace contains this information and the
40 * JVM must make sure that the data in the backtrace is still usable after
41 * a class redefinition.
42 *
43 * After the PermGen removal there was a bug when the last reference to a Method
44 * was in the backtrace. The class of the method was kept alive, because of the
45 * mirror stored in the backtrace, but the old versions of the redefined method
46 * could be freed, since class redefinition didn't know about the backtraces.
47 */
48 public class RedefineMethodInBacktraceApp {
49 public static void main(String args[]) throws Exception {
50 System.out.println("Hello from RedefineMethodInBacktraceApp!");
51
52 new RedefineMethodInBacktraceApp().doTest();
53
54 System.exit(0);
75 private void doMethodInBacktraceTestB() throws Exception {
76 // Start a thread which blocks in method
77 Thread t = new Thread(RedefineMethodInBacktraceTargetB::methodToRedefine);
78 t.setDaemon(true);
79 t.start();
80
81 // Wait here until the new thread is in the method we want to redefine
82 called.await();
83
84 // Now redefine the class while the method is still on the stack of the new thread
85 doRedefine(RedefineMethodInBacktraceTargetB.class);
86
87 // Do thread dumps in two different ways (to exercise different code paths)
88 // while the old class is still on the stack
89
90 ThreadInfo[] tis = ManagementFactory.getThreadMXBean().dumpAllThreads(false, false);
91 for(ThreadInfo ti : tis) {
92 System.out.println(ti);
93 }
94
95 String[] threadPrintArgs = {};
96 Object[] dcmdArgs = {threadPrintArgs};
97 String[] signature = {String[].class.getName()};
98 DiagnosticCommandMBean dcmd = ManagementFactoryHelper.getDiagnosticCommandMBean();
99 System.out.println(dcmd.invoke("threadPrint", dcmdArgs, signature));
100
101 // release the thread
102 stop.countDown();
103 }
104
105 private static Throwable getThrowableFromMethodToRedefine() throws Exception {
106 Class<RedefineMethodInBacktraceTarget> c =
107 RedefineMethodInBacktraceTarget.class;
108 Method method = c.getMethod("methodToRedefine");
109
110 Throwable thrownFromMethodToRedefine = null;
111 try {
112 method.invoke(null);
113 } catch (InvocationTargetException e) {
114 thrownFromMethodToRedefine = e.getCause();
115 if (!(thrownFromMethodToRedefine instanceof RuntimeException)) {
116 throw e;
117 }
118 }
119 method = null;
|
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 import com.sun.management.DiagnosticCommandMBean;
25 import java.io.File;
26 import java.io.FileInputStream;
27 import java.io.InputStream;
28 import java.lang.instrument.ClassDefinition;
29 import java.lang.management.ManagementFactory;
30 import java.lang.management.ThreadInfo;
31 import java.lang.reflect.InvocationTargetException;
32 import java.lang.reflect.Method;
33 import java.util.concurrent.CountDownLatch;
34 import javax.management.MBeanServer;
35 import javax.management.ObjectName;
36
37 /**
38 * When an exception is thrown, the JVM collects just enough information
39 * about the stack trace to be able to create a full fledged stack trace
40 * (StackTraceElement[]). The backtrace contains this information and the
41 * JVM must make sure that the data in the backtrace is still usable after
42 * a class redefinition.
43 *
44 * After the PermGen removal there was a bug when the last reference to a Method
45 * was in the backtrace. The class of the method was kept alive, because of the
46 * mirror stored in the backtrace, but the old versions of the redefined method
47 * could be freed, since class redefinition didn't know about the backtraces.
48 */
49 public class RedefineMethodInBacktraceApp {
50 public static void main(String args[]) throws Exception {
51 System.out.println("Hello from RedefineMethodInBacktraceApp!");
52
53 new RedefineMethodInBacktraceApp().doTest();
54
55 System.exit(0);
76 private void doMethodInBacktraceTestB() throws Exception {
77 // Start a thread which blocks in method
78 Thread t = new Thread(RedefineMethodInBacktraceTargetB::methodToRedefine);
79 t.setDaemon(true);
80 t.start();
81
82 // Wait here until the new thread is in the method we want to redefine
83 called.await();
84
85 // Now redefine the class while the method is still on the stack of the new thread
86 doRedefine(RedefineMethodInBacktraceTargetB.class);
87
88 // Do thread dumps in two different ways (to exercise different code paths)
89 // while the old class is still on the stack
90
91 ThreadInfo[] tis = ManagementFactory.getThreadMXBean().dumpAllThreads(false, false);
92 for(ThreadInfo ti : tis) {
93 System.out.println(ti);
94 }
95
96 MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
97 ObjectName name = new ObjectName("com.sun.management:type=DiagnosticCommand");
98 String[] threadPrintArgs = {};
99 Object[] dcmdArgs = {threadPrintArgs};
100 String[] signature = {String[].class.getName()};
101 Object result = mbs.invoke(name, "threadPrint", dcmdArgs, signature);
102 System.out.println(result);
103
104 // release the thread
105 stop.countDown();
106 }
107
108 private static Throwable getThrowableFromMethodToRedefine() throws Exception {
109 Class<RedefineMethodInBacktraceTarget> c =
110 RedefineMethodInBacktraceTarget.class;
111 Method method = c.getMethod("methodToRedefine");
112
113 Throwable thrownFromMethodToRedefine = null;
114 try {
115 method.invoke(null);
116 } catch (InvocationTargetException e) {
117 thrownFromMethodToRedefine = e.getCause();
118 if (!(thrownFromMethodToRedefine instanceof RuntimeException)) {
119 throw e;
120 }
121 }
122 method = null;
|