1 /*
2  * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 
24 
25 package org.graalvm.compiler.replacements.test;
26 
27 import static org.graalvm.compiler.test.SubprocessUtil.getVMCommandLine;
28 import static org.graalvm.compiler.test.SubprocessUtil.withoutDebuggerArguments;
29 
30 import java.nio.file.Files;
31 import java.nio.file.Path;
32 import java.nio.file.Paths;
33 import java.util.List;
34 
35 import org.graalvm.compiler.core.test.CustomizedBytecodePatternTest;
36 import org.graalvm.compiler.serviceprovider.JavaVersionUtil;
37 import org.graalvm.compiler.test.SubprocessUtil;
38 import org.graalvm.compiler.test.SubprocessUtil.Subprocess;
39 import org.junit.Test;
40 import org.objectweb.asm.ClassWriter;
41 import org.objectweb.asm.MethodVisitor;
42 import org.objectweb.asm.Type;
43 
44 public class InvokerSignatureMismatchTest extends CustomizedBytecodePatternTest {
45 
46     @SuppressWarnings("try")
47     @Test
test()48     public void test() throws Throwable {
49         List<String> args = withoutDebuggerArguments(getVMCommandLine());
50         try (TemporaryDirectory temp = new TemporaryDirectory(null, getClass().getSimpleName())) {
51             if (JavaVersionUtil.JAVA_SPEC > 8) {
52                 args.add("--class-path=" + temp);
53                 args.add("--patch-module=java.base=" + temp);
54             } else {
55                 args.add("-Xbootclasspath/a:" + temp);
56             }
57             args.add("-XX:-TieredCompilation");
58             args.add("-XX:+UnlockExperimentalVMOptions");
59             args.add("-XX:+EnableJVMCI");
60             args.add("-XX:+UseJVMCICompiler");
61 
62             Path invokeDir = Files.createDirectories(temp.path.resolve(Paths.get("java", "lang", "invoke")));
63             Files.write(temp.path.resolve("ISMTest.class"), generateClass("ISMTest"));
64             Files.write(invokeDir.resolve("MethodHandleHelper.class"), generateClass("java/lang/invoke/MethodHandleHelper"));
65 
66             args.add("ISMTest");
67             Subprocess proc = SubprocessUtil.java(args);
68             if (proc.exitCode != 0) {
69                 throw new AssertionError(proc.toString());
70             }
71         }
72     }
73 
74     @Override
generateClass(String className)75     protected byte[] generateClass(String className) {
76         String[] exceptions = new String[]{"java/lang/Throwable"};
77         ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
78         cw.visit(52, ACC_SUPER | ACC_PUBLIC, className, null, "java/lang/Object", null);
79 
80         if (className.equals("java/lang/invoke/MethodHandleHelper")) {
81             MethodVisitor internalMemberName = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "internalMemberName", "(Ljava/lang/invoke/MethodHandle;)Ljava/lang/Object;", null, exceptions);
82             internalMemberName.visitCode();
83             internalMemberName.visitVarInsn(ALOAD, 0);
84             internalMemberName.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle", "internalMemberName", "()Ljava/lang/invoke/MemberName;", false);
85             internalMemberName.visitInsn(ARETURN);
86             internalMemberName.visitMaxs(1, 1);
87             internalMemberName.visitEnd();
88 
89             MethodVisitor linkToStatic = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "linkToStatic", "(FLjava/lang/Object;)I", null, exceptions);
90             linkToStatic.visitCode();
91             linkToStatic.visitVarInsn(FLOAD, 0);
92             linkToStatic.visitVarInsn(ALOAD, 1);
93             linkToStatic.visitMethodInsn(INVOKESTATIC, "java/lang/invoke/MethodHandle", "linkToStatic", "(FLjava/lang/Object;)I", false);
94             linkToStatic.visitInsn(IRETURN);
95             linkToStatic.visitMaxs(1, 1);
96             linkToStatic.visitEnd();
97 
98             MethodVisitor invokeBasicI = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "invokeBasicI", "(Ljava/lang/invoke/MethodHandle;F)I", null, exceptions);
99             invokeBasicI.visitCode();
100             invokeBasicI.visitVarInsn(ALOAD, 0);
101             invokeBasicI.visitVarInsn(FLOAD, 1);
102             invokeBasicI.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandle", "invokeBasic", "(F)I", false);
103             invokeBasicI.visitInsn(IRETURN);
104             invokeBasicI.visitMaxs(1, 1);
105             invokeBasicI.visitEnd();
106 
107         } else {
108             assert className.equals("ISMTest") : className;
109             cw.visitField(ACC_FINAL | ACC_STATIC, "INT_MH", "Ljava/lang/invoke/MethodHandle;", null, null).visitAnnotation("Ljava/lang/invoke/Stable.class;", true).visitEnd();
110             MethodVisitor clinit = cw.visitMethod(ACC_STATIC, "<clinit>", "()V", null, exceptions);
111             clinit.visitCode();
112             clinit.visitInsn(ACONST_NULL);
113             clinit.visitVarInsn(ASTORE, 0);
114             clinit.visitMethodInsn(INVOKESTATIC, "java/lang/invoke/MethodHandles", "lookup", "()Ljava/lang/invoke/MethodHandles$Lookup;", false);
115             clinit.visitLdcInsn(Type.getObjectType(className));
116             clinit.visitLdcInsn("bodyI");
117             clinit.visitFieldInsn(GETSTATIC, "java/lang/Integer", "TYPE", "Ljava/lang/Class;");
118             clinit.visitFieldInsn(GETSTATIC, "java/lang/Integer", "TYPE", "Ljava/lang/Class;");
119             clinit.visitMethodInsn(INVOKESTATIC, "java/lang/invoke/MethodType", "methodType", "(Ljava/lang/Class;Ljava/lang/Class;)Ljava/lang/invoke/MethodType;", false);
120             clinit.visitMethodInsn(INVOKEVIRTUAL, "java/lang/invoke/MethodHandles$Lookup", "findStatic",
121                             "(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle;", false);
122             clinit.visitFieldInsn(PUTSTATIC, className, "INT_MH", "Ljava/lang/invoke/MethodHandle;");
123             clinit.visitInsn(RETURN);
124             clinit.visitMaxs(1, 1);
125             clinit.visitEnd();
126 
127             MethodVisitor mainLink = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "mainLink", "(I)I", null, exceptions);
128             mainLink.visitCode();
129             mainLink.visitFieldInsn(GETSTATIC, className, "INT_MH", "Ljava/lang/invoke/MethodHandle;");
130             mainLink.visitMethodInsn(INVOKESTATIC, "java/lang/invoke/MethodHandleHelper", "internalMemberName", "(Ljava/lang/invoke/MethodHandle;)Ljava/lang/Object;", false);
131             mainLink.visitVarInsn(ASTORE, 1);
132             mainLink.visitVarInsn(ILOAD, 0);
133             mainLink.visitInsn(I2F);
134             mainLink.visitVarInsn(ALOAD, 1);
135             mainLink.visitMethodInsn(INVOKESTATIC, "java/lang/invoke/MethodHandleHelper", "linkToStatic", "(FLjava/lang/Object;)I", false);
136             mainLink.visitInsn(IRETURN);
137             mainLink.visitMaxs(1, 1);
138             mainLink.visitEnd();
139 
140             MethodVisitor mainInvoke = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "mainInvoke", "(I)I", null, exceptions);
141             mainInvoke.visitCode();
142             mainInvoke.visitFieldInsn(GETSTATIC, className, "INT_MH", "Ljava/lang/invoke/MethodHandle;");
143             mainInvoke.visitVarInsn(ILOAD, 0);
144             mainInvoke.visitInsn(I2F);
145             mainInvoke.visitMethodInsn(INVOKESTATIC, "java/lang/invoke/MethodHandleHelper", "invokeBasicI", "(Ljava/lang/invoke/MethodHandle;F)I", false);
146             mainInvoke.visitInsn(IRETURN);
147             mainInvoke.visitMaxs(1, 1);
148             mainInvoke.visitEnd();
149 
150             MethodVisitor bodyI = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "bodyI", "(I)I", null, null);
151             bodyI.visitCode();
152             bodyI.visitVarInsn(ILOAD, 0);
153             bodyI.visitIntInsn(SIPUSH, 1023);
154             bodyI.visitInsn(IAND);
155             bodyI.visitInsn(IRETURN);
156             bodyI.visitMaxs(1, 1);
157             bodyI.visitEnd();
158 
159             MethodVisitor main = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "main", "([Ljava/lang/String;)V", null, exceptions);
160             main.visitCode();
161             main.visitIntInsn(SIPUSH, 100);
162             main.visitMethodInsn(INVOKESTATIC, "ISMTest", "mainLink", "(I)I", false);
163             main.visitInsn(POP);
164             main.visitIntInsn(SIPUSH, 100);
165             main.visitMethodInsn(INVOKESTATIC, "ISMTest", "mainInvoke", "(I)I", false);
166             main.visitInsn(POP);
167             main.visitInsn(RETURN);
168             main.visitMaxs(1, 1);
169             main.visitEnd();
170 
171         }
172         cw.visitEnd();
173         return cw.toByteArray();
174     }
175 }
176