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