1/*
2 * Copyright (c) 2011, 2016, 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;
24
25import static org.graalvm.compiler.core.common.CompilationIdentifier.INVALID_COMPILATION_ID;
26
27import org.graalvm.compiler.bytecode.Bytecode;
28import org.graalvm.compiler.bytecode.BytecodeProvider;
29import org.graalvm.compiler.core.common.spi.ConstantFieldProvider;
30import org.graalvm.compiler.core.common.type.Stamp;
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.nodes.CallTargetNode.InvokeKind;
36import org.graalvm.compiler.nodes.FixedNode;
37import org.graalvm.compiler.nodes.FixedWithNextNode;
38import org.graalvm.compiler.nodes.FrameState;
39import org.graalvm.compiler.nodes.ParameterNode;
40import org.graalvm.compiler.nodes.ReturnNode;
41import org.graalvm.compiler.nodes.StateSplit;
42import org.graalvm.compiler.nodes.StructuredGraph;
43import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
44import org.graalvm.compiler.nodes.ValueNode;
45import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
46import org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext;
47import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
48import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin.Receiver;
49import org.graalvm.compiler.nodes.spi.StampProvider;
50
51import jdk.vm.ci.code.BailoutException;
52import jdk.vm.ci.code.BytecodeFrame;
53import jdk.vm.ci.meta.ConstantReflectionProvider;
54import jdk.vm.ci.meta.JavaKind;
55import jdk.vm.ci.meta.JavaType;
56import jdk.vm.ci.meta.MetaAccessProvider;
57import jdk.vm.ci.meta.ResolvedJavaMethod;
58import jdk.vm.ci.meta.ResolvedJavaType;
59import jdk.vm.ci.meta.Signature;
60
61/**
62 * Implementation of {@link GraphBuilderContext} used to produce a graph for a method based on an
63 * {@link InvocationPlugin} for the method.
64 */
65public class IntrinsicGraphBuilder implements GraphBuilderContext, Receiver {
66
67    protected final MetaAccessProvider metaAccess;
68    protected final ConstantReflectionProvider constantReflection;
69    protected final ConstantFieldProvider constantFieldProvider;
70    protected final StampProvider stampProvider;
71    protected final StructuredGraph graph;
72    protected final Bytecode code;
73    protected final ResolvedJavaMethod method;
74    protected final int invokeBci;
75    protected FixedWithNextNode lastInstr;
76    protected ValueNode[] arguments;
77    protected ValueNode returnValue;
78
79    public IntrinsicGraphBuilder(MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, ConstantFieldProvider constantFieldProvider, StampProvider stampProvider,
80                    Bytecode code, int invokeBci) {
81        this(metaAccess, constantReflection, constantFieldProvider, stampProvider, code, invokeBci, AllowAssumptions.YES);
82    }
83
84    protected IntrinsicGraphBuilder(MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, ConstantFieldProvider constantFieldProvider, StampProvider stampProvider,
85                    Bytecode code, int invokeBci, AllowAssumptions allowAssumptions) {
86        this.metaAccess = metaAccess;
87        this.constantReflection = constantReflection;
88        this.constantFieldProvider = constantFieldProvider;
89        this.stampProvider = stampProvider;
90        this.code = code;
91        this.method = code.getMethod();
92        this.graph = new StructuredGraph(method, allowAssumptions, INVALID_COMPILATION_ID);
93        this.invokeBci = invokeBci;
94        this.lastInstr = graph.start();
95
96        Signature sig = method.getSignature();
97        int max = sig.getParameterCount(false);
98        this.arguments = new ValueNode[max + (method.isStatic() ? 0 : 1)];
99
100        int javaIndex = 0;
101        int index = 0;
102        if (!method.isStatic()) {
103            // add the receiver
104            Stamp receiverStamp = StampFactory.objectNonNull(TypeReference.createWithoutAssumptions(method.getDeclaringClass()));
105            ValueNode receiver = graph.addWithoutUnique(new ParameterNode(javaIndex, StampPair.createSingle(receiverStamp)));
106            arguments[index] = receiver;
107            javaIndex = 1;
108            index = 1;
109        }
110        ResolvedJavaType accessingClass = method.getDeclaringClass();
111        for (int i = 0; i < max; i++) {
112            JavaType type = sig.getParameterType(i, accessingClass).resolve(accessingClass);
113            JavaKind kind = type.getJavaKind();
114            Stamp stamp;
115            if (kind == JavaKind.Object && type instanceof ResolvedJavaType) {
116                stamp = StampFactory.object(TypeReference.createWithoutAssumptions((ResolvedJavaType) type));
117            } else {
118                stamp = StampFactory.forKind(kind);
119            }
120            ValueNode param = graph.addWithoutUnique(new ParameterNode(index, StampPair.createSingle(stamp)));
121            arguments[index] = param;
122            javaIndex += kind.getSlotCount();
123            index++;
124        }
125    }
126
127    private <T extends ValueNode> void updateLastInstruction(T v) {
128        if (v instanceof FixedNode) {
129            FixedNode fixedNode = (FixedNode) v;
130            lastInstr.setNext(fixedNode);
131            if (fixedNode instanceof FixedWithNextNode) {
132                FixedWithNextNode fixedWithNextNode = (FixedWithNextNode) fixedNode;
133                assert fixedWithNextNode.next() == null : "cannot append instruction to instruction which isn't end";
134                lastInstr = fixedWithNextNode;
135            } else {
136                lastInstr = null;
137            }
138        }
139    }
140
141    @Override
142    public <T extends ValueNode> T append(T v) {
143        if (v.graph() != null) {
144            return v;
145        }
146        T added = graph.addOrUnique(v);
147        if (added == v) {
148            updateLastInstruction(v);
149        }
150        return added;
151    }
152
153    @Override
154    public <T extends ValueNode> T recursiveAppend(T v) {
155        if (v.graph() != null) {
156            return v;
157        }
158        T added = graph.addOrUniqueWithInputs(v);
159        if (added == v) {
160            updateLastInstruction(v);
161        }
162        return added;
163    }
164
165    @Override
166    public void push(JavaKind kind, ValueNode value) {
167        assert kind != JavaKind.Void;
168        assert returnValue == null;
169        returnValue = value;
170    }
171
172    @Override
173    public void handleReplacedInvoke(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] args, boolean forceInlineEverything) {
174        throw GraalError.shouldNotReachHere();
175    }
176
177    @Override
178    public StampProvider getStampProvider() {
179        return stampProvider;
180    }
181
182    @Override
183    public MetaAccessProvider getMetaAccess() {
184        return metaAccess;
185    }
186
187    @Override
188    public ConstantReflectionProvider getConstantReflection() {
189        return constantReflection;
190    }
191
192    @Override
193    public ConstantFieldProvider getConstantFieldProvider() {
194        return constantFieldProvider;
195    }
196
197    @Override
198    public StructuredGraph getGraph() {
199        return graph;
200    }
201
202    @Override
203    public void setStateAfter(StateSplit sideEffect) {
204        assert sideEffect.hasSideEffect();
205        FrameState stateAfter = getGraph().add(new FrameState(BytecodeFrame.BEFORE_BCI));
206        sideEffect.setStateAfter(stateAfter);
207    }
208
209    @Override
210    public GraphBuilderContext getParent() {
211        return null;
212    }
213
214    @Override
215    public Bytecode getCode() {
216        return code;
217    }
218
219    @Override
220    public ResolvedJavaMethod getMethod() {
221        return method;
222    }
223
224    @Override
225    public int bci() {
226        return invokeBci;
227    }
228
229    @Override
230    public InvokeKind getInvokeKind() {
231        return method.isStatic() ? InvokeKind.Static : InvokeKind.Virtual;
232    }
233
234    @Override
235    public JavaType getInvokeReturnType() {
236        return method.getSignature().getReturnType(method.getDeclaringClass());
237    }
238
239    @Override
240    public int getDepth() {
241        return 0;
242    }
243
244    @Override
245    public boolean parsingIntrinsic() {
246        return true;
247    }
248
249    @Override
250    public IntrinsicContext getIntrinsic() {
251        throw GraalError.shouldNotReachHere();
252    }
253
254    @Override
255    public BailoutException bailout(String string) {
256        throw GraalError.shouldNotReachHere();
257    }
258
259    @Override
260    public ValueNode get(boolean performNullCheck) {
261        return arguments[0];
262    }
263
264    public StructuredGraph buildGraph(InvocationPlugin plugin) {
265        Receiver receiver = method.isStatic() ? null : this;
266        if (plugin.execute(this, method, receiver, arguments)) {
267            assert (returnValue != null) == (method.getSignature().getReturnKind() != JavaKind.Void) : method;
268            append(new ReturnNode(returnValue));
269            return graph;
270        }
271        return null;
272    }
273
274    @Override
275    public boolean intrinsify(BytecodeProvider bytecodeProvider, ResolvedJavaMethod targetMethod, ResolvedJavaMethod substitute, InvocationPlugin.Receiver receiver, ValueNode[] args) {
276        throw GraalError.shouldNotReachHere();
277    }
278
279    @Override
280    public String toString() {
281        return String.format("%s:intrinsic", method.format("%H.%n(%p)"));
282    }
283}
284