001/*
002 * Copyright (c) 2013, 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.replacements.nodes;
024
025import static sun.misc.Version.*;
026
027import java.lang.invoke.*;
028
029import jdk.internal.jvmci.common.*;
030import jdk.internal.jvmci.meta.*;
031
032import com.oracle.graal.graph.*;
033import com.oracle.graal.nodeinfo.*;
034import com.oracle.graal.nodes.*;
035import com.oracle.graal.nodes.java.*;
036import com.oracle.graal.nodes.spi.*;
037
038/**
039 * A call target that replaces itself in the graph when being lowered by restoring the original
040 * {@link MethodHandle} invocation target. Prior to
041 * https://bugs.openjdk.java.net/browse/JDK-8072008, this is required for when a
042 * {@link MethodHandle} call is resolved to a constant target but the target was not inlined. In
043 * that case, the original invocation must be restored with all of its original arguments. Why?
044 * HotSpot linkage for {@link MethodHandle} intrinsics (see
045 * {@code MethodHandles::generate_method_handle_dispatch}) expects certain implicit arguments to be
046 * on the stack such as the MemberName suffix argument for a call to one of the MethodHandle.linkTo*
047 * methods. An {@linkplain MethodHandleNode#tryResolveTargetInvoke resolved} {@link MethodHandle}
048 * invocation drops these arguments which means the interpreter won't find them.
049 */
050@NodeInfo
051public final class ResolvedMethodHandleCallTargetNode extends MethodCallTargetNode implements Lowerable {
052
053    public static final NodeClass<ResolvedMethodHandleCallTargetNode> TYPE = NodeClass.create(ResolvedMethodHandleCallTargetNode.class);
054
055    /**
056     * Creates a call target for an invocation on a direct target derived by resolving a constant
057     * {@link MethodHandle}.
058     */
059    public static MethodCallTargetNode create(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] arguments, JavaType returnType, ResolvedJavaMethod originalTargetMethod,
060                    ValueNode[] originalArguments, JavaType originalReturnType) {
061        if (jdkMajorVersion() >= 1 && jdkMinorVersion() >= 8 && jdkMicroVersion() >= 0 && jdkUpdateVersion() >= 60) {
062            // https://bugs.openjdk.java.net/browse/JDK-8072008 is targeted for 8u60
063            return new MethodCallTargetNode(invokeKind, targetMethod, arguments, returnType, null);
064        }
065        return new ResolvedMethodHandleCallTargetNode(invokeKind, targetMethod, arguments, returnType, originalTargetMethod, originalArguments, originalReturnType);
066    }
067
068    protected final ResolvedJavaMethod originalTargetMethod;
069    protected final JavaType originalReturnType;
070    @Input NodeInputList<ValueNode> originalArguments;
071
072    protected ResolvedMethodHandleCallTargetNode(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] arguments, JavaType returnType, ResolvedJavaMethod originalTargetMethod,
073                    ValueNode[] originalArguments, JavaType originalReturnType) {
074        super(TYPE, invokeKind, targetMethod, arguments, returnType, null);
075        this.originalTargetMethod = originalTargetMethod;
076        this.originalReturnType = originalReturnType;
077        this.originalArguments = new NodeInputList<>(this, originalArguments);
078    }
079
080    @Override
081    public void lower(LoweringTool tool) {
082        InvokeKind replacementInvokeKind = originalTargetMethod.isStatic() ? InvokeKind.Static : InvokeKind.Special;
083        MethodCallTargetNode replacement = graph().add(
084                        new MethodCallTargetNode(replacementInvokeKind, originalTargetMethod, originalArguments.toArray(new ValueNode[originalArguments.size()]), originalReturnType, null));
085
086        // Replace myself...
087        this.replaceAndDelete(replacement);
088    }
089
090    @Override
091    public void generate(NodeLIRBuilderTool gen) {
092        throw JVMCIError.shouldNotReachHere("should have replaced itself");
093    }
094}