1 /* 2 * Copyright (c) 2015, 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.nodes.graphbuilderconf; 26 27 import java.lang.invoke.MethodHandle; 28 import java.lang.reflect.Method; 29 30 import org.graalvm.compiler.debug.GraalError; 31 import org.graalvm.compiler.nodes.Invoke; 32 import org.graalvm.compiler.nodes.ValueNode; 33 import org.graalvm.compiler.nodes.type.StampTool; 34 35 import jdk.vm.ci.meta.MetaAccessProvider; 36 import jdk.vm.ci.meta.ResolvedJavaMethod; 37 38 /** 39 * Plugin for handling a specific method invocation. 40 */ 41 public interface InvocationPlugin extends GraphBuilderPlugin { 42 43 /** 44 * The receiver in a non-static method. The class literal for this interface must be used with 45 * {@link InvocationPlugins#put(InvocationPlugin, boolean, boolean, Class, String, Class...)} to 46 * denote the receiver argument for such a non-static method. 47 */ 48 public interface Receiver { 49 /** 50 * Gets the receiver value, null checking it first if necessary. 51 * 52 * @return the receiver value with a {@linkplain StampTool#isPointerNonNull(ValueNode) 53 * non-null} stamp 54 */ get()55 default ValueNode get() { 56 return get(true); 57 } 58 59 /** 60 * Gets the receiver value, optionally null checking it first if necessary. 61 */ get(boolean performNullCheck)62 ValueNode get(boolean performNullCheck); 63 64 /** 65 * Determines if the receiver is constant. 66 */ isConstant()67 default boolean isConstant() { 68 return false; 69 } 70 } 71 72 /** 73 * Determines if this plugin is for a method with a polymorphic signature (e.g. 74 * {@link MethodHandle#invokeExact(Object...)}). 75 */ isSignaturePolymorphic()76 default boolean isSignaturePolymorphic() { 77 return false; 78 } 79 80 /** 81 * Determines if this plugin can only be used when inlining the method is it associated with. 82 * That is, this plugin cannot be used when the associated method is the compilation root. 83 */ inlineOnly()84 default boolean inlineOnly() { 85 return isSignaturePolymorphic(); 86 } 87 88 /** 89 * Determines if this plugin only decorates the method is it associated with. That is, it 90 * inserts nodes prior to the invocation (e.g. some kind of marker nodes) but still expects the 91 * parser to process the invocation further. 92 */ isDecorator()93 default boolean isDecorator() { 94 return false; 95 } 96 97 /** 98 * Handles invocation of a signature polymorphic method. 99 * 100 * @param receiver access to the receiver, {@code null} if {@code targetMethod} is static 101 * @param argsIncludingReceiver all arguments to the invocation include the raw receiver in 102 * position 0 if {@code targetMethod} is not static 103 * @see #execute 104 */ applyPolymorphic(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode... argsIncludingReceiver)105 default boolean applyPolymorphic(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode... argsIncludingReceiver) { 106 return defaultHandler(b, targetMethod, receiver, argsIncludingReceiver); 107 } 108 109 /** 110 * @see #execute 111 */ apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver)112 default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver) { 113 return defaultHandler(b, targetMethod, receiver); 114 } 115 116 /** 117 * @see #execute 118 */ apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode arg)119 default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode arg) { 120 return defaultHandler(b, targetMethod, receiver, arg); 121 } 122 123 /** 124 * @see #execute 125 */ apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode arg1, ValueNode arg2)126 default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode arg1, ValueNode arg2) { 127 return defaultHandler(b, targetMethod, receiver, arg1, arg2); 128 } 129 130 /** 131 * @see #execute 132 */ apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode arg1, ValueNode arg2, ValueNode arg3)133 default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode arg1, ValueNode arg2, ValueNode arg3) { 134 return defaultHandler(b, targetMethod, receiver, arg1, arg2, arg3); 135 } 136 137 /** 138 * @see #execute 139 */ apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode arg1, ValueNode arg2, ValueNode arg3, ValueNode arg4)140 default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode arg1, ValueNode arg2, ValueNode arg3, ValueNode arg4) { 141 return defaultHandler(b, targetMethod, receiver, arg1, arg2, arg3, arg4); 142 } 143 144 /** 145 * @see #execute 146 */ apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode arg1, ValueNode arg2, ValueNode arg3, ValueNode arg4, ValueNode arg5)147 default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode arg1, ValueNode arg2, ValueNode arg3, ValueNode arg4, ValueNode arg5) { 148 return defaultHandler(b, targetMethod, receiver, arg1, arg2, arg3, arg4, arg5); 149 } 150 151 /** 152 * @see #execute 153 */ apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode arg1, ValueNode arg2, ValueNode arg3, ValueNode arg4, ValueNode arg5, ValueNode arg6)154 default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode arg1, ValueNode arg2, ValueNode arg3, ValueNode arg4, ValueNode arg5, 155 ValueNode arg6) { 156 return defaultHandler(b, targetMethod, receiver, arg1, arg2, arg3, arg4, arg5, arg6); 157 } 158 159 /** 160 * @see #execute 161 */ apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode arg1, ValueNode arg2, ValueNode arg3, ValueNode arg4, ValueNode arg5, ValueNode arg6, ValueNode arg7)162 default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode arg1, ValueNode arg2, ValueNode arg3, ValueNode arg4, ValueNode arg5, 163 ValueNode arg6, ValueNode arg7) { 164 return defaultHandler(b, targetMethod, receiver, arg1, arg2, arg3, arg4, arg5, arg6, arg7); 165 } 166 167 /** 168 * Executes this plugin against a set of invocation arguments. 169 * 170 * The default implementation in {@link InvocationPlugin} dispatches to the {@code apply(...)} 171 * method that matches the number of arguments or to {@link #applyPolymorphic} if {@code plugin} 172 * is {@linkplain #isSignaturePolymorphic() signature polymorphic}. 173 * 174 * @param targetMethod the method for which this plugin is being applied 175 * @param receiver access to the receiver, {@code null} if {@code targetMethod} is static 176 * @param argsIncludingReceiver all arguments to the invocation include the receiver in position 177 * 0 if {@code targetMethod} is not static 178 * @return {@code true} if this plugin handled the invocation of {@code targetMethod} 179 * {@code false} if the graph builder should process the invoke further (e.g., by 180 * inlining it or creating an {@link Invoke} node). A plugin that does not handle an 181 * invocation must not modify the graph being constructed unless it is a 182 * {@linkplain InvocationPlugin#isDecorator() decorator}. 183 */ execute(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode[] argsIncludingReceiver)184 default boolean execute(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode[] argsIncludingReceiver) { 185 if (isSignaturePolymorphic()) { 186 return applyPolymorphic(b, targetMethod, receiver, argsIncludingReceiver); 187 } else if (receiver != null) { 188 assert !targetMethod.isStatic(); 189 assert argsIncludingReceiver.length > 0; 190 if (argsIncludingReceiver.length == 1) { 191 return apply(b, targetMethod, receiver); 192 } else if (argsIncludingReceiver.length == 2) { 193 return apply(b, targetMethod, receiver, argsIncludingReceiver[1]); 194 } else if (argsIncludingReceiver.length == 3) { 195 return apply(b, targetMethod, receiver, argsIncludingReceiver[1], argsIncludingReceiver[2]); 196 } else if (argsIncludingReceiver.length == 4) { 197 return apply(b, targetMethod, receiver, argsIncludingReceiver[1], argsIncludingReceiver[2], argsIncludingReceiver[3]); 198 } else if (argsIncludingReceiver.length == 5) { 199 return apply(b, targetMethod, receiver, argsIncludingReceiver[1], argsIncludingReceiver[2], argsIncludingReceiver[3], argsIncludingReceiver[4]); 200 } else if (argsIncludingReceiver.length == 6) { 201 return apply(b, targetMethod, receiver, argsIncludingReceiver[1], argsIncludingReceiver[2], argsIncludingReceiver[3], argsIncludingReceiver[4], argsIncludingReceiver[5]); 202 } else if (argsIncludingReceiver.length == 7) { 203 return apply(b, targetMethod, receiver, argsIncludingReceiver[1], argsIncludingReceiver[2], argsIncludingReceiver[3], argsIncludingReceiver[4], argsIncludingReceiver[5], 204 argsIncludingReceiver[6]); 205 } else { 206 return defaultHandler(b, targetMethod, receiver, argsIncludingReceiver); 207 } 208 } else { 209 assert targetMethod.isStatic(); 210 if (argsIncludingReceiver.length == 0) { 211 return apply(b, targetMethod, null); 212 } else if (argsIncludingReceiver.length == 1) { 213 return apply(b, targetMethod, null, argsIncludingReceiver[0]); 214 } else if (argsIncludingReceiver.length == 2) { 215 return apply(b, targetMethod, null, argsIncludingReceiver[0], argsIncludingReceiver[1]); 216 } else if (argsIncludingReceiver.length == 3) { 217 return apply(b, targetMethod, null, argsIncludingReceiver[0], argsIncludingReceiver[1], argsIncludingReceiver[2]); 218 } else if (argsIncludingReceiver.length == 4) { 219 return apply(b, targetMethod, null, argsIncludingReceiver[0], argsIncludingReceiver[1], argsIncludingReceiver[2], argsIncludingReceiver[3]); 220 } else if (argsIncludingReceiver.length == 5) { 221 return apply(b, targetMethod, null, argsIncludingReceiver[0], argsIncludingReceiver[1], argsIncludingReceiver[2], argsIncludingReceiver[3], argsIncludingReceiver[4]); 222 } else if (argsIncludingReceiver.length == 6) { 223 return apply(b, targetMethod, null, argsIncludingReceiver[0], argsIncludingReceiver[1], argsIncludingReceiver[2], argsIncludingReceiver[3], argsIncludingReceiver[4], 224 argsIncludingReceiver[5]); 225 } else if (argsIncludingReceiver.length == 7) { 226 return apply(b, targetMethod, null, argsIncludingReceiver[0], argsIncludingReceiver[1], argsIncludingReceiver[2], argsIncludingReceiver[3], argsIncludingReceiver[4], 227 argsIncludingReceiver[5], argsIncludingReceiver[6]); 228 } else { 229 return defaultHandler(b, targetMethod, receiver, argsIncludingReceiver); 230 } 231 232 } 233 } 234 235 /** 236 * Handles an invocation when a specific {@code apply} method is not available. 237 */ defaultHandler(@uppressWarningsR) GraphBuilderContext b, ResolvedJavaMethod targetMethod, @SuppressWarnings(R) InvocationPlugin.Receiver receiver, ValueNode... args)238 default boolean defaultHandler(@SuppressWarnings("unused") GraphBuilderContext b, ResolvedJavaMethod targetMethod, @SuppressWarnings("unused") InvocationPlugin.Receiver receiver, 239 ValueNode... args) { 240 throw new GraalError("Invocation plugin for %s does not handle invocations with %d arguments", targetMethod.format("%H.%n(%p)"), args.length); 241 } 242 getApplySourceLocation(MetaAccessProvider metaAccess)243 default StackTraceElement getApplySourceLocation(MetaAccessProvider metaAccess) { 244 Class<?> c = getClass(); 245 for (Method m : c.getDeclaredMethods()) { 246 if (m.getName().equals("apply")) { 247 return metaAccess.lookupJavaMethod(m).asStackTraceElement(0); 248 } else if (m.getName().equals("defaultHandler")) { 249 return metaAccess.lookupJavaMethod(m).asStackTraceElement(0); 250 } 251 } 252 throw new GraalError("could not find method named \"apply\" or \"defaultHandler\" in " + c.getName()); 253 } 254 } 255