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