1/*
2 * Copyright (c) 2013, 2015, 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 */
23package org.graalvm.compiler.replacements.nodes;
24
25import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
26import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_UNKNOWN;
27
28import java.lang.invoke.MethodHandle;
29import java.util.Arrays;
30
31import org.graalvm.compiler.core.common.type.StampFactory;
32import org.graalvm.compiler.core.common.type.StampPair;
33import org.graalvm.compiler.core.common.type.TypeReference;
34import org.graalvm.compiler.debug.GraalError;
35import org.graalvm.compiler.graph.NodeClass;
36import org.graalvm.compiler.graph.spi.Simplifiable;
37import org.graalvm.compiler.graph.spi.SimplifierTool;
38import org.graalvm.compiler.nodeinfo.NodeInfo;
39import org.graalvm.compiler.nodes.CallTargetNode;
40import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind;
41import org.graalvm.compiler.nodes.FixedGuardNode;
42import org.graalvm.compiler.nodes.FixedNode;
43import org.graalvm.compiler.nodes.FixedWithNextNode;
44import org.graalvm.compiler.nodes.GuardNode;
45import org.graalvm.compiler.nodes.InvokeNode;
46import org.graalvm.compiler.nodes.LogicNode;
47import org.graalvm.compiler.nodes.PiNode;
48import org.graalvm.compiler.nodes.StructuredGraph;
49import org.graalvm.compiler.nodes.ValueNode;
50import org.graalvm.compiler.nodes.extended.AnchoringNode;
51import org.graalvm.compiler.nodes.extended.GuardingNode;
52import org.graalvm.compiler.nodes.extended.ValueAnchorNode;
53import org.graalvm.compiler.nodes.java.InstanceOfNode;
54import org.graalvm.compiler.nodes.java.MethodCallTargetNode;
55import org.graalvm.compiler.nodes.type.StampTool;
56import org.graalvm.compiler.nodes.util.GraphUtil;
57
58import jdk.vm.ci.meta.Assumptions;
59import jdk.vm.ci.meta.Assumptions.AssumptionResult;
60import jdk.vm.ci.meta.DeoptimizationAction;
61import jdk.vm.ci.meta.DeoptimizationReason;
62import jdk.vm.ci.meta.JavaConstant;
63import jdk.vm.ci.meta.JavaKind;
64import jdk.vm.ci.meta.JavaType;
65import jdk.vm.ci.meta.MethodHandleAccessProvider;
66import jdk.vm.ci.meta.MethodHandleAccessProvider.IntrinsicMethod;
67import jdk.vm.ci.meta.ResolvedJavaMethod;
68import jdk.vm.ci.meta.ResolvedJavaType;
69import jdk.vm.ci.meta.Signature;
70
71/**
72 * Node for invocation methods defined on the class {@link MethodHandle}.
73 */
74@NodeInfo(cycles = CYCLES_UNKNOWN, size = SIZE_UNKNOWN)
75public final class MethodHandleNode extends MacroStateSplitNode implements Simplifiable {
76    public static final NodeClass<MethodHandleNode> TYPE = NodeClass.create(MethodHandleNode.class);
77
78    protected final IntrinsicMethod intrinsicMethod;
79
80    public MethodHandleNode(IntrinsicMethod intrinsicMethod, InvokeKind invokeKind, ResolvedJavaMethod targetMethod, int bci, StampPair returnStamp, ValueNode... arguments) {
81        super(TYPE, invokeKind, targetMethod, bci, returnStamp, arguments);
82        this.intrinsicMethod = intrinsicMethod;
83    }
84
85    /**
86     * Attempts to transform application of an intrinsifiable {@link MethodHandle} method into an
87     * invocation on another method with possibly transformed arguments.
88     *
89     * @param methodHandleAccess objects for accessing the implementation internals of a
90     *            {@link MethodHandle}
91     * @param intrinsicMethod denotes the intrinsifiable {@link MethodHandle} method being processed
92     * @param bci the BCI of the original {@link MethodHandle} call
93     * @param returnStamp return stamp of the original {@link MethodHandle} call
94     * @param arguments arguments to the original {@link MethodHandle} call
95     * @return a more direct invocation derived from the {@link MethodHandle} call or null
96     */
97    public static InvokeNode tryResolveTargetInvoke(GraphAdder adder, MethodHandleAccessProvider methodHandleAccess, IntrinsicMethod intrinsicMethod,
98                    ResolvedJavaMethod original, int bci,
99                    StampPair returnStamp, ValueNode... arguments) {
100        switch (intrinsicMethod) {
101            case INVOKE_BASIC:
102                return getInvokeBasicTarget(adder, intrinsicMethod, methodHandleAccess, original, bci, returnStamp, arguments);
103            case LINK_TO_STATIC:
104            case LINK_TO_SPECIAL:
105            case LINK_TO_VIRTUAL:
106            case LINK_TO_INTERFACE:
107                return getLinkToTarget(adder, intrinsicMethod, methodHandleAccess, original, bci, returnStamp, arguments);
108            default:
109                throw GraalError.shouldNotReachHere();
110        }
111    }
112
113    /**
114     * A simple utility class for adding nodes to the graph when building a MethodHandle invoke.
115     */
116    public abstract static class GraphAdder {
117        private final StructuredGraph graph;
118
119        public GraphAdder(StructuredGraph graph) {
120            this.graph = graph;
121        }
122
123        /**
124         * Call {@link StructuredGraph#addOrUnique(org.graalvm.compiler.graph.Node)} on {@code node}
125         * and link any {@link FixedWithNextNode}s into the current control flow.
126         *
127         * @param node
128         * @return the newly added node
129         */
130        public abstract <T extends ValueNode> T add(T node);
131
132        /**
133         * @return an {@link AnchoringNode} if floating guards should be created, otherwise
134         *         {@link FixedGuardNode}s will be used.
135         */
136        public AnchoringNode getGuardAnchor() {
137            return null;
138        }
139
140        public Assumptions getAssumptions() {
141            return graph.getAssumptions();
142        }
143    }
144
145    @Override
146    public void simplify(SimplifierTool tool) {
147        MethodHandleAccessProvider methodHandleAccess = tool.getConstantReflection().getMethodHandleAccess();
148        ValueNode[] argumentsArray = arguments.toArray(new ValueNode[arguments.size()]);
149
150        final FixedNode before = this;
151        GraphAdder adder = new GraphAdder(graph()) {
152            @Override
153            public <T extends ValueNode> T add(T node) {
154                T added = graph().addOrUnique(node);
155                if (added instanceof FixedWithNextNode) {
156                    graph().addBeforeFixed(before, (FixedWithNextNode) added);
157                }
158                return added;
159            }
160        };
161        InvokeNode invoke = tryResolveTargetInvoke(adder, methodHandleAccess, intrinsicMethod, targetMethod, bci, returnStamp, argumentsArray);
162        if (invoke != null) {
163            assert invoke.graph() == null;
164            invoke = graph().addOrUniqueWithInputs(invoke);
165            invoke.setStateAfter(stateAfter());
166            FixedNode currentNext = next();
167            replaceAtUsages(invoke);
168            GraphUtil.removeFixedWithUnusedInputs(this);
169            graph().addBeforeFixed(currentNext, invoke);
170        }
171    }
172
173    /**
174     * Get the receiver of a MethodHandle.invokeBasic call.
175     *
176     * @return the receiver argument node
177     */
178    private static ValueNode getReceiver(ValueNode[] arguments) {
179        return arguments[0];
180    }
181
182    /**
183     * Get the MemberName argument of a MethodHandle.linkTo* call.
184     *
185     * @return the MemberName argument node (which is the last argument)
186     */
187    private static ValueNode getMemberName(ValueNode[] arguments) {
188        return arguments[arguments.length - 1];
189    }
190
191    /**
192     * Used for the MethodHandle.invokeBasic method (the {@link IntrinsicMethod#INVOKE_BASIC }
193     * method) to get the target {@link InvokeNode} if the method handle receiver is constant.
194     *
195     * @param adder
196     *
197     * @return invoke node for the {@link java.lang.invoke.MethodHandle} target
198     */
199    private static InvokeNode getInvokeBasicTarget(GraphAdder adder, IntrinsicMethod intrinsicMethod, MethodHandleAccessProvider methodHandleAccess,
200                    ResolvedJavaMethod original,
201                    int bci,
202                    StampPair returnStamp, ValueNode[] arguments) {
203        ValueNode methodHandleNode = getReceiver(arguments);
204        if (methodHandleNode.isConstant()) {
205            return getTargetInvokeNode(adder, intrinsicMethod, bci, returnStamp, arguments, methodHandleAccess.resolveInvokeBasicTarget(methodHandleNode.asJavaConstant(), true), original);
206        }
207        return null;
208    }
209
210    /**
211     * Used for the MethodHandle.linkTo* methods (the {@link IntrinsicMethod#LINK_TO_STATIC},
212     * {@link IntrinsicMethod#LINK_TO_SPECIAL}, {@link IntrinsicMethod#LINK_TO_VIRTUAL}, and
213     * {@link IntrinsicMethod#LINK_TO_INTERFACE} methods) to get the target {@link InvokeNode} if
214     * the member name argument is constant.
215     *
216     * @param adder
217     *
218     * @return invoke node for the member name target
219     */
220    private static InvokeNode getLinkToTarget(GraphAdder adder, IntrinsicMethod intrinsicMethod, MethodHandleAccessProvider methodHandleAccess,
221                    ResolvedJavaMethod original,
222                    int bci,
223                    StampPair returnStamp, ValueNode[] arguments) {
224        ValueNode memberNameNode = getMemberName(arguments);
225        if (memberNameNode.isConstant()) {
226            return getTargetInvokeNode(adder, intrinsicMethod, bci, returnStamp, arguments, methodHandleAccess.resolveLinkToTarget(memberNameNode.asJavaConstant()), original);
227        }
228        return null;
229    }
230
231    /**
232     * Helper function to get the {@link InvokeNode} for the targetMethod of a
233     * java.lang.invoke.MemberName.
234     *
235     * @param adder
236     * @param target the target, already loaded from the member name node
237     *
238     * @return invoke node for the member name target
239     */
240    private static InvokeNode getTargetInvokeNode(GraphAdder adder, IntrinsicMethod intrinsicMethod, int bci, StampPair returnStamp, ValueNode[] originalArguments, ResolvedJavaMethod target,
241                    ResolvedJavaMethod original) {
242        if (target == null) {
243            return null;
244        }
245
246        // In lambda forms we erase signature types to avoid resolving issues
247        // involving class loaders. When we optimize a method handle invoke
248        // to a direct call we must cast the receiver and arguments to its
249        // actual types.
250        Signature signature = target.getSignature();
251        final boolean isStatic = target.isStatic();
252        final int receiverSkip = isStatic ? 0 : 1;
253
254        Assumptions assumptions = adder.getAssumptions();
255        ResolvedJavaMethod realTarget = null;
256        if (target.canBeStaticallyBound()) {
257            realTarget = target;
258        } else {
259            ResolvedJavaType targetType = target.getDeclaringClass();
260            // Try to bind based on the declaredType
261            AssumptionResult<ResolvedJavaMethod> concreteMethod = targetType.findUniqueConcreteMethod(target);
262            if (concreteMethod == null) {
263                // Try to get the most accurate receiver type
264                if (intrinsicMethod == IntrinsicMethod.LINK_TO_VIRTUAL || intrinsicMethod == IntrinsicMethod.LINK_TO_INTERFACE) {
265                    ValueNode receiver = getReceiver(originalArguments);
266                    TypeReference receiverType = StampTool.typeReferenceOrNull(receiver.stamp());
267                    if (receiverType != null) {
268                        concreteMethod = receiverType.getType().findUniqueConcreteMethod(target);
269                    }
270                }
271
272            }
273            if (concreteMethod != null && concreteMethod.canRecordTo(assumptions)) {
274                concreteMethod.recordTo(assumptions);
275                realTarget = concreteMethod.getResult();
276            }
277        }
278
279        if (realTarget != null) {
280            // Don't mutate the passed in arguments
281            ValueNode[] arguments = originalArguments.clone();
282
283            // Cast receiver to its type.
284            if (!isStatic) {
285                JavaType receiverType = target.getDeclaringClass();
286                maybeCastArgument(adder, arguments, 0, receiverType);
287            }
288
289            // Cast reference arguments to its type.
290            for (int index = 0; index < signature.getParameterCount(false); index++) {
291                JavaType parameterType = signature.getParameterType(index, target.getDeclaringClass());
292                maybeCastArgument(adder, arguments, receiverSkip + index, parameterType);
293            }
294            InvokeNode invoke = createTargetInvokeNode(assumptions, intrinsicMethod, realTarget, original, bci, returnStamp, arguments);
295            assert invoke != null : "graph has been modified so this must result an invoke";
296            return invoke;
297        }
298        return null;
299    }
300
301    /**
302     * Inserts a node to cast the argument at index to the given type if the given type is more
303     * concrete than the argument type.
304     *
305     * @param adder
306     * @param index of the argument to be cast
307     * @param type the type the argument should be cast to
308     */
309    private static void maybeCastArgument(GraphAdder adder, ValueNode[] arguments, int index, JavaType type) {
310        ValueNode argument = arguments[index];
311        if (type instanceof ResolvedJavaType && !((ResolvedJavaType) type).isJavaLangObject()) {
312            Assumptions assumptions = adder.getAssumptions();
313            TypeReference targetType = TypeReference.create(assumptions, (ResolvedJavaType) type);
314            /*
315             * When an argument is a Word type, we can have a mismatch of primitive/object types
316             * here. Not inserting a PiNode is a safe fallback, and Word types need no additional
317             * type information anyway.
318             */
319            if (targetType != null && !targetType.getType().isPrimitive() && !argument.getStackKind().isPrimitive()) {
320                ResolvedJavaType argumentType = StampTool.typeOrNull(argument.stamp());
321                if (argumentType == null || (argumentType.isAssignableFrom(targetType.getType()) && !argumentType.equals(targetType.getType()))) {
322                    LogicNode inst = InstanceOfNode.createAllowNull(targetType, argument, null, null);
323                    assert !inst.isAlive();
324                    if (!inst.isTautology()) {
325                        inst = adder.add(inst);
326                        AnchoringNode guardAnchor = adder.getGuardAnchor();
327                        DeoptimizationReason reason = DeoptimizationReason.ClassCastException;
328                        DeoptimizationAction action = DeoptimizationAction.InvalidateRecompile;
329                        JavaConstant speculation = JavaConstant.NULL_POINTER;
330                        GuardingNode guard;
331                        if (guardAnchor == null) {
332                            FixedGuardNode fixedGuard = adder.add(new FixedGuardNode(inst, reason, action, speculation, false));
333                            guard = fixedGuard;
334                        } else {
335                            GuardNode newGuard = adder.add(new GuardNode(inst, guardAnchor, reason, action, false, speculation));
336                            adder.add(new ValueAnchorNode(newGuard));
337                            guard = newGuard;
338                        }
339                        ValueNode valueNode = adder.add(PiNode.create(argument, StampFactory.object(targetType), guard.asNode()));
340                        arguments[index] = valueNode;
341                    }
342                }
343            }
344        }
345    }
346
347    /**
348     * Creates an {@link InvokeNode} for the given target method. The {@link CallTargetNode} passed
349     * to the InvokeNode is in fact a {@link ResolvedMethodHandleCallTargetNode}.
350     *
351     * @return invoke node for the member name target
352     */
353    private static InvokeNode createTargetInvokeNode(Assumptions assumptions, IntrinsicMethod intrinsicMethod, ResolvedJavaMethod target, ResolvedJavaMethod original, int bci, StampPair returnStamp,
354                    ValueNode[] arguments) {
355        InvokeKind targetInvokeKind = target.isStatic() ? InvokeKind.Static : InvokeKind.Special;
356        JavaType targetReturnType = target.getSignature().getReturnType(null);
357
358        // MethodHandleLinkTo* nodes have a trailing MemberName argument which
359        // needs to be popped.
360        ValueNode[] targetArguments;
361        switch (intrinsicMethod) {
362            case INVOKE_BASIC:
363                targetArguments = arguments;
364                break;
365            case LINK_TO_STATIC:
366            case LINK_TO_SPECIAL:
367            case LINK_TO_VIRTUAL:
368            case LINK_TO_INTERFACE:
369                targetArguments = Arrays.copyOfRange(arguments, 0, arguments.length - 1);
370                break;
371            default:
372                throw GraalError.shouldNotReachHere();
373        }
374        StampPair targetReturnStamp = StampFactory.forDeclaredType(assumptions, targetReturnType, false);
375
376        MethodCallTargetNode callTarget = ResolvedMethodHandleCallTargetNode.create(targetInvokeKind, target, targetArguments, targetReturnStamp, original, arguments, returnStamp);
377
378        // The call target can have a different return type than the invoker,
379        // e.g. the target returns an Object but the invoker void. In this case
380        // we need to use the stamp of the invoker. Note: always using the
381        // invoker's stamp would be wrong because it's a less concrete type
382        // (usually java.lang.Object).
383        if (returnStamp.getTrustedStamp().getStackKind() == JavaKind.Void) {
384            return new InvokeNode(callTarget, bci, StampFactory.forVoid());
385        } else {
386            return new InvokeNode(callTarget, bci);
387        }
388    }
389}
390