Path: blob/master/test/hotspot/jtreg/compiler/cha/Utils.java
64474 views
/*1* Copyright (c) 2021, 2022, 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.invoke.MethodType;37import java.lang.reflect.Method;38import java.util.HashMap;39import java.util.concurrent.Callable;4041import static jdk.internal.org.objectweb.asm.ClassWriter.COMPUTE_FRAMES;42import static jdk.internal.org.objectweb.asm.ClassWriter.COMPUTE_MAXS;43import static jdk.internal.org.objectweb.asm.Opcodes.*;44import static jdk.test.lib.Asserts.assertTrue;4546public class Utils {47public static final Unsafe U = Unsafe.getUnsafe();48public static final WhiteBox WB = WhiteBox.getWhiteBox();4950interface Test<T> {51void call(T o);52T receiver(int id);5354default Runnable monomophic() {55return () -> {56call(receiver(0)); // 100%57};58}5960default Runnable bimorphic() {61return () -> {62call(receiver(0)); // 50%63call(receiver(1)); // 50%64};65}6667default Runnable polymorphic() {68return () -> {69for (int i = 0; i < 23; i++) {70call(receiver(0)); // 92%71}72call(receiver(1)); // 4%73call(receiver(2)); // 4%74};75}7677default Runnable megamorphic() {78return () -> {79call(receiver(0)); // 33%80call(receiver(1)); // 33%81call(receiver(2)); // 33%82};83}8485default void load(Class<?>... cs) {86// nothing to do87}8889default void initialize(Class<?>... cs) {90for (Class<?> c : cs) {91U.ensureClassInitialized(c);92}93}9495default void repeat(int cnt, Runnable r) {96for (int i = 0; i < cnt; i++) {97r.run();98}99}100}101102public static abstract class ATest<T> implements Test<T> {103public 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) throws Throwable;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}134135public void compile(Runnable r) {136while (!WB.isMethodCompiled(TEST)) {137for (int i = 0; i < 100; i++) {138r.run();139}140}141assertCompiled(); // record nmethod info142}143144private NMethod prevNM = null;145146public void assertNotCompiled() {147NMethod curNM = NMethod.get(TEST, false);148assertTrue(prevNM != null); // was previously compiled149assertTrue(curNM == null || prevNM.compile_id != curNM.compile_id); // either no nmethod present or recompiled150prevNM = curNM; // update nmethod info151}152153public void assertCompiled() {154NMethod curNM = NMethod.get(TEST, false);155assertTrue(curNM != null); // nmethod is present156assertTrue(prevNM == null || prevNM.compile_id == curNM.compile_id); // no recompilations if nmethod present157prevNM = curNM; // update nmethod info158}159160@Override161public void call(T i) {162try {163assertTrue(test(i) != WRONG);164} catch (Throwable e) {165throw new InternalError(e);166}167}168169public static <T> T compute(Callable<T> c) {170try {171return c.call();172} catch (Exception e) {173throw new Error(e);174}175}176177public static MethodHandle findVirtualHelper(Class<?> refc, String name, Class<?> returnType, MethodHandles.Lookup lookup) {178return compute(() -> lookup.findVirtual(refc, name, MethodType.methodType(returnType)));179}180}181182@Retention(value = RetentionPolicy.RUNTIME)183public @interface TestCase {}184185static void run(Class<?> test, Class<?> enclosed) {186try {187for (Method m : test.getMethods()) {188if (m.isAnnotationPresent(TestCase.class)) {189System.out.println(m.toString());190ClassLoader cl = new MyClassLoader(enclosed);191Class<?> c = cl.loadClass(test.getName());192c.getMethod(m.getName()).invoke(c.getDeclaredConstructor().newInstance());193}194}195} catch (Exception e) {196throw new Error(e);197}198}199200static void run(Class<?> test) {201run(test, test);202}203204static class ObjectToStringHelper {205static Object testHelper(Object o) {206throw new Error("not used");207}208}209static class ObjectHashCodeHelper {210static int testHelper(Object o) {211throw new Error("not used");212}213}214215static final class MyClassLoader extends ClassLoader {216private final Class<?> test;217218MyClassLoader(Class<?> test) {219this.test = test;220}221222static String intl(String s) {223return s.replace('.', '/');224}225226Class<?> subclass(Class<?> c, int id) {227String name = c.getName() + id;228Class<?> sub = findLoadedClass(name);229if (sub == null) {230ClassWriter cw = new ClassWriter(COMPUTE_MAXS | COMPUTE_FRAMES);231cw.visit(52, ACC_PUBLIC | ACC_SUPER, intl(name), null, intl(c.getName()), null);232233{ // Default constructor: <init>()V234MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);235mv.visitCode();236mv.visitVarInsn(ALOAD, 0);237mv.visitMethodInsn(INVOKESPECIAL, intl(c.getName()), "<init>", "()V", false);238mv.visitInsn(RETURN);239mv.visitMaxs(0, 0);240mv.visitEnd();241}242243byte[] classFile = cw.toByteArray();244return defineClass(name, classFile, 0, classFile.length);245}246return sub;247}248249protected Class<?> loadClass(String name, boolean resolve)250throws ClassNotFoundException251{252// First, check if the class has already been loaded253Class<?> c = findLoadedClass(name);254if (c == null) {255try {256c = getParent().loadClass(name);257if (name.endsWith("ObjectToStringHelper")) {258ClassWriter cw = new ClassWriter(COMPUTE_MAXS | COMPUTE_FRAMES);259cw.visit(52, ACC_PUBLIC | ACC_SUPER, intl(name), null, "java/lang/Object", null);260261{262MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "testHelper", "(Ljava/lang/Object;)Ljava/lang/Object;", null, null);263mv.visitCode();264mv.visitVarInsn(ALOAD, 0);265mv.visitMethodInsn(INVOKEINTERFACE, intl(test.getName()) + "$I", "toString", "()Ljava/lang/String;", true);266mv.visitInsn(ARETURN);267mv.visitMaxs(0, 0);268mv.visitEnd();269}270271byte[] classFile = cw.toByteArray();272return defineClass(name, classFile, 0, classFile.length);273} else if (name.endsWith("ObjectHashCodeHelper")) {274ClassWriter cw = new ClassWriter(COMPUTE_MAXS | COMPUTE_FRAMES);275cw.visit(52, ACC_PUBLIC | ACC_SUPER, intl(name), null, "java/lang/Object", null);276277{278MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "testHelper", "(Ljava/lang/Object;)I", null, null);279mv.visitCode();280mv.visitVarInsn(ALOAD, 0);281mv.visitMethodInsn(INVOKEINTERFACE, intl(test.getName()) + "$I", "hashCode", "()I", true);282mv.visitInsn(IRETURN);283mv.visitMaxs(0, 0);284mv.visitEnd();285}286287byte[] classFile = cw.toByteArray();288return defineClass(name, classFile, 0, classFile.length);289} else if (c == test || name.startsWith(test.getName())) {290try {291String path = name.replace('.', '/') + ".class";292byte[] classFile = getParent().getResourceAsStream(path).readAllBytes();293return defineClass(name, classFile, 0, classFile.length);294} catch (IOException e) {295throw new Error(e);296}297}298} catch (ClassNotFoundException e) {299// ClassNotFoundException thrown if class not found300// from the non-null parent class loader301}302303if (c == null) {304// If still not found, then invoke findClass in order305// to find the class.306c = findClass(name);307}308}309if (resolve) {310resolveClass(c);311}312return c;313}314}315316public interface RunnableWithException {317void run() throws Throwable;318}319320public static void shouldThrow(Class<? extends Throwable> expectedException, RunnableWithException r) {321try {322r.run();323throw new AssertionError("Exception not thrown: " + expectedException.getName());324} catch (Throwable e) {325if (expectedException == e.getClass()) {326// success: proper exception is thrown327} else {328throw new Error(expectedException.getName() + " is expected", e);329}330}331}332333public static MethodHandle unsafeCastMH(Class<?> cls) {334try {335MethodHandle mh = MethodHandles.identity(Object.class);336return MethodHandles.explicitCastArguments(mh, mh.type().changeReturnType(cls));337} catch (Throwable e) {338throw new Error(e);339}340}341}342343344