Merge
This commit is contained in:
commit
009f0fb913
@ -777,11 +777,22 @@ bool ClassLoaderDataGraph::do_unloading(BoolObjectClosure* is_alive_closure) {
|
||||
// unneeded entries.
|
||||
bool has_redefined_a_class = JvmtiExport::has_redefined_a_class();
|
||||
MetadataOnStackMark md_on_stack;
|
||||
while (data != NULL) {
|
||||
if (data->is_alive(is_alive_closure)) {
|
||||
if (has_redefined_a_class) {
|
||||
if (has_redefined_a_class) {
|
||||
// purge_previous_versions also cleans weak method links. Because
|
||||
// one method's MDO can reference another method from another
|
||||
// class loader, we need to first clean weak method links for all
|
||||
// class loaders here. Below, we can then free redefined methods
|
||||
// for all class loaders.
|
||||
while (data != NULL) {
|
||||
if (data->is_alive(is_alive_closure)) {
|
||||
data->classes_do(InstanceKlass::purge_previous_versions);
|
||||
}
|
||||
data = data->next();
|
||||
}
|
||||
}
|
||||
data = _head;
|
||||
while (data != NULL) {
|
||||
if (data->is_alive(is_alive_closure)) {
|
||||
data->free_deallocate_list();
|
||||
prev = data;
|
||||
data = data->next();
|
||||
|
@ -1556,7 +1556,7 @@ class CleanExtraDataMethodClosure : public CleanExtraDataClosure {
|
||||
public:
|
||||
CleanExtraDataMethodClosure() {}
|
||||
bool is_live(Method* m) {
|
||||
return m->on_stack();
|
||||
return !m->is_old() || m->on_stack();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -0,0 +1,4 @@
|
||||
public class A {
|
||||
void m() {
|
||||
}
|
||||
}
|
@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import java.security.*;
|
||||
import java.lang.instrument.*;
|
||||
import java.lang.reflect.*;
|
||||
import java.lang.management.ManagementFactory;
|
||||
import com.sun.tools.attach.VirtualMachine;
|
||||
import java.lang.reflect.*;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
public class Agent implements ClassFileTransformer {
|
||||
public static ClassLoader newClassLoader() {
|
||||
try {
|
||||
return new URLClassLoader(new URL[] {
|
||||
Paths.get(System.getProperty("test.classes",".")).toUri().toURL(),
|
||||
}, null);
|
||||
} catch (MalformedURLException e){
|
||||
throw new RuntimeException("Unexpected URL conversion failure", e);
|
||||
}
|
||||
}
|
||||
|
||||
static public Class Test_class;
|
||||
|
||||
static public void main(String[] args) throws Exception {
|
||||
|
||||
// loader2 must be first on the list so loader 1 must be used first
|
||||
ClassLoader loader1 = newClassLoader();
|
||||
Class dummy = loader1.loadClass("Test");
|
||||
|
||||
ClassLoader loader2 = newClassLoader();
|
||||
|
||||
Test_class = loader2.loadClass("Test");
|
||||
Method m3 = Test_class.getMethod("m3", ClassLoader.class);
|
||||
// Add speculative trap in m2() (loaded by loader1) that
|
||||
// references m4() (loaded by loader2).
|
||||
m3.invoke(Test_class.newInstance(), loader1);
|
||||
|
||||
String nameOfRunningVM = ManagementFactory.getRuntimeMXBean().getName();
|
||||
int p = nameOfRunningVM.indexOf('@');
|
||||
String pid = nameOfRunningVM.substring(0, p);
|
||||
|
||||
// Make the nmethod go away
|
||||
for (int i = 0; i < 10; i++) {
|
||||
System.gc();
|
||||
}
|
||||
|
||||
// Redefine class Test loaded by loader2
|
||||
for (int i = 0; i < 2; i++) {
|
||||
try {
|
||||
VirtualMachine vm = VirtualMachine.attach(pid);
|
||||
vm.loadAgent(System.getProperty("test.classes",".") + "/agent.jar", "");
|
||||
vm.detach();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
// Will process loader2 first, find m4() is redefined and
|
||||
// needs to be freed then process loader1, check the
|
||||
// speculative trap in m2() and try to access m4() which was
|
||||
// freed already.
|
||||
for (int i = 0; i < 10; i++) {
|
||||
System.gc();
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized byte[] transform(final ClassLoader classLoader,
|
||||
final String className,
|
||||
Class<?> classBeingRedefined,
|
||||
ProtectionDomain protectionDomain,
|
||||
byte[] classfileBuffer) {
|
||||
System.out.println("Transforming class " + className + " "+ classLoader);
|
||||
return classfileBuffer;
|
||||
}
|
||||
|
||||
public static void redefine(String agentArgs, Instrumentation instrumentation, Class to_redefine) {
|
||||
|
||||
try {
|
||||
instrumentation.retransformClasses(to_redefine);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void agentmain(String agentArgs, Instrumentation instrumentation) throws Exception {
|
||||
Agent transformer = new Agent();
|
||||
instrumentation.addTransformer(transformer, true);
|
||||
|
||||
redefine(agentArgs, instrumentation, Test_class);
|
||||
}
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
public class B extends A {
|
||||
void m() {
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
import java.io.PrintWriter;
|
||||
import com.oracle.java.testlibrary.*;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8040237
|
||||
* @library /testlibrary
|
||||
* @build Agent Test A B
|
||||
* @run main ClassFileInstaller Agent
|
||||
* @run main Launcher
|
||||
* @run main/othervm -XX:-TieredCompilation -XX:-BackgroundCompilation -XX:-UseOnStackReplacement -XX:TypeProfileLevel=222 -XX:ReservedCodeCacheSize=3M Agent
|
||||
*/
|
||||
public class Launcher {
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
||||
PrintWriter pw = new PrintWriter("MANIFEST.MF");
|
||||
pw.println("Agent-Class: Agent");
|
||||
pw.println("Can-Retransform-Classes: true");
|
||||
pw.close();
|
||||
|
||||
ProcessBuilder pb = new ProcessBuilder();
|
||||
pb.command(new String[] { JDKToolFinder.getJDKTool("jar"), "cmf", "MANIFEST.MF", System.getProperty("test.classes",".") + "/agent.jar", "Agent.class"});
|
||||
pb.start().waitFor();
|
||||
}
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
import java.lang.reflect.*;
|
||||
|
||||
public class Test {
|
||||
|
||||
public boolean m1(A a, Boolean early_return) {
|
||||
if (early_return.booleanValue()) return true;
|
||||
boolean res = m2(a);
|
||||
return res;
|
||||
}
|
||||
|
||||
public boolean m2(A a) {
|
||||
boolean res = false;
|
||||
if (a.getClass() == B.class) {
|
||||
a.m();
|
||||
} else {
|
||||
res = true;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
public void m3(ClassLoader loader) throws Exception {
|
||||
Class Test_class = loader.loadClass("Test");
|
||||
Object test = Test_class.newInstance();
|
||||
Class A_class = loader.loadClass("A");
|
||||
Object a = A_class.newInstance();
|
||||
Class B_class = loader.loadClass("B");
|
||||
Object b = B_class.newInstance();
|
||||
Method m1 = Test_class.getMethod("m1", A_class, Boolean.class);
|
||||
|
||||
// So we don't hit uncommon trap in the next loop
|
||||
for (int i = 0; i < 4000; i++) {
|
||||
m4(m1, test, a, Boolean.TRUE);
|
||||
m4(m1, test, b, Boolean.TRUE);
|
||||
}
|
||||
for (int i = 0; i < 20000; i++) {
|
||||
m4(m1, test, a, Boolean.FALSE);
|
||||
}
|
||||
for (int i = 0; i < 4; i++) {
|
||||
m4(m1, test, b, Boolean.FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
public Object m4(Method m, Object test, Object a, Object early_return) throws Exception {
|
||||
return m.invoke(test, a, early_return);
|
||||
}
|
||||
|
||||
static public A a = new A();
|
||||
static public B b = new B();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user