40 import org.graalvm.compiler.nodes.StructuredGraph; |
40 import org.graalvm.compiler.nodes.StructuredGraph; |
41 import org.graalvm.compiler.nodes.ValueNode; |
41 import org.graalvm.compiler.nodes.ValueNode; |
42 |
42 |
43 import jdk.vm.ci.meta.MetaAccessProvider; |
43 import jdk.vm.ci.meta.MetaAccessProvider; |
44 import jdk.vm.ci.meta.ResolvedJavaMethod; |
44 import jdk.vm.ci.meta.ResolvedJavaMethod; |
|
45 import jdk.vm.ci.meta.ResolvedJavaType; |
45 |
46 |
46 /** |
47 /** |
47 * An {@link InvocationPlugin} for a method where the implementation of the method is provided by a |
48 * An {@link InvocationPlugin} for a method where the implementation of the method is provided by a |
48 * {@linkplain #getSubstitute(MetaAccessProvider) substitute} method. A substitute method must be |
49 * {@linkplain #getSubstitute(MetaAccessProvider) substitute} method. A substitute method must be |
49 * static even if the substituted method is not. |
50 * static even if the substituted method is not. |
54 * recommended practice is to use {@link MethodSubstitutionPlugin} only for complex |
55 * recommended practice is to use {@link MethodSubstitutionPlugin} only for complex |
55 * intrinsifications which is typically those using non-straight-line control flow. |
56 * intrinsifications which is typically those using non-straight-line control flow. |
56 */ |
57 */ |
57 public final class MethodSubstitutionPlugin implements InvocationPlugin { |
58 public final class MethodSubstitutionPlugin implements InvocationPlugin { |
58 |
59 |
|
60 private InvocationPlugins.Registration registration; |
|
61 |
59 private ResolvedJavaMethod cachedSubstitute; |
62 private ResolvedJavaMethod cachedSubstitute; |
60 |
63 |
61 /** |
64 /** |
62 * The class in which the substitute method is declared. |
65 * The class in which the substitute method is declared. |
63 */ |
66 */ |
64 private final Class<?> declaringClass; |
67 private final Class<?> declaringClass; |
65 |
68 |
66 /** |
69 /** |
67 * The name of the original and substitute method. |
70 * The name of the substitute method. |
68 */ |
71 */ |
69 private final String name; |
72 private final String substituteName; |
|
73 |
|
74 /** |
|
75 * The name of the original method. |
|
76 */ |
|
77 private final String originalName; |
70 |
78 |
71 /** |
79 /** |
72 * The parameter types of the substitute method. |
80 * The parameter types of the substitute method. |
73 */ |
81 */ |
74 private final Type[] parameters; |
82 private final Type[] parameters; |
79 |
87 |
80 /** |
88 /** |
81 * Creates a method substitution plugin. |
89 * Creates a method substitution plugin. |
82 * |
90 * |
83 * @param bytecodeProvider used to get the bytecodes to parse for the substitute method |
91 * @param bytecodeProvider used to get the bytecodes to parse for the substitute method |
|
92 * @param originalName the name of the original method |
84 * @param declaringClass the class in which the substitute method is declared |
93 * @param declaringClass the class in which the substitute method is declared |
85 * @param name the name of the substitute method |
94 * @param substituteName the name of the substitute method |
86 * @param parameters the parameter types of the substitute method. If the original method is not |
95 * @param parameters the parameter types of the substitute method. If the original method is not |
87 * static, then {@code parameters[0]} must be the {@link Class} value denoting |
96 * static, then {@code parameters[0]} must be the {@link Class} value denoting |
88 * {@link InvocationPlugin.Receiver} |
97 * {@link InvocationPlugin.Receiver} |
89 */ |
98 */ |
90 public MethodSubstitutionPlugin(BytecodeProvider bytecodeProvider, Class<?> declaringClass, String name, Type... parameters) { |
99 public MethodSubstitutionPlugin(InvocationPlugins.Registration registration, BytecodeProvider bytecodeProvider, String originalName, Class<?> declaringClass, String substituteName, |
|
100 Type... parameters) { |
|
101 assert bytecodeProvider != null : "Requires a non-null methodSubstitutionBytecodeProvider"; |
|
102 this.registration = registration; |
91 this.bytecodeProvider = bytecodeProvider; |
103 this.bytecodeProvider = bytecodeProvider; |
|
104 this.originalName = originalName; |
92 this.declaringClass = declaringClass; |
105 this.declaringClass = declaringClass; |
93 this.name = name; |
106 this.substituteName = substituteName; |
94 this.parameters = parameters; |
107 this.parameters = parameters; |
95 this.originalIsStatic = parameters.length == 0 || parameters[0] != InvocationPlugin.Receiver.class; |
108 this.originalIsStatic = parameters.length == 0 || parameters[0] != InvocationPlugin.Receiver.class; |
96 } |
109 } |
97 |
110 |
98 @Override |
111 @Override |
142 |
155 |
143 /** |
156 /** |
144 * Determines if a given method is the substitute method of this plugin. |
157 * Determines if a given method is the substitute method of this plugin. |
145 */ |
158 */ |
146 private boolean isSubstitute(Method m) { |
159 private boolean isSubstitute(Method m) { |
147 if (Modifier.isStatic(m.getModifiers()) && m.getName().equals(name)) { |
160 if (Modifier.isStatic(m.getModifiers()) && m.getName().equals(substituteName)) { |
148 if (parameters.length == m.getParameterCount()) { |
161 if (parameters.length == m.getParameterCount()) { |
149 Class<?>[] mparams = m.getParameterTypes(); |
162 Class<?>[] mparams = m.getParameterTypes(); |
150 int start = 0; |
163 int start = 0; |
151 if (!originalIsStatic) { |
164 if (!originalIsStatic) { |
152 start = 1; |
165 start = 1; |
187 } |
200 } |
188 |
201 |
189 @Override |
202 @Override |
190 public boolean execute(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode[] argsIncludingReceiver) { |
203 public boolean execute(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode[] argsIncludingReceiver) { |
191 if (IS_IN_NATIVE_IMAGE || (UseEncodedGraphs.getValue(b.getOptions()) && !b.parsingIntrinsic())) { |
204 if (IS_IN_NATIVE_IMAGE || (UseEncodedGraphs.getValue(b.getOptions()) && !b.parsingIntrinsic())) { |
192 if (!IS_IN_NATIVE_IMAGE && UseEncodedGraphs.getValue(b.getOptions())) { |
|
193 b.getReplacements().registerMethodSubstitution(this, targetMethod, INLINE_AFTER_PARSING, b.getOptions()); |
|
194 } |
|
195 StructuredGraph subst = b.getReplacements().getMethodSubstitution(this, |
205 StructuredGraph subst = b.getReplacements().getMethodSubstitution(this, |
196 targetMethod, |
206 targetMethod, |
197 INLINE_AFTER_PARSING, |
207 INLINE_AFTER_PARSING, |
198 StructuredGraph.AllowAssumptions.ifNonNull(b.getAssumptions()), |
208 StructuredGraph.AllowAssumptions.ifNonNull(b.getAssumptions()), |
199 null /* cancellable */, |
209 null /* cancellable */, |
218 throw new GraalError("could not find method named \"execute\" in " + c.getName()); |
228 throw new GraalError("could not find method named \"execute\" in " + c.getName()); |
219 } |
229 } |
220 |
230 |
221 @Override |
231 @Override |
222 public String toString() { |
232 public String toString() { |
223 return String.format("%s[%s.%s(%s)]", getClass().getSimpleName(), declaringClass.getName(), name, |
233 return String.format("%s[%s.%s(%s)]", getClass().getSimpleName(), declaringClass.getName(), substituteName, |
224 Arrays.asList(parameters).stream().map(c -> c.getTypeName()).collect(Collectors.joining(", "))); |
234 Arrays.asList(parameters).stream().map(c -> c.getTypeName()).collect(Collectors.joining(", "))); |
225 } |
235 } |
|
236 |
|
237 public String originalMethodAsString() { |
|
238 return String.format("%s.%s(%s)", declaringClass.getName(), substituteName, Arrays.asList(parameters).stream().map(c -> c.getTypeName()).collect(Collectors.joining(", "))); |
|
239 } |
|
240 |
|
241 public ResolvedJavaMethod getOriginalMethod(MetaAccessProvider metaAccess) { |
|
242 Class<?> clazz = resolveType(registration.getDeclaringType(), false); |
|
243 if (clazz == null) { |
|
244 throw new GraalError("Can't find original class for " + this + " with class " + registration.getDeclaringType()); |
|
245 } |
|
246 ResolvedJavaType type = metaAccess.lookupJavaType(clazz); |
|
247 String argumentsDescriptor = InvocationPlugins.toArgumentDescriptor(originalIsStatic, this.parameters); |
|
248 for (ResolvedJavaMethod declared : type.getDeclaredMethods()) { |
|
249 if (declared.getName().equals(originalName) && declared.isStatic() == originalIsStatic && |
|
250 declared.getSignature().toMethodDescriptor().startsWith(argumentsDescriptor)) { |
|
251 return declared; |
|
252 } |
|
253 } |
|
254 throw new GraalError("Can't find original method for " + this + " with class " + registration.getDeclaringType()); |
|
255 } |
226 } |
256 } |