001/*
002 * Copyright (c) 2011, 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.nodes.extended;
024
025import java.util.*;
026
027import jdk.internal.jvmci.code.*;
028import jdk.internal.jvmci.meta.*;
029
030import com.oracle.graal.compiler.common.spi.*;
031import com.oracle.graal.compiler.common.type.*;
032import com.oracle.graal.graph.*;
033import com.oracle.graal.nodeinfo.*;
034import com.oracle.graal.nodes.*;
035import com.oracle.graal.nodes.memory.*;
036import com.oracle.graal.nodes.spi.*;
037
038/**
039 * Node for a {@linkplain ForeignCallDescriptor foreign} call.
040 */
041@NodeInfo(nameTemplate = "ForeignCall#{p#descriptor/s}", allowedUsageTypes = {InputType.Memory})
042public class ForeignCallNode extends AbstractMemoryCheckpoint implements LIRLowerable, DeoptimizingNode.DeoptDuring, MemoryCheckpoint.Multi {
043    public static final NodeClass<ForeignCallNode> TYPE = NodeClass.create(ForeignCallNode.class);
044
045    @Input protected NodeInputList<ValueNode> arguments;
046    @OptionalInput(InputType.State) protected FrameState stateDuring;
047    protected final ForeignCallsProvider foreignCalls;
048
049    protected final ForeignCallDescriptor descriptor;
050    protected int bci = BytecodeFrame.UNKNOWN_BCI;
051
052    public ForeignCallNode(@InjectedNodeParameter ForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor, ValueNode... arguments) {
053        this(TYPE, foreignCalls, descriptor, arguments);
054    }
055
056    public ForeignCallNode(@InjectedNodeParameter ForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor, Stamp stamp, List<ValueNode> arguments) {
057        super(TYPE, stamp);
058        this.arguments = new NodeInputList<>(this, arguments);
059        this.descriptor = descriptor;
060        this.foreignCalls = foreignCalls;
061    }
062
063    public ForeignCallNode(@InjectedNodeParameter ForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor, Stamp stamp) {
064        super(TYPE, stamp);
065        this.arguments = new NodeInputList<>(this);
066        this.descriptor = descriptor;
067        this.foreignCalls = foreignCalls;
068    }
069
070    protected ForeignCallNode(NodeClass<? extends ForeignCallNode> c, ForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor, ValueNode... arguments) {
071        super(c, StampFactory.forKind(Kind.fromJavaClass(descriptor.getResultType())));
072        this.arguments = new NodeInputList<>(this, arguments);
073        this.descriptor = descriptor;
074        this.foreignCalls = foreignCalls;
075    }
076
077    @Override
078    public boolean hasSideEffect() {
079        return !foreignCalls.isReexecutable(descriptor);
080    }
081
082    public ForeignCallDescriptor getDescriptor() {
083        return descriptor;
084    }
085
086    @Override
087    public LocationIdentity[] getLocationIdentities() {
088        return foreignCalls.getKilledLocations(descriptor);
089    }
090
091    protected Value[] operands(NodeLIRBuilderTool gen) {
092        Value[] operands = new Value[arguments.size()];
093        for (int i = 0; i < operands.length; i++) {
094            operands[i] = gen.operand(arguments.get(i));
095        }
096        return operands;
097    }
098
099    @Override
100    public void generate(NodeLIRBuilderTool gen) {
101        ForeignCallLinkage linkage = gen.getLIRGeneratorTool().getForeignCalls().lookupForeignCall(descriptor);
102        Value[] operands = operands(gen);
103        Value result = gen.getLIRGeneratorTool().emitForeignCall(linkage, gen.state(this), operands);
104        if (result != null) {
105            gen.setResult(this, result);
106        }
107    }
108
109    @Override
110    public void setStateAfter(FrameState x) {
111        assert hasSideEffect() || x == null;
112        super.setStateAfter(x);
113    }
114
115    @Override
116    public FrameState stateDuring() {
117        return stateDuring;
118    }
119
120    @Override
121    public void setStateDuring(FrameState stateDuring) {
122        updateUsages(this.stateDuring, stateDuring);
123        this.stateDuring = stateDuring;
124    }
125
126    /**
127     * Set the {@code bci} of the invoke bytecode for use when converting a stateAfter into a
128     * stateDuring.
129     */
130    public void setBci(int bci) {
131        this.bci = bci;
132    }
133
134    @Override
135    public void computeStateDuring(FrameState currentStateAfter) {
136        FrameState newStateDuring;
137        if ((currentStateAfter.stackSize() > 0 && currentStateAfter.stackAt(currentStateAfter.stackSize() - 1) == this) ||
138                        (currentStateAfter.stackSize() > 1 && currentStateAfter.stackAt(currentStateAfter.stackSize() - 2) == this)) {
139            // The result of this call is on the top of stack, so roll back to the previous bci.
140            assert bci != BytecodeFrame.UNKNOWN_BCI : this;
141            newStateDuring = currentStateAfter.duplicateModifiedDuringCall(bci, this.getKind());
142        } else {
143            newStateDuring = currentStateAfter;
144        }
145        setStateDuring(newStateDuring);
146    }
147
148    @Override
149    public String toString(Verbosity verbosity) {
150        if (verbosity == Verbosity.Name) {
151            return super.toString(verbosity) + "#" + descriptor;
152        }
153        return super.toString(verbosity);
154    }
155
156    @Override
157    public boolean canDeoptimize() {
158        return foreignCalls.canDeoptimize(descriptor);
159    }
160}