jdk-24/test/hotspot/jtreg/vmTestbase/vm/runtime/defmeth/RedefineTest.java
Vladimir Ivanov 229a6e2f36 8267095: Miscellaneous cleanups in vm.runtime.defmeth tests
Reviewed-by: dholmes, hseigel
2021-06-01 11:09:35 +00:00

256 lines
9.1 KiB
Java

/*
* Copyright (c) 2013, 2021, 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.
*/
/*
* @test
*
* @modules java.base/jdk.internal.org.objectweb.asm:+open java.base/jdk.internal.org.objectweb.asm.util:+open
* @library /vmTestbase /test/lib
*
* @comment build retransform.jar in current dir
* @run driver vm.runtime.defmeth.shared.BuildJar
*
* @run driver jdk.test.lib.FileInstaller . .
* @run main/othervm/native
* -agentlib:redefineClasses
* -javaagent:retransform.jar
* vm.runtime.defmeth.RedefineTest
*/
package vm.runtime.defmeth;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import nsk.share.Pair;
import vm.runtime.defmeth.shared.DefMethTest;
import vm.runtime.defmeth.shared.DefMethTestFailure;
import vm.runtime.defmeth.shared.MemoryClassLoader;
import vm.runtime.defmeth.shared.annotation.NotApplicableFor;
import vm.runtime.defmeth.shared.builder.TestBuilder;
import vm.runtime.defmeth.shared.executor.TestExecutor;
import vm.runtime.defmeth.shared.data.Clazz;
import vm.runtime.defmeth.shared.data.ConcreteClass;
import vm.runtime.defmeth.shared.data.Interface;
import vm.runtime.defmeth.shared.data.Tester;
import static jdk.internal.org.objectweb.asm.Opcodes.*;
import static vm.runtime.defmeth.shared.ExecutionMode.*;
/*
* Basic scenarios on class redefinition.
*/
public class RedefineTest extends DefMethTest {
public static void main(String[] args) {
DefMethTest.runTest(RedefineTest.class,
/* majorVer */ Set.of(MIN_MAJOR_VER, MAX_MAJOR_VER),
/* flags */ Set.of(0, ACC_SYNCHRONIZED),
/* redefine */ Set.of(true),
/* execMode */ Set.of(DIRECT, INVOKE_EXACT, INVOKE_GENERIC, INDY));
}
@Override
protected void configure() {
// There are no testers being generated for reflection-based scenarios,
// so scenarios on class redefinition don't work
String mode = factory.getExecutionMode();
if ("REFLECTION".equals(mode) || "INVOKE_WITH_ARGS".equals(mode)) {
getLog().warn("RedefineTest isn't applicable to reflection-based execution scenario (REDEFINE & INVOKE_WITH_ARGS).");
}
}
/**
* Run test {@code b1} w/ redefined {@code classes} from {@code b2}.
*
* @param b1
* @param b2
* @param classes
*/
private void redefineAndRun(TestBuilder b1, TestBuilder b2, Clazz... classes) {
TestExecutor executor = b1.prepare();
getLog().info("Before");
List<Pair<Tester,Throwable>> errorsBefore =
executor.run(); // run b1
// redefine in b1
MemoryClassLoader cl = executor.getLoader(); // b1.cl
Map<String,byte[]> cf = b2.produce(); //
Map<String,byte[]> forRedef = new HashMap<>();
for (Clazz clz : classes) {
String name = clz.name();
forRedef.put(name, cf.get(name));
}
cl.modifyClasses(forRedef, factory.isRetransformClasses());
getLog().info("After");
List<Pair<Tester,Throwable>> errorsAfter =
executor.run();
if (!errorsBefore.isEmpty()) {
throw new DefMethTestFailure(errorsBefore);
}
if (!errorsAfter.isEmpty()) {
throw new DefMethTestFailure(errorsAfter);
}
}
/*
* Before redefinition:
* interface I { public int m() { return 1; } }
* class C extends I { public int m() { return 2; } }
*
* TEST: I i = new C(); i.m() == 2
* TEST: C c = new C(); c.m() == 2
*
* After redefinition:
* interface I { public int m() { return 1; } }
* class C extends I { public int m() { return 3; } }
*
* TEST: I i = new C(); i.m() == 3
* TEST: C c = new C(); c.m() == 3
*/
@NotApplicableFor(modes = { REFLECTION, INVOKE_WITH_ARGS }) // reflection-based scenarios rely on checks in bytecode
public void testRedefineConcreteMethod() {
TestBuilder before = factory.getBuilder();
{ // Before redefinition
Interface I = before.intf("I")
.defaultMethod("m", "()I").returns(1).build()
.build();
ConcreteClass C = before.clazz("C").implement(I)
.concreteMethod("m", "()I").returns(2).build()
.build();
before.test().callSite(I, C, "m", "()I").returns(2).done()
.test().callSite(C, C, "m", "()I").returns(2).done();
}
{ // After redefinition
TestBuilder after = factory.getBuilder();
Interface I = after.intf("I")
.defaultMethod("m", "()I").returns(1).build()
.build();
ConcreteClass C = after.clazz("C").implement(I)
.concreteMethod("m", "()I").returns(3).build()
.build();
Tester T1 = after.test().callSite(I, C, "m", "()I").returns(3).build();
Tester T2 = after.test().callSite(C, C, "m", "()I").returns(3).build();
redefineAndRun(before, after, C, T1, T2);
}
}
/*
* Before redefinition:
* interface I { public int m() { return 1; } }
* class C extends I { public int m() { return 2; } }
*
* TEST: I i = new C(); i.m() == 2
* TEST: C c = new C(); c.m() == 2
*
* After redefinition:
* interface I { public int m() { return 3; } }
* class C extends I { public int m() { return 2; } }
*
* TEST: I i = new C(); i.m() == 2
* TEST: C c = new C(); c.m() == 2
*/
@NotApplicableFor(modes = { REFLECTION, INVOKE_WITH_ARGS }) // reflection-based scenarios rely on checks in bytecode
public void testRedefineDefaultMethod() {
TestBuilder before = factory.getBuilder();
{ // Before redefinition
Interface I = before.intf("I")
.defaultMethod("m", "()I").returns(1).build()
.build();
ConcreteClass C = before.clazz("C").implement(I)
.concreteMethod("m", "()I").returns(2).build()
.build();
before.test().callSite(I, C, "m", "()I").returns(2).done()
.test().callSite(C, C, "m", "()I").returns(2).done();
}
{ // After redefinition
TestBuilder after = factory.getBuilder();
Interface I = after.intf("I")
.defaultMethod("m", "()I").returns(3).build()
.build();
ConcreteClass C = after.clazz("C").implement(I)
.concreteMethod("m", "()I").returns(2).build()
.build();
redefineAndRun(before, after, C);
}
}
/*
* Before redefinition:
* interface I { public int m() { return 1; } }
* class C extends I {}
*
* TEST: I i = new C(); i.m() == 1
* TEST: C c = new C(); c.m() == 1
*
* After redefinition:
* interface I { public int m() { return 2; } }
* class C extends I {}
*
* TEST: I i = new C(); i.m() == 2
* TEST: C c = new C(); c.m() == 2
*/
@NotApplicableFor(modes = { REFLECTION, INVOKE_WITH_ARGS }) // reflection-based scenarios rely on checks in bytecode
public void testRedefineDefMethInConcreteClass() {
TestBuilder before = factory.getBuilder();
{ // Before redefinition
Interface I = before.intf("I")
.defaultMethod("m", "()I").returns(1).build()
.build();
ConcreteClass C = before.clazz("C").implement(I).build();
before.test().callSite(I, C, "m", "()I").returns(1).done()
.test().callSite(C, C, "m", "()I").returns(1).done();
}
{ // After redefinition
TestBuilder after = factory.getBuilder();
Interface I = after.intf("I")
.defaultMethod("m", "()I").returns(2).build()
.build();
ConcreteClass C = after.clazz("C").implement(I).build();
Tester T1 = after.test().callSite(I, C, "m", "()I").returns(2).build();
Tester T2 = after.test().callSite(C, C, "m", "()I").returns(2).build();
redefineAndRun(before, after, I, T1, T2);
}
}
}