Path: blob/master/test/hotspot/jtreg/compiler/cha/Utils.java
41149 views
/*1* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/22package compiler.cha;2324import jdk.internal.misc.Unsafe;25import jdk.internal.org.objectweb.asm.ClassWriter;26import jdk.internal.org.objectweb.asm.MethodVisitor;27import jdk.internal.vm.annotation.DontInline;28import sun.hotspot.WhiteBox;29import sun.hotspot.code.NMethod;3031import java.io.IOException;32import java.lang.annotation.Retention;33import java.lang.annotation.RetentionPolicy;34import java.lang.invoke.MethodHandle;35import java.lang.invoke.MethodHandles;36import java.lang.reflect.Method;37import java.util.HashMap;38import java.util.concurrent.Callable;3940import static jdk.internal.org.objectweb.asm.ClassWriter.COMPUTE_FRAMES;41import static jdk.internal.org.objectweb.asm.ClassWriter.COMPUTE_MAXS;42import static jdk.internal.org.objectweb.asm.Opcodes.*;43import static jdk.test.lib.Asserts.assertTrue;4445public class Utils {46public static final Unsafe U = Unsafe.getUnsafe();4748interface Test<T> {49void call(T o);50T receiver(int id);5152default Runnable monomophic() {53return () -> {54call(receiver(0)); // 100%55};56}5758default Runnable bimorphic() {59return () -> {60call(receiver(0)); // 50%61call(receiver(1)); // 50%62};63}6465default Runnable polymorphic() {66return () -> {67for (int i = 0; i < 23; i++) {68call(receiver(0)); // 92%69}70call(receiver(1)); // 4%71call(receiver(2)); // 4%72};73}7475default Runnable megamorphic() {76return () -> {77call(receiver(0)); // 33%78call(receiver(1)); // 33%79call(receiver(2)); // 33%80};81}8283default void load(Class<?>... cs) {84// nothing to do85}8687default void initialize(Class<?>... cs) {88for (Class<?> c : cs) {89U.ensureClassInitialized(c);90}91}9293default void repeat(int cnt, Runnable r) {94for (int i = 0; i < cnt; i++) {95r.run();96}97}98}99100public static abstract class ATest<T> implements Test<T> {101public static final WhiteBox WB = WhiteBox.getWhiteBox();102103public static final Object CORRECT = new Object();104public static final Object WRONG = new Object();105106final Method TEST;107private final Class<T> declared;108private final Class<?> receiver;109110private final HashMap<Integer, T> receivers = new HashMap<>();111112public ATest(Class<T> declared, Class<?> receiver) {113this.declared = declared;114this.receiver = receiver;115TEST = compute(() -> this.getClass().getDeclaredMethod("test", declared));116}117118@DontInline119public abstract Object test(T i);120121public abstract void checkInvalidReceiver();122123public T receiver(int id) {124return receivers.computeIfAbsent(id, (i -> {125try {126MyClassLoader cl = (MyClassLoader) receiver.getClassLoader();127Class<?> sub = cl.subclass(receiver, i);128return (T)sub.getDeclaredConstructor().newInstance();129} catch (Exception e) {130throw new Error(e);131}132}));133}134135136public void compile(Runnable r) {137while (!WB.isMethodCompiled(TEST)) {138for (int i = 0; i < 100; i++) {139r.run();140}141}142assertCompiled(); // record nmethod info143}144145private NMethod prevNM = null;146147public void assertNotCompiled() {148NMethod curNM = NMethod.get(TEST, false);149assertTrue(prevNM != null); // was previously compiled150assertTrue(curNM == null || prevNM.compile_id != curNM.compile_id); // either no nmethod present or recompiled151prevNM = curNM; // update nmethod info152}153154public void assertCompiled() {155NMethod curNM = NMethod.get(TEST, false);156assertTrue(curNM != null); // nmethod is present157assertTrue(prevNM == null || prevNM.compile_id == curNM.compile_id); // no recompilations if nmethod present158prevNM = curNM; // update nmethod info159}160161@Override162public void call(T i) {163assertTrue(test(i) != WRONG);164}165}166167@Retention(value = RetentionPolicy.RUNTIME)168public @interface TestCase {}169170static void run(Class<?> test) {171try {172for (Method m : test.getDeclaredMethods()) {173if (m.isAnnotationPresent(TestCase.class)) {174System.out.println(m.toString());175ClassLoader cl = new MyClassLoader(test);176Class<?> c = cl.loadClass(test.getName());177c.getMethod(m.getName()).invoke(c.getDeclaredConstructor().newInstance());178}179}180} catch (Exception e) {181throw new Error(e);182}183}184185static class ObjectToStringHelper {186static Object testHelper(Object o) {187throw new Error("not used");188}189}190static class ObjectHashCodeHelper {191static int testHelper(Object o) {192throw new Error("not used");193}194}195196static final class MyClassLoader extends ClassLoader {197private final Class<?> test;198199MyClassLoader(Class<?> test) {200this.test = test;201}202203static String intl(String s) {204return s.replace('.', '/');205}206207Class<?> subclass(Class<?> c, int id) {208String name = c.getName() + id;209Class<?> sub = findLoadedClass(name);210if (sub == null) {211ClassWriter cw = new ClassWriter(COMPUTE_MAXS | COMPUTE_FRAMES);212cw.visit(52, ACC_PUBLIC | ACC_SUPER, intl(name), null, intl(c.getName()), null);213214{ // Default constructor: <init>()V215MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);216mv.visitCode();217mv.visitVarInsn(ALOAD, 0);218mv.visitMethodInsn(INVOKESPECIAL, intl(c.getName()), "<init>", "()V", false);219mv.visitInsn(RETURN);220mv.visitMaxs(0, 0);221mv.visitEnd();222}223224byte[] classFile = cw.toByteArray();225return defineClass(name, classFile, 0, classFile.length);226}227return sub;228}229230protected Class<?> loadClass(String name, boolean resolve)231throws ClassNotFoundException232{233// First, check if the class has already been loaded234Class<?> c = findLoadedClass(name);235if (c == null) {236try {237c = getParent().loadClass(name);238if (name.endsWith("ObjectToStringHelper")) {239ClassWriter cw = new ClassWriter(COMPUTE_MAXS | COMPUTE_FRAMES);240cw.visit(52, ACC_PUBLIC | ACC_SUPER, intl(name), null, "java/lang/Object", null);241242{243MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "testHelper", "(Ljava/lang/Object;)Ljava/lang/Object;", null, null);244mv.visitCode();245mv.visitVarInsn(ALOAD, 0);246mv.visitMethodInsn(INVOKEINTERFACE, intl(test.getName()) + "$I", "toString", "()Ljava/lang/String;", true);247mv.visitInsn(ARETURN);248mv.visitMaxs(0, 0);249mv.visitEnd();250}251252byte[] classFile = cw.toByteArray();253return defineClass(name, classFile, 0, classFile.length);254} else if (name.endsWith("ObjectHashCodeHelper")) {255ClassWriter cw = new ClassWriter(COMPUTE_MAXS | COMPUTE_FRAMES);256cw.visit(52, ACC_PUBLIC | ACC_SUPER, intl(name), null, "java/lang/Object", null);257258{259MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "testHelper", "(Ljava/lang/Object;)I", null, null);260mv.visitCode();261mv.visitVarInsn(ALOAD, 0);262mv.visitMethodInsn(INVOKEINTERFACE, intl(test.getName()) + "$I", "hashCode", "()I", true);263mv.visitInsn(IRETURN);264mv.visitMaxs(0, 0);265mv.visitEnd();266}267268byte[] classFile = cw.toByteArray();269return defineClass(name, classFile, 0, classFile.length);270} else if (c == test || name.startsWith(test.getName())) {271try {272String path = name.replace('.', '/') + ".class";273byte[] classFile = getParent().getResourceAsStream(path).readAllBytes();274return defineClass(name, classFile, 0, classFile.length);275} catch (IOException e) {276throw new Error(e);277}278}279} catch (ClassNotFoundException e) {280// ClassNotFoundException thrown if class not found281// from the non-null parent class loader282}283284if (c == null) {285// If still not found, then invoke findClass in order286// to find the class.287c = findClass(name);288}289}290if (resolve) {291resolveClass(c);292}293return c;294}295}296297public interface RunnableWithException {298void run() throws Throwable;299}300301public static void shouldThrow(Class<? extends Throwable> expectedException, RunnableWithException r) {302try {303r.run();304throw new AssertionError("Exception not thrown: " + expectedException.getName());305} catch(Throwable e) {306if (expectedException == e.getClass()) {307// success: proper exception is thrown308} else {309throw new Error(expectedException.getName() + " is expected", e);310}311}312}313314public static MethodHandle unsafeCastMH(Class<?> cls) {315try {316MethodHandle mh = MethodHandles.identity(Object.class);317return MethodHandles.explicitCastArguments(mh, mh.type().changeReturnType(cls));318} catch (Throwable e) {319throw new Error(e);320}321}322323static <T> T compute(Callable<T> c) {324try {325return c.call();326} catch (Exception e) {327throw new Error(e);328}329}330}331332333