Mercurial > hg > graal-compiler
annotate graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/AbstractMethodHandleNode.java @ 11265:ef6915cf1e59
Add illegal stamp
Remove ValueNode.(object|integer)Stamp: use explicit tests/casts
Fix ObjectStamp.join
Introduce ObjectStamp.castTo
Add some tests for ObjectStamp.join
author | Gilles Duboscq <duboscq@ssw.jku.at> |
---|---|
date | Thu, 08 Aug 2013 18:17:47 +0200 |
parents | 747b2517feae |
children | da9db8331658 |
rev | line source |
---|---|
9691 | 1 /* |
2 * Copyright (c) 2013, 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 package com.oracle.graal.hotspot.replacements; | |
24 | |
25 import java.lang.reflect.Modifier; | |
26 import java.util.Arrays; | |
27 | |
28 import com.oracle.graal.api.meta.Constant; | |
29 import com.oracle.graal.api.meta.JavaType; | |
30 import com.oracle.graal.api.meta.ResolvedJavaField; | |
31 import com.oracle.graal.api.meta.ResolvedJavaMethod; | |
32 import com.oracle.graal.api.meta.ResolvedJavaType; | |
33 import com.oracle.graal.graph.GraalInternalError; | |
34 import com.oracle.graal.graph.NodeInputList; | |
35 import com.oracle.graal.hotspot.meta.HotSpotResolvedJavaMethod; | |
36 import com.oracle.graal.hotspot.meta.HotSpotResolvedObjectType; | |
37 import com.oracle.graal.hotspot.meta.HotSpotSignature; | |
38 import com.oracle.graal.nodes.CallTargetNode; | |
39 import com.oracle.graal.nodes.Invoke; | |
40 import com.oracle.graal.nodes.InvokeNode; | |
41 import com.oracle.graal.nodes.PiNode; | |
42 import com.oracle.graal.nodes.ValueNode; | |
43 import com.oracle.graal.nodes.java.MethodCallTargetNode; | |
44 import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind; | |
45 import com.oracle.graal.nodes.java.SelfReplacingMethodCallTargetNode; | |
46 import com.oracle.graal.nodes.spi.Canonicalizable; | |
11265 | 47 import com.oracle.graal.nodes.type.*; |
9691 | 48 import com.oracle.graal.replacements.nodes.MacroNode; |
49 | |
50 /** | |
51 * Common base class for method handle invoke nodes. | |
52 */ | |
53 public abstract class AbstractMethodHandleNode extends MacroNode implements Canonicalizable { | |
54 | |
55 private static final ResolvedJavaField methodHandleFormField; | |
56 private static final ResolvedJavaField lambdaFormVmentryField; | |
57 private static final ResolvedJavaField memberNameClazzField; | |
58 private static final ResolvedJavaField memberNameVmtargetField; | |
59 | |
60 // Replacement method data | |
61 private ResolvedJavaMethod replacementTargetMethod; | |
62 private JavaType replacementReturnType; | |
9715
badabdca0c53
fix final-ness of @Input node inputs
Lukas Stadler <lukas.stadler@jku.at>
parents:
9691
diff
changeset
|
63 @Input private final NodeInputList<ValueNode> replacementArguments; |
9691 | 64 |
65 /** | |
66 * Search for an instance field with the given name in a class. | |
67 * | |
68 * @param className name of the class to search in | |
69 * @param fieldName name of the field to be searched | |
70 * @return resolved java field | |
71 * @throws ClassNotFoundException | |
72 */ | |
73 private static ResolvedJavaField findFieldInClass(String className, String fieldName) throws ClassNotFoundException { | |
74 Class<?> clazz = Class.forName(className); | |
75 ResolvedJavaType type = HotSpotResolvedObjectType.fromClass(clazz); | |
76 ResolvedJavaField[] fields = type.getInstanceFields(false); | |
77 for (ResolvedJavaField field : fields) { | |
78 if (field.getName().equals(fieldName)) { | |
79 return field; | |
80 } | |
81 } | |
82 return null; | |
83 } | |
84 | |
85 static { | |
86 try { | |
87 methodHandleFormField = findFieldInClass("java.lang.invoke.MethodHandle", "form"); | |
88 lambdaFormVmentryField = findFieldInClass("java.lang.invoke.LambdaForm", "vmentry"); | |
89 memberNameClazzField = findFieldInClass("java.lang.invoke.MemberName", "clazz"); | |
90 memberNameVmtargetField = findFieldInClass("java.lang.invoke.MemberName", "vmtarget"); | |
91 } catch (ClassNotFoundException | SecurityException ex) { | |
92 throw GraalInternalError.shouldNotReachHere(); | |
93 } | |
94 } | |
95 | |
96 public AbstractMethodHandleNode(Invoke invoke) { | |
97 super(invoke); | |
98 | |
99 // See if we need to save some replacement method data. | |
100 CallTargetNode callTarget = invoke.callTarget(); | |
101 if (callTarget instanceof SelfReplacingMethodCallTargetNode) { | |
102 SelfReplacingMethodCallTargetNode selfReplacingMethodCallTargetNode = (SelfReplacingMethodCallTargetNode) callTarget; | |
103 replacementTargetMethod = selfReplacingMethodCallTargetNode.replacementTargetMethod(); | |
104 replacementReturnType = selfReplacingMethodCallTargetNode.replacementReturnType(); | |
105 replacementArguments = selfReplacingMethodCallTargetNode.replacementArguments(); | |
106 } else { | |
107 // NodeInputList can't be null. | |
108 replacementArguments = new NodeInputList<>(this); | |
109 } | |
110 } | |
111 | |
112 /** | |
113 * Get the receiver of a MethodHandle.invokeBasic call. | |
114 * | |
115 * @return the receiver argument node | |
116 */ | |
117 private ValueNode getReceiver() { | |
118 return arguments.first(); | |
119 } | |
120 | |
121 /** | |
122 * Get the MemberName argument of a MethodHandle.linkTo* call. | |
123 * | |
124 * @return the MemberName argument node (which is the last argument) | |
125 */ | |
126 private ValueNode getMemberName() { | |
127 return arguments.last(); | |
128 } | |
129 | |
130 /** | |
131 * Used from {@link MethodHandleInvokeBasicNode} to get the target {@link InvokeNode} if the | |
132 * method handle receiver is constant. | |
133 * | |
134 * @return invoke node for the {@link java.lang.invoke.MethodHandle} target | |
135 */ | |
136 protected InvokeNode getInvokeBasicTarget() { | |
137 ValueNode methodHandleNode = getReceiver(); | |
138 if (methodHandleNode.isConstant() && !methodHandleNode.isNullConstant()) { | |
139 // Get the data we need from MethodHandle.LambdaForm.MemberName | |
140 Constant methodHandle = methodHandleNode.asConstant(); | |
141 Constant lambdaForm = methodHandleFormField.readValue(methodHandle); | |
142 Constant memberName = lambdaFormVmentryField.readValue(lambdaForm); | |
143 return getTargetInvokeNode(memberName); | |
144 } | |
145 return null; | |
146 } | |
147 | |
148 /** | |
149 * Used from {@link MethodHandleLinkToStaticNode}, {@link MethodHandleLinkToSpecialNode}, | |
150 * {@link MethodHandleLinkToVirtualNode}, and {@link MethodHandleLinkToInterfaceNode} to get the | |
151 * target {@link InvokeNode} if the member name argument is constant. | |
152 * | |
153 * @return invoke node for the member name target | |
154 */ | |
155 protected InvokeNode getLinkToTarget() { | |
156 ValueNode memberNameNode = getMemberName(); | |
157 if (memberNameNode.isConstant() && !memberNameNode.isNullConstant()) { | |
158 Constant memberName = memberNameNode.asConstant(); | |
159 return getTargetInvokeNode(memberName); | |
160 } | |
161 return null; | |
162 } | |
163 | |
164 /** | |
165 * Helper function to get the {@link InvokeNode} for the vmtarget of a | |
166 * java.lang.invoke.MemberName. | |
167 * | |
168 * @param memberName constant member name node | |
169 * @return invoke node for the member name target | |
170 */ | |
171 private InvokeNode getTargetInvokeNode(Constant memberName) { | |
172 // Get the data we need from MemberName | |
173 Constant clazz = memberNameClazzField.readValue(memberName); | |
174 Constant vmtarget = memberNameVmtargetField.readValue(memberName); | |
175 | |
176 // Create a method from the vmtarget pointer | |
177 Class<?> c = (Class<?>) clazz.asObject(); | |
178 HotSpotResolvedObjectType holderClass = (HotSpotResolvedObjectType) HotSpotResolvedObjectType.fromClass(c); | |
179 HotSpotResolvedJavaMethod targetMethod = holderClass.createMethod(vmtarget.asLong()); | |
180 | |
181 // In lamda forms we erase signature types to avoid resolving issues | |
182 // involving class loaders. When we optimize a method handle invoke | |
183 // to a direct call we must cast the receiver and arguments to its | |
184 // actual types. | |
185 HotSpotSignature signature = targetMethod.getSignature(); | |
186 final boolean isStatic = Modifier.isStatic(targetMethod.getModifiers()); | |
187 final int receiverSkip = isStatic ? 0 : 1; | |
188 | |
189 // Cast receiver to its type. | |
190 if (!isStatic) { | |
191 JavaType receiverType = holderClass; | |
192 maybeCastArgument(0, receiverType); | |
193 } | |
194 | |
195 // Cast reference arguments to its type. | |
196 for (int index = 0; index < signature.getParameterCount(false); index++) { | |
197 JavaType parameterType = signature.getParameterType(index, holderClass); | |
198 maybeCastArgument(receiverSkip + index, parameterType); | |
199 } | |
200 | |
201 // Try to get the most accurate receiver type | |
202 if (this instanceof MethodHandleLinkToVirtualNode || this instanceof MethodHandleLinkToInterfaceNode) { | |
11265 | 203 ResolvedJavaType receiverType = ObjectStamp.typeOrNull(getReceiver().stamp()); |
9691 | 204 if (receiverType != null) { |
205 ResolvedJavaMethod concreteMethod = receiverType.findUniqueConcreteMethod(targetMethod); | |
206 if (concreteMethod != null) { | |
207 return createTargetInvokeNode(concreteMethod); | |
208 } | |
209 } | |
210 } | |
211 | |
212 if (targetMethod.canBeStaticallyBound()) { | |
213 return createTargetInvokeNode(targetMethod); | |
214 } | |
215 | |
216 ResolvedJavaMethod concreteMethod = targetMethod.uniqueConcreteMethod(); | |
217 if (concreteMethod != null) { | |
218 return createTargetInvokeNode(concreteMethod); | |
219 } | |
220 | |
221 return null; | |
222 } | |
223 | |
224 /** | |
225 * Inserts a node to cast the argument at index to the given type if the given type is more | |
226 * concrete than the argument type. | |
227 * | |
228 * @param index of the argument to be cast | |
229 * @param type the type the argument should be cast to | |
230 */ | |
231 private void maybeCastArgument(int index, JavaType type) { | |
232 if (type instanceof ResolvedJavaType) { | |
233 ResolvedJavaType targetType = (ResolvedJavaType) type; | |
234 if (!targetType.isPrimitive()) { | |
235 ValueNode argument = arguments.get(index); | |
11265 | 236 ResolvedJavaType argumentType = ObjectStamp.typeOrNull(argument.stamp()); |
9691 | 237 if (argumentType == null || (argumentType.isAssignableFrom(targetType) && !argumentType.equals(targetType))) { |
238 PiNode piNode = graph().unique(new PiNode(argument, StampFactory.declared(targetType))); | |
239 arguments.set(index, piNode); | |
240 } | |
241 } | |
242 } | |
243 } | |
244 | |
245 /** | |
246 * Creates an {@link InvokeNode} for the given target method. The {@link CallTargetNode} passed | |
247 * to the InvokeNode is in fact a {@link SelfReplacingMethodCallTargetNode}. | |
248 * | |
249 * @param targetMethod the method the be called | |
250 * @return invoke node for the member name target | |
251 */ | |
252 private InvokeNode createTargetInvokeNode(ResolvedJavaMethod targetMethod) { | |
253 InvokeKind invokeKind = Modifier.isStatic(targetMethod.getModifiers()) ? InvokeKind.Static : InvokeKind.Special; | |
254 JavaType returnType = targetMethod.getSignature().getReturnType(null); | |
255 | |
256 // MethodHandleLinkTo* nodes have a trailing MemberName argument which | |
257 // needs to be popped. | |
258 ValueNode[] originalArguments = arguments.toArray(new ValueNode[arguments.size()]); | |
259 ValueNode[] targetArguments; | |
260 if (this instanceof MethodHandleInvokeBasicNode) { | |
261 targetArguments = originalArguments; | |
262 } else { | |
263 assert this instanceof MethodHandleLinkToStaticNode || this instanceof MethodHandleLinkToSpecialNode || this instanceof MethodHandleLinkToVirtualNode || | |
264 this instanceof MethodHandleLinkToInterfaceNode : this; | |
265 targetArguments = Arrays.copyOfRange(originalArguments, 0, arguments.size() - 1); | |
266 } | |
267 | |
268 // If there is already replacement information, use that instead. | |
269 MethodCallTargetNode callTarget; | |
270 if (replacementTargetMethod == null) { | |
271 callTarget = new SelfReplacingMethodCallTargetNode(invokeKind, targetMethod, targetArguments, returnType, getTargetMethod(), originalArguments, getReturnType()); | |
272 } else { | |
273 ValueNode[] args = replacementArguments.toArray(new ValueNode[replacementArguments.size()]); | |
274 callTarget = new SelfReplacingMethodCallTargetNode(invokeKind, targetMethod, targetArguments, returnType, replacementTargetMethod, args, replacementReturnType); | |
275 } | |
9784
747b2517feae
use invoker's stamp if target's return stamp is of different type
twisti
parents:
9715
diff
changeset
|
276 graph().add(callTarget); |
9691 | 277 |
9784
747b2517feae
use invoker's stamp if target's return stamp is of different type
twisti
parents:
9715
diff
changeset
|
278 // The call target can have a different return type than the invoker, |
747b2517feae
use invoker's stamp if target's return stamp is of different type
twisti
parents:
9715
diff
changeset
|
279 // e.g. the target returns an Object but the invoker void. In this case |
747b2517feae
use invoker's stamp if target's return stamp is of different type
twisti
parents:
9715
diff
changeset
|
280 // we need to use the stamp of the invoker. Note: always using the |
747b2517feae
use invoker's stamp if target's return stamp is of different type
twisti
parents:
9715
diff
changeset
|
281 // invoker's stamp would be wrong because it's a less concrete type |
747b2517feae
use invoker's stamp if target's return stamp is of different type
twisti
parents:
9715
diff
changeset
|
282 // (usually java.lang.Object). |
747b2517feae
use invoker's stamp if target's return stamp is of different type
twisti
parents:
9715
diff
changeset
|
283 InvokeNode invoke; |
747b2517feae
use invoker's stamp if target's return stamp is of different type
twisti
parents:
9715
diff
changeset
|
284 if (callTarget.returnStamp().kind() != stamp().kind()) { |
747b2517feae
use invoker's stamp if target's return stamp is of different type
twisti
parents:
9715
diff
changeset
|
285 invoke = new InvokeNode(callTarget, getBci(), stamp()); |
747b2517feae
use invoker's stamp if target's return stamp is of different type
twisti
parents:
9715
diff
changeset
|
286 } else { |
747b2517feae
use invoker's stamp if target's return stamp is of different type
twisti
parents:
9715
diff
changeset
|
287 invoke = new InvokeNode(callTarget, getBci()); |
747b2517feae
use invoker's stamp if target's return stamp is of different type
twisti
parents:
9715
diff
changeset
|
288 } |
747b2517feae
use invoker's stamp if target's return stamp is of different type
twisti
parents:
9715
diff
changeset
|
289 graph().add(invoke); |
9691 | 290 invoke.setStateAfter(stateAfter()); |
291 return invoke; | |
292 } | |
293 | |
294 } |