This commit is contained in:
Vladimir Kozlov 2014-07-11 14:32:02 -07:00
commit 009f0fb913
8 changed files with 236 additions and 4 deletions

View File

@ -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();

View File

@ -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();
}
};

View File

@ -0,0 +1,4 @@
public class A {
void m() {
}
}

View File

@ -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);
}
}

View File

@ -0,0 +1,5 @@
public class B extends A {
void m() {
}
}

View File

@ -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();
}
}

View File

@ -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();
}