001/*
002 * Copyright (c) 2011, 2013, 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;
024
025import jdk.internal.jvmci.code.*;
026import jdk.internal.jvmci.common.*;
027import jdk.internal.jvmci.meta.*;
028
029import com.oracle.graal.compiler.common.type.*;
030import com.oracle.graal.graphbuilderconf.*;
031import com.oracle.graal.graphbuilderconf.InvocationPlugin.Receiver;
032import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
033import com.oracle.graal.nodes.*;
034import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
035import com.oracle.graal.nodes.calc.*;
036import com.oracle.graal.nodes.spi.*;
037
038/**
039 * Implementation of {@link GraphBuilderContext} used to produce a graph for a method based on an
040 * {@link InvocationPlugin} for the method.
041 */
042public class IntrinsicGraphBuilder implements GraphBuilderContext, Receiver {
043
044    private final MetaAccessProvider metaAccess;
045    private final ConstantReflectionProvider constantReflection;
046    private final StampProvider stampProvider;
047    private final StructuredGraph graph;
048    private final ResolvedJavaMethod method;
049    private final int invokeBci;
050    private FixedWithNextNode lastInstr;
051    private ValueNode[] arguments;
052    private ValueNode returnValue;
053
054    public IntrinsicGraphBuilder(MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, StampProvider stampProvider, ResolvedJavaMethod method, int invokeBci) {
055        this.metaAccess = metaAccess;
056        this.constantReflection = constantReflection;
057        this.stampProvider = stampProvider;
058        this.graph = new StructuredGraph(method, AllowAssumptions.YES);
059        this.method = method;
060        this.invokeBci = invokeBci;
061        this.lastInstr = graph.start();
062
063        Signature sig = method.getSignature();
064        int max = sig.getParameterCount(false);
065        this.arguments = new ValueNode[max + (method.isStatic() ? 0 : 1)];
066
067        int javaIndex = 0;
068        int index = 0;
069        if (!method.isStatic()) {
070            // add the receiver
071            Stamp receiverStamp = StampFactory.declaredNonNull(method.getDeclaringClass());
072            FloatingNode receiver = graph.addWithoutUnique(new ParameterNode(javaIndex, receiverStamp));
073            arguments[index] = receiver;
074            javaIndex = 1;
075            index = 1;
076        }
077        ResolvedJavaType accessingClass = method.getDeclaringClass();
078        for (int i = 0; i < max; i++) {
079            JavaType type = sig.getParameterType(i, accessingClass).resolve(accessingClass);
080            Kind kind = type.getKind();
081            Stamp stamp;
082            if (kind == Kind.Object && type instanceof ResolvedJavaType) {
083                stamp = StampFactory.declared((ResolvedJavaType) type);
084            } else {
085                stamp = StampFactory.forKind(kind);
086            }
087            FloatingNode param = graph.addWithoutUnique(new ParameterNode(index, stamp));
088            arguments[index] = param;
089            javaIndex += kind.getSlotCount();
090            index++;
091        }
092    }
093
094    private <T extends ValueNode> void updateLastInstruction(T v) {
095        if (v instanceof FixedNode) {
096            FixedNode fixedNode = (FixedNode) v;
097            lastInstr.setNext(fixedNode);
098            if (fixedNode instanceof FixedWithNextNode) {
099                FixedWithNextNode fixedWithNextNode = (FixedWithNextNode) fixedNode;
100                assert fixedWithNextNode.next() == null : "cannot append instruction to instruction which isn't end";
101                lastInstr = fixedWithNextNode;
102            } else {
103                lastInstr = null;
104            }
105        }
106    }
107
108    public <T extends ValueNode> T append(T v) {
109        if (v.graph() != null) {
110            return v;
111        }
112        T added = graph.addOrUnique(v);
113        if (added == v) {
114            updateLastInstruction(v);
115        }
116        return added;
117    }
118
119    public <T extends ValueNode> T recursiveAppend(T v) {
120        if (v.graph() != null) {
121            return v;
122        }
123        T added = graph.addOrUniqueWithInputs(v);
124        if (added == v) {
125            updateLastInstruction(v);
126        }
127        return added;
128    }
129
130    public void push(Kind kind, ValueNode value) {
131        assert kind != Kind.Void;
132        assert returnValue == null;
133        returnValue = value;
134    }
135
136    public void handleReplacedInvoke(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] args, boolean forceInlineEverything) {
137        throw JVMCIError.shouldNotReachHere();
138    }
139
140    public StampProvider getStampProvider() {
141        return stampProvider;
142    }
143
144    public MetaAccessProvider getMetaAccess() {
145        return metaAccess;
146    }
147
148    public ConstantReflectionProvider getConstantReflection() {
149        return constantReflection;
150    }
151
152    public StructuredGraph getGraph() {
153        return graph;
154    }
155
156    public void setStateAfter(StateSplit sideEffect) {
157        assert sideEffect.hasSideEffect();
158        FrameState stateAfter = getGraph().add(new FrameState(BytecodeFrame.BEFORE_BCI));
159        sideEffect.setStateAfter(stateAfter);
160    }
161
162    public GraphBuilderContext getParent() {
163        return null;
164    }
165
166    public ResolvedJavaMethod getMethod() {
167        return method;
168    }
169
170    public int bci() {
171        return invokeBci;
172    }
173
174    public InvokeKind getInvokeKind() {
175        return method.isStatic() ? InvokeKind.Static : InvokeKind.Virtual;
176    }
177
178    public JavaType getInvokeReturnType() {
179        return method.getSignature().getReturnType(method.getDeclaringClass());
180    }
181
182    public int getDepth() {
183        return 0;
184    }
185
186    public boolean parsingIntrinsic() {
187        return true;
188    }
189
190    public IntrinsicContext getIntrinsic() {
191        throw JVMCIError.shouldNotReachHere();
192    }
193
194    public BailoutException bailout(String string) {
195        throw JVMCIError.shouldNotReachHere();
196    }
197
198    public ValueNode get() {
199        return arguments[0];
200    }
201
202    public StructuredGraph buildGraph(InvocationPlugin plugin) {
203        Receiver receiver = method.isStatic() ? null : this;
204        if (plugin.execute(this, method, receiver, arguments)) {
205            assert (returnValue != null) == (method.getSignature().getReturnKind() != Kind.Void) : method;
206            append(new ReturnNode(returnValue));
207            return graph;
208        }
209        return null;
210    }
211
212    public void intrinsify(ResolvedJavaMethod targetMethod, ResolvedJavaMethod substitute, ValueNode[] args) {
213        throw JVMCIError.shouldNotReachHere();
214    }
215
216    @Override
217    public String toString() {
218        return String.format("%s:intrinsic", method.format("%H.%n(%p)"));
219    }
220}