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