001/* 002 * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. 008 * 009 * This code is distributed in the hope that it will be useful, but WITHOUT 010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 011 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 012 * version 2 for more details (a copy is included in the LICENSE file that 013 * accompanied this code). 014 * 015 * You should have received a copy of the GNU General Public License version 016 * 2 along with this work; if not, write to the Free Software Foundation, 017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 018 * 019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 020 * or visit www.oracle.com if you need additional information or have any 021 * questions. 022 */ 023package com.oracle.graal.graphbuilderconf; 024 025import java.lang.invoke.*; 026import java.lang.reflect.*; 027 028import jdk.internal.jvmci.common.*; 029import jdk.internal.jvmci.meta.*; 030 031import com.oracle.graal.nodes.*; 032import com.oracle.graal.nodes.type.*; 033 034/** 035 * Plugin for handling a specific method invocation. 036 */ 037public interface InvocationPlugin extends GraphBuilderPlugin { 038 039 /** 040 * The receiver in a non-static method. The class literal for this interface must be used with 041 * {@link MethodIdMap#put(Object, boolean, boolean, Class, String, Class...)} to denote the 042 * receiver argument for such a non-static method. 043 */ 044 public interface Receiver { 045 /** 046 * Gets the receiver value, null checking it first if necessary. 047 * 048 * @return the receiver value with a {@linkplain StampTool#isPointerNonNull(ValueNode) 049 * non-null} stamp 050 */ 051 ValueNode get(); 052 053 /** 054 * Determines if the receiver is constant. 055 */ 056 default boolean isConstant() { 057 return false; 058 } 059 } 060 061 /** 062 * Determines if this plugin is for a method with a polymorphic signature (e.g. 063 * {@link MethodHandle#invokeExact(Object...)}). 064 */ 065 default boolean isSignaturePolymorphic() { 066 return false; 067 } 068 069 /** 070 * Determines if this plugin can only be used when inlining the method is it associated with. 071 * That is, this plugin cannot be used when the associated method is the compilation root. 072 */ 073 default boolean inlineOnly() { 074 return isSignaturePolymorphic(); 075 } 076 077 /** 078 * Handles invocation of a signature polymorphic method. 079 * 080 * @param receiver access to the receiver, {@code null} if {@code targetMethod} is static 081 * @param argsIncludingReceiver all arguments to the invocation include the raw receiver in 082 * position 0 if {@code targetMethod} is not static 083 * @see #execute 084 */ 085 default boolean applyPolymorphic(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode... argsIncludingReceiver) { 086 return defaultHandler(b, targetMethod, receiver, argsIncludingReceiver); 087 } 088 089 /** 090 * @see #execute 091 */ 092 default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver) { 093 return defaultHandler(b, targetMethod, receiver); 094 } 095 096 /** 097 * @see #execute 098 */ 099 default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode arg) { 100 return defaultHandler(b, targetMethod, receiver, arg); 101 } 102 103 /** 104 * @see #execute 105 */ 106 default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode arg1, ValueNode arg2) { 107 return defaultHandler(b, targetMethod, receiver, arg1, arg2); 108 } 109 110 /** 111 * @see #execute 112 */ 113 default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode arg1, ValueNode arg2, ValueNode arg3) { 114 return defaultHandler(b, targetMethod, receiver, arg1, arg2, arg3); 115 } 116 117 /** 118 * @see #execute 119 */ 120 default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode arg1, ValueNode arg2, ValueNode arg3, ValueNode arg4) { 121 return defaultHandler(b, targetMethod, receiver, arg1, arg2, arg3, arg4); 122 } 123 124 /** 125 * @see #execute 126 */ 127 default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode arg1, ValueNode arg2, ValueNode arg3, ValueNode arg4, ValueNode arg5) { 128 return defaultHandler(b, targetMethod, receiver, arg1, arg2, arg3, arg4, arg5); 129 } 130 131 /** 132 * Executes this plugin against a set of invocation arguments. 133 * 134 * The default implementation in {@link InvocationPlugin} dispatches to the {@code apply(...)} 135 * method that matches the number of arguments or to {@link #applyPolymorphic} if {@code plugin} 136 * is {@linkplain #isSignaturePolymorphic() signature polymorphic}. 137 * 138 * @param targetMethod the method for which this plugin is being applied 139 * @param receiver access to the receiver, {@code null} if {@code targetMethod} is static 140 * @param argsIncludingReceiver all arguments to the invocation include the receiver in position 141 * 0 if {@code targetMethod} is not static 142 * @return {@code true} if this plugin handled the invocation of {@code targetMethod} 143 * {@code false} if the graph builder should process the invoke further (e.g., by 144 * inlining it or creating an {@link Invoke} node). A plugin that does not handle an 145 * invocation must not modify the graph being constructed. 146 */ 147 default boolean execute(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode[] argsIncludingReceiver) { 148 if (isSignaturePolymorphic()) { 149 return applyPolymorphic(b, targetMethod, receiver, argsIncludingReceiver); 150 } else if (receiver != null) { 151 assert !targetMethod.isStatic(); 152 assert argsIncludingReceiver.length > 0; 153 if (argsIncludingReceiver.length == 1) { 154 return apply(b, targetMethod, receiver); 155 } else if (argsIncludingReceiver.length == 2) { 156 return apply(b, targetMethod, receiver, argsIncludingReceiver[1]); 157 } else if (argsIncludingReceiver.length == 3) { 158 return apply(b, targetMethod, receiver, argsIncludingReceiver[1], argsIncludingReceiver[2]); 159 } else if (argsIncludingReceiver.length == 4) { 160 return apply(b, targetMethod, receiver, argsIncludingReceiver[1], argsIncludingReceiver[2], argsIncludingReceiver[3]); 161 } else if (argsIncludingReceiver.length == 5) { 162 return apply(b, targetMethod, receiver, argsIncludingReceiver[1], argsIncludingReceiver[2], argsIncludingReceiver[3], argsIncludingReceiver[4]); 163 } else { 164 return defaultHandler(b, targetMethod, receiver, argsIncludingReceiver); 165 } 166 } else { 167 assert targetMethod.isStatic(); 168 if (argsIncludingReceiver.length == 0) { 169 return apply(b, targetMethod, null); 170 } else if (argsIncludingReceiver.length == 1) { 171 return apply(b, targetMethod, null, argsIncludingReceiver[0]); 172 } else if (argsIncludingReceiver.length == 2) { 173 return apply(b, targetMethod, null, argsIncludingReceiver[0], argsIncludingReceiver[1]); 174 } else if (argsIncludingReceiver.length == 3) { 175 return apply(b, targetMethod, null, argsIncludingReceiver[0], argsIncludingReceiver[1], argsIncludingReceiver[2]); 176 } else if (argsIncludingReceiver.length == 4) { 177 return apply(b, targetMethod, null, argsIncludingReceiver[0], argsIncludingReceiver[1], argsIncludingReceiver[2], argsIncludingReceiver[3]); 178 } else if (argsIncludingReceiver.length == 5) { 179 return apply(b, targetMethod, null, argsIncludingReceiver[0], argsIncludingReceiver[1], argsIncludingReceiver[2], argsIncludingReceiver[3], argsIncludingReceiver[4]); 180 } else { 181 return defaultHandler(b, targetMethod, receiver, argsIncludingReceiver); 182 } 183 184 } 185 } 186 187 /** 188 * Handles an invocation when a specific {@code apply} method is not available. 189 */ 190 default boolean defaultHandler(@SuppressWarnings("unused") GraphBuilderContext b, ResolvedJavaMethod targetMethod, @SuppressWarnings("unused") InvocationPlugin.Receiver receiver, 191 ValueNode... args) { 192 throw new JVMCIError("Invocation plugin for %s does not handle invocations with %d arguments", targetMethod.format("%H.%n(%p)"), args.length); 193 } 194 195 default StackTraceElement getApplySourceLocation(MetaAccessProvider metaAccess) { 196 Class<?> c = getClass(); 197 for (Method m : c.getDeclaredMethods()) { 198 if (m.getName().equals("apply")) { 199 return metaAccess.lookupJavaMethod(m).asStackTraceElement(0); 200 } else if (m.getName().equals("defaultHandler")) { 201 return metaAccess.lookupJavaMethod(m).asStackTraceElement(0); 202 } 203 } 204 throw new JVMCIError("could not find method named \"apply\" or \"defaultHandler\" in " + c.getName()); 205 } 206}