diff --git a/compiler/mx.compiler/suite.py b/compiler/mx.compiler/suite.py index 5c78c8c8675d..94568ea02e03 100644 --- a/compiler/mx.compiler/suite.py +++ b/compiler/mx.compiler/suite.py @@ -294,7 +294,7 @@ "truffle:TRUFFLE_DSL_PROCESSOR" ], "checkstyle" : "jdk.graal.compiler", - "javaCompliance" : "21+", + "javaCompliance" : "23+", "jacoco" : "exclude", "graalCompilerSourceEdition": "ignore", }, @@ -335,8 +335,8 @@ }, "jacoco" : "exclude", "checkstyle": "jdk.graal.compiler", - "javaCompliance" : "21+", - "javaPreviewNeeded": "21+", + "javaCompliance" : "23+", + "javaPreviewNeeded": "23+", "workingSets" : "Graal,HotSpot,Test", "graalCompilerSourceEdition": "ignore", }, @@ -372,7 +372,7 @@ "sourceDirs" : ["src"], "dependencies" : ["mx:JMH_1_21", "jdk.graal.compiler.microbenchmarks"], "checkstyle" : "jdk.graal.compiler", - "javaCompliance" : "21+", + "javaCompliance" : "23+", "annotationProcessors" : ["mx:JMH_1_21"], "spotbugsIgnoresGenerated" : True, "workingSets" : "Graal,Bench", @@ -395,7 +395,7 @@ ], }, "checkstyle" : "jdk.graal.compiler", - "javaCompliance" : "21+", + "javaCompliance" : "23+", "checkPackagePrefix" : "false", "annotationProcessors" : ["mx:JMH_1_21"], "spotbugsIgnoresGenerated" : True, diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/CustomizedBytecodePatternTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/CustomizedBytecodePattern.java similarity index 68% rename from compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/CustomizedBytecodePatternTest.java rename to compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/CustomizedBytecodePattern.java index 705b27b9b11b..ee154b8be0dc 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/CustomizedBytecodePatternTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/CustomizedBytecodePattern.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, 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 @@ -24,39 +24,38 @@ */ package jdk.graal.compiler.core.test; +import static java.lang.classfile.ClassFile.ACC_PUBLIC; +import static java.lang.classfile.ClassFile.ACC_STATIC; + import java.io.File; import java.io.IOException; +import java.lang.constant.ClassDesc; import java.nio.file.Files; import java.util.function.Function; -import org.objectweb.asm.Opcodes; +public interface CustomizedBytecodePattern { -public abstract class CustomizedBytecodePatternTest extends GraalCompilerTest implements Opcodes { + class CachedLoader extends ClassLoader { - protected Class getClass(String className) throws ClassNotFoundException { - return new CachedLoader(CustomizedBytecodePatternTest.class.getClassLoader(), className, this::generateClass).findClass(className); - } + private static final File GENERATED_CLASS_FILE_OUTPUT_DIRECTORY; - private static final File GENERATED_CLASS_FILE_OUTPUT_DIRECTORY; - static { - String prop = System.getProperty("save.generated.classfile.dir"); - File file = null; - if (prop != null) { - file = new File(prop); - ensureDirectoryExists(file); - assert file.exists() : file; + static { + String prop = System.getProperty("save.generated.classfile.dir"); + File file = null; + if (prop != null) { + file = new File(prop); + ensureDirectoryExists(file); + assert file.exists() : file; + } + GENERATED_CLASS_FILE_OUTPUT_DIRECTORY = file; } - GENERATED_CLASS_FILE_OUTPUT_DIRECTORY = file; - } - private static File ensureDirectoryExists(File file) { - if (!file.exists()) { - file.mkdirs(); + private static File ensureDirectoryExists(File file) { + if (!file.exists()) { + file.mkdirs(); + } + return file; } - return file; - } - - public static class CachedLoader extends ClassLoader { final String className; Class loaded; @@ -72,7 +71,7 @@ public CachedLoader(ClassLoader parent, String className, Function findClass(String name) throws ClassNotFoundException { if (name.equals(className)) { if (loaded == null) { - byte[] classfileBytes = classfileSupplier.apply(name.replace('.', '/')); + byte[] classfileBytes = classfileSupplier.apply(name); if (GENERATED_CLASS_FILE_OUTPUT_DIRECTORY != null) { try { File classfile = new File(GENERATED_CLASS_FILE_OUTPUT_DIRECTORY, name.replace('.', File.separatorChar) + ".class"); @@ -90,8 +89,17 @@ public Class findClass(String name) throws ClassNotFoundException { return super.findClass(name); } } + } + + int ACC_PUBLIC_STATIC = ACC_PUBLIC | ACC_STATIC; + + default ClassDesc cd(Class klass) { + return klass.describeConstable().orElseThrow(); + } + default Class getClass(String className) throws ClassNotFoundException { + return new CachedLoader(CustomizedBytecodePattern.class.getClassLoader(), className, this::generateClass).findClass(className); } - protected abstract byte[] generateClass(String internalClassName); + byte[] generateClass(String className); } diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/DynamicConstantTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/DynamicConstantTest.java index a893b5382d52..2777436f06fd 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/DynamicConstantTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/DynamicConstantTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, 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 @@ -24,6 +24,15 @@ */ package jdk.graal.compiler.core.test; +import java.lang.classfile.ClassFile; +import java.lang.classfile.CodeBuilder; +import java.lang.classfile.TypeKind; +import java.lang.constant.ClassDesc; +import java.lang.constant.ConstantDescs; +import java.lang.constant.DirectMethodHandleDesc.Kind; +import java.lang.constant.DynamicConstantDesc; +import java.lang.constant.MethodHandleDesc; +import java.lang.constant.MethodTypeDesc; import java.lang.invoke.MethodHandles; import java.util.Arrays; import java.util.LinkedHashMap; @@ -32,11 +41,6 @@ import org.junit.Assume; import org.junit.Test; -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.ConstantDynamic; -import org.objectweb.asm.Handle; -import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Type; import jdk.vm.ci.meta.ConstantPool; import jdk.vm.ci.meta.ResolvedJavaMethod; @@ -47,13 +51,7 @@ * @see "https://openjdk.java.net/jeps/309" * @see "https://bugs.openjdk.java.net/browse/JDK-8177279" */ -public class DynamicConstantTest extends CustomizedBytecodePatternTest { - - private static final int PUBLIC_STATIC = ACC_PUBLIC | ACC_STATIC; - - static final String testClassInternalName = DynamicConstantTest.class.getName().replace('.', '/'); - static final String constantBootstrapsClassInternalName = "java/lang/invoke/ConstantBootstraps"; - +public class DynamicConstantTest extends GraalCompilerTest { /** * Map of test class generators keyed by internal class name. */ @@ -88,11 +86,11 @@ enum CondyType { * Generates a class with a static {@code run} method that returns a value loaded from * CONSTANT_Dynamic constant pool entry. */ - static class TestGenerator { + static class TestGenerator implements CustomizedBytecodePattern { /** * Type of value returned by the generated {@code run} method. */ - final Type type; + final ClassDesc type; /** * Type of condy used to produce the returned value. @@ -112,58 +110,43 @@ static class TestGenerator { TestGenerator(Class type, CondyType condyType) { String typeName = type.getSimpleName(); - this.type = Type.getType(type); + this.type = cd(type); this.condyType = condyType; this.getter = "get" + typeName.substring(0, 1).toUpperCase() + typeName.substring(1); this.className = DynamicConstantTest.class.getName() + "$" + typeName + '_' + condyType; } - void generate(ClassWriter cw) { + @Override + public byte[] generateClass(String className) { + return ClassFile.of().build(ClassDesc.of(className), classBuilder -> classBuilder + .withMethodBody("run", MethodTypeDesc.of(type), ACC_PUBLIC_STATIC, this::generate)); + } + + private void generate(CodeBuilder b) { // @formatter:off // Object ConstantBootstraps.invoke(MethodHandles.Lookup lookup, String name, Class type, MethodHandle handle, Object... args) // @formatter:on - String invokeSig = "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;Ljava/lang/invoke/MethodHandle;[Ljava/lang/Object;)Ljava/lang/Object;"; - Handle invokeHandle = new Handle(H_INVOKESTATIC, constantBootstrapsClassInternalName, "invoke", invokeSig, false); + ClassDesc outerClass = cd(DynamicConstantTest.class); + String desc = type.descriptorString(); - String desc = type.getDescriptor(); if (condyType == CondyType.CALL_DIRECT_BSM) { // Example: int DynamicConstantTest.getIntBSM(MethodHandles.Lookup l, String name, // Class type) String sig = "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;)" + desc; - Handle handle = new Handle(H_INVOKESTATIC, testClassInternalName, getter + "BSM", sig, false); - - ConstantDynamic condy = new ConstantDynamic("const", desc, handle); - MethodVisitor run = cw.visitMethod(PUBLIC_STATIC, "run", "()" + desc, null, null); - run.visitLdcInsn(condy); - run.visitInsn(type.getOpcode(IRETURN)); - run.visitMaxs(0, 0); - run.visitEnd(); + var condy = DynamicConstantDesc.ofNamed(MethodHandleDesc.of(Kind.STATIC, outerClass, getter + "BSM", sig), "consnt", type); + b.ldc(condy).return_(TypeKind.from(type)); } else if (condyType == CondyType.CALL_INDIRECT_BSM) { // Example: int DynamicConstantTest.getInt() - Handle handle = new Handle(H_INVOKESTATIC, testClassInternalName, getter, "()" + desc, false); - - ConstantDynamic condy = new ConstantDynamic("const", desc, invokeHandle, handle); - MethodVisitor run = cw.visitMethod(PUBLIC_STATIC, "run", "()" + desc, null, null); - run.visitLdcInsn(condy); - run.visitInsn(type.getOpcode(IRETURN)); - run.visitMaxs(0, 0); - run.visitEnd(); + var condy = DynamicConstantDesc.ofNamed(ConstantDescs.BSM_INVOKE, "consnt", type, MethodHandleDesc.of(Kind.STATIC, outerClass, getter, "()" + desc)); + b.ldc(condy).return_(TypeKind.from(type)); } else { assert condyType == CondyType.CALL_INDIRECT_WITH_ARGS_BSM; // Example: int DynamicConstantTest.getInt() - Handle handle1 = new Handle(H_INVOKESTATIC, testClassInternalName, getter, "()" + desc, false); - + var condy1 = DynamicConstantDesc.ofNamed(ConstantDescs.BSM_INVOKE, "consnt1", type, MethodHandleDesc.of(Kind.STATIC, outerClass, getter, "()" + desc)); // Example: int DynamicConstantTest.getInt(int v1, int v2) - Handle handle2 = new Handle(H_INVOKESTATIC, testClassInternalName, getter, "(" + desc + desc + ")" + desc, false); - - ConstantDynamic condy1 = new ConstantDynamic("const1", desc, invokeHandle, handle1); - ConstantDynamic condy2 = new ConstantDynamic("const2", desc, invokeHandle, handle2, condy1, condy1); - - MethodVisitor run = cw.visitMethod(PUBLIC_STATIC, "run", "()" + desc, null, null); - run.visitLdcInsn(condy2); - run.visitInsn(type.getOpcode(IRETURN)); - run.visitMaxs(0, 0); - run.visitEnd(); + var condy2 = DynamicConstantDesc.ofNamed(ConstantDescs.BSM_INVOKE, "consnt2", type, MethodHandleDesc.of(Kind.STATIC, outerClass, getter, "(" + desc + desc + ")" + desc), condy1, + condy1); + b.ldc(condy2).return_(TypeKind.from(type)); } } } @@ -226,21 +209,12 @@ public DynamicConstantTest() { private static final boolean VERBOSE = Boolean.getBoolean(DynamicConstantTest.class.getSimpleName() + ".verbose"); - @Override - protected byte[] generateClass(String internalClassName) { - ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); - cw.visit(55, ACC_SUPER | ACC_PUBLIC, internalClassName, null, "java/lang/Object", null); - generators.get(internalClassName).generate(cw); - cw.visitEnd(); - return cw.toByteArray(); - } - @SuppressWarnings("try") @Test public void test() throws Throwable { boolean jvmciCompatibilityChecked = false; for (TestGenerator e : generators.values()) { - Class testClass = getClass(e.className); + Class testClass = e.getClass(e.className); ResolvedJavaMethod run = getResolvedJavaMethod(testClass, "run"); if (!jvmciCompatibilityChecked) { checkJVMCICompatibility(run); diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/ExceptionHandlerReachabilityTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/ExceptionHandlerReachabilityTest.java index bde63885ae1d..f9d454405890 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/ExceptionHandlerReachabilityTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/ExceptionHandlerReachabilityTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, 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 @@ -24,20 +24,19 @@ */ package jdk.graal.compiler.core.test; -import java.io.IOException; +import static java.lang.constant.ConstantDescs.CD_int; + +import java.lang.classfile.ClassFile; +import java.lang.classfile.Label; +import java.lang.constant.ClassDesc; +import java.lang.constant.MethodTypeDesc; import org.junit.Assert; import org.junit.Test; -import org.objectweb.asm.ClassReader; -import org.objectweb.asm.ClassVisitor; -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.Label; -import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Opcodes; import jdk.graal.compiler.core.common.PermanentBailoutException; import jdk.graal.compiler.debug.GraalError; -import jdk.graal.compiler.nodes.StructuredGraph; +import jdk.graal.compiler.nodes.StructuredGraph.AllowAssumptions; import jdk.vm.ci.meta.ResolvedJavaMethod; /** @@ -74,20 +73,16 @@ * * */ -public class ExceptionHandlerReachabilityTest extends CustomizedBytecodePatternTest { +public class ExceptionHandlerReachabilityTest extends GraalCompilerTest implements CustomizedBytecodePattern { @Test public void test() { - testParseAndRun(SharedExceptionHandlerClass.class.getName(), "sharedExceptionHandlerMethod", new Class[]{int.class}); - } - - public void testParseAndRun(String clazzName, String methodName, Class[] args) { try { - Class testClass = getClass(clazzName); - ResolvedJavaMethod method = asResolvedJavaMethod(testClass.getMethod(methodName, args)); + Class testClass = getClass(SharedExceptionHandlerClass.class.getName() + "$Test"); + ResolvedJavaMethod method = asResolvedJavaMethod(testClass.getMethod("sharedExceptionHandlerMethod", int.class)); // test successful parsing - parseEager(method, StructuredGraph.AllowAssumptions.YES, getInitialOptions()); + parseEager(method, AllowAssumptions.YES, getInitialOptions()); // test successful compilation + execution int actual = (int) test(method, null, 11).returnValue; @@ -98,109 +93,55 @@ public void testParseAndRun(String clazzName, String methodName, Class[] args } catch (ClassNotFoundException | NoSuchMethodException e) { throw GraalError.shouldNotReachHere(e); } - } @Override - protected byte[] generateClass(String className) { - try { - ClassReader classReader = new ClassReader(className); - final ClassWriter cw = new ClassWriter(classReader, ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); - classReader.accept(new ClassVisitor(Opcodes.ASM9, cw) { - - @Override - public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { - MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions); - if (name.equals("sharedExceptionHandlerMethod")) { - return new SharedExceptionHandlerReplacer(mv, className.replace('.', '/')); - } - return mv; - } - - }, ClassReader.EXPAND_FRAMES); - - return cw.toByteArray(); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - private static class SharedExceptionHandlerReplacer extends MethodVisitor { - private final MethodVisitor mv; - private final String clazzName; - - SharedExceptionHandlerReplacer(MethodVisitor methodVisitor, String clazzName) { - super(ASM9, null); - this.mv = methodVisitor; - this.clazzName = clazzName; - } - - @Override - public void visitCode() { - mv.visitCode(); - Label label0 = new Label(); - Label label1 = new Label(); - - Label startEx1 = new Label(); - Label endEx1 = new Label(); - Label handlerEx1 = new Label(); - Label startEx2 = new Label(); - Label endEx2 = new Label(); - Label handlerEx2 = new Label(); - mv.visitVarInsn(ILOAD, 0); - mv.visitVarInsn(ISTORE, 1); - mv.visitTryCatchBlock(startEx1, endEx1, handlerEx1, "java/lang/IllegalArgumentException"); - mv.visitLabel(startEx1); - mv.visitVarInsn(ILOAD, 1); - mv.visitMethodInsn(INVOKESTATIC, clazzName, "foo", "(I)I", false); - mv.visitVarInsn(ISTORE, 1); - mv.visitLabel(endEx1); - mv.visitJumpInsn(GOTO, label0); - mv.visitLabel(handlerEx1); - // --- REMOVE storing exception to make stack frames compatible: - // mv.visitVarInsn(ASTORE, 2); - mv.visitVarInsn(ILOAD, 1); - mv.visitMethodInsn(INVOKESTATIC, clazzName, "baz", "(I)I", false); - mv.visitVarInsn(ISTORE, 1); - mv.visitVarInsn(ILOAD, 1); - mv.visitInsn(IRETURN); - mv.visitLabel(label0); - mv.visitTryCatchBlock(startEx2, endEx2, handlerEx2, "java/lang/NumberFormatException"); - mv.visitLabel(startEx2); - mv.visitVarInsn(ILOAD, 1); - mv.visitMethodInsn(INVOKESTATIC, clazzName, "bar", "(I)I", false); - mv.visitVarInsn(ISTORE, 1); - mv.visitLabel(endEx2); - mv.visitJumpInsn(GOTO, label1); - mv.visitLabel(handlerEx2); - // --- REMOVE storing exception to make stack frames compatible: - // mv.visitVarInsn(ASTORE, 2); - mv.visitVarInsn(ILOAD, 1); - mv.visitMethodInsn(INVOKESTATIC, clazzName, "doSomething", "(I)I", false); - mv.visitVarInsn(ISTORE, 1); - // --- ADD jump to first exception handler from within second exception handler: - mv.visitJumpInsn(GOTO, handlerEx1); - // --- REMOVE duplicate code from first handler: - // mv.visitVarInsn(ILOAD, 1); - // mv.visitMethodInsn(INVOKESTATIC, clazzName, "baz", "(I)I", false); - // mv.visitVarInsn(ISTORE, 1); - // mv.visitVarInsn(ILOAD, 1); - // mv.visitInsn(IRETURN); - mv.visitLabel(label1); - mv.visitVarInsn(ILOAD, 1); - mv.visitInsn(IRETURN); - mv.visitMaxs(1, 3); - mv.visitEnd(); - } + public byte[] generateClass(String className) { + ClassDesc classSharedExceptionHandlerClass = cd(SharedExceptionHandlerClass.class); + + return ClassFile.of().build(ClassDesc.of(className), classBuilder -> classBuilder + .withMethodBody("sharedExceptionHandlerMethod", MethodTypeDesc.of(CD_int, CD_int), ACC_PUBLIC_STATIC, b -> { + Label handlerEx1 = b.newLabel(); + b + .iload(0) + .istore(1) + .trying(tryBlock -> { + tryBlock + .iload(1) + .invokestatic(classSharedExceptionHandlerClass, "foo", MethodTypeDesc.of(CD_int, CD_int)) + .istore(1); + }, catchBuilder -> catchBuilder.catching(cd(IllegalArgumentException.class), catchBlock -> { + catchBlock + .labelBinding(handlerEx1) + .iload(1) + .invokestatic(classSharedExceptionHandlerClass, "baz", MethodTypeDesc.of(CD_int, CD_int)) + .istore(1) + .iload(1) + .ireturn(); + })) + .trying(tryBlock -> { + tryBlock + .iload(1) + .invokestatic(classSharedExceptionHandlerClass, "bar", MethodTypeDesc.of(CD_int, CD_int)) + .istore(1); + }, catchBuilder -> catchBuilder.catching(cd(NumberFormatException.class), catchBlock -> { + catchBlock + .iload(1) + .invokestatic(classSharedExceptionHandlerClass, "doSomething", MethodTypeDesc.of(CD_int, CD_int)) + .istore(1) + .goto_(handlerEx1); + })) + .iload(1) + .ireturn(); + })); } public class SharedExceptionHandlerClass { - /** - * The bytecode of this method will be modified by {@link SharedExceptionHandlerReplacer}. - * The modified bytecode contains a {@code goto} from within the second exception handler to - * the first exception handler. This reduces the overall bytecode size due to code sharing. - * The pattern is produced by code obfuscation tools, see [GR-47376]. + * The bytecode of this method will be modified and placed in an inner class. The modified + * bytecode contains a {@code goto} from within the second exception handler to the first + * exception handler. This reduces the overall bytecode size due to code sharing. The + * pattern is produced by code obfuscation tools, see [GR-47376]. */ public static int sharedExceptionHandlerMethod(int i) { int x = i; diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/GraphUtilOriginalValueTests.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/GraphUtilOriginalValueTests.java index 868d924aefb7..6460aeab6d13 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/GraphUtilOriginalValueTests.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/GraphUtilOriginalValueTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, 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 @@ -24,24 +24,29 @@ */ package jdk.graal.compiler.core.test; +import static java.lang.constant.ConstantDescs.CD_Object; +import static java.lang.constant.ConstantDescs.CD_String; +import static java.lang.constant.ConstantDescs.CD_void; + +import java.lang.classfile.ClassFile; +import java.lang.classfile.Label; +import java.lang.constant.ClassDesc; +import java.lang.constant.MethodTypeDesc; import java.lang.invoke.ConstantCallSite; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; -import jdk.graal.compiler.nodes.util.GraphUtil; import org.junit.Assert; import org.junit.Test; -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.Label; -import org.objectweb.asm.MethodVisitor; +import jdk.graal.compiler.nodes.util.GraphUtil; import jdk.vm.ci.code.BailoutException; import jdk.vm.ci.meta.ResolvedJavaMethod; /** * Unit tests derived from https://github.com/oracle/graal/pull/1690. */ -public class GraphUtilOriginalValueTests extends CustomizedBytecodePatternTest { +public class GraphUtilOriginalValueTests extends GraalCompilerTest implements CustomizedBytecodePattern { static class LinkedNode { LinkedNode next; @@ -113,16 +118,7 @@ public void testGetTarget() { } @Override - protected byte[] generateClass(String internalClassName) { - ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); - cw.visit(52, ACC_SUPER | ACC_PUBLIC, internalClassName, null, "java/lang/Object", null); - - String getDescriptor = "(Ljava/lang/Object;)V"; - MethodVisitor m = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "unbalancedMonitors", getDescriptor, null, null); - Label loopHead = new Label(); - Label end = new Label(); - m.visitCode(); - + public byte[] generateClass(String className) { // @formatter:off /* * void unbalancedMonitors(Object o) { @@ -134,27 +130,27 @@ protected byte[] generateClass(String internalClassName) { * } */ // @formatter:on - - m.visitVarInsn(ALOAD, 0); - m.visitInsn(MONITORENTER); - m.visitLabel(loopHead); - m.visitVarInsn(ALOAD, 0); - m.visitInsn(MONITOREXIT); - m.visitVarInsn(ALOAD, 0); - m.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", "()Ljava/lang/String;", false); - m.visitVarInsn(ALOAD, 0); - m.visitJumpInsn(IF_ACMPEQ, end); - m.visitVarInsn(ALOAD, 0); - m.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "toString", "()Ljava/lang/String;", false); - m.visitVarInsn(ASTORE, 0); - m.visitJumpInsn(GOTO, loopHead); - m.visitLabel(end); - m.visitInsn(RETURN); - m.visitMaxs(2, 2); - m.visitEnd(); - - cw.visitEnd(); - return cw.toByteArray(); + return ClassFile.of().build(ClassDesc.of(className), classBuilder -> classBuilder + .withMethodBody("unbalancedMonitors", MethodTypeDesc.of(CD_void, CD_Object), ACC_PUBLIC_STATIC, b -> { + Label loopHead = b.newLabel(); + Label end = b.newLabel(); + b + .aload(0) + .monitorenter() + .labelBinding(loopHead) + .aload(0) + .monitorexit() + .aload(0) + .invokevirtual(CD_Object, "toString", MethodTypeDesc.of(CD_String)) + .aload(0) + .if_acmpeq(end) + .aload(0) + .invokevirtual(CD_Object, "toString", MethodTypeDesc.of(CD_String)) + .astore(0) + .goto_(loopHead) + .labelBinding(end) + .return_(); + })); } /** diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/InterfaceMethodHandleTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/InterfaceMethodHandleTest.java index d0ad3635a418..538553618001 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/InterfaceMethodHandleTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/InterfaceMethodHandleTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, 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 @@ -24,23 +24,28 @@ */ package jdk.graal.compiler.core.test; +import static java.lang.classfile.ClassFile.ACC_PRIVATE; +import static java.lang.classfile.ClassFile.ACC_PUBLIC; +import static java.lang.constant.ConstantDescs.CD_Object; +import static java.lang.constant.ConstantDescs.CD_int; +import static java.lang.constant.ConstantDescs.INIT_NAME; +import static java.lang.constant.ConstantDescs.MTD_void; + +import java.lang.classfile.ClassFile; +import java.lang.constant.ClassDesc; +import java.lang.constant.MethodTypeDesc; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; -import jdk.graal.compiler.api.test.ExportingClassLoader; -import jdk.graal.compiler.code.CompilationResult; -import jdk.graal.compiler.debug.DebugContext; import org.junit.Test; -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.Label; -import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Opcodes; +import jdk.graal.compiler.code.CompilationResult; +import jdk.graal.compiler.debug.DebugContext; import jdk.vm.ci.code.InstalledCode; import jdk.vm.ci.meta.ResolvedJavaMethod; -public final class InterfaceMethodHandleTest extends GraalCompilerTest { +public final class InterfaceMethodHandleTest extends GraalCompilerTest implements CustomizedBytecodePattern { private static final MethodHandle INTERFACE_HANDLE_M; private static final MethodHandle INTERFACE_HANDLE_M2; @@ -99,7 +104,7 @@ public void testInvokeInterface01() { @Test public void testInvokeInterface02() throws Exception { - test("invokeInterfaceHandle", loader.findClass(NAME).getDeclaredConstructor().newInstance()); + test("invokeInterfaceHandle", getClass(NAME).getDeclaredConstructor().newInstance()); } public static Object invokeInterfaceHandle2(I o, int a, int b, int c, int d, int e, int f, int g, int h, int i, int j) throws Throwable { @@ -138,84 +143,20 @@ public void testInvokeInterface03() throws Throwable { private static final String BASENAME = InterfaceMethodHandleTest.class.getName(); private static final String NAME = BASENAME + "_B"; - private final AsmLoader loader; - - public InterfaceMethodHandleTest() { - loader = new AsmLoader(UnbalancedMonitorsTest.class.getClassLoader()); - } - - static class Gen implements Opcodes { - /** - * Construct a type which claims to implement {@link I} but with incorrect access on - * {@link I#m} so that an exception must be thrown. - */ - public static byte[] bytesForB() { - - ClassWriter cw = new ClassWriter(0); - MethodVisitor mv; - String jvmName = NAME.replace('.', '/'); - cw.visit(52, ACC_SUPER | ACC_PUBLIC, jvmName, null, "java/lang/Object", new String[]{BASENAME.replace('.', '/') + "$I"}); - - mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); - mv.visitCode(); - Label l0 = new Label(); - mv.visitLabel(l0); - mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); - mv.visitInsn(RETURN); - Label l1 = new Label(); - mv.visitLabel(l1); - mv.visitMaxs(1, 1); - mv.visitEnd(); - - mv = cw.visitMethod(ACC_PRIVATE, "m", "()I", null, null); - mv.visitCode(); - l0 = new Label(); - mv.visitLabel(l0); - mv.visitInsn(ICONST_0); - mv.visitInsn(IRETURN); - l1 = new Label(); - mv.visitLabel(l1); - mv.visitMaxs(1, 1); - mv.visitEnd(); - - cw.visitEnd(); - - mv = cw.visitMethod(ACC_PRIVATE, "m2", "(IIIIIIIIII)I", null, null); - mv.visitCode(); - l0 = new Label(); - mv.visitLabel(l0); - mv.visitInsn(ICONST_0); - mv.visitInsn(IRETURN); - l1 = new Label(); - mv.visitLabel(l1); - mv.visitMaxs(1, 11); - mv.visitEnd(); - - cw.visitEnd(); - - return cw.toByteArray(); - } - } - - public static class AsmLoader extends ExportingClassLoader { - Class loaded; - public AsmLoader(ClassLoader parent) { - super(parent); - } - - @Override - protected Class findClass(String name) throws ClassNotFoundException { - if (name.equals(NAME)) { - if (loaded != null) { - return loaded; - } - byte[] bytes = Gen.bytesForB(); - return (loaded = defineClass(name, bytes, 0, bytes.length)); - } else { - return super.findClass(name); - } - } + @Override + public byte[] generateClass(String className) { + return ClassFile.of().build(ClassDesc.of(className), classBuilder -> classBuilder + .withInterfaceSymbols(cd(I.class)) + .withMethodBody(INIT_NAME, MTD_void, ACC_PUBLIC, b -> b + .aload(0) + .invokespecial(CD_Object, INIT_NAME, MTD_void) + .return_()) + .withMethodBody("m", MethodTypeDesc.of(CD_int), ACC_PRIVATE, b -> b + .iconst_0() + .ireturn()) + .withMethodBody("m2", MethodTypeDesc.of(CD_int, CD_int, CD_int, CD_int, CD_int, CD_int, CD_int, CD_int, CD_int, CD_int, CD_int), ACC_PRIVATE, b -> b + .iconst_0() + .ireturn())); } } diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/OptionsVerifierTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/OptionsVerifierTest.java index abae403b7992..0bfc21e1f8ce 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/OptionsVerifierTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/OptionsVerifierTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, 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 @@ -25,28 +25,42 @@ package jdk.graal.compiler.core.test; import static java.lang.String.format; +import static java.lang.constant.ConstantDescs.CD_Boolean; +import static java.lang.constant.ConstantDescs.CD_Byte; +import static java.lang.constant.ConstantDescs.CD_Character; +import static java.lang.constant.ConstantDescs.CD_Double; +import static java.lang.constant.ConstantDescs.CD_Float; +import static java.lang.constant.ConstantDescs.CD_Integer; +import static java.lang.constant.ConstantDescs.CD_Long; +import static java.lang.constant.ConstantDescs.CD_Short; +import static java.lang.constant.ConstantDescs.CLASS_INIT_NAME; import java.io.IOException; -import java.lang.reflect.Constructor; -import java.lang.reflect.Executable; -import java.lang.reflect.Method; -import java.util.Arrays; +import java.lang.classfile.Attributes; +import java.lang.classfile.ClassFile; +import java.lang.classfile.ClassModel; +import java.lang.classfile.CodeElement; +import java.lang.classfile.CodeModel; +import java.lang.classfile.MethodModel; +import java.lang.classfile.Opcode; +import java.lang.classfile.constantpool.MemberRefEntry; +import java.lang.classfile.instruction.FieldInstruction; +import java.lang.classfile.instruction.InvokeInstruction; +import java.lang.classfile.instruction.LineNumber; +import java.lang.constant.ClassDesc; +import java.lang.constant.ConstantDescs; import java.util.HashSet; +import java.util.List; import java.util.Set; import java.util.TreeSet; +import org.junit.Test; + import jdk.graal.compiler.options.OptionDescriptor; import jdk.graal.compiler.options.OptionDescriptors; import jdk.graal.compiler.options.OptionKey; import jdk.graal.compiler.options.OptionsParser; import jdk.graal.compiler.serviceprovider.GraalServices; -import org.junit.Test; -import org.objectweb.asm.ClassReader; -import org.objectweb.asm.ClassVisitor; -import org.objectweb.asm.Label; -import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.Type; /** * Verifies a class declaring one or more {@linkplain OptionKey options} has a class initializer @@ -55,11 +69,11 @@ */ public class OptionsVerifierTest { - private static Set ALLOWLIST = new TreeSet<>(Arrays.asList(// + private static final Set ALLOWLIST = new TreeSet<>(List.of(// "jdk.graal.compiler.truffle.TruffleCompilerOptions")); @Test - public void verifyOptions() throws IOException { + public void verifyOptions() throws IOException, ReflectiveOperationException { HashSet> checked = new HashSet<>(); for (OptionDescriptors opts : OptionsParser.getOptionsLoader()) { for (OptionDescriptor desc : opts) { @@ -71,9 +85,9 @@ public void verifyOptions() throws IOException { } } - static final class OptionsVerifier extends ClassVisitor { + static final class OptionsVerifier { - public static void checkClass(Class cls, OptionDescriptor option, Set> checked) throws IOException { + public static void checkClass(Class cls, OptionDescriptor option, Set> checked) throws IOException, ReflectiveOperationException { if (!checked.contains(cls)) { checked.add(cls); Class superclass = cls.getSuperclass(); @@ -81,11 +95,7 @@ public static void checkClass(Class cls, OptionDescriptor option, Set cls, OptionDescriptor option, Set} method is being verified. @@ -103,32 +115,17 @@ public static void checkClass(Class cls, OptionDescriptor option, Set[] boxingTypes = {Boolean.class, Byte.class, Short.class, Character.class, Integer.class, Float.class, Long.class, Double.class}; - - private static Class resolve(String name) { - try { - return Class.forName(name.replace('/', '.')); - } catch (ClassNotFoundException e) { - throw new InternalError(e); - } - } - OptionsVerifier(Class cls, OptionDescriptor desc) { - super(Opcodes.ASM7); this.cls = cls; this.option = desc; - } - - @Override - public void visitSource(String source, String debug) { - this.sourceFile = source; + this.optionClassDesc = option.getDeclaringClass().describeConstable().orElseThrow(); } void verify(boolean condition, String message) { @@ -138,83 +135,64 @@ void verify(boolean condition, String message) { } void error(String message) { - String errorMessage = format( - "%s:%d: Illegal code in %s. which may be executed when %s.%s is initialized:%n%n %s%n%n" + "The recommended solution is to move " + option.getName() + - " into a separate class (e.g., %s.Options).%n", - sourceFile, lineNo, cls.getSimpleName(), option.getDeclaringClass().getSimpleName(), option.getName(), - message, option.getDeclaringClass().getSimpleName()); + String errorMessage = format(""" + %s:%d: Illegal code in %s. which may be executed when %s.%s is initialized: + %s + The recommended solution is to move %s into a separate class (e.g., %s.Options). + """, sourceFile, lineNo, cls.getSimpleName(), option.getDeclaringClass().getSimpleName(), option.getName(), + message, option.getName(), option.getDeclaringClass().getSimpleName()); throw new InternalError(errorMessage); - } - @Override - public MethodVisitor visitMethod(int access, String name, String d, String signature, String[] exceptions) { - if (name.equals("")) { - return new MethodVisitor(Opcodes.ASM5) { - - @Override - public void visitLineNumber(int line, Label start) { - lineNo = line; - } + private static Class resolve(String name) { + try { + return Class.forName(name.replace('/', '.')); + } catch (ClassNotFoundException e) { + throw new InternalError(e); + } + } - @Override - public void visitFieldInsn(int opcode, String owner, String fieldName, String fieldDesc) { - if (opcode == Opcodes.PUTFIELD || opcode == Opcodes.PUTSTATIC) { - verify(resolve(owner).equals(option.getDeclaringClass()), format("store to field %s.%s", resolve(owner).getSimpleName(), fieldName)); - verify(opcode != Opcodes.PUTFIELD, format("store to non-static field %s.%s", resolve(owner).getSimpleName(), fieldName)); - } - } + private static final List boxingTypes = List.of(CD_Boolean, CD_Byte, CD_Short, CD_Character, CD_Integer, CD_Float, CD_Long, CD_Double); - private Executable resolveMethod(String owner, String methodName, String methodDesc) { - Class declaringClass = resolve(owner); - if (methodName.equals("")) { - for (Constructor c : declaringClass.getDeclaredConstructors()) { - if (methodDesc.equals(Type.getConstructorDescriptor(c))) { - return c; - } - } - } else { - Type[] argumentTypes = Type.getArgumentTypes(methodDesc); - for (Method m : declaringClass.getDeclaredMethods()) { - if (m.getName().equals(methodName)) { - if (Arrays.equals(argumentTypes, Type.getArgumentTypes(m))) { - if (Type.getReturnType(methodDesc).equals(Type.getReturnType(m))) { - return m; - } - } - } - } - } - throw new NoSuchMethodError(declaringClass + "." + methodName + methodDesc); - } + /** + * Checks whether a given method is allowed to be called. + */ + private boolean checkInvokeTarget(MemberRefEntry method) throws ReflectiveOperationException { + ClassDesc owner = method.owner().asSymbol(); + String methodName = method.name().stringValue(); + + if ("".equals(methodName)) { + return OptionKey.class.isAssignableFrom(resolve(method.owner().asInternalName())); + } else if ("valueOf".equals(methodName)) { + return boxingTypes.contains(owner); + } else if ("desiredAssertionStatus".equals(methodName)) { + return ConstantDescs.CD_Class.equals(owner); + } + return false; + } - /** - * Checks whether a given method is allowed to be called. - */ - private boolean checkInvokeTarget(Executable method) { - Class holder = method.getDeclaringClass(); - if (method instanceof Constructor) { - if (OptionKey.class.isAssignableFrom(holder)) { - return true; + public void apply() throws IOException, ReflectiveOperationException { + ClassModel cm = ClassFile.of().parse(GraalServices.getClassfileAsStream(cls).readAllBytes()); + + cm.findAttribute(Attributes.sourceFile()).ifPresent(attr -> sourceFile = attr.sourceFile().stringValue()); + + for (MethodModel methodModel : cm.methods()) { + if (CLASS_INIT_NAME.equals(methodModel.methodName().stringValue())) { + CodeModel code = methodModel.code().orElseThrow(); + for (CodeElement instruction : code) { + switch (instruction) { + case LineNumber line -> lineNo = line.line(); + case FieldInstruction fi when fi.opcode() == Opcode.PUTFIELD -> + error(format("store to non-static field %s.%s", fi.owner().asInternalName(), fi.name().stringValue())); + case FieldInstruction fi when fi.opcode() == Opcode.PUTSTATIC -> + verify(fi.owner().asSymbol().equals(optionClassDesc), format("store to static field %s.%s", fi.owner().asInternalName(), fi.name().stringValue())); + case InvokeInstruction invoke -> verify(checkInvokeTarget(invoke.method()), "invocation of " + invoke.method()); + default -> { } - } else if (Arrays.asList(boxingTypes).contains(holder)) { - return method.getName().equals("valueOf"); - } else if (method.getDeclaringClass().equals(Class.class)) { - return method.getName().equals("desiredAssertionStatus"); } - return false; - } - - @Override - public void visitMethodInsn(int opcode, String owner, String methodName, String methodDesc, boolean itf) { - Executable callee = resolveMethod(owner, methodName, methodDesc); - verify(checkInvokeTarget(callee), "invocation of " + callee); } - }; - } else { - return null; + } } } } - } diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/ResolveDynamicConstantTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/ResolveDynamicConstantTest.java index ff1231a39fff..62c7a57f72ff 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/ResolveDynamicConstantTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/ResolveDynamicConstantTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, 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 @@ -24,28 +24,43 @@ */ package jdk.graal.compiler.core.test; -import java.lang.reflect.Method; +import static java.lang.classfile.ClassFile.ACC_VARARGS; +import static java.lang.constant.ConstantDescs.CD_MethodHandles_Lookup; +import static java.lang.constant.ConstantDescs.CD_Object; +import static java.lang.constant.ConstantDescs.CD_String; +import static java.lang.constant.ConstantDescs.CD_boolean; +import static java.lang.constant.ConstantDescs.CD_double; +import static java.lang.constant.ConstantDescs.CD_int; +import static java.lang.constant.ConstantDescs.CD_void; + +import java.io.PrintStream; +import java.lang.classfile.ClassFile; +import java.lang.classfile.Label; +import java.lang.classfile.constantpool.ConstantPoolBuilder; +import java.lang.classfile.constantpool.FieldRefEntry; +import java.lang.constant.ClassDesc; +import java.lang.constant.DirectMethodHandleDesc.Kind; +import java.lang.constant.DynamicConstantDesc; +import java.lang.constant.MethodHandleDesc; +import java.lang.constant.MethodTypeDesc; import java.time.Clock; import java.time.Instant; import org.junit.Assert; import org.junit.Test; -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.ConstantDynamic; -import org.objectweb.asm.FieldVisitor; -import org.objectweb.asm.Handle; -import org.objectweb.asm.Label; -import org.objectweb.asm.MethodVisitor; import jdk.vm.ci.meta.ResolvedJavaMethod; -public class ResolveDynamicConstantTest extends CustomizedBytecodePatternTest { - - private static final int PUBLIC_STATIC = ACC_PUBLIC | ACC_STATIC; +public class ResolveDynamicConstantTest extends GraalCompilerTest { @Test public void test00601m001() throws Throwable { - runTest("test.resolveDynamicConstant00601m001"); + runTest(new ResolveDynamicConstant00601m001Gen().getClass("test.resolveDynamicConstant00601m001")); + } + + @Test + public void test00602m008() throws Throwable { + runTest(new ResolveDynamicConstant00602m008Gen().getClass("test.resolveDynamicConstant00602m008")); } public static void main(String[] args) { @@ -59,125 +74,95 @@ public static void main(String[] args) { } } - @Test - public void test00602m008() throws Throwable { - runTest("test.resolveDynamicConstant00602m008"); - } - - static void resolveDynamicConstant00601m001Gen(String internalClassName, ClassWriter cw) { - FieldVisitor fv = cw.visitField(PUBLIC_STATIC, "bsmInvocationCount", "I", null, null); - fv.visitEnd(); - - String sig; - Handle handle; - - sig = "(Ljava/lang/invoke/MethodHandles$Lookup;[Ljava/lang/Object;)I"; - handle = new Handle(H_INVOKESTATIC, internalClassName, "getConstant", sig, false); - ConstantDynamic iconst = new ConstantDynamic("constantdynamic", "I", handle); - - MethodVisitor run = cw.visitMethod(PUBLIC_STATIC, "run", "()Z", null, null); - run.visitFieldInsn(GETSTATIC, internalClassName, "bsmInvocationCount", "I"); - Label labelFalse = new Label(); - run.visitJumpInsn(IFNE, labelFalse); - run.visitLdcInsn(iconst); - run.visitInsn(POP); - run.visitFieldInsn(GETSTATIC, internalClassName, "bsmInvocationCount", "I"); - run.visitJumpInsn(IFEQ, labelFalse); - run.visitInsn(ICONST_1); - run.visitInsn(IRETURN); - run.visitLabel(labelFalse); - run.visitInsn(ICONST_0); - run.visitInsn(IRETURN); - run.visitMaxs(0, 0); - run.visitEnd(); - - MethodVisitor getConstant = cw.visitMethod(PUBLIC_STATIC | ACC_VARARGS, "getConstant", "(Ljava/lang/invoke/MethodHandles$Lookup;[Ljava/lang/Object;)I", null, null); - getConstant.visitFieldInsn(GETSTATIC, internalClassName, "bsmInvocationCount", "I"); - getConstant.visitInsn(ICONST_1); - getConstant.visitInsn(IADD); - getConstant.visitFieldInsn(PUTSTATIC, internalClassName, "bsmInvocationCount", "I"); - getConstant.visitInsn(ICONST_1); - getConstant.visitInsn(IRETURN); - getConstant.visitMaxs(0, 0); - getConstant.visitEnd(); - } - - static void resolveDynamicConstant00602m008Gen(String internalClassName, ClassWriter cw) { - FieldVisitor fv = cw.visitField(PUBLIC_STATIC, "staticBSMInvocationCount", "I", null, null); - fv.visitEnd(); - - String sig; - Handle handle; - - sig = "(Ljava/lang/invoke/MethodHandles$Lookup;[Ljava/lang/Object;)D"; - handle = new Handle(H_INVOKESTATIC, internalClassName, "getStaticConstant", sig, false); - ConstantDynamic dconst = new ConstantDynamic("constantdynamic", "D", handle); - - sig = "(Ljava/lang/invoke/MethodHandles$Lookup;[Ljava/lang/Object;)I"; - handle = new Handle(H_INVOKESTATIC, internalClassName, "getConstant", sig, false); - ConstantDynamic iconst = new ConstantDynamic("constantdynamic", "I", handle, dconst); - - MethodVisitor run = cw.visitMethod(PUBLIC_STATIC, "run", "()Z", null, null); - run.visitFieldInsn(GETSTATIC, internalClassName, "staticBSMInvocationCount", "I"); - Label labelFalse = new Label(); - run.visitJumpInsn(IFNE, labelFalse); - run.visitLdcInsn(iconst); - run.visitInsn(POP); - run.visitFieldInsn(GETSTATIC, internalClassName, "staticBSMInvocationCount", "I"); - run.visitLdcInsn(Integer.valueOf(1)); - run.visitJumpInsn(IF_ICMPNE, labelFalse); - run.visitInsn(ICONST_1); - run.visitInsn(IRETURN); - run.visitLabel(labelFalse); - run.visitInsn(ICONST_0); - run.visitInsn(IRETURN); - run.visitMaxs(0, 0); - run.visitEnd(); - - MethodVisitor getConstant = cw.visitMethod(PUBLIC_STATIC | ACC_VARARGS, "getConstant", "(Ljava/lang/invoke/MethodHandles$Lookup;[Ljava/lang/Object;)I", null, null); - getConstant.visitInsn(ICONST_1); - getConstant.visitInsn(IRETURN); - getConstant.visitMaxs(0, 0); - getConstant.visitEnd(); - - MethodVisitor getStaticConstant = cw.visitMethod(PUBLIC_STATIC | ACC_VARARGS, "getStaticConstant", "(Ljava/lang/invoke/MethodHandles$Lookup;[Ljava/lang/Object;)D", null, null); - getStaticConstant.visitFieldInsn(GETSTATIC, internalClassName, "staticBSMInvocationCount", "I"); - getStaticConstant.visitInsn(ICONST_1); - getStaticConstant.visitInsn(IADD); - getStaticConstant.visitFieldInsn(PUTSTATIC, internalClassName, "staticBSMInvocationCount", "I"); - getStaticConstant.visitInsn(DCONST_1); - getStaticConstant.visitInsn(DRETURN); - getStaticConstant.visitMaxs(0, 0); - getStaticConstant.visitEnd(); + static class ResolveDynamicConstant00601m001Gen implements CustomizedBytecodePattern { + @Override + public byte[] generateClass(String className) { + ClassDesc thisClass = ClassDesc.of(className); + FieldRefEntry field = ConstantPoolBuilder.of().fieldRefEntry(thisClass, "bsmInvocationCount", CD_int); + + return ClassFile.of().build(thisClass, classBuilder -> classBuilder + .withField("bsmInvocationCount", CD_int, ACC_PUBLIC_STATIC) + .withMethodBody("main", MethodTypeDesc.of(CD_void, CD_String.arrayType()), ACC_PUBLIC_STATIC, b -> b + .getstatic(cd(System.class), "out", cd(PrintStream.class)) + .invokestatic(thisClass, "run", MethodTypeDesc.of(CD_boolean)) + .invokevirtual(cd(PrintStream.class), "println", MethodTypeDesc.of(CD_void, CD_boolean)) + .return_()) + .withMethodBody("run", MethodTypeDesc.of(CD_boolean), ACC_PUBLIC_STATIC, b -> { + Label labelFalse = b.newLabel(); + var iconst = DynamicConstantDesc.ofNamed(MethodHandleDesc.of(Kind.STATIC, thisClass, "getConstant", + "(Ljava/lang/invoke/MethodHandles$Lookup;[Ljava/lang/Object;)I"), "constantdynamic", CD_int); + + b + .getstatic(field) + .ifne(labelFalse) + .ldc(iconst) + .pop() + .getstatic(field) + .ifeq(labelFalse) + .iconst_1() + .ireturn() + .labelBinding(labelFalse) + .iconst_0() + .ireturn(); + }) + .withMethodBody("getConstant", MethodTypeDesc.of(CD_int, CD_MethodHandles_Lookup, CD_Object.arrayType()), ACC_PUBLIC_STATIC | ACC_VARARGS, b -> b + .getstatic(field) + .iconst_1() + .iadd() + .putstatic(field) + .iconst_1() + .ireturn())); + } } - @Override - protected byte[] generateClass(String internalClassName) { - ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); - cw.visit(55, ACC_SUPER | ACC_PUBLIC, internalClassName, null, "java/lang/Object", null); - - try { - String simpleName = internalClassName.substring("test/".length()); - Method method = getClass().getDeclaredMethod(simpleName + "Gen", String.class, ClassWriter.class); - method.invoke(this, internalClassName, cw); - } catch (Exception e) { - throw new AssertionError(e); + static class ResolveDynamicConstant00602m008Gen implements CustomizedBytecodePattern { + @Override + public byte[] generateClass(String className) { + ClassDesc thisClass = ClassDesc.of(className); + FieldRefEntry field = ConstantPoolBuilder.of().fieldRefEntry(thisClass, "staticBSMInvocationCount", CD_int); + + return ClassFile.of().build(thisClass, classBuilder -> classBuilder + .withField("staticBSMInvocationCount", CD_int, ACC_PUBLIC_STATIC) + .withMethodBody("main", MethodTypeDesc.of(CD_void, CD_String.arrayType()), ACC_PUBLIC_STATIC, b -> b + .getstatic(cd(System.class), "out", cd(PrintStream.class)) + .invokestatic(thisClass, "run", MethodTypeDesc.of(CD_boolean)) + .invokevirtual(cd(PrintStream.class), "println", MethodTypeDesc.of(CD_void, CD_boolean)) + .return_()) + .withMethodBody("run", MethodTypeDesc.of(CD_boolean), ACC_PUBLIC_STATIC, b -> { + Label labelFalse = b.newLabel(); + var dconst = DynamicConstantDesc.ofNamed(MethodHandleDesc.of(Kind.STATIC, thisClass, "getStaticConstant", + "(Ljava/lang/invoke/MethodHandles$Lookup;[Ljava/lang/Object;)D"), "constantdynamic", CD_double); + var iconst = DynamicConstantDesc.of(MethodHandleDesc.of(Kind.STATIC, thisClass, "getConstant", + "(Ljava/lang/invoke/MethodHandles$Lookup;[Ljava/lang/Object;)I"), "constantdynamic", CD_int, dconst); + + b + .getstatic(field) + .ifne(labelFalse) + .ldc(iconst) + .pop() + .getstatic(field) + .ldc(1) + .if_icmpne(labelFalse) + .iconst_1() + .ireturn() + .labelBinding(labelFalse) + .iconst_0() + .ireturn(); + }) + .withMethodBody("getConstant", MethodTypeDesc.of(CD_int, CD_MethodHandles_Lookup, CD_Object.arrayType()), ACC_PUBLIC_STATIC | ACC_VARARGS, b -> b + .iconst_1() + .ireturn()) + .withMethodBody("getStaticConstant", MethodTypeDesc.of(CD_double, CD_MethodHandles_Lookup, CD_Object.arrayType()), ACC_PUBLIC_STATIC | ACC_VARARGS, b -> b + .getstatic(field) + .iconst_1() + .iadd() + .putstatic(field) + .dconst_1() + .dreturn())); } - - MethodVisitor main = cw.visitMethod(PUBLIC_STATIC, "main", "([Ljava/lang/String;)V", null, null); - main.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); - main.visitMethodInsn(INVOKESTATIC, internalClassName, "run", "()Z", false); - main.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Z)V", false); - main.visitInsn(RETURN); - main.visitMaxs(0, 0); - main.visitEnd(); - - cw.visitEnd(); - return cw.toByteArray(); } - private void runTest(String internalClassName) throws Throwable { - Class testClass = getClass(internalClassName); + private void runTest(Class testClass) throws Throwable { ResolvedJavaMethod run = getResolvedJavaMethod(testClass, "run"); Result actual = executeActual(run, null); if (actual.exception != null) { diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/SubWordArrayStoreTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/SubWordArrayStoreTest.java index e1e9d8f0b370..1009c2cef7ee 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/SubWordArrayStoreTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/SubWordArrayStoreTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, 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 @@ -24,21 +24,35 @@ */ package jdk.graal.compiler.core.test; +import static java.lang.classfile.ClassFile.ACC_STATIC; +import static java.lang.constant.ConstantDescs.CD_Object; +import static java.lang.constant.ConstantDescs.CD_boolean; +import static java.lang.constant.ConstantDescs.CD_long; +import static java.lang.constant.ConstantDescs.CD_void; +import static java.lang.constant.ConstantDescs.MTD_void; +import static jdk.graal.compiler.core.test.SubWordFieldStoreTest.getUnsafePutMethodName; + +import java.lang.classfile.ClassFile; +import java.lang.classfile.CodeBuilder; +import java.lang.classfile.Opcode; +import java.lang.classfile.TypeKind; +import java.lang.classfile.constantpool.ConstantPoolBuilder; +import java.lang.classfile.constantpool.FieldRefEntry; +import java.lang.constant.ClassDesc; +import java.lang.constant.MethodTypeDesc; import java.util.ArrayList; import java.util.List; -import jdk.graal.compiler.debug.GraalError; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.FieldVisitor; -import org.objectweb.asm.MethodVisitor; -import jdk.vm.ci.meta.JavaKind; +import jdk.graal.compiler.debug.GraalError; +import jdk.graal.compiler.test.GraalTest; +import jdk.internal.misc.Unsafe; @RunWith(Parameterized.class) -public class SubWordArrayStoreTest extends CustomizedBytecodePatternTest { +public class SubWordArrayStoreTest extends GraalCompilerTest implements CustomizedBytecodePattern { @Parameterized.Parameters(name = "{0}, {1}, {2}, {3}") public static List data() { @@ -46,10 +60,10 @@ public static List data() { for (int i : new int[]{0xFFFF0000, 0xFFFF0001, 0x0000FFFF, 0x01020304}) { for (boolean unsafeStore : new boolean[]{false, true}) { for (boolean unsafeLoad : new boolean[]{false, true}) { - ret.add(new Object[]{JavaKind.Boolean, i, unsafeStore, unsafeLoad}); - ret.add(new Object[]{JavaKind.Byte, i, unsafeStore, unsafeLoad}); - ret.add(new Object[]{JavaKind.Short, i, unsafeStore, unsafeLoad}); - ret.add(new Object[]{JavaKind.Char, i, unsafeStore, unsafeLoad}); + ret.add(new Object[]{TypeKind.BOOLEAN, i, unsafeStore, unsafeLoad}); + ret.add(new Object[]{TypeKind.BYTE, i, unsafeStore, unsafeLoad}); + ret.add(new Object[]{TypeKind.SHORT, i, unsafeStore, unsafeLoad}); + ret.add(new Object[]{TypeKind.CHAR, i, unsafeStore, unsafeLoad}); } } } @@ -57,13 +71,14 @@ public static List data() { } private static final String SNIPPET = "snippet"; + private static final String FIELD = "array"; - private final JavaKind kind; + private final TypeKind kind; private final int value; private final boolean unsafeStore; private final boolean unsafeLoad; - public SubWordArrayStoreTest(JavaKind kind, int value, boolean unsafeStore, boolean unsafeLoad) { + public SubWordArrayStoreTest(TypeKind kind, int value, boolean unsafeStore, boolean unsafeLoad) { this.kind = kind; this.value = value; this.unsafeStore = unsafeStore; @@ -76,119 +91,83 @@ public void testArrayStore() throws ClassNotFoundException { test(getResolvedJavaMethod(testClass, SNIPPET), null); } - private static long arrayBaseOffset(JavaKind kind) { - switch (kind) { - case Boolean: - return UNSAFE.arrayBaseOffset(boolean[].class); - case Byte: - return UNSAFE.arrayBaseOffset(byte[].class); - case Short: - return UNSAFE.arrayBaseOffset(short[].class); - case Char: - return UNSAFE.arrayBaseOffset(char[].class); - default: - throw GraalError.shouldNotReachHereUnexpectedValue(kind); // ExcludeFromJacocoGeneratedReport - } - } - - static int toASMType(JavaKind kind) { - switch (kind) { - case Boolean: - return T_BOOLEAN; - case Byte: - return T_BYTE; - case Short: - return T_SHORT; - case Char: - return T_CHAR; - default: - throw GraalError.shouldNotReachHereUnexpectedValue(kind); // ExcludeFromJacocoGeneratedReport - } - } - - private static int toArrayStoreOpcode(JavaKind kind) { - switch (kind) { - case Boolean: - case Byte: - return BASTORE; - case Short: - return SASTORE; - case Char: - return CASTORE; - default: - throw GraalError.shouldNotReachHereUnexpectedValue(kind); // ExcludeFromJacocoGeneratedReport - } + @Override + public byte[] generateClass(String className) { + ClassDesc thisClass = ClassDesc.of(className); + ClassDesc targetType = kind.upperBound(); + + return ClassFile.of().build(thisClass, classBuilder -> classBuilder + .withField(FIELD, targetType.arrayType(), ACC_PUBLIC_STATIC) + .withMethodBody("", MTD_void, ACC_STATIC, b -> b + .bipush(16) + .newarray(kind) + .putstatic(thisClass, FIELD, targetType.arrayType())) + .withMethodBody(SNIPPET, MethodTypeDesc.of(CD_boolean), ACC_PUBLIC_STATIC, b -> generateSnippet(b, thisClass))); } - private static int toArrayLoadOpcode(JavaKind kind) { - switch (kind) { - case Boolean: - case Byte: - return BALOAD; - case Short: - return SALOAD; - case Char: - return CALOAD; - default: - throw GraalError.shouldNotReachHereUnexpectedValue(kind); // ExcludeFromJacocoGeneratedReport - } + private static long arrayBaseOffset(TypeKind kind) { + return switch (kind) { + case BOOLEAN -> UNSAFE.arrayBaseOffset(boolean[].class); + case BYTE -> UNSAFE.arrayBaseOffset(byte[].class); + case SHORT -> UNSAFE.arrayBaseOffset(short[].class); + case CHAR -> UNSAFE.arrayBaseOffset(char[].class); + default -> throw GraalError.shouldNotReachHereUnexpectedValue(kind); + }; } - @Override - protected byte[] generateClass(String internalClassName) { - ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); - cw.visit(52, ACC_SUPER | ACC_PUBLIC, internalClassName, null, "java/lang/Object", null); - - final String fieldName = "array"; - final String fieldDescriptor = "[" + kind.getTypeChar(); - - FieldVisitor field = cw.visitField(ACC_PUBLIC | ACC_STATIC, fieldName, fieldDescriptor, null, null); - field.visitEnd(); + private void generateSnippet(CodeBuilder b, ClassDesc thisClass) { + ClassDesc targetType = kind.upperBound(); - MethodVisitor clinit = cw.visitMethod(ACC_STATIC, "", "()V", null, null); - clinit.visitCode(); - clinit.visitIntInsn(BIPUSH, 16); - clinit.visitIntInsn(NEWARRAY, toASMType(kind)); - clinit.visitFieldInsn(PUTSTATIC, internalClassName, fieldName, fieldDescriptor); - clinit.visitInsn(RETURN); - clinit.visitMaxs(1, 0); - clinit.visitEnd(); + ClassDesc classGraalTest = cd(GraalTest.class); + ClassDesc classUnsafe = cd(Unsafe.class); - MethodVisitor snippet = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, SNIPPET, "()Z", null, null); - snippet.visitCode(); + ConstantPoolBuilder cpb = ConstantPoolBuilder.of(); + FieldRefEntry unsafeField = cpb.fieldRefEntry(classGraalTest, "UNSAFE", classUnsafe); + FieldRefEntry arrayField = cpb.fieldRefEntry(thisClass, FIELD, targetType.arrayType()); if (unsafeStore) { - SubWordTestUtil.getUnsafe(snippet); - snippet.visitFieldInsn(GETSTATIC, internalClassName, fieldName, fieldDescriptor); - snippet.visitLdcInsn(arrayBaseOffset(kind)); - snippet.visitLdcInsn(value); - snippet.visitMethodInsn(INVOKEVIRTUAL, "jdk/internal/misc/Unsafe", "put" + SubWordTestUtil.getUnsafePutMethodName(kind), "(Ljava/lang/Object;J" + kind.getTypeChar() + ")V", false); + b + .getstatic(unsafeField) + .getstatic(arrayField) + .ldc(arrayBaseOffset(kind)) + .ldc(value) + .invokevirtual(classUnsafe, "put" + getUnsafePutMethodName(kind), MethodTypeDesc.of(CD_void, CD_Object, CD_long, targetType)); } else { - snippet.visitFieldInsn(GETSTATIC, internalClassName, fieldName, fieldDescriptor); - snippet.visitInsn(ICONST_0); - snippet.visitLdcInsn(value); - snippet.visitInsn(toArrayStoreOpcode(kind)); + b + .getstatic(arrayField) + .iconst_0() + .ldc(value); + + switch (kind) { + case BOOLEAN, BYTE -> b.bastore(); + case SHORT -> b.sastore(); + case CHAR -> b.castore(); + } } if (unsafeLoad) { - SubWordTestUtil.getUnsafe(snippet); - snippet.visitFieldInsn(GETSTATIC, internalClassName, fieldName, fieldDescriptor); - snippet.visitLdcInsn(arrayBaseOffset(kind)); - snippet.visitMethodInsn(INVOKEVIRTUAL, "jdk/internal/misc/Unsafe", "get" + SubWordTestUtil.getUnsafePutMethodName(kind), "(Ljava/lang/Object;J)" + kind.getTypeChar(), false); + b + .getstatic(unsafeField) + .getstatic(arrayField) + .ldc(arrayBaseOffset(kind)) + .invokevirtual(classUnsafe, "get" + getUnsafePutMethodName(kind), MethodTypeDesc.of(targetType, CD_Object, CD_long)); } else { - snippet.visitFieldInsn(GETSTATIC, internalClassName, fieldName, fieldDescriptor); - snippet.visitInsn(ICONST_0); - snippet.visitInsn(toArrayLoadOpcode(kind)); + b + .getstatic(arrayField) + .iconst_0(); + + switch (kind) { + case BOOLEAN, BYTE -> b.baload(); + case SHORT -> b.saload(); + case CHAR -> b.caload(); + } } - snippet.visitLdcInsn(value); - SubWordTestUtil.convertToKind(snippet, kind); - SubWordTestUtil.testEqual(snippet); - - snippet.visitMaxs(5, 0); - snippet.visitEnd(); - - cw.visitEnd(); - return cw.toByteArray(); + b + .ldc(value) + .conversion(TypeKind.INT, kind) + .ifThenElse(Opcode.IF_ICMPNE, + thenBlock -> thenBlock.iconst_1().ireturn(), + elseBlock -> elseBlock.iconst_0().ireturn()); } } diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/SubWordFieldStoreTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/SubWordFieldStoreTest.java index 194748442d36..d8b047e86ed6 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/SubWordFieldStoreTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/SubWordFieldStoreTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, 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 @@ -24,21 +24,36 @@ */ package jdk.graal.compiler.core.test; +import static java.lang.constant.ConstantDescs.CD_Class; +import static java.lang.constant.ConstantDescs.CD_Exception; +import static java.lang.constant.ConstantDescs.CD_Object; +import static java.lang.constant.ConstantDescs.CD_String; +import static java.lang.constant.ConstantDescs.CD_boolean; +import static java.lang.constant.ConstantDescs.CD_long; +import static java.lang.constant.ConstantDescs.CD_void; + +import java.lang.classfile.ClassFile; +import java.lang.classfile.CodeBuilder; +import java.lang.classfile.Opcode; +import java.lang.classfile.TypeKind; +import java.lang.classfile.attribute.ExceptionsAttribute; +import java.lang.classfile.constantpool.ConstantPoolBuilder; +import java.lang.classfile.constantpool.FieldRefEntry; +import java.lang.constant.ClassDesc; +import java.lang.constant.MethodTypeDesc; +import java.lang.reflect.Field; import java.util.ArrayList; import java.util.List; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.FieldVisitor; -import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Type; -import jdk.vm.ci.meta.JavaKind; +import jdk.graal.compiler.test.GraalTest; +import jdk.internal.misc.Unsafe; @RunWith(Parameterized.class) -public class SubWordFieldStoreTest extends CustomizedBytecodePatternTest { +public class SubWordFieldStoreTest extends GraalCompilerTest implements CustomizedBytecodePattern { @Parameterized.Parameters(name = "{0}, {1}, {2}, {3}") public static List data() { @@ -46,10 +61,10 @@ public static List data() { for (int i : new int[]{0xFFFF0000, 0xFFFF0001, 0x0000FFFF, 0x01020304}) { for (boolean unsafeStore : new boolean[]{false, true}) { for (boolean unsafeLoad : new boolean[]{false, true}) { - ret.add(new Object[]{JavaKind.Boolean, i, unsafeStore, unsafeLoad}); - ret.add(new Object[]{JavaKind.Byte, i, unsafeStore, unsafeLoad}); - ret.add(new Object[]{JavaKind.Short, i, unsafeStore, unsafeLoad}); - ret.add(new Object[]{JavaKind.Char, i, unsafeStore, unsafeLoad}); + ret.add(new Object[]{TypeKind.BOOLEAN, i, unsafeStore, unsafeLoad}); + ret.add(new Object[]{TypeKind.BYTE, i, unsafeStore, unsafeLoad}); + ret.add(new Object[]{TypeKind.SHORT, i, unsafeStore, unsafeLoad}); + ret.add(new Object[]{TypeKind.CHAR, i, unsafeStore, unsafeLoad}); } } } @@ -57,13 +72,14 @@ public static List data() { } private static final String SNIPPET = "snippet"; + private static final String FIELD = "field"; - private final JavaKind kind; + private final TypeKind kind; private final int value; private final boolean unsafeStore; private final boolean unsafeLoad; - public SubWordFieldStoreTest(JavaKind kind, int value, boolean unsafeStore, boolean unsafeLoad) { + public SubWordFieldStoreTest(TypeKind kind, int value, boolean unsafeStore, boolean unsafeLoad) { this.kind = kind; this.value = value; this.unsafeStore = unsafeStore; @@ -77,78 +93,70 @@ public void testFieldStore() throws ClassNotFoundException { } @Override - protected byte[] generateClass(String internalClassName) { - ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); - cw.visit(52, ACC_SUPER | ACC_PUBLIC, internalClassName, null, "java/lang/Object", null); - - final String fieldName = "field"; - final String fieldDescriptor = Character.toString(kind.getTypeChar()); + public byte[] generateClass(String className) { + ClassDesc thisClass = ClassDesc.of(className); + ClassDesc targetType = kind.upperBound(); + + return ClassFile.of().build(thisClass, classBuilder -> classBuilder + .withField(FIELD, targetType, ACC_PUBLIC_STATIC) + .withMethod(SNIPPET, MethodTypeDesc.of(CD_boolean), ACC_PUBLIC_STATIC, methodBuilder -> methodBuilder + .with(ExceptionsAttribute.ofSymbols(CD_Exception)) + .withCode(b -> generateSnippet(b, thisClass)))); + } - FieldVisitor field = cw.visitField(ACC_PUBLIC | ACC_STATIC, fieldName, fieldDescriptor, null, value); - field.visitEnd(); + static String getUnsafePutMethodName(TypeKind kind) { + String name = kind.name(); + return name.charAt(0) + name.substring(1).toLowerCase(); + } - MethodVisitor snippet = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, SNIPPET, "()Z", null, new String[]{"java/lang/NoSuchFieldException"}); - snippet.visitCode(); + private void generateSnippet(CodeBuilder b, ClassDesc thisClass) { + ClassDesc targetType = kind.upperBound(); + + ClassDesc classField = cd(Field.class); + ClassDesc classGraalTest = cd(GraalTest.class); + ClassDesc classUnsafe = cd(Unsafe.class); + + FieldRefEntry unsafeField = ConstantPoolBuilder.of().fieldRefEntry(classGraalTest, "UNSAFE", classUnsafe); + + if (unsafeStore | unsafeLoad) { + b + .ldc(thisClass) + .ldc(FIELD) + .invokevirtual(CD_Class, "getField", MethodTypeDesc.of(classField, CD_String)) + .astore(0) + .getstatic(unsafeField) + .aload(0) + .invokevirtual(classUnsafe, "staticFieldBase", MethodTypeDesc.of(CD_Object, classField)) + .astore(1) + .getstatic(unsafeField) + .aload(0) + .invokevirtual(classUnsafe, "staticFieldOffset", MethodTypeDesc.of(CD_long, classField)) + .lstore(2); + } if (unsafeStore) { - snippet.visitLdcInsn(Type.getObjectType(internalClassName)); - snippet.visitLdcInsn(fieldName); - snippet.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getField", "(Ljava/lang/String;)Ljava/lang/reflect/Field;", false); - snippet.visitVarInsn(ASTORE, 0); - - SubWordTestUtil.getUnsafe(snippet); - snippet.visitVarInsn(ALOAD, 0); - snippet.visitMethodInsn(INVOKEVIRTUAL, "jdk/internal/misc/Unsafe", "staticFieldBase", "(Ljava/lang/reflect/Field;)Ljava/lang/Object;", false); - snippet.visitVarInsn(ASTORE, 1); - - SubWordTestUtil.getUnsafe(snippet); - snippet.visitVarInsn(ALOAD, 0); - snippet.visitMethodInsn(INVOKEVIRTUAL, "jdk/internal/misc/Unsafe", "staticFieldOffset", "(Ljava/lang/reflect/Field;)J", false); - snippet.visitVarInsn(LSTORE, 2); - - SubWordTestUtil.getUnsafe(snippet); - snippet.visitVarInsn(ALOAD, 1); - snippet.visitVarInsn(LLOAD, 2); - snippet.visitLdcInsn(value); - snippet.visitMethodInsn(INVOKEVIRTUAL, "jdk/internal/misc/Unsafe", "put" + SubWordTestUtil.getUnsafePutMethodName(kind), "(Ljava/lang/Object;J" + kind.getTypeChar() + ")V", false); + b.getstatic(unsafeField) + .aload(1) + .lload(2) + .ldc(value) + .invokevirtual(classUnsafe, "put" + getUnsafePutMethodName(kind), MethodTypeDesc.of(CD_void, CD_Object, CD_long, targetType)); } else { - snippet.visitLdcInsn(value); - snippet.visitFieldInsn(PUTSTATIC, internalClassName, fieldName, fieldDescriptor); + b.ldc(value) + .putstatic(thisClass, FIELD, targetType); } - if (unsafeLoad) { - if (!unsafeStore) { - snippet.visitLdcInsn(Type.getObjectType(internalClassName)); - snippet.visitLdcInsn(fieldName); - snippet.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getField", "(Ljava/lang/String;)Ljava/lang/reflect/Field;", false); - snippet.visitVarInsn(ASTORE, 0); - - SubWordTestUtil.getUnsafe(snippet); - snippet.visitVarInsn(ALOAD, 0); - snippet.visitMethodInsn(INVOKEVIRTUAL, "jdk/internal/misc/Unsafe", "staticFieldBase", "(Ljava/lang/reflect/Field;)Ljava/lang/Object;", false); - snippet.visitVarInsn(ASTORE, 1); - - SubWordTestUtil.getUnsafe(snippet); - snippet.visitVarInsn(ALOAD, 0); - snippet.visitMethodInsn(INVOKEVIRTUAL, "jdk/internal/misc/Unsafe", "staticFieldOffset", "(Ljava/lang/reflect/Field;)J", false); - snippet.visitVarInsn(LSTORE, 2); - } - SubWordTestUtil.getUnsafe(snippet); - snippet.visitVarInsn(ALOAD, 1); - snippet.visitVarInsn(LLOAD, 2); - snippet.visitMethodInsn(INVOKEVIRTUAL, "jdk/internal/misc/Unsafe", "get" + SubWordTestUtil.getUnsafePutMethodName(kind), "(Ljava/lang/Object;J)" + kind.getTypeChar(), false); + b.getstatic(unsafeField) + .aload(1) + .lload(2) + .invokevirtual(classUnsafe, "get" + getUnsafePutMethodName(kind), MethodTypeDesc.of(targetType, CD_Object, CD_long)); } else { - snippet.visitFieldInsn(GETSTATIC, internalClassName, fieldName, fieldDescriptor); + b.getstatic(thisClass, FIELD, targetType); } - snippet.visitLdcInsn(value); - SubWordTestUtil.convertToKind(snippet, kind); - SubWordTestUtil.testEqual(snippet); - - snippet.visitMaxs(5, 4); - snippet.visitEnd(); - - cw.visitEnd(); - return cw.toByteArray(); + b.ldc(value) + .conversion(TypeKind.INT, kind) + .ifThenElse(Opcode.IF_ICMPNE, + thenBlock -> thenBlock.iconst_1().ireturn(), + elseBlock -> elseBlock.iconst_0().ireturn()); } } diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/SubWordInputTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/SubWordInputTest.java index ba1b31f357d7..878198d2d1a2 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/SubWordInputTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/SubWordInputTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, 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 @@ -24,6 +24,14 @@ */ package jdk.graal.compiler.core.test; +import static java.lang.constant.ConstantDescs.CD_boolean; +import static java.lang.constant.ConstantDescs.CD_int; + +import java.lang.classfile.ClassFile; +import java.lang.classfile.Opcode; +import java.lang.classfile.TypeKind; +import java.lang.constant.ClassDesc; +import java.lang.constant.MethodTypeDesc; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -31,24 +39,21 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.MethodVisitor; +import org.junit.runners.Parameterized.Parameters; -import jdk.vm.ci.meta.DeoptimizationReason; -import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.ResolvedJavaMethod; @RunWith(Parameterized.class) -public class SubWordInputTest extends CustomizedBytecodePatternTest { +public class SubWordInputTest extends GraalCompilerTest implements CustomizedBytecodePattern { - @Parameterized.Parameters(name = "{0}, {1}") + @Parameters(name = "{0}, {1}") public static List data() { ArrayList ret = new ArrayList<>(); for (int i : new int[]{0xFFFF0000, 0xFFFF0001, 0x0000FFFF}) { - ret.add(new Object[]{JavaKind.Boolean, i}); - ret.add(new Object[]{JavaKind.Byte, i}); - ret.add(new Object[]{JavaKind.Short, i}); - ret.add(new Object[]{JavaKind.Char, i}); + ret.add(new Object[]{TypeKind.BOOLEAN, i}); + ret.add(new Object[]{TypeKind.BYTE, i}); + ret.add(new Object[]{TypeKind.SHORT, i}); + ret.add(new Object[]{TypeKind.CHAR, i}); } return ret; } @@ -56,10 +61,10 @@ public static List data() { private static final String GET = "get"; private static final String WRAPPER = "wrapper"; - private final JavaKind kind; + private final TypeKind kind; private final int value; - public SubWordInputTest(JavaKind kind, int value) { + public SubWordInputTest(TypeKind kind, int value) { this.kind = kind; this.value = value; } @@ -73,40 +78,26 @@ public void testSubWordInput() throws ClassNotFoundException { getCode(getResolvedJavaMethod(testClass, GET), null, false, true, getInitialOptions()); assertEquals(executeExpected(wrapper, null, value), expected); // test with inlining - testAgainstExpected(wrapper, expected, Collections. emptySet(), null, value); + testAgainstExpected(wrapper, expected, Collections.emptySet(), null, value); } @Override - protected byte[] generateClass(String internalClassName) { - ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); - cw.visit(52, ACC_SUPER | ACC_PUBLIC, internalClassName, null, "java/lang/Object", null); - - final char typeChar = kind.getTypeChar(); - - // Generates a method that returns the input subword immediately. - String getDescriptor = "(" + typeChar + ")" + typeChar; - MethodVisitor get = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, GET, getDescriptor, null, null); - get.visitCode(); - get.visitVarInsn(ILOAD, 0); - get.visitInsn(IRETURN); - get.visitMaxs(1, 1); - get.visitEnd(); - - // Genearates a method that compares the return value of the preceding method by passing the - // input value, and a manual masking of the input value. - MethodVisitor snippet = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, WRAPPER, "(I)Z", null, null); - snippet.visitCode(); - snippet.visitVarInsn(ILOAD, 0); - snippet.visitMethodInsn(INVOKESTATIC, internalClassName, GET, getDescriptor, false); - - snippet.visitVarInsn(ILOAD, 0); - SubWordTestUtil.convertToKind(snippet, kind); - SubWordTestUtil.testEqual(snippet); - - snippet.visitMaxs(2, 1); - snippet.visitEnd(); - - cw.visitEnd(); - return cw.toByteArray(); + public byte[] generateClass(String className) { + ClassDesc thisClass = ClassDesc.of(className); + ClassDesc targetType = kind.upperBound(); + MethodTypeDesc getMethodTypeDesc = MethodTypeDesc.of(targetType, targetType); + + return ClassFile.of().build(thisClass, classBuilder -> classBuilder + .withMethodBody(GET, getMethodTypeDesc, ACC_PUBLIC_STATIC, b -> b + .iload(0) + .ireturn()) + .withMethodBody(WRAPPER, MethodTypeDesc.of(CD_boolean, CD_int), ACC_PUBLIC_STATIC, b -> b + .iload(0) + .invokestatic(thisClass, GET, getMethodTypeDesc) + .iload(0) + .conversion(TypeKind.INT, kind) + .ifThenElse(Opcode.IF_ICMPNE, + thenBlock -> thenBlock.iconst_1().ireturn(), + elseBlock -> elseBlock.iconst_0().ireturn()))); } } diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/SubWordInputTest2.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/SubWordInputTest2.java index 76b6a15c3916..f33a5c0a02cc 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/SubWordInputTest2.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/SubWordInputTest2.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, 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 @@ -24,6 +24,14 @@ */ package jdk.graal.compiler.core.test; +import static java.lang.constant.ConstantDescs.CD_boolean; +import static java.lang.constant.ConstantDescs.CD_int; + +import java.lang.classfile.ClassFile; +import java.lang.classfile.Opcode; +import java.lang.classfile.TypeKind; +import java.lang.constant.ClassDesc; +import java.lang.constant.MethodTypeDesc; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -31,24 +39,19 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.Label; -import org.objectweb.asm.MethodVisitor; -import jdk.vm.ci.meta.DeoptimizationReason; -import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.ResolvedJavaMethod; @RunWith(Parameterized.class) -public class SubWordInputTest2 extends CustomizedBytecodePatternTest { +public class SubWordInputTest2 extends GraalCompilerTest implements CustomizedBytecodePattern { @Parameterized.Parameters(name = "{0}, {1}") public static List data() { ArrayList ret = new ArrayList<>(); for (int i : new int[]{0xFFFF0000, 0xFFFF0001, 0x0000FFFF}) { - ret.add(new Object[]{JavaKind.Byte, i}); - ret.add(new Object[]{JavaKind.Short, i}); - ret.add(new Object[]{JavaKind.Char, i}); + ret.add(new Object[]{TypeKind.BYTE, i}); + ret.add(new Object[]{TypeKind.SHORT, i}); + ret.add(new Object[]{TypeKind.CHAR, i}); } return ret; } @@ -56,10 +59,10 @@ public static List data() { private static final String GET = "get"; private static final String WRAPPER = "wrapper"; - private final JavaKind kind; + private final TypeKind kind; private final int value; - public SubWordInputTest2(JavaKind kind, int value) { + public SubWordInputTest2(TypeKind kind, int value) { this.kind = kind; this.value = value; } @@ -73,38 +76,24 @@ public void testSubWordInput() throws ClassNotFoundException { getCode(getResolvedJavaMethod(testClass, GET), null, false, true, getInitialOptions()); assertEquals(executeExpected(wrapper, null, value), expected); // test with inlining - testAgainstExpected(wrapper, expected, Collections. emptySet(), null, value); + testAgainstExpected(wrapper, expected, Collections.emptySet(), null, value); } @Override - protected byte[] generateClass(String internalClassName) { - ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); - cw.visit(52, ACC_SUPER | ACC_PUBLIC, internalClassName, null, "java/lang/Object", null); - - final char typeChar = kind.getTypeChar(); - String getDescriptor = "(" + typeChar + ")" + "Z"; - MethodVisitor get = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, GET, getDescriptor, null, null); - get.visitCode(); - get.visitVarInsn(ILOAD, 0); - Label label = new Label(); - get.visitJumpInsn(IFGE, label); - get.visitInsn(ICONST_0); - get.visitInsn(IRETURN); - get.visitLabel(label); - get.visitInsn(ICONST_1); - get.visitInsn(IRETURN); - get.visitMaxs(1, 1); - get.visitEnd(); - - MethodVisitor snippet = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, WRAPPER, "(I)Z", null, null); - snippet.visitCode(); - snippet.visitVarInsn(ILOAD, 0); - snippet.visitMethodInsn(INVOKESTATIC, internalClassName, GET, getDescriptor, false); - snippet.visitInsn(IRETURN); - snippet.visitMaxs(1, 1); - snippet.visitEnd(); + public byte[] generateClass(String className) { + ClassDesc thisClass = ClassDesc.of(className); + ClassDesc targetType = kind.upperBound(); + MethodTypeDesc getMethodTypeDesc = MethodTypeDesc.of(CD_boolean, targetType); - cw.visitEnd(); - return cw.toByteArray(); + return ClassFile.of().build(thisClass, classBuilder -> classBuilder + .withMethodBody(GET, getMethodTypeDesc, ACC_PUBLIC_STATIC, b -> b + .iload(0) + .ifThenElse(Opcode.IFGE, + thenBlock -> thenBlock.iconst_0().ireturn(), + elseBlock -> elseBlock.iconst_1().ireturn())) + .withMethodBody(WRAPPER, MethodTypeDesc.of(CD_boolean, CD_int), ACC_PUBLIC_STATIC, b -> b + .iload(0) + .invokestatic(thisClass, GET, getMethodTypeDesc) + .ireturn())); } } diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/SubWordReturnTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/SubWordReturnTest.java index 9b56bddecefa..19cef3b44afe 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/SubWordReturnTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/SubWordReturnTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, 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 @@ -24,6 +24,15 @@ */ package jdk.graal.compiler.core.test; +import static java.lang.classfile.ClassFile.ACC_STATIC; +import static java.lang.constant.ConstantDescs.CD_int; +import static java.lang.constant.ConstantDescs.CLASS_INIT_NAME; +import static java.lang.constant.ConstantDescs.MTD_void; + +import java.lang.classfile.ClassFile; +import java.lang.classfile.TypeKind; +import java.lang.constant.ClassDesc; +import java.lang.constant.MethodTypeDesc; import java.util.ArrayList; import java.util.List; @@ -31,32 +40,32 @@ import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.FieldVisitor; -import org.objectweb.asm.MethodVisitor; -import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.ResolvedJavaMethod; @RunWith(Parameterized.class) -public class SubWordReturnTest extends CustomizedBytecodePatternTest { - - private final JavaKind kind; - private final int value; +public class SubWordReturnTest extends GraalCompilerTest implements CustomizedBytecodePattern { @Parameters(name = "{0}, {1}") public static List data() { ArrayList ret = new ArrayList<>(); for (int i : new int[]{1000000, 1000001, -1000000, -1}) { - ret.add(new Object[]{JavaKind.Boolean, i}); - ret.add(new Object[]{JavaKind.Byte, i}); - ret.add(new Object[]{JavaKind.Short, i}); - ret.add(new Object[]{JavaKind.Char, i}); + ret.add(new Object[]{TypeKind.BOOLEAN, i}); + ret.add(new Object[]{TypeKind.BYTE, i}); + ret.add(new Object[]{TypeKind.SHORT, i}); + ret.add(new Object[]{TypeKind.CHAR, i}); } return ret; } - public SubWordReturnTest(JavaKind kind, int value) { + private static final String GET = "get"; + private static final String WRAPPER = "wrapper"; + private static final String FIELD = "intField"; + + private final TypeKind kind; + private final int value; + + public SubWordReturnTest(TypeKind kind, int value) { this.kind = kind; this.value = value; } @@ -64,7 +73,7 @@ public SubWordReturnTest(JavaKind kind, int value) { @Test public void testSubWordReturn() throws ClassNotFoundException { Class testClass = getClass(SubWordReturnTest.class.getName() + "$" + kind.toString() + "Getter"); - ResolvedJavaMethod method = getResolvedJavaMethod(testClass, "testSnippet"); + ResolvedJavaMethod method = getResolvedJavaMethod(testClass, WRAPPER); test(method, null); } @@ -82,35 +91,28 @@ private static byte get() { return 0; } - public static int testByteSnippet() { + public static int wrapper() { return get(); } } @Override - protected byte[] generateClass(String internalClassName) { - ClassWriter cw = new ClassWriter(0); - cw.visit(52, ACC_SUPER | ACC_PUBLIC, internalClassName, null, "java/lang/Object", null); - - FieldVisitor intField = cw.visitField(ACC_PRIVATE | ACC_STATIC, "intField", "I", null, value); - intField.visitEnd(); - - MethodVisitor get = cw.visitMethod(ACC_PRIVATE | ACC_STATIC, "get", "()" + kind.getTypeChar(), null, null); - get.visitCode(); - get.visitFieldInsn(GETSTATIC, internalClassName, "intField", "I"); - get.visitInsn(IRETURN); - get.visitMaxs(1, 0); - get.visitEnd(); - - MethodVisitor snippet = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "testSnippet", "()I", null, null); - snippet.visitCode(); - snippet.visitMethodInsn(INVOKESTATIC, internalClassName, "get", "()" + kind.getTypeChar(), false); - snippet.visitInsn(IRETURN); - snippet.visitMaxs(1, 0); - snippet.visitEnd(); - - cw.visitEnd(); - return cw.toByteArray(); + public byte[] generateClass(String className) { + ClassDesc thisClass = ClassDesc.of(className); + ClassDesc targetType = kind.upperBound(); + MethodTypeDesc getMethodTypeDesc = MethodTypeDesc.of(targetType); + + return ClassFile.of().build(thisClass, classBuilder -> classBuilder + .withField(FIELD, CD_int, ACC_PUBLIC_STATIC) + .withMethodBody(CLASS_INIT_NAME, MTD_void, ACC_STATIC, b -> b + .ldc(value) + .putstatic(thisClass, FIELD, CD_int) + .return_()) + .withMethodBody(GET, getMethodTypeDesc, ACC_PUBLIC_STATIC, b -> b + .getstatic(thisClass, FIELD, CD_int) + .ireturn()) + .withMethodBody(WRAPPER, MethodTypeDesc.of(CD_int), ACC_PUBLIC_STATIC, b -> b + .invokestatic(thisClass, GET, getMethodTypeDesc) + .ireturn())); } - } diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/SubWordTestUtil.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/SubWordTestUtil.java deleted file mode 100644 index d1766808325c..000000000000 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/SubWordTestUtil.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2018, 2024, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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. - */ -package jdk.graal.compiler.core.test; - -import jdk.graal.compiler.debug.GraalError; -import jdk.graal.compiler.test.GraalTest; -import org.objectweb.asm.Label; -import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Opcodes; - -import jdk.vm.ci.meta.JavaKind; - -public final class SubWordTestUtil implements Opcodes { - - private SubWordTestUtil() { - } - - static void convertToKind(MethodVisitor snippet, JavaKind kind) { - switch (kind) { - case Boolean: - snippet.visitInsn(ICONST_1); - snippet.visitInsn(IAND); - break; - case Byte: - snippet.visitInsn(I2B); - break; - case Short: - snippet.visitInsn(I2S); - break; - case Char: - snippet.visitInsn(I2C); - break; - default: - throw GraalError.shouldNotReachHereUnexpectedValue(kind); // ExcludeFromJacocoGeneratedReport - } - } - - static void testEqual(MethodVisitor snippet) { - Label label = new Label(); - snippet.visitJumpInsn(IF_ICMPNE, label); - snippet.visitInsn(ICONST_1); - snippet.visitInsn(IRETURN); - snippet.visitLabel(label); - snippet.visitInsn(ICONST_0); - snippet.visitInsn(IRETURN); - } - - static void getUnsafe(MethodVisitor snippet) { - snippet.visitFieldInsn(GETSTATIC, GraalTest.class.getName().replace('.', '/'), "UNSAFE", "Ljdk/internal/misc/Unsafe;"); - } - - static String getUnsafePutMethodName(JavaKind kind) { - String name = kind.getJavaName(); - return name.substring(0, 1).toUpperCase() + name.substring(1); - } - -} diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/SwitchFoldingTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/SwitchFoldingTest.java index 61a4bbaee2a7..0af80a813d30 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/SwitchFoldingTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/SwitchFoldingTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, 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 @@ -25,21 +25,24 @@ package jdk.graal.compiler.core.test; -import static org.objectweb.asm.Opcodes.ACC_PUBLIC; -import static org.objectweb.asm.Opcodes.ACC_STATIC; -import static org.objectweb.asm.Opcodes.ACC_SUPER; -import static org.objectweb.asm.Opcodes.GOTO; -import static org.objectweb.asm.Opcodes.ICONST_0; -import static org.objectweb.asm.Opcodes.ICONST_1; -import static org.objectweb.asm.Opcodes.ICONST_5; -import static org.objectweb.asm.Opcodes.ICONST_M1; -import static org.objectweb.asm.Opcodes.IFLT; -import static org.objectweb.asm.Opcodes.ILOAD; -import static org.objectweb.asm.Opcodes.INVOKESTATIC; -import static org.objectweb.asm.Opcodes.IRETURN; +import static java.lang.classfile.ClassFile.ACC_PUBLIC; +import static java.lang.classfile.ClassFile.ACC_STATIC; +import static java.lang.constant.ConstantDescs.CD_boolean; +import static java.lang.constant.ConstantDescs.CD_int; +import static java.lang.constant.ConstantDescs.MTD_void; + +import java.lang.classfile.ClassFile; +import java.lang.classfile.Label; +import java.lang.classfile.instruction.SwitchCase; +import java.lang.constant.ClassDesc; +import java.lang.constant.MethodTypeDesc; +import java.util.ArrayList; +import java.util.List; + +import org.junit.Assert; +import org.junit.Test; import jdk.graal.compiler.api.directives.GraalDirectives; -import jdk.graal.compiler.api.test.ExportingClassLoader; import jdk.graal.compiler.debug.DebugContext; import jdk.graal.compiler.graph.iterators.NodeIterable; import jdk.graal.compiler.loop.phases.ConvertDeoptimizeToGuardPhase; @@ -50,16 +53,10 @@ import jdk.graal.compiler.nodes.ReturnNode; import jdk.graal.compiler.nodes.StructuredGraph; import jdk.graal.compiler.nodes.extended.IntegerSwitchNode; -import org.junit.Assert; -import org.junit.Test; -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.Label; -import org.objectweb.asm.MethodVisitor; - import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.ResolvedJavaMethod; -public class SwitchFoldingTest extends GraalCompilerTest { +public class SwitchFoldingTest extends GraalCompilerTest implements CustomizedBytecodePattern { private static final String REFERENCE_SNIPPET = "referenceSnippet"; private static final String REFERENCE_SNIPPET_2 = "reference2Snippet"; @@ -558,130 +555,97 @@ private static boolean compareGraphs(StructuredGraph g1, StructuredGraph g2) { return true; } - private static final String NAME = "D"; - private static final byte[] clazz = makeClass(); - - public static class MyClassLoader extends ExportingClassLoader { - @Override - protected Class findClass(String className) throws ClassNotFoundException { - return defineClass(NAME.replace('/', '.'), clazz, 0, clazz.length); - } - } - - private static byte[] makeClass() { - ClassWriter cw = new ClassWriter(0); - MethodVisitor mv; - String jvmName = NAME.replace('.', '/'); - cw.visit(49, ACC_SUPER | ACC_PUBLIC, jvmName, null, "java/lang/Object", new String[]{}); - - // Checkstyle: stop AvoidNestedBlocks - { - /*- - * public static int m(boolean, int) { - * ILOAD_0 - * IFLT L1 - * ILOAD_1 - * LOOKUPSWITCH - * [1, 2] -> - * return some int - * [5, 7] -> - * GOTO L1 - * [3, 6, 9] -> - * GOTO L2 (Different blocks) - * [0, 4, 8] -> - * GOTO L2 (Same block) - * L1: - * deopt - * return 0 - * L2: - * return 5 - * } - * - * Optimization should coalesce branches [5, 7] and [3, 6, 9] - */ - Label outMerge = new Label(); - Label inMerge = new Label(); - Label commonTarget = new Label(); - Label def = new Label(); - - int[] keys = new int[10]; - Label[] labels = new Label[10]; - - Label[] inMerges = new Label[3]; - Label[] outMerges = new Label[2]; - Label[] simple = new Label[2]; - - for (int i = 0; i < inMerges.length; i++) { - inMerges[i] = new Label(); - } - for (int i = 0; i < simple.length; i++) { - simple[i] = new Label(); - } - for (int i = 0; i < outMerges.length; i++) { - outMerges[i] = new Label(); - } - for (int i = 0; i < keys.length; i++) { - keys[i] = i; - } - int in = 0; - int out = 0; - int s = 0; - labels[0] = commonTarget; - labels[1] = simple[s++]; - labels[2] = simple[s++]; - labels[3] = inMerges[in++]; - labels[4] = commonTarget; - labels[5] = outMerges[out++]; - labels[6] = inMerges[in++]; - labels[7] = outMerges[out++]; - labels[8] = commonTarget; - labels[9] = inMerges[in++]; - - mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "m", "(ZI)I", null, null); - mv.visitCode(); - mv.visitIntInsn(ILOAD, 0); - mv.visitJumpInsn(IFLT, outMerge); - - mv.visitIntInsn(ILOAD, 1); - mv.visitLookupSwitchInsn(def, keys, labels); - - for (int i = 0; i < inMerges.length; i++) { - mv.visitLabel(inMerges[i]); - mv.visitJumpInsn(GOTO, inMerge); - } - for (int i = 0; i < outMerges.length; i++) { - mv.visitLabel(outMerges[i]); - mv.visitJumpInsn(GOTO, outMerge); - } - for (int i = 0; i < simple.length; i++) { - mv.visitLabel(simple[i]); - mv.visitInsn(ICONST_0 + i); - mv.visitInsn(IRETURN); - } - - mv.visitLabel(def); - mv.visitInsn(ICONST_1); - mv.visitInsn(IRETURN); - - mv.visitLabel(inMerge); - mv.visitInsn(ICONST_5); - mv.visitInsn(IRETURN); - - mv.visitLabel(commonTarget); - mv.visitJumpInsn(GOTO, inMerge); - - mv.visitLabel(outMerge); - mv.visitMethodInsn(INVOKESTATIC, GraalDirectives.class.getName().replace('.', '/'), "deoptimize", "()V", false); - mv.visitInsn(ICONST_M1); - mv.visitInsn(IRETURN); - - mv.visitMaxs(3, 2); - mv.visitEnd(); - } - // Checkstyle: resume AvoidNestedBlocks - - cw.visitEnd(); - return cw.toByteArray(); + public byte[] generateClass(String className) { + /*- + * public static int m(boolean, int) { + * ILOAD_0 + * IFLT L1 + * ILOAD_1 + * LOOKUPSWITCH + * [1, 2] -> + * return some int + * [5, 7] -> + * GOTO L1 + * [3, 6, 9] -> + * GOTO L2 (Different blocks) + * [0, 4, 8] -> + * GOTO L2 (Same block) + * L1: + * deopt + * return 0 + * L2: + * return 5 + * } + * + * Optimization should coalesce branches [5, 7] and [3, 6, 9] + */ + return ClassFile.of().build(ClassDesc.of(className), classBuilder -> classBuilder + .withMethodBody("m", MethodTypeDesc.of(CD_int, CD_boolean, CD_int), ACC_STATIC | ACC_PUBLIC, b -> { + Label outMerge = b.newLabel(); + Label inMerge = b.newLabel(); + Label commonTarget = b.newLabel(); + Label def = b.newLabel(); + + Label[] inMerges = new Label[3]; + Label[] outMerges = new Label[2]; + Label[] simple = new Label[2]; + + for (int i = 0; i < inMerges.length; i++) { + inMerges[i] = b.newLabel(); + } + for (int i = 0; i < simple.length; i++) { + simple[i] = b.newLabel(); + } + for (int i = 0; i < outMerges.length; i++) { + outMerges[i] = b.newLabel(); + } + + int in = 0; + int out = 0; + int s = 0; + + List cases = new ArrayList<>(); + cases.add(SwitchCase.of(0, commonTarget)); + cases.add(SwitchCase.of(1, simple[s++])); + cases.add(SwitchCase.of(2, simple[s++])); + cases.add(SwitchCase.of(3, inMerges[in++])); + cases.add(SwitchCase.of(4, commonTarget)); + cases.add(SwitchCase.of(5, outMerges[out++])); + cases.add(SwitchCase.of(6, inMerges[in++])); + cases.add(SwitchCase.of(7, outMerges[out++])); + cases.add(SwitchCase.of(8, commonTarget)); + cases.add(SwitchCase.of(9, inMerges[in++])); + + b + .iload(0) + .iflt(outMerge) + .iload(1) + .lookupswitch(def, cases); + + for (int i = 0; i < inMerges.length; i++) { + b.labelBinding(inMerges[i]).goto_(inMerge); + } + + for (int i = 0; i < outMerges.length; i++) { + b.labelBinding(outMerges[i]).goto_(outMerge); + } + for (int i = 0; i < simple.length; i++) { + b.labelBinding(simple[i]).sipush(i).ireturn(); + } + + b.labelBinding(def) + .iconst_1() + .ireturn() + .labelBinding(inMerge) + .iconst_5() + .ireturn() + .labelBinding(commonTarget) + .goto_(inMerge) + .labelBinding(outMerge) + .invokestatic(cd(GraalDirectives.class), "deoptimize", MTD_void) + .iconst_m1() + .ireturn(); + })); } /** @@ -691,8 +655,7 @@ private static byte[] makeClass() { @Test public void compileTest() { try { - MyClassLoader loader = new MyClassLoader(); - Class c = loader.findClass(NAME); + Class c = getClass("D"); ResolvedJavaMethod method = getResolvedJavaMethod(c, "m"); StructuredGraph graph = parse(builder(method, StructuredGraph.AllowAssumptions.NO), getEagerGraphBuilderSuite()); graph.getDebug().dump(DebugContext.BASIC_LEVEL, graph, "Graph"); diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/TwoSlotMarkerClearingTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/TwoSlotMarkerClearingTest.java index b21aa2c8613b..6669c6bdb5a9 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/TwoSlotMarkerClearingTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/TwoSlotMarkerClearingTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, 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 @@ -25,14 +25,19 @@ package jdk.graal.compiler.core.test; +import static java.lang.constant.ConstantDescs.CD_int; +import static java.lang.constant.ConstantDescs.CD_long; + +import java.lang.classfile.ClassFile; +import java.lang.classfile.Opcode; +import java.lang.constant.ClassDesc; +import java.lang.constant.MethodTypeDesc; + import org.junit.Test; -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Label; import jdk.vm.ci.meta.ResolvedJavaMethod; -public class TwoSlotMarkerClearingTest extends CustomizedBytecodePatternTest { +public class TwoSlotMarkerClearingTest extends GraalCompilerTest implements CustomizedBytecodePattern { @Test public void testTwoSlotMarkerClearing() throws ClassNotFoundException { @@ -44,43 +49,21 @@ public void testTwoSlotMarkerClearing() throws ClassNotFoundException { } @Override - protected byte[] generateClass(String className) { - ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); - cw.visit(52, ACC_SUPER | ACC_PUBLIC, className, null, "java/lang/Object", null); - - String getDescriptor = "(" + "JII" + ")" + "I"; - MethodVisitor t1 = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "t1", getDescriptor, null, null); - t1.visitCode(); - t1.visitVarInsn(ILOAD, 2); - t1.visitVarInsn(ISTORE, 0); - t1.visitVarInsn(ILOAD, 0); - Label label = new Label(); - t1.visitJumpInsn(IFGE, label); - t1.visitVarInsn(ILOAD, 0); - t1.visitInsn(IRETURN); - t1.visitLabel(label); - t1.visitVarInsn(ILOAD, 3); - t1.visitInsn(IRETURN); - t1.visitMaxs(4, 1); - t1.visitEnd(); - - getDescriptor = "(" + "IJIJ" + ")" + "J"; - MethodVisitor t2 = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "t2", getDescriptor, null, null); - t2.visitCode(); - t2.visitVarInsn(LLOAD, 1); - t2.visitVarInsn(LSTORE, 0); - t2.visitVarInsn(ILOAD, 3); - Label label1 = new Label(); - t2.visitJumpInsn(IFGE, label1); - t2.visitVarInsn(LLOAD, 0); - t2.visitInsn(LRETURN); - t2.visitLabel(label1); - t2.visitVarInsn(LLOAD, 4); - t2.visitInsn(LRETURN); - t2.visitMaxs(6, 2); - t2.visitEnd(); - - cw.visitEnd(); - return cw.toByteArray(); + public byte[] generateClass(String className) { + return ClassFile.of().build(ClassDesc.of(className), classBuilder -> classBuilder + .withMethodBody("t1", MethodTypeDesc.of(CD_int, CD_long, CD_int, CD_int), ACC_PUBLIC_STATIC, b -> b + .iload(2) + .istore(0) + .iload(0) + .ifThenElse(Opcode.IFLT, + thenBlock -> thenBlock.iload(0).ireturn(), + elseBlock -> elseBlock.iload(3).ireturn())) + .withMethodBody("t2", MethodTypeDesc.of(CD_long, CD_int, CD_long, CD_int, CD_long), ACC_PUBLIC_STATIC, b -> b + .lload(1) + .lstore(0) + .iload(3) + .ifThenElse(Opcode.IFLT, + thenBlock -> thenBlock.lload(0).lreturn(), + elseBlock -> elseBlock.lload(4).lreturn()))); } } diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/UnbalancedLockingTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/UnbalancedLockingTest.java index 45639c00fa81..21dfa4eb8c50 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/UnbalancedLockingTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/UnbalancedLockingTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, 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 @@ -24,24 +24,32 @@ */ package jdk.graal.compiler.core.test; +import static java.lang.constant.ConstantDescs.CD_Object; +import static java.lang.constant.ConstantDescs.CD_int; +import static java.lang.constant.ConstantDescs.CD_void; +import static java.lang.constant.ConstantDescs.MTD_void; + +import java.lang.classfile.ClassFile; +import java.lang.classfile.CodeBuilder; +import java.lang.classfile.Label; +import java.lang.classfile.Opcode; +import java.lang.constant.ClassDesc; +import java.lang.constant.MethodTypeDesc; import java.lang.reflect.InvocationTargetException; +import org.junit.Ignore; +import org.junit.Test; + import jdk.graal.compiler.core.common.GraalOptions; import jdk.graal.compiler.java.BciBlockMapping; import jdk.graal.compiler.java.BytecodeParserOptions; import jdk.graal.compiler.options.OptionValues; -import org.junit.Ignore; -import org.junit.Test; -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.Label; -import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Type; /** * Test class exercising irreducible loop duplication logic in {@link BciBlockMapping} in * conjunction with locking and exception handlers. */ -public class UnbalancedLockingTest extends CustomizedBytecodePatternTest { +public class UnbalancedLockingTest extends GraalCompilerTest implements CustomizedBytecodePattern { /** * Run many calls to a test method to force a c1/c2 compile, check with -XX:+PrintCompilation. @@ -77,15 +85,13 @@ public void testIrreducibleLoop() throws ClassNotFoundException { * {@linkp BciBlockMapping.Options#DuplicateIrreducibleLoops}. */ @Override - protected byte[] generateClass(String internalClassName) { - ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); - cw.visit(52, ACC_SUPER | ACC_PUBLIC, internalClassName, null, "java/lang/Object", null); - createTestMethod(cw); - createIllegalLockingMethod(cw); - createIrreducibleMethod(cw); - cw.visitEnd(); - // Checkstyle: resume - return cw.toByteArray(); + public byte[] generateClass(String internalClassName) { + ClassDesc thisClass = ClassDesc.of(internalClassName); + + return ClassFile.of().build(thisClass, classBuilder -> classBuilder + .withMethodBody("test", MTD_void, ACC_PUBLIC_STATIC, UnbalancedLockingTest::createTestMethod) + .withMethodBody("snippet", MethodTypeDesc.of(CD_void, CD_int, CD_Object, CD_Object), ACC_PUBLIC_STATIC, UnbalancedLockingTest::createIllegalLockingMethod) + .withMethodBody("bar", MethodTypeDesc.of(CD_void, CD_int, CD_int, CD_Object, CD_Object), ACC_PUBLIC_STATIC, b -> createIrreducibleMethod(thisClass, b))); } /** @@ -122,110 +128,53 @@ protected byte[] generateClass(String internalClassName) { * } * */ - private static void createIrreducibleMethod(ClassWriter cw) { - // Checkstyle: stop - { - - MethodVisitor snippet = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "bar", "(IILjava/lang/Object;Ljava/lang/Object;)V", null, null); - Label assignmentEnd = new Label(); - Label assignmentElse = new Label(); - - snippet.visitVarInsn(ILOAD, 0); - snippet.visitIntInsn(BIPUSH, 12); - snippet.visitJumpInsn(IF_ICMPLE, assignmentElse); - { - snippet.visitVarInsn(ALOAD, 2); - snippet.visitVarInsn(ASTORE, 6); - snippet.visitJumpInsn(GOTO, assignmentEnd); - } - snippet.visitLabel(assignmentElse); - { - - snippet.visitVarInsn(ALOAD, 3); - snippet.visitVarInsn(ASTORE, 6); - } - - snippet.visitLabel(assignmentEnd); - - Label exceptionHandler = new Label(); - Label irreducible = new Label(); - Label loopHeader1 = new Label(); - Label end1 = new Label(); - Label loopHeader2 = new Label(); - Label end2 = new Label(); - - snippet.visitCode(); - - snippet.visitInsn(ICONST_0); - snippet.visitVarInsn(ISTORE, 3); - snippet.visitVarInsn(ILOAD, 0); - snippet.visitVarInsn(ILOAD, 1); - Label elseBranch = new Label(); - snippet.visitJumpInsn(IF_ICMPNE, elseBranch); - { - snippet.visitLabel(loopHeader1); - { - snippet.visitVarInsn(ILOAD, 3); - snippet.visitVarInsn(ILOAD, 0); - snippet.visitJumpInsn(IF_ICMPGE, end1); - snippet.visitIincInsn(3, 1); - - Label exceptionStart = new Label(); - Label exceptionEnd = new Label(); - - snippet.visitTryCatchBlock(exceptionStart, exceptionEnd, exceptionHandler, null); - - snippet.visitLabel(exceptionStart); - - snippet.visitVarInsn(ALOAD, 6); - snippet.visitInsn(MONITORENTER); - - snippet.visitMethodInsn(INVOKESTATIC, Type.getInternalName(UnbalancedLockingTest.class) + "$ABC", "test", "()V", false); - - snippet.visitVarInsn(ALOAD, 6); - snippet.visitInsn(MONITOREXIT); - snippet.visitLabel(irreducible); - - snippet.visitLabel(exceptionEnd); - - snippet.visitJumpInsn(GOTO, loopHeader1); - } - snippet.visitLabel(end1); - snippet.visitInsn(RETURN); - } - snippet.visitLabel(elseBranch); - { - Label secondEnd = new Label(); - snippet.visitLabel(loopHeader2); - { - snippet.visitVarInsn(ILOAD, 3); - snippet.visitVarInsn(ILOAD, 0); - snippet.visitJumpInsn(IF_ICMPGE, end2); - snippet.visitIincInsn(3, 1); - snippet.visitJumpInsn(GOTO, loopHeader2); - } - snippet.visitLabel(end2); - snippet.visitVarInsn(ALOAD, 2); - snippet.visitJumpInsn(IFNULL, secondEnd); - { - // irreducible jump into other loops body - snippet.visitJumpInsn(GOTO, irreducible); - } - snippet.visitLabel(secondEnd); - snippet.visitInsn(RETURN); - } - - snippet.visitLabel(exceptionHandler); - { - snippet.visitVarInsn(ALOAD, 6); - snippet.visitInsn(MONITOREXIT); - snippet.visitInsn(ATHROW); - } - - snippet.visitMaxs(1, 4); - snippet.visitEnd(); - } - // Checkstyle: resume + private static void createIrreducibleMethod(ClassDesc thisClass, CodeBuilder b) { + Label irreducible = b.newLabel(); + Label loopHeader1 = b.newLabel(); + Label loopHeader2 = b.newLabel(); + + b + .iload(0) + .bipush(12) + .ifThenElse(Opcode.IF_ICMPGE, + thenBlock -> thenBlock.aload(2).astore(6), + elseBlock -> elseBlock.aload(3).astore(6)) + .iconst_0() + .istore(3) + .iload(0) + .iload(1) + .ifThenElse(Opcode.IF_ICMPEQ, + thenBlock -> thenBlock + .labelBinding(loopHeader1) + .iload(3) + .iload(0) + .ifThen(Opcode.IF_ICMPLT, thenBlock1 -> thenBlock1 + .iinc(3, 1) + .trying(tryBlock -> { + tryBlock + .aload(6) + .monitorenter() + .invokestatic(thisClass, "test", MTD_void) + .aload(6) + .monitorexit(); + }, catchBuilder -> catchBuilder.catchingAll(catchBlock -> { + catchBlock + .aload(6) + .monitorexit() + .athrow(); + })) + .labelBinding(irreducible) + .goto_(loopHeader1)), + elseBlock -> elseBlock + .labelBinding(loopHeader2) + .iload(3) + .iload(0) + .ifThen(Opcode.IF_ICMPLT, thenBlock1 -> thenBlock1 + .iinc(3, 1) + .goto_(loopHeader2)) + .aload(2) + .ifnonnull(irreducible)) + .return_(); } /** @@ -246,44 +195,23 @@ private static void createIrreducibleMethod(ClassWriter cw) { * } * */ - private static void createIllegalLockingMethod(ClassWriter cw) { - // Checkstyle: stop - { - MethodVisitor snippet = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "snippet", "(ILjava/lang/Object;Ljava/lang/Object;)V", null, null); - snippet.visitCode(); - snippet.visitVarInsn(ILOAD, 0); - - Label falseBranch = new Label(); - Label merge = new Label(); - - snippet.visitJumpInsn(IFNE, falseBranch); - {// true branch - snippet.visitVarInsn(ALOAD, 1); - snippet.visitVarInsn(ASTORE, 3); - - snippet.visitVarInsn(ALOAD, 1); - snippet.visitInsn(MONITORENTER); - - snippet.visitJumpInsn(GOTO, merge); - } - {// false branch - snippet.visitLabel(falseBranch); - snippet.visitVarInsn(ALOAD, 2); - snippet.visitVarInsn(ASTORE, 3); - - snippet.visitVarInsn(ALOAD, 2); - snippet.visitInsn(MONITORENTER); - } - snippet.visitLabel(merge); - - snippet.visitVarInsn(ALOAD, 3); - snippet.visitInsn(MONITOREXIT); - - snippet.visitInsn(RETURN); - snippet.visitMaxs(1, 4); - snippet.visitEnd(); - } - // Checkstyle: resume + private static void createIllegalLockingMethod(CodeBuilder b) { + b + .iload(0) + .ifThenElse( + thenBlock -> thenBlock + .aload(1) + .astore(3) + .aload(1) + .monitorenter(), + elseBlock -> elseBlock + .aload(2) + .astore(3) + .aload(2) + .monitorenter()) + .aload(3) + .monitorexit() + .return_(); } /** @@ -294,16 +222,7 @@ private static void createIllegalLockingMethod(ClassWriter cw) { * } * */ - private static void createTestMethod(ClassWriter cw) { - // Checkstyle: stop - { - MethodVisitor snippet = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "test", "()V", null, null); - snippet.visitCode(); - snippet.visitInsn(RETURN); - snippet.visitMaxs(1, 4); - snippet.visitEnd(); - } - // Checkstyle: resume + private static void createTestMethod(CodeBuilder b) { + b.return_(); } - } diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/UnbalancedMonitorsTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/UnbalancedMonitorsTest.java index e969929ebc8d..71916e58281f 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/UnbalancedMonitorsTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/UnbalancedMonitorsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, 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 @@ -24,11 +24,19 @@ */ package jdk.graal.compiler.core.test; +import static java.lang.classfile.ClassFile.ACC_PUBLIC; +import static java.lang.constant.ConstantDescs.CD_Object; +import static java.lang.constant.ConstantDescs.CD_boolean; +import static java.lang.constant.ConstantDescs.INIT_NAME; +import static java.lang.constant.ConstantDescs.MTD_void; + +import java.lang.classfile.ClassFile; +import java.lang.classfile.CodeBuilder; +import java.lang.classfile.Label; +import java.lang.constant.ClassDesc; +import java.lang.constant.MethodTypeDesc; + import org.junit.Test; -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.Label; -import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Opcodes; import jdk.graal.compiler.java.GraphBuilderPhase; import jdk.graal.compiler.nodes.StructuredGraph; @@ -52,17 +60,15 @@ * Since [GR-51446], Graal defers some checks to run time, e.g., if it cannot be proven statically * that an unlocked object matches the object on top of the monitor stack. */ -public class UnbalancedMonitorsTest extends GraalCompilerTest { +public class UnbalancedMonitorsTest extends GraalCompilerTest implements CustomizedBytecodePattern { private static final String CLASS_NAME = UnbalancedMonitorsTest.class.getName(); private static final String INNER_CLASS_NAME = CLASS_NAME + "$UnbalancedMonitors"; private static final String CLASS_NAME_INTERNAL = CLASS_NAME.replace('.', '/'); private static final String INNER_CLASS_NAME_INTERNAL = INNER_CLASS_NAME.replace('.', '/'); - private static AsmLoader LOADER = new AsmLoader(UnbalancedMonitorsTest.class.getClassLoader()); - @Test public void runWrongOrder() throws Exception { - Class clazz = LOADER.findClass(INNER_CLASS_NAME); + Class clazz = getClass(INNER_CLASS_NAME); ResolvedJavaMethod method = getResolvedJavaMethod(clazz, "wrongOrder"); Object instance = clazz.getName(); InstalledCode code = getCode(method); @@ -91,7 +97,7 @@ public void runTooManyExitsExceptional() throws Exception { } private void checkForBailout(String name) throws ClassNotFoundException { - ResolvedJavaMethod method = getResolvedJavaMethod(LOADER.findClass(INNER_CLASS_NAME), name); + ResolvedJavaMethod method = getResolvedJavaMethod(getClass(INNER_CLASS_NAME), name); try { OptionValues options = getInitialOptions(); StructuredGraph graph = new StructuredGraph.Builder(options, getDebugContext(options, null, method)).method(method).build(); @@ -112,8 +118,6 @@ private void checkForBailout(String name) throws ClassNotFoundException { assertTrue("should have bailed out", false); } - static class Gen implements Opcodes { - // @formatter:off // Template class used with Bytecode Outline to generate ASM code // public static class UnbalancedMonitors { @@ -146,188 +150,120 @@ static class Gen implements Opcodes { // } // } // @formatter:on + @Override + public byte[] generateClass(String className) { + return ClassFile.of().build(ClassDesc.of(className), classBuilder -> classBuilder + .withMethodBody(INIT_NAME, MTD_void, ACC_PUBLIC, b -> b + .aload(0) + .invokespecial(CD_Object, INIT_NAME, MTD_void) + .return_()) + .withMethodBody("wrongOrder", MethodTypeDesc.of(CD_Object, CD_Object, CD_Object), ACC_PUBLIC, UnbalancedMonitorsTest::visitWrongOrder) + .withMethodBody("tooManyExits", MethodTypeDesc.of(CD_boolean, CD_Object, CD_Object), ACC_PUBLIC, b -> visitBlockStructured(b, true, true)) + .withMethodBody("tooFewExits", MethodTypeDesc.of(CD_boolean, CD_Object, CD_Object), ACC_PUBLIC, b -> visitBlockStructured(b, true, false)) + .withMethodBody("tooManyExitsExceptional", MethodTypeDesc.of(CD_boolean, CD_Object, CD_Object), ACC_PUBLIC, b -> visitBlockStructured(b, false, true)) + .withMethodBody("tooFewExitsExceptional", MethodTypeDesc.of(CD_boolean, CD_Object, CD_Object), ACC_PUBLIC, b -> visitBlockStructured(b, false, false))); + } - public static byte[] generateClass() { - - ClassWriter cw = new ClassWriter(0); - - cw.visit(52, ACC_SUPER | ACC_PUBLIC, INNER_CLASS_NAME_INTERNAL, null, "java/lang/Object", null); - - cw.visitSource("UnbalancedMonitorsTest.java", null); - - cw.visitInnerClass(INNER_CLASS_NAME_INTERNAL, CLASS_NAME_INTERNAL, "UnbalancedMonitors", ACC_STATIC); + private static void visitBlockStructured(CodeBuilder b, boolean normalReturnError, boolean tooMany) { + // Generate too many or too few exits down either the normal or exceptional return paths + int exceptionalExitCount = normalReturnError ? 1 : (tooMany ? 2 : 0); + int normalExitCount = normalReturnError ? (tooMany ? 2 : 0) : 1; - visitConstructor(cw); - visitWrongOrder(cw); - visitBlockStructured(cw, true, false); - visitBlockStructured(cw, true, true); - visitBlockStructured(cw, false, false); - visitBlockStructured(cw, false, true); - cw.visitEnd(); + Label l0 = b.newLabel(); + Label l1 = b.newLabel(); + Label l2 = b.newLabel(); + Label l3 = b.newLabel(); + Label l4 = b.newLabel(); + Label l5 = b.newLabel(); + Label l6 = b.newLabel(); + Label l7 = b.newLabel(); + Label l8 = b.newLabel(); - return cw.toByteArray(); + b.labelBinding(l8) + .aload(1) + .dup() + .astore(3) + .monitorenter() + .labelBinding(l4) + .aload(2) + .dup() + .astore(4) + .monitorenter() + .labelBinding(l0) + .aload(2) + .aload(1) + .invokevirtual(CD_Object, "equals", MethodTypeDesc.of(CD_boolean, CD_Object)) + .aload(4) + .monitorexit() + .labelBinding(l1); + for (int i = 0; i < normalExitCount; i++) { + b.aload(3).monitorexit(); } - private static void visitBlockStructured(ClassWriter cw, boolean normalReturnError, boolean tooMany) { - String name = (tooMany ? "tooMany" : "tooFew") + "Exits" + (normalReturnError ? "" : "Exceptional"); - // Generate too many or too few exits down the either the normal or exceptional return - // paths - int exceptionalExitCount = normalReturnError ? 1 : (tooMany ? 2 : 0); - int normalExitCount = normalReturnError ? (tooMany ? 2 : 0) : 1; - MethodVisitor mv; - mv = cw.visitMethod(ACC_PUBLIC, name, "(Ljava/lang/Object;Ljava/lang/Object;)Z", null, null); - mv.visitCode(); - Label l0 = new Label(); - Label l1 = new Label(); - Label l2 = new Label(); - mv.visitTryCatchBlock(l0, l1, l2, null); - Label l3 = new Label(); - mv.visitTryCatchBlock(l2, l3, l2, null); - Label l4 = new Label(); - Label l5 = new Label(); - Label l6 = new Label(); - mv.visitTryCatchBlock(l4, l5, l6, null); - Label l7 = new Label(); - mv.visitTryCatchBlock(l2, l7, l6, null); - Label l8 = new Label(); - mv.visitLabel(l8); - mv.visitVarInsn(ALOAD, 1); - mv.visitInsn(DUP); - mv.visitVarInsn(ASTORE, 3); - mv.visitInsn(MONITORENTER); - mv.visitLabel(l4); - mv.visitVarInsn(ALOAD, 2); - mv.visitInsn(DUP); - mv.visitVarInsn(ASTORE, 4); - mv.visitInsn(MONITORENTER); - mv.visitLabel(l0); - mv.visitVarInsn(ALOAD, 2); - mv.visitVarInsn(ALOAD, 1); - mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "equals", "(Ljava/lang/Object;)Z", false); - mv.visitVarInsn(ALOAD, 4); - mv.visitInsn(MONITOREXIT); - mv.visitLabel(l1); - for (int i = 0; i < normalExitCount; i++) { - mv.visitVarInsn(ALOAD, 3); - mv.visitInsn(MONITOREXIT); - } - mv.visitLabel(l5); - mv.visitInsn(IRETURN); - mv.visitLabel(l2); - mv.visitFrame(Opcodes.F_FULL, 5, new Object[]{INNER_CLASS_NAME_INTERNAL, "java/lang/Object", "java/lang/Object", "java/lang/Object", - "java/lang/Object"}, 1, new Object[]{"java/lang/Throwable"}); - mv.visitVarInsn(ALOAD, 4); - mv.visitInsn(MONITOREXIT); - mv.visitLabel(l3); - mv.visitInsn(ATHROW); - mv.visitLabel(l6); - mv.visitFrame(Opcodes.F_FULL, 4, new Object[]{INNER_CLASS_NAME_INTERNAL, "java/lang/Object", "java/lang/Object", "java/lang/Object"}, 1, - new Object[]{"java/lang/Throwable"}); - for (int i = 0; i < exceptionalExitCount; i++) { - mv.visitVarInsn(ALOAD, 3); - mv.visitInsn(MONITOREXIT); - } - mv.visitLabel(l7); - mv.visitInsn(ATHROW); - Label l9 = new Label(); - mv.visitLabel(l9); - mv.visitMaxs(2, 5); - mv.visitEnd(); - } + b.labelBinding(l5) + .ireturn() + .labelBinding(l2) + .aload(4) + .monitorexit() + .labelBinding(l3) + .athrow() + .labelBinding(l6); - private static void visitWrongOrder(ClassWriter cw) { - MethodVisitor mv; - mv = cw.visitMethod(ACC_PUBLIC, "wrongOrder", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", null, null); - mv.visitCode(); - Label l0 = new Label(); - Label l1 = new Label(); - Label l2 = new Label(); - mv.visitTryCatchBlock(l0, l1, l2, null); - Label l3 = new Label(); - mv.visitTryCatchBlock(l2, l3, l2, null); - Label l4 = new Label(); - Label l5 = new Label(); - Label l6 = new Label(); - mv.visitTryCatchBlock(l4, l5, l6, null); - Label l7 = new Label(); - mv.visitTryCatchBlock(l2, l7, l6, null); - Label l8 = new Label(); - mv.visitLabel(l8); - mv.visitVarInsn(ALOAD, 1); - mv.visitInsn(DUP); - mv.visitVarInsn(ASTORE, 3); - mv.visitInsn(MONITORENTER); - mv.visitLabel(l4); - mv.visitVarInsn(ALOAD, 2); - mv.visitInsn(DUP); - mv.visitVarInsn(ASTORE, 4); - mv.visitInsn(MONITORENTER); - mv.visitLabel(l0); - mv.visitVarInsn(ALOAD, 2); - mv.visitVarInsn(ALOAD, 3); - mv.visitInsn(MONITOREXIT); - mv.visitLabel(l1); - // Swapped exit order with exit above - mv.visitVarInsn(ALOAD, 4); - mv.visitInsn(MONITOREXIT); - mv.visitLabel(l5); - mv.visitInsn(ARETURN); - mv.visitLabel(l2); - mv.visitFrame(Opcodes.F_FULL, 5, new Object[]{INNER_CLASS_NAME_INTERNAL, "java/lang/Object", "java/lang/Object", "java/lang/Object", - "java/lang/Object"}, 1, new Object[]{"java/lang/Throwable"}); - mv.visitVarInsn(ALOAD, 4); - mv.visitInsn(MONITOREXIT); - mv.visitLabel(l3); - mv.visitInsn(ATHROW); - mv.visitLabel(l6); - mv.visitFrame(Opcodes.F_FULL, 4, new Object[]{INNER_CLASS_NAME_INTERNAL, "java/lang/Object", "java/lang/Object", "java/lang/Object"}, 1, - new Object[]{"java/lang/Throwable"}); - mv.visitVarInsn(ALOAD, 3); - mv.visitInsn(MONITOREXIT); - mv.visitLabel(l7); - mv.visitInsn(ATHROW); - Label l9 = new Label(); - mv.visitLabel(l9); - mv.visitMaxs(2, 5); - mv.visitEnd(); + for (int i = 0; i < exceptionalExitCount; i++) { + b.aload(3).monitorexit(); } - private static void visitConstructor(ClassWriter cw) { - MethodVisitor mv; - mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); - mv.visitCode(); - Label l0 = new Label(); - mv.visitLabel(l0); - mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); - Label l1 = new Label(); - mv.visitLabel(l1); - mv.visitInsn(RETURN); - Label l2 = new Label(); - mv.visitLabel(l2); - mv.visitMaxs(1, 1); - mv.visitEnd(); - } + b.labelBinding(l7) + .athrow() + .exceptionCatchAll(l0, l1, l2) + .exceptionCatchAll(l2, l3, l2) + .exceptionCatchAll(l4, l5, l6) + .exceptionCatchAll(l2, l7, l6); } - public static class AsmLoader extends ClassLoader { - Class loaded; + private static void visitWrongOrder(CodeBuilder b) { + Label l0 = b.newLabel(); + Label l1 = b.newLabel(); + Label l2 = b.newLabel(); + Label l3 = b.newLabel(); + Label l4 = b.newLabel(); + Label l5 = b.newLabel(); + Label l6 = b.newLabel(); + Label l7 = b.newLabel(); + Label l8 = b.newLabel(); - public AsmLoader(ClassLoader parent) { - super(parent); - } - - @Override - protected Class findClass(String name) throws ClassNotFoundException { - if (name.equals(INNER_CLASS_NAME)) { - if (loaded != null) { - return loaded; - } - byte[] bytes = Gen.generateClass(); - return (loaded = defineClass(name, bytes, 0, bytes.length)); - } else { - return super.findClass(name); - } - } + b.labelBinding(l8) + .aload(1) + .dup() + .astore(3) + .monitorenter() + .labelBinding(l4) + .aload(2) + .dup() + .astore(4) + .monitorenter() + .labelBinding(l0) + .aload(2) + .aload(3) + .monitorexit() + .labelBinding(l1) + .aload(4) + .monitorexit() + .labelBinding(l5) + .areturn() + .labelBinding(l2) + .aload(4) + .monitorexit() + .labelBinding(l3) + .athrow() + .labelBinding(l6) + .aload(3) + .monitorexit() + .labelBinding(l7) + .athrow() + .exceptionCatchAll(l0, l1, l2) + .exceptionCatchAll(l2, l3, l2) + .exceptionCatchAll(l4, l5, l6) + .exceptionCatchAll(l2, l7, l6); } } diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/jfr/TestGetEventWriter.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/jfr/TestGetEventWriter.java index eaafe8cd4f87..c51102f1ddb8 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/jfr/TestGetEventWriter.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/jfr/TestGetEventWriter.java @@ -24,19 +24,25 @@ */ package jdk.graal.compiler.core.test.jfr; +import static java.lang.classfile.ClassFile.ACC_PUBLIC; +import static java.lang.constant.ConstantDescs.INIT_NAME; +import static java.lang.constant.ConstantDescs.MTD_void; + import java.io.IOException; -import java.lang.reflect.Constructor; +import java.lang.classfile.Annotation; +import java.lang.classfile.AnnotationElement; +import java.lang.classfile.ClassFile; +import java.lang.classfile.attribute.RuntimeVisibleAnnotationsAttribute; +import java.lang.constant.ClassDesc; +import java.lang.constant.MethodTypeDesc; import java.lang.reflect.InvocationTargetException; import org.junit.Assert; import org.junit.Assume; import org.junit.Test; -import org.objectweb.asm.AnnotationVisitor; -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Opcodes; import jdk.graal.compiler.core.common.PermanentBailoutException; +import jdk.graal.compiler.core.test.CustomizedBytecodePattern; import jdk.graal.compiler.core.test.SubprocessTest; import jdk.graal.compiler.serviceprovider.JavaVersionUtil; import jdk.graal.compiler.test.AddExports; @@ -123,14 +129,14 @@ public void testInitializationEvent() { // attempts to resolve and link against EventWriterFactory. This user implementation // is not blessed for linkage. public void testNonEvent() throws Throwable { - testEvent("Non", "java/lang/Object", null, "commit", false); + testEvent("Non", "java.lang.Object", null, "commit", false); } // The user has defined a class which overrides and implements the "commit()V" // method declared final in jdk.jfr.Event. // This user implementation is not blessed for linkage. public void testRegisteredTrueEvent() throws Throwable { - testEvent("Registered", "jdk/jfr/Event", true, "commit", false); + testEvent("Registered", "jdk.jfr.Event", true, "commit", false); } // The user has defined a class which overrides and implements the "commit()V" @@ -142,14 +148,14 @@ public void testRegisteredTrueEvent() throws Throwable { // such a class throws an IllegalArgumentException. The user-defined // "commit()V" method is still not blessed for linkage, even after registration. public void testRegisteredFalseEvent() throws Throwable { - testEvent("Registered", "jdk/jfr/Event", false, "commit", false); + testEvent("Registered", "jdk.jfr.Event", false, "commit", false); } // The user has implemented another method, "myCommit()V", not an override nor // overload. that attempts to resolve and link EventWriterFactory. This will fail, // because "myCommit()V" is not blessed for linkage. public void testMyCommitRegisteredTrue() throws Throwable { - testEvent("MyCommit", "jdk/jfr/Event", true, "myCommit", false); + testEvent("MyCommit", "jdk.jfr.Event", true, "myCommit", false); } // The user has implemented another method, "myCommit()V", not an override, @@ -158,14 +164,14 @@ public void testMyCommitRegisteredTrue() throws Throwable { // the class is not excluded wholesale from the JFR system. // Invoking the real "commit()V", installed by the framework, is OK. public void testMyCommitRegisteredFalse() throws Throwable { - testEvent("MyCommit", "jdk/jfr/Event", false, "myCommit", false); + testEvent("MyCommit", "jdk.jfr.Event", false, "myCommit", false); } // Events located in the boot class loader can create a static // commit-method to emit events. It must not be used by code // outside of the boot class loader. public void testStaticCommit() throws Throwable { - testEvent("StaticCommit", "jdk/jfr/Event", null, "commit", true); + testEvent("StaticCommit", "jdk.jfr.Event", null, "commit", true); } private void testEvent(String name, String superClass, Boolean isRegistered, String commitName, boolean isStatic) throws Throwable { @@ -205,78 +211,57 @@ private void testEvent(String name, String superClass, Boolean isRegistered, Str * } */ // @formatter:on - Runnable newEventObject(String superClass, Boolean isRegistered, String commitName, boolean isStatic, String className) + Runnable newEventObject(String superClassName, Boolean isRegistered, String commitName, boolean isStatic, String className) throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException { - ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES); - String[] interfaces = {"java/lang/Runnable"}; - cw.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC, className.replace('.', '/'), null, superClass, interfaces); + return (Runnable) new CustomizedClass(superClassName, isRegistered, commitName, isStatic).getClass(className).getConstructor().newInstance(); + } - if (isRegistered != null) { - AnnotationVisitor registered = cw.visitAnnotation("Ljdk/jfr/Registered;", true); - registered.visit("value", isRegistered); - registered.visitEnd(); - } + static class CustomizedClass implements CustomizedBytecodePattern { - // constructor - MethodVisitor constructor = cw.visitMethod(Opcodes.ACC_PUBLIC, "", "()V", null, null); - constructor.visitCode(); - constructor.visitVarInsn(Opcodes.ALOAD, 0); - constructor.visitMethodInsn(Opcodes.INVOKESPECIAL, superClass, "", "()V", false); - constructor.visitInsn(Opcodes.RETURN); - constructor.visitMaxs(0, 0); - constructor.visitEnd(); + private String superClassName; + private Boolean isRegistered; + private String commitName; + private boolean isStatic; - int commitAccess = Opcodes.ACC_PUBLIC; - if (isStatic) { - commitAccess |= Opcodes.ACC_STATIC; + public CustomizedClass(String superClassName, Boolean isRegistered, String commitName, boolean isStatic) { + this.superClassName = superClassName; + this.isRegistered = isRegistered; + this.commitName = commitName; + this.isStatic = isStatic; } - MethodVisitor commit = cw.visitMethod(commitAccess, commitName, "()V", null, null); - commit.visitCode(); - commit.visitMethodInsn(Opcodes.INVOKESTATIC, "jdk/jfr/internal/event/EventWriter", "getEventWriter", "()Ljdk/jfr/internal/event/EventWriter;", false); - commit.visitInsn(Opcodes.POP); - commit.visitInsn(Opcodes.RETURN); - commit.visitMaxs(0, 0); - commit.visitEnd(); - - MethodVisitor run = cw.visitMethod(Opcodes.ACC_PUBLIC, "run", "()V", null, null); - run.visitCode(); - if (isStatic) { - run.visitMethodInsn(Opcodes.INVOKESTATIC, className.replace('.', '/'), commitName, "()V", false); - } else { - run.visitVarInsn(Opcodes.ALOAD, 0); - run.visitMethodInsn(Opcodes.INVOKEVIRTUAL, className.replace('.', '/'), commitName, "()V", false); - } - run.visitInsn(Opcodes.RETURN); - run.visitMaxs(0, 0); - run.visitEnd(); - - cw.visitEnd(); - byte[] bytes = cw.toByteArray(); - BytesClassLoader bc = new BytesClassLoader(bytes, className); - Class clazz = bc.loadClass(className); - Constructor cons = clazz.getConstructor(); - - Runnable event = (Runnable) cons.newInstance(); - return event; - } + @Override + public byte[] generateClass(String className) { + ClassDesc thisClass = ClassDesc.of(className); + ClassDesc superClass = ClassDesc.of(superClassName); - private static class BytesClassLoader extends ClassLoader { - private final byte[] bytes; - private final String className; + return ClassFile.of().build(thisClass, classBuilder -> { + if (isRegistered != null) { + classBuilder.with(RuntimeVisibleAnnotationsAttribute.of(Annotation.of(ClassDesc.of("jdk.jfr.Registered"), + AnnotationElement.ofBoolean("value", isRegistered)))); + } - BytesClassLoader(byte[] bytes, String name) { - this.bytes = bytes; - this.className = name; - } - - @Override - public Class loadClass(String name) throws ClassNotFoundException { - if (name.equals(className)) { - return defineClass(name, bytes, 0, bytes.length); - } else { - return super.loadClass(name); - } + classBuilder + .withSuperclass(superClass) + .withInterfaceSymbols(cd(Runnable.class)) + .withMethodBody(INIT_NAME, MTD_void, ACC_PUBLIC, b -> b + .aload(0) + .invokespecial(superClass, INIT_NAME, MTD_void) + .return_()) + .withMethodBody(commitName, MTD_void, isStatic ? ACC_PUBLIC_STATIC : ACC_PUBLIC, b -> b + .invokestatic(ClassDesc.of("jdk.jfr.internal.event.EventWriter"), "getEventWriter", + MethodTypeDesc.of(ClassDesc.of("jdk.jfr.internal.event.EventWriter"))) + .pop() + .return_()) + .withMethodBody("run", MTD_void, ACC_PUBLIC, b -> { + if (isStatic) { + b.invokestatic(thisClass, commitName, MTD_void); + } else { + b.aload(0).invokevirtual(thisClass, commitName, MTD_void); + } + b.return_(); + }); + }); } } } diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/LambdaStableNameTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/LambdaStableNameTest.java index 827493c0f366..5dc2c684d315 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/LambdaStableNameTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/LambdaStableNameTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, 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 @@ -33,7 +33,6 @@ import java.math.BigInteger; import org.junit.Test; -import org.objectweb.asm.Type; import jdk.graal.compiler.java.LambdaUtils; import jdk.vm.ci.meta.ResolvedJavaType; @@ -54,7 +53,7 @@ public void checkStableLamdaNameForRunnableAndAutoCloseable() { String acName = LambdaUtils.findStableLambdaName(acType); assertEquals("Both stable lambda names are the same as they reference the same method", name, acName); - String myName = Type.getInternalName(getClass()); + String myName = getClass().getName().replace('.', '/'); assertEquals("The name known in 24.0 version is computed", "L" + myName + "$$Lambda.0x605511206480068bfd9e0bafd4f79e22;", name); } diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/SafeConstructionTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/SafeConstructionTest.java index 8991482e8b5d..b1b022741bf9 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/SafeConstructionTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/hotspot/test/SafeConstructionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, 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 @@ -24,19 +24,26 @@ */ package jdk.graal.compiler.hotspot.test; +import static java.lang.classfile.ClassFile.ACC_PRIVATE; +import static java.lang.classfile.ClassFile.ACC_PUBLIC; +import static java.lang.constant.ConstantDescs.CD_int; +import static java.lang.constant.ConstantDescs.CD_short; +import static java.lang.constant.ConstantDescs.CD_void; +import static java.lang.constant.ConstantDescs.INIT_NAME; +import static java.lang.constant.ConstantDescs.MTD_void; + import java.io.IOException; +import java.lang.classfile.Annotation; +import java.lang.classfile.ClassFile; +import java.lang.classfile.attribute.RuntimeVisibleAnnotationsAttribute; +import java.lang.constant.ClassDesc; +import java.lang.constant.MethodTypeDesc; import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; import java.lang.reflect.Constructor; import java.util.List; import org.junit.Assert; import org.junit.Test; -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.FieldVisitor; -import org.objectweb.asm.MethodVisitor; - -import com.oracle.truffle.api.impl.asm.Opcodes; import jdk.graal.compiler.core.test.SubprocessTest; import jdk.graal.compiler.nodes.StructuredGraph; @@ -114,52 +121,32 @@ private void checkStableWriteConstructors() { * This generates TestClass but in privileged location, allowing @Stable to be effective. */ private static Class generatePrivilegedTestClass() throws IllegalAccessException { - String clazzInternalName = "java/lang/TestClass"; - String init = ""; - String aName = "a"; - String bName = "b"; - String intTypeDesc = int.class.descriptorString(); - - ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES); - cw.visit(Opcodes.V21, Opcodes.ACC_PUBLIC, clazzInternalName, null, "java/lang/Object", null); - MethodVisitor mv; - cw.visitField(Opcodes.ACC_PRIVATE, aName, intTypeDesc, null, null); - FieldVisitor fv = cw.visitField(Opcodes.ACC_PRIVATE, bName, intTypeDesc, null, null); - fv.visitAnnotation(Stable.class.descriptorString(), true); - - mv = cw.visitMethod(Opcodes.ACC_PUBLIC, init, MethodType.methodType(void.class).descriptorString(), null, null); - mv.visitCode(); - mv.visitIntInsn(Opcodes.ALOAD, 0); - mv.visitInsn(Opcodes.ICONST_4); - mv.visitFieldInsn(Opcodes.PUTFIELD, clazzInternalName, aName, intTypeDesc); - mv.visitInsn(Opcodes.RETURN); - mv.visitMaxs(0, 0); - mv.visitEnd(); - - mv = cw.visitMethod(Opcodes.ACC_PUBLIC, init, MethodType.methodType(void.class, int.class).descriptorString(), null, null); - mv.visitCode(); - mv.visitIntInsn(Opcodes.ALOAD, 0); - mv.visitIntInsn(Opcodes.ILOAD, 1); - mv.visitFieldInsn(Opcodes.PUTFIELD, clazzInternalName, bName, intTypeDesc); - mv.visitInsn(Opcodes.RETURN); - mv.visitMaxs(0, 0); - mv.visitEnd(); - - mv = cw.visitMethod(Opcodes.ACC_PUBLIC, init, MethodType.methodType(void.class, short.class).descriptorString(), null, null); - mv.visitCode(); - mv.visitIntInsn(Opcodes.ALOAD, 0); - mv.visitInsn(Opcodes.DUP); - mv.visitInsn(Opcodes.ICONST_0); - mv.visitFieldInsn(Opcodes.PUTFIELD, clazzInternalName, bName, intTypeDesc); - mv.visitIntInsn(Opcodes.ILOAD, 1); - mv.visitFieldInsn(Opcodes.PUTFIELD, clazzInternalName, aName, intTypeDesc); - mv.visitInsn(Opcodes.RETURN); - mv.visitMaxs(0, 0); - mv.visitEnd(); - - cw.visitEnd(); + ClassDesc thisClass = ClassDesc.of("java.lang.TestClass"); + byte[] clazz = ClassFile.of().build(thisClass, classBuilder -> classBuilder + .withField("a", CD_int, ACC_PRIVATE) + .withField("b", CD_int, fieldBuilder -> fieldBuilder + .withFlags(ACC_PRIVATE) + .with(RuntimeVisibleAnnotationsAttribute.of(Annotation.of(ClassDesc.of("jdk.internal.vm.annotation.Stable"))))) + .withMethodBody(INIT_NAME, MTD_void, ACC_PUBLIC, b -> b + .aload(0) + .iconst_4() + .putfield(thisClass, "a", CD_int) + .return_()) + .withMethodBody(INIT_NAME, MethodTypeDesc.of(CD_void, CD_int), ACC_PUBLIC, b -> b + .aload(0) + .iload(1) + .putfield(thisClass, "b", CD_int) + .return_()) + .withMethodBody(INIT_NAME, MethodTypeDesc.of(CD_void, CD_short), ACC_PUBLIC, b -> b + .aload(0) + .dup() + .iconst_0() + .putfield(thisClass, "b", CD_int) + .iload(1) + .putfield(thisClass, "a", CD_int) + .return_())); MethodHandles.Lookup lookup = MethodHandles.privateLookupIn(String.class, MethodHandles.lookup()); - return lookup.defineClass(cw.toByteArray()); + return lookup.defineClass(clazz); } } diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/jtt/backend/LargeConstantSectionTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/jtt/backend/LargeConstantSectionTest.java index 5077c4c7783f..143a96f77d7d 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/jtt/backend/LargeConstantSectionTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/jtt/backend/LargeConstantSectionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, 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 @@ -24,32 +24,29 @@ */ package jdk.graal.compiler.jtt.backend; -import static org.objectweb.asm.Opcodes.ACC_FINAL; -import static org.objectweb.asm.Opcodes.ACC_PUBLIC; -import static org.objectweb.asm.Opcodes.ACC_STATIC; -import static org.objectweb.asm.Opcodes.ACC_SUPER; -import static org.objectweb.asm.Opcodes.ILOAD; -import static org.objectweb.asm.Opcodes.LRETURN; +import static java.lang.constant.ConstantDescs.CD_int; +import static java.lang.constant.ConstantDescs.CD_long; +import java.lang.classfile.ClassFile; +import java.lang.classfile.Label; +import java.lang.classfile.instruction.SwitchCase; +import java.lang.constant.ClassDesc; +import java.lang.constant.MethodTypeDesc; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collection; import java.util.List; -import jdk.graal.compiler.debug.GraalError; -import jdk.graal.compiler.jtt.JTTTest; -import jdk.graal.compiler.api.test.ExportingClassLoader; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameter; import org.junit.runners.Parameterized.Parameters; -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.Label; -import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Opcodes; +import jdk.graal.compiler.api.test.ExportingClassLoader; +import jdk.graal.compiler.debug.GraalError; +import jdk.graal.compiler.jtt.JTTTest; import jdk.vm.ci.meta.ResolvedJavaMethod; import junit.framework.AssertionFailedError; @@ -107,39 +104,27 @@ public LargeConstantClassLoader(ClassLoader parent) { @Override protected Class findClass(String name) throws ClassNotFoundException { if (name.equals(NAME)) { - ClassWriter cw = new ClassWriter(0); - MethodVisitor mv; - cw.visit(52, ACC_PUBLIC + ACC_SUPER, NAME, null, "java/lang/Object", null); + byte[] bytes = ClassFile.of().build(ClassDesc.of(NAME), classBuilder -> classBuilder + .withMethodBody("run", MethodTypeDesc.of(CD_long, CD_int), ClassFile.ACC_PUBLIC | ClassFile.ACC_STATIC | ClassFile.ACC_FINAL, b -> { + Label defaultLabel = b.newLabel(); + List cases = new ArrayList<>(numberBlocks); - mv = cw.visitMethod(ACC_PUBLIC + ACC_FINAL + ACC_STATIC, "run", "(I)J", null, null); - mv.visitCode(); - Label begin = new Label(); - mv.visitLabel(begin); - mv.visitVarInsn(ILOAD, 0); - Label[] labels = new Label[numberBlocks]; - int[] keys = new int[numberBlocks]; - for (int i = 0; i < labels.length; i++) { - labels[i] = new Label(); - keys[i] = i; - } - Label defaultLabel = new Label(); - mv.visitLookupSwitchInsn(defaultLabel, keys, labels); - for (int i = 0; i < labels.length; i++) { - mv.visitLabel(labels[i]); - mv.visitFrame(Opcodes.F_NEW, 1, new Object[]{Opcodes.INTEGER}, 0, new Object[]{}); - mv.visitLdcInsn(Long.valueOf(LARGE_CONSTANT + i)); - mv.visitInsn(LRETURN); - } - mv.visitLabel(defaultLabel); - mv.visitFrame(Opcodes.F_NEW, 1, new Object[]{Opcodes.INTEGER}, 0, new Object[]{}); - mv.visitLdcInsn(Long.valueOf(3L)); - mv.visitInsn(LRETURN); - Label end = new Label(); - mv.visitLabel(end); - mv.visitLocalVariable("a", "I", null, begin, end, 0); - mv.visitMaxs(2, 1); - mv.visitEnd(); - byte[] bytes = cw.toByteArray(); + for (int i = 0; i < cases.size(); i++) { + cases.add(SwitchCase.of(i, b.newLabel())); + } + + b.iload(0).lookupswitch(defaultLabel, cases); + + for (int i = 0; i < cases.size(); i++) { + b.labelBinding(cases.get(i).target()) + .ldc(Long.valueOf(0xF0F0F0F0F0L + i)) + .lreturn(); + } + + b.labelBinding(defaultLabel) + .ldc(Long.valueOf(3L)) + .lreturn(); + })); return defineClass(name, bytes, 0, bytes.length); } else { return super.findClass(name); diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/jtt/except/UntrustedInterfaces.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/jtt/except/UntrustedInterfaces.java index fe388c7809f0..810ec876ee22 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/jtt/except/UntrustedInterfaces.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/jtt/except/UntrustedInterfaces.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, 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 @@ -24,14 +24,21 @@ */ package jdk.graal.compiler.jtt.except; -import jdk.graal.compiler.jtt.JTTTest; -import jdk.graal.compiler.api.test.ExportingClassLoader; +import static java.lang.classfile.ClassFile.ACC_PUBLIC; +import static java.lang.constant.ConstantDescs.CD_Object; +import static java.lang.constant.ConstantDescs.CD_int; +import static java.lang.constant.ConstantDescs.INIT_NAME; +import static java.lang.constant.ConstantDescs.MTD_void; + +import java.lang.classfile.ClassFile; +import java.lang.constant.ClassDesc; +import java.lang.constant.MethodTypeDesc; + import org.junit.BeforeClass; import org.junit.Test; -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.Type; + +import jdk.graal.compiler.core.test.CustomizedBytecodePattern; +import jdk.graal.compiler.jtt.JTTTest; public class UntrustedInterfaces extends JTTTest { @@ -152,7 +159,7 @@ public TestInterface returnCheckcast(Pill pill) { // Checkstyle: stop @BeforeClass public static void setUp() throws Exception { - poisonPill = (Pill) new PoisonLoader().findClass(PoisonLoader.POISON_IMPL_NAME).getDeclaredConstructor().newInstance(); + poisonPill = (Pill) new PoisonLoader().getClass(PoisonLoader.POISON_IMPL_NAME).getDeclaredConstructor().newInstance(); } // Checkstyle: resume @@ -217,71 +224,46 @@ public void testReturn2() { runTest("returnCheckcast", poisonPill); } - private static final class PoisonLoader extends ExportingClassLoader { + private static final class PoisonLoader implements CustomizedBytecodePattern { + public static final String POISON_IMPL_NAME = "jdk.graal.compiler.jtt.except.PoisonPill"; @Override - protected Class findClass(String name) throws ClassNotFoundException { - if (name.equals(POISON_IMPL_NAME)) { - ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES); - - cw.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC, POISON_IMPL_NAME.replace('.', '/'), null, Type.getInternalName(Pill.class), null); - // constructor - MethodVisitor constructor = cw.visitMethod(Opcodes.ACC_PUBLIC, "", "()V", null, null); - constructor.visitCode(); - constructor.visitVarInsn(Opcodes.ALOAD, 0); - constructor.visitMethodInsn(Opcodes.INVOKESPECIAL, Type.getInternalName(Pill.class), "", "()V", false); - constructor.visitInsn(Opcodes.RETURN); - constructor.visitMaxs(0, 0); - constructor.visitEnd(); - - MethodVisitor setList = cw.visitMethod(Opcodes.ACC_PUBLIC, "setField", "()V", null, null); - setList.visitCode(); - setList.visitVarInsn(Opcodes.ALOAD, 0); - setList.visitTypeInsn(Opcodes.NEW, Type.getInternalName(Object.class)); - setList.visitInsn(Opcodes.DUP); - setList.visitMethodInsn(Opcodes.INVOKESPECIAL, Type.getInternalName(Object.class), "", "()V", false); - setList.visitFieldInsn(Opcodes.PUTFIELD, Type.getInternalName(Pill.class), "field", Type.getDescriptor(TestInterface.class)); - setList.visitInsn(Opcodes.RETURN); - setList.visitMaxs(0, 0); - setList.visitEnd(); - - MethodVisitor setStaticList = cw.visitMethod(Opcodes.ACC_PUBLIC, "setStaticField", "()V", null, null); - setStaticList.visitCode(); - setStaticList.visitTypeInsn(Opcodes.NEW, Type.getInternalName(Object.class)); - setStaticList.visitInsn(Opcodes.DUP); - setStaticList.visitMethodInsn(Opcodes.INVOKESPECIAL, Type.getInternalName(Object.class), "", "()V", false); - setStaticList.visitFieldInsn(Opcodes.PUTSTATIC, Type.getInternalName(Pill.class), "staticField", Type.getDescriptor(TestInterface.class)); - setStaticList.visitInsn(Opcodes.RETURN); - setStaticList.visitMaxs(0, 0); - setStaticList.visitEnd(); - - MethodVisitor callMe = cw.visitMethod(Opcodes.ACC_PUBLIC, "callMe", Type.getMethodDescriptor(Type.INT_TYPE, Type.getType(CallBack.class)), null, null); - callMe.visitCode(); - callMe.visitVarInsn(Opcodes.ALOAD, 1); - callMe.visitTypeInsn(Opcodes.NEW, Type.getInternalName(Object.class)); - callMe.visitInsn(Opcodes.DUP); - callMe.visitMethodInsn(Opcodes.INVOKESPECIAL, Type.getInternalName(Object.class), "", "()V", false); - callMe.visitMethodInsn(Opcodes.INVOKEINTERFACE, Type.getInternalName(CallBack.class), "callBack", Type.getMethodDescriptor(Type.INT_TYPE, Type.getType(TestInterface.class)), true); - callMe.visitInsn(Opcodes.IRETURN); - callMe.visitMaxs(0, 0); - callMe.visitEnd(); - - MethodVisitor getList = cw.visitMethod(Opcodes.ACC_PUBLIC, "get", Type.getMethodDescriptor(Type.getType(TestInterface.class)), null, null); - getList.visitCode(); - getList.visitTypeInsn(Opcodes.NEW, Type.getInternalName(Object.class)); - getList.visitInsn(Opcodes.DUP); - getList.visitMethodInsn(Opcodes.INVOKESPECIAL, Type.getInternalName(Object.class), "", "()V", false); - getList.visitInsn(Opcodes.ARETURN); - getList.visitMaxs(0, 0); - getList.visitEnd(); - - cw.visitEnd(); - - byte[] bytes = cw.toByteArray(); - return defineClass(name, bytes, 0, bytes.length); - } - return super.findClass(name); + public byte[] generateClass(String className) { + ClassDesc classPill = cd(Pill.class); + ClassDesc classTestInterface = cd(TestInterface.class); + + return ClassFile.of().build(ClassDesc.of(className), classBuilder -> classBuilder + .withSuperclass(classPill) + .withMethodBody(INIT_NAME, MTD_void, ACC_PUBLIC, b -> b + .aload(0) + .invokespecial(classPill, INIT_NAME, MTD_void) + .return_()) + .withMethodBody("setField", MTD_void, ACC_PUBLIC, b -> b + .aload(0) + .new_(CD_Object) + .dup() + .invokespecial(CD_Object, INIT_NAME, MTD_void) + .putfield(classPill, "field", classTestInterface) + .return_()) + .withMethodBody("setStaticField", MTD_void, ACC_PUBLIC, b -> b + .new_(CD_Object) + .dup() + .invokespecial(CD_Object, INIT_NAME, MTD_void) + .putstatic(classPill, "staticField", classTestInterface) + .return_()) + .withMethodBody("callMe", MethodTypeDesc.of(CD_int, cd(CallBack.class)), ACC_PUBLIC, b -> b + .aload(1) + .new_(CD_Object) + .dup() + .invokespecial(CD_Object, INIT_NAME, MTD_void) + .invokeinterface(cd(CallBack.class), "callBack", MethodTypeDesc.of(CD_int, classTestInterface)) + .ireturn()) + .withMethodBody("get", MethodTypeDesc.of(classTestInterface), ACC_PUBLIC, b -> b + .new_(CD_Object) + .dup() + .invokespecial(CD_Object, INIT_NAME, MTD_void) + .areturn())); } } } diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/DeoptimizeOnExceptionTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/DeoptimizeOnExceptionTest.java index bc8e07f03c02..2778e79f76dd 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/DeoptimizeOnExceptionTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/DeoptimizeOnExceptionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2025, 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 @@ -24,24 +24,34 @@ */ package jdk.graal.compiler.replacements.test; +import static java.lang.classfile.ClassFile.ACC_PUBLIC; +import static java.lang.classfile.ClassFile.JAVA_5_VERSION; +import static java.lang.constant.ConstantDescs.CD_Object; +import static java.lang.constant.ConstantDescs.CD_long; +import static java.lang.constant.ConstantDescs.INIT_NAME; +import static java.lang.constant.ConstantDescs.MTD_void; + +import java.lang.classfile.ClassFile; +import java.lang.classfile.Label; +import java.lang.classfile.Opcode; +import java.lang.classfile.instruction.DiscontinuedInstruction.JsrInstruction; +import java.lang.classfile.instruction.DiscontinuedInstruction.RetInstruction; +import java.lang.constant.ClassDesc; +import java.lang.constant.MethodTypeDesc; import java.util.Random; +import org.junit.Assert; +import org.junit.Test; + import jdk.graal.compiler.api.directives.GraalDirectives; -import jdk.graal.compiler.api.test.ExportingClassLoader; import jdk.graal.compiler.core.phases.HighTier; +import jdk.graal.compiler.core.test.CustomizedBytecodePattern; import jdk.graal.compiler.core.test.GraalCompilerTest; import jdk.graal.compiler.nodes.ValueNode; import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderContext; import jdk.graal.compiler.nodes.graphbuilderconf.InlineInvokePlugin; import jdk.graal.compiler.options.OptionValues; import jdk.graal.compiler.phases.common.AbstractInliningPhase; -import org.junit.Assert; -import org.junit.Test; -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.Label; -import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Opcodes; - import jdk.vm.ci.code.InstalledCode; import jdk.vm.ci.meta.DeoptimizationReason; import jdk.vm.ci.meta.ResolvedJavaMethod; @@ -49,7 +59,7 @@ /** * Tests that deoptimization upon exception handling works. */ -public class DeoptimizeOnExceptionTest extends GraalCompilerTest { +public class DeoptimizeOnExceptionTest extends GraalCompilerTest implements CustomizedBytecodePattern { @SuppressWarnings("this-escape") public DeoptimizeOnExceptionTest() { @@ -74,31 +84,80 @@ public static String test1Snippet(String m1, String m2, String m3, String m4, St } @Test - public void test2() { - test("test2Snippet"); - } - - public String test2Snippet() throws Exception { + public void test2() throws ReflectiveOperationException { try { - ClassLoader testCl = new MyClassLoader(); - @SuppressWarnings("unchecked") - Class c = (Class) testCl.loadClass(name); - Runnable r = c.getDeclaredConstructor().newInstance(); + Class testClass = (Class) getClass(DeoptimizeOnExceptionTest.class.getName() + "$" + "TestJSR"); + Runnable r = testClass.getDeclaredConstructor().newInstance(); ct = Long.MAX_VALUE; // warmup for (int i = 0; i < 100; i++) { r.run(); } - // compile - ResolvedJavaMethod method = getResolvedJavaMethod(c, "run"); - getCode(method); ct = 0; - r.run(); + InstalledCode compiledMethod = getCode(getResolvedJavaMethod(testClass, "run")); + compiledMethod.executeVarargs(r); } catch (Throwable e) { e.printStackTrace(System.out); Assert.fail(); } - return "SUCCESS"; + } + + public static void methodB() { + Random r = new Random(System.currentTimeMillis()); + while (r.nextFloat() > .03f) { + // Empty + } + + return; + } + + public static void methodA() { + Random r = new Random(System.currentTimeMillis()); + while (r.nextDouble() > .05) { + // Empty + } + return; + } + + private static Object m = new Object(); + static long ct = Long.MAX_VALUE; + + public static Object getM() { + if (ct-- > 0) { + return m; + } else { + return null; + } + } + + @Override + public byte[] generateClass(String className) { + ClassDesc outerClass = cd(DeoptimizeOnExceptionTest.class); + + return ClassFile.of().build(ClassDesc.of(className), classBuilder -> classBuilder + .withVersion(JAVA_5_VERSION, 0) + .withInterfaceSymbols(cd(Runnable.class)) + .withMethodBody(INIT_NAME, MTD_void, ACC_PUBLIC, b -> b + .aload(0) + .invokespecial(CD_Object, INIT_NAME, MTD_void) + .return_()) + .withMethodBody("run", MTD_void, ACC_PUBLIC, b -> { + Label l1 = b.newLabel(); + b + .invokestatic(outerClass, "getM", MethodTypeDesc.of(CD_Object)) + .with(JsrInstruction.of(l1)) + .return_() + .labelBinding(l1) + .astore(1) + .invokestatic(cd(System.class), "currentTimeMillis", MethodTypeDesc.of(CD_long)) + .pop2() + .invokestatic(outerClass, "getM", MethodTypeDesc.of(CD_Object)) + .dup() + .ifThenElse(Opcode.IFNONNULL, + thenBlock -> thenBlock.invokestatic(outerClass, "methodA", MTD_void), + elseBlock -> elseBlock.invokestatic(outerClass, "methodB", MTD_void)) + .with(RetInstruction.of(1)); + })); } @Test @@ -154,87 +213,4 @@ public static boolean test3Snippet(boolean rethrowException) throws Exception { return GraalDirectives.inCompiledCode(); } - - public static class MyClassLoader extends ExportingClassLoader { - @Override - protected Class findClass(String className) throws ClassNotFoundException { - return defineClass(name.replace('/', '.'), clazz, 0, clazz.length); - } - } - - public static void methodB() { - Random r = new Random(System.currentTimeMillis()); - while (r.nextFloat() > .03f) { - // Empty - } - - return; - } - - public static void methodA() { - Random r = new Random(System.currentTimeMillis()); - while (r.nextDouble() > .05) { - // Empty - } - return; - } - - private static Object m = new Object(); - static long ct = Long.MAX_VALUE; - - public static Object getM() { - if (ct-- > 0) { - return m; - } else { - return null; - } - } - - private static String name = "t/TestJSR"; - - private static final byte[] clazz = makeClazz(); - - private static byte[] makeClazz() { - // Code generated the class below using asm. - String clazzName = DeoptimizeOnExceptionTest.class.getName().replace('.', '/'); - final ClassWriter w = new ClassWriter(0); - w.visit(Opcodes.V1_5, Opcodes.ACC_PUBLIC, - "t/TestJSR", null, "java/lang/Object", - new String[]{"java/lang/Runnable"}); - MethodVisitor mv = w.visitMethod(Opcodes.ACC_PUBLIC, "", "()V", null, new String[]{}); - mv.visitCode(); - mv.visitVarInsn(Opcodes.ALOAD, 0); - mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "", "()V", false); - mv.visitInsn(Opcodes.RETURN); - mv.visitMaxs(10, 10); - mv.visitEnd(); - - mv = w.visitMethod(Opcodes.ACC_PUBLIC, "run", "()V", null, null); - mv.visitCode(); - mv.visitMethodInsn(Opcodes.INVOKESTATIC, clazzName, "getM", "()Ljava/lang/Object;", false); - Label l1 = new Label(); - mv.visitJumpInsn(Opcodes.JSR, l1); - mv.visitInsn(Opcodes.RETURN); - - mv.visitLabel(l1); - mv.visitVarInsn(Opcodes.ASTORE, 1); - - Label lElse = new Label(); - Label lEnd = new Label(); - mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/System", "currentTimeMillis", "()J", false); - mv.visitInsn(Opcodes.POP2); - mv.visitMethodInsn(Opcodes.INVOKESTATIC, clazzName, "getM", "()Ljava/lang/Object;", false); - mv.visitInsn(Opcodes.DUP); - mv.visitJumpInsn(Opcodes.IFNULL, lElse); - mv.visitMethodInsn(Opcodes.INVOKESTATIC, clazzName, "methodA", "()V", false); - mv.visitJumpInsn(Opcodes.GOTO, lEnd); - mv.visitLabel(lElse); - mv.visitMethodInsn(Opcodes.INVOKESTATIC, clazzName, "methodB", "()V", false); - mv.visitLabel(lEnd); - - mv.visitVarInsn(Opcodes.RET, 1); - mv.visitMaxs(10, 10); - mv.visitEnd(); - return w.toByteArray(); - } } diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/InvokerSignatureMismatchTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/InvokerSignatureMismatchTest.java index ce2cbeac46b1..9cb626b951b2 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/InvokerSignatureMismatchTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/InvokerSignatureMismatchTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, 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 @@ -24,23 +24,44 @@ */ package jdk.graal.compiler.replacements.test; +import static java.lang.classfile.ClassFile.ACC_FINAL; +import static java.lang.classfile.ClassFile.ACC_STATIC; +import static java.lang.constant.ConstantDescs.CD_Class; +import static java.lang.constant.ConstantDescs.CD_Exception; +import static java.lang.constant.ConstantDescs.CD_Integer; +import static java.lang.constant.ConstantDescs.CD_MethodHandle; +import static java.lang.constant.ConstantDescs.CD_MethodHandles; +import static java.lang.constant.ConstantDescs.CD_MethodHandles_Lookup; +import static java.lang.constant.ConstantDescs.CD_MethodType; +import static java.lang.constant.ConstantDescs.CD_Object; +import static java.lang.constant.ConstantDescs.CD_String; +import static java.lang.constant.ConstantDescs.CD_float; +import static java.lang.constant.ConstantDescs.CD_int; +import static java.lang.constant.ConstantDescs.CD_void; +import static java.lang.constant.ConstantDescs.CLASS_INIT_NAME; +import static java.lang.constant.ConstantDescs.MTD_void; +import static jdk.graal.compiler.core.test.CustomizedBytecodePattern.ACC_PUBLIC_STATIC; import static jdk.graal.compiler.test.SubprocessUtil.getVMCommandLine; import static jdk.graal.compiler.test.SubprocessUtil.withoutDebuggerArguments; +import java.lang.classfile.Annotation; +import java.lang.classfile.ClassFile; +import java.lang.classfile.attribute.ExceptionsAttribute; +import java.lang.classfile.attribute.RuntimeVisibleAnnotationsAttribute; +import java.lang.constant.ClassDesc; +import java.lang.constant.MethodTypeDesc; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.List; -import jdk.graal.compiler.core.test.CustomizedBytecodePatternTest; +import org.junit.Test; + +import jdk.graal.compiler.core.test.GraalCompilerTest; import jdk.graal.compiler.test.SubprocessUtil; import jdk.graal.compiler.test.SubprocessUtil.Subprocess; -import org.junit.Test; -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Type; -public class InvokerSignatureMismatchTest extends CustomizedBytecodePatternTest { +public class InvokerSignatureMismatchTest extends GraalCompilerTest { @SuppressWarnings("try") @Test @@ -55,8 +76,8 @@ public void test() throws Throwable { args.add("-XX:+UseJVMCICompiler"); Path invokeDir = Files.createDirectories(temp.path.resolve(Paths.get("java", "lang", "invoke"))); - Files.write(temp.path.resolve("ISMTest.class"), generateClass("ISMTest")); - Files.write(invokeDir.resolve("MethodHandleHelper.class"), generateClass("java/lang/invoke/MethodHandleHelper")); + Files.write(temp.path.resolve("ISMTest.class"), generateISMTest()); + Files.write(invokeDir.resolve("MethodHandleHelper.class"), generateMethodHandleHelper()); args.add("ISMTest"); Subprocess proc = SubprocessUtil.java(args); @@ -66,105 +87,84 @@ public void test() throws Throwable { } } - @Override - protected byte[] generateClass(String className) { - String[] exceptions = new String[]{"java/lang/Throwable"}; - ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); - cw.visit(52, ACC_SUPER | ACC_PUBLIC, className, null, "java/lang/Object", null); - - if (className.equals("java/lang/invoke/MethodHandleHelper")) { - MethodVisitor internalMemberName = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "internalMemberName", "(Ljava/lang/invoke/MethodHandle;)Ljava/lang/Object;", null, exceptions); - internalMemberName.visitCode(); - internalMemberName.visitVarInsn(ALOAD, 0); - internalMemberName.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle", "internalMemberName", "()Ljava/lang/invoke/MemberName;", false); - internalMemberName.visitInsn(ARETURN); - internalMemberName.visitMaxs(1, 1); - internalMemberName.visitEnd(); - - MethodVisitor linkToStatic = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "linkToStatic", "(FLjava/lang/Object;)I", null, exceptions); - linkToStatic.visitCode(); - linkToStatic.visitVarInsn(FLOAD, 0); - linkToStatic.visitVarInsn(ALOAD, 1); - linkToStatic.visitMethodInsn(INVOKESTATIC, "java/lang/invoke/MethodHandle", "linkToStatic", "(FLjava/lang/Object;)I", false); - linkToStatic.visitInsn(IRETURN); - linkToStatic.visitMaxs(1, 1); - linkToStatic.visitEnd(); - - MethodVisitor invokeBasicI = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "invokeBasicI", "(Ljava/lang/invoke/MethodHandle;F)I", null, exceptions); - invokeBasicI.visitCode(); - invokeBasicI.visitVarInsn(ALOAD, 0); - invokeBasicI.visitVarInsn(FLOAD, 1); - invokeBasicI.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle", "invokeBasic", "(F)I", false); - invokeBasicI.visitInsn(IRETURN); - invokeBasicI.visitMaxs(1, 1); - invokeBasicI.visitEnd(); - - } else { - assert className.equals("ISMTest") : className; - cw.visitField(ACC_FINAL | ACC_STATIC, "INT_MH", "Ljava/lang/invoke/MethodHandle;", null, null).visitAnnotation("Ljava/lang/invoke/Stable.class;", true).visitEnd(); - MethodVisitor clinit = cw.visitMethod(ACC_STATIC, "", "()V", null, exceptions); - clinit.visitCode(); - clinit.visitInsn(ACONST_NULL); - clinit.visitVarInsn(ASTORE, 0); - clinit.visitMethodInsn(INVOKESTATIC, "java/lang/invoke/MethodHandles", "lookup", "()Ljava/lang/invoke/MethodHandles$Lookup;", false); - clinit.visitLdcInsn(Type.getObjectType(className)); - clinit.visitLdcInsn("bodyI"); - clinit.visitFieldInsn(GETSTATIC, "java/lang/Integer", "TYPE", "Ljava/lang/Class;"); - clinit.visitFieldInsn(GETSTATIC, "java/lang/Integer", "TYPE", "Ljava/lang/Class;"); - clinit.visitMethodInsn(INVOKESTATIC, "java/lang/invoke/MethodType", "methodType", "(Ljava/lang/Class;Ljava/lang/Class;)Ljava/lang/invoke/MethodType;", false); - clinit.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandles$Lookup", "findStatic", - "(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle;", false); - clinit.visitFieldInsn(PUTSTATIC, className, "INT_MH", "Ljava/lang/invoke/MethodHandle;"); - clinit.visitInsn(RETURN); - clinit.visitMaxs(1, 1); - clinit.visitEnd(); - - MethodVisitor mainLink = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "mainLink", "(I)I", null, exceptions); - mainLink.visitCode(); - mainLink.visitFieldInsn(GETSTATIC, className, "INT_MH", "Ljava/lang/invoke/MethodHandle;"); - mainLink.visitMethodInsn(INVOKESTATIC, "java/lang/invoke/MethodHandleHelper", "internalMemberName", "(Ljava/lang/invoke/MethodHandle;)Ljava/lang/Object;", false); - mainLink.visitVarInsn(ASTORE, 1); - mainLink.visitVarInsn(ILOAD, 0); - mainLink.visitInsn(I2F); - mainLink.visitVarInsn(ALOAD, 1); - mainLink.visitMethodInsn(INVOKESTATIC, "java/lang/invoke/MethodHandleHelper", "linkToStatic", "(FLjava/lang/Object;)I", false); - mainLink.visitInsn(IRETURN); - mainLink.visitMaxs(1, 1); - mainLink.visitEnd(); - - MethodVisitor mainInvoke = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "mainInvoke", "(I)I", null, exceptions); - mainInvoke.visitCode(); - mainInvoke.visitFieldInsn(GETSTATIC, className, "INT_MH", "Ljava/lang/invoke/MethodHandle;"); - mainInvoke.visitVarInsn(ILOAD, 0); - mainInvoke.visitInsn(I2F); - mainInvoke.visitMethodInsn(INVOKESTATIC, "java/lang/invoke/MethodHandleHelper", "invokeBasicI", "(Ljava/lang/invoke/MethodHandle;F)I", false); - mainInvoke.visitInsn(IRETURN); - mainInvoke.visitMaxs(1, 1); - mainInvoke.visitEnd(); - - MethodVisitor bodyI = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "bodyI", "(I)I", null, null); - bodyI.visitCode(); - bodyI.visitVarInsn(ILOAD, 0); - bodyI.visitIntInsn(SIPUSH, 1023); - bodyI.visitInsn(IAND); - bodyI.visitInsn(IRETURN); - bodyI.visitMaxs(1, 1); - bodyI.visitEnd(); - - MethodVisitor main = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "main", "([Ljava/lang/String;)V", null, exceptions); - main.visitCode(); - main.visitIntInsn(SIPUSH, 100); - main.visitMethodInsn(INVOKESTATIC, "ISMTest", "mainLink", "(I)I", false); - main.visitInsn(POP); - main.visitIntInsn(SIPUSH, 100); - main.visitMethodInsn(INVOKESTATIC, "ISMTest", "mainInvoke", "(I)I", false); - main.visitInsn(POP); - main.visitInsn(RETURN); - main.visitMaxs(1, 1); - main.visitEnd(); + private static byte[] generateMethodHandleHelper() { + return ClassFile.of().build(ClassDesc.of("java.lang.invoke.MethodHandleHelper"), classBuilder -> classBuilder + .withMethod("internalMemberName", MethodTypeDesc.of(CD_Object, CD_MethodHandle), ACC_PUBLIC_STATIC, methodBuilder -> methodBuilder + .with(ExceptionsAttribute.ofSymbols(CD_Exception)) + .withCode(b -> b + .aload(0) + .invokevirtual(CD_MethodHandle, "internalMemberName", MethodTypeDesc.of(ClassDesc.of("java.lang.invoke.MemberName"))) + .areturn())) + .withMethod("linkToStatic", MethodTypeDesc.of(CD_int, CD_float, CD_Object), ACC_PUBLIC_STATIC, methodBuilder -> methodBuilder + .with(ExceptionsAttribute.ofSymbols(CD_Exception)) + .withCode(b -> b + .fload(0) + .aload(1) + .invokestatic(CD_MethodHandle, "linkToStatic", MethodTypeDesc.of(CD_int, CD_float, CD_Object)) + .ireturn())) + .withMethod("invokeBasicI", MethodTypeDesc.of(CD_int, CD_MethodHandle, CD_float), ACC_PUBLIC_STATIC, methodBuilder -> methodBuilder + .with(ExceptionsAttribute.ofSymbols(CD_Exception)) + .withCode(b -> b + .aload(0) + .fload(1) + .invokevirtual(CD_MethodHandle, "invokeBasic", MethodTypeDesc.of(CD_int, CD_float)) + .ireturn()))); + } - } - cw.visitEnd(); - return cw.toByteArray(); + private static byte[] generateISMTest() { + ClassDesc thisClass = ClassDesc.of("ISMTest"); + ClassDesc methodHandleHelper = ClassDesc.of("java.lang.invoke.MethodHandleHelper"); + + return ClassFile.of().build(thisClass, classBuilder -> classBuilder + .withField("INT_MH", CD_MethodHandle, fieldBuilder -> fieldBuilder + .withFlags(ACC_FINAL | ACC_STATIC) + .with(RuntimeVisibleAnnotationsAttribute.of(Annotation.of(ClassDesc.of("jdk.internal.vm.annotation.Stable"))))) + .withMethod(CLASS_INIT_NAME, MTD_void, ACC_STATIC, methodBuilder -> methodBuilder + .withCode(b -> b + .aconst_null() + .astore(0) + .invokestatic(CD_MethodHandles, "lookup", MethodTypeDesc.of(CD_MethodHandles_Lookup)) + .ldc(thisClass) + .ldc("bodyI") + .getstatic(CD_Integer, "TYPE", CD_Class) + .getstatic(CD_Integer, "TYPE", CD_Class) + .invokestatic(CD_MethodType, "methodType", MethodTypeDesc.of(CD_MethodType, CD_Class, CD_Class)) + .invokevirtual(CD_MethodHandles_Lookup, "findStatic", MethodTypeDesc.of(CD_MethodHandle, CD_Class, CD_String, CD_MethodType)) + .putstatic(thisClass, "INT_MH", CD_MethodHandle) + .return_())) + .withMethod("mainLink", MethodTypeDesc.of(CD_int, CD_int), ACC_PUBLIC_STATIC, methodBuilder -> methodBuilder + .with(ExceptionsAttribute.ofSymbols(CD_Exception)) + .withCode(b -> b + .getstatic(thisClass, "INT_MH", CD_MethodHandle) + .invokestatic(methodHandleHelper, "internalMemberName", MethodTypeDesc.of(CD_Object, CD_MethodHandle)) + .astore(1) + .iload(0) + .i2f() + .aload(1) + .invokestatic(methodHandleHelper, "linkToStatic", MethodTypeDesc.of(CD_int, CD_float, CD_Object)) + .ireturn())) + .withMethod("mainInvoke", MethodTypeDesc.of(CD_int, CD_int), ACC_PUBLIC_STATIC, methodBuilder -> methodBuilder + .with(ExceptionsAttribute.ofSymbols(CD_Exception)) + .withCode(b -> b + .getstatic(thisClass, "INT_MH", CD_MethodHandle) + .iload(0) + .i2f() + .invokestatic(methodHandleHelper, "invokeBasicI", MethodTypeDesc.of(CD_int, CD_MethodHandle, CD_float)) + .ireturn())) + .withMethod("bodyI", MethodTypeDesc.of(CD_int, CD_int), ACC_PUBLIC_STATIC, methodBuilder -> methodBuilder + .withCode(b -> b + .iload(0) + .sipush(1023) + .iand() + .ireturn())) + .withMethod("main", MethodTypeDesc.of(CD_void, CD_String.arrayType()), ACC_PUBLIC_STATIC, methodBuilder -> methodBuilder + .withCode(b -> b + .sipush(100) + .invokestatic(thisClass, "mainLink", MethodTypeDesc.of(CD_int, CD_int)) + .pop() + .sipush(100) + .invokestatic(thisClass, "mainInvoke", MethodTypeDesc.of(CD_int, CD_int)) + .pop() + .return_()))); } } diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/UnsafeObjectReplacementsTest.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/UnsafeObjectReplacementsTest.java index 1cfefda2bc0e..b8651a629d1c 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/UnsafeObjectReplacementsTest.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/replacements/test/UnsafeObjectReplacementsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, 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 @@ -25,18 +25,18 @@ package jdk.graal.compiler.replacements.test; import java.io.IOException; +import java.lang.classfile.ClassFile; +import java.lang.classfile.ClassTransform; +import java.lang.classfile.CodeTransform; +import java.lang.classfile.MethodTransform; +import java.lang.classfile.instruction.InvokeInstruction; import java.lang.reflect.Method; -import jdk.graal.compiler.core.test.CustomizedBytecodePatternTest.CachedLoader; -import jdk.graal.compiler.test.AddExports; import org.junit.Test; -import org.objectweb.asm.ClassReader; -import org.objectweb.asm.ClassVisitor; -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.Type; +import jdk.graal.compiler.core.test.CustomizedBytecodePattern; +import jdk.graal.compiler.serviceprovider.GraalServices; +import jdk.graal.compiler.test.AddExports; import jdk.internal.misc.Unsafe; import jdk.vm.ci.meta.ResolvedJavaMethod; @@ -46,7 +46,7 @@ * @see "https://bugs.openjdk.java.net/browse/JDK-8207146" */ @AddExports("java.base/jdk.internal.misc") -public class UnsafeObjectReplacementsTest extends MethodSubstitutionTest { +public class UnsafeObjectReplacementsTest extends MethodSubstitutionTest implements CustomizedBytecodePattern { public static class Container { public volatile Object objectField = dummyValue; @@ -127,10 +127,8 @@ public void testUnsafeObjectMethods() { * rewritten to invoke the corresponding {@code *Reference*} methods. */ private Class loadModifiedMethodsClass() { - String className = Methods.class.getName(); - CachedLoader cl = new CachedLoader(getClass().getClassLoader(), className, Generator::generate); try { - return cl.findClass(className); + return getClass(Methods.class.getName()); } catch (ClassNotFoundException e) { throw new AssertionError(e); } @@ -145,34 +143,22 @@ private static boolean unsafeHasReferenceMethods() { } } - static class Generator { - static byte[] generate(String className) { - int api = Opcodes.ASM9; - try { - ClassReader cr = new ClassReader(className); - ClassWriter cw = new ClassWriter(cr, 0); - ClassVisitor cv = new ClassVisitor(api, cw) { - @Override - public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { - return new MethodVisitor(api, super.visitMethod(access, name, descriptor, signature, exceptions)) { - @Override - public void visitMethodInsn(int opcode, String owner, String methodName, String methodDescriptor, boolean isInterface) { - if (methodName.contains("Object") && owner.equals(Type.getInternalName(Unsafe.class))) { - super.visitMethodInsn(opcode, owner, methodName.replace("Object", "Reference"), methodDescriptor, isInterface); - } else { - super.visitMethodInsn(opcode, owner, methodName, methodDescriptor, isInterface); - } - } - }; - } - }; - - cr.accept(cv, 0); - cw.visitEnd(); - return cw.toByteArray(); - } catch (IOException e) { - throw new RuntimeException(e); + @Override + public byte[] generateClass(String className) { + CodeTransform codeTransform = (codeBuilder, e) -> { + switch (e) { + case InvokeInstruction i when i.owner().asSymbol().equals(cd(Unsafe.class)) && i.method().name().stringValue().contains("Object") -> + codeBuilder.invoke(i.opcode(), i.owner().asSymbol(), i.method().name().stringValue().replace("Object", "Reference"), i.typeSymbol(), i.isInterface()); + default -> codeBuilder.accept(e); } + }; + + try { + ClassFile cf = ClassFile.of(); + return cf.transformClass(cf.parse(GraalServices.getClassfileAsStream(Methods.class).readAllBytes()), + ClassTransform.transformingMethods(MethodTransform.transformingCode(codeTransform))); + } catch (IOException e) { + return new byte[0]; } } }