1 /*
   2  * Copyright (c) 2013, 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.hotspot;
  26 
  27 import static jdk.vm.ci.services.Services.IS_BUILDING_NATIVE_IMAGE;
  28 import static jdk.vm.ci.services.Services.IS_IN_NATIVE_IMAGE;
  29 import static org.graalvm.compiler.replacements.ReplacementsImpl.Options.UseEncodedSnippets;
  30 
  31 import java.util.Set;
  32 
  33 import jdk.internal.vm.compiler.collections.EconomicSet;
  34 import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
  35 import org.graalvm.compiler.bytecode.BytecodeProvider;
  36 import org.graalvm.compiler.core.common.CompilationIdentifier;
  37 import org.graalvm.compiler.debug.DebugContext;
  38 import org.graalvm.compiler.debug.GraalError;
  39 import org.graalvm.compiler.graph.NodeSourcePosition;
  40 import org.graalvm.compiler.hotspot.meta.HotSpotWordOperationPlugin;
  41 import org.graalvm.compiler.hotspot.word.HotSpotOperation;
  42 import org.graalvm.compiler.nodes.Invoke;
  43 import org.graalvm.compiler.nodes.StructuredGraph;
  44 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
  45 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderPlugin;
  46 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
  47 import org.graalvm.compiler.nodes.graphbuilderconf.MethodSubstitutionPlugin;
  48 import org.graalvm.compiler.options.OptionValues;
  49 import org.graalvm.compiler.phases.util.Providers;
  50 import org.graalvm.compiler.printer.GraalDebugHandlersFactory;
  51 import org.graalvm.compiler.replacements.ReplacementsImpl;
  52 
  53 import jdk.vm.ci.code.TargetDescription;
  54 import jdk.vm.ci.common.NativeImageReinitialize;
  55 import jdk.vm.ci.meta.ResolvedJavaMethod;
  56 
  57 /**
  58  * Filters certain method substitutions based on whether there is underlying hardware support for
  59  * them.
  60  */
  61 public class HotSpotReplacementsImpl extends ReplacementsImpl {
  62     public HotSpotReplacementsImpl(OptionValues options, Providers providers, SnippetReflectionProvider snippetReflection, BytecodeProvider bytecodeProvider, TargetDescription target) {
  63         super(options, new GraalDebugHandlersFactory(snippetReflection), providers, snippetReflection, bytecodeProvider, target);
  64     }
  65 
  66     protected HotSpotReplacementsImpl(HotSpotReplacementsImpl replacements, Providers providers) {
  67         super(replacements.options, new GraalDebugHandlersFactory(replacements.snippetReflection), providers, replacements.snippetReflection,
  68                         replacements.getDefaultReplacementBytecodeProvider(), replacements.target);
  69     }
  70 
  71     @Override
  72     public Class<? extends GraphBuilderPlugin> getIntrinsifyingPlugin(ResolvedJavaMethod method) {
  73         return method.getAnnotation(HotSpotOperation.class) != null ? HotSpotWordOperationPlugin.class : super.getIntrinsifyingPlugin(method);
  74     }
  75 
  76     public void registerMethodSubstitution(ResolvedJavaMethod method, ResolvedJavaMethod original) {
  77         if (!IS_IN_NATIVE_IMAGE) {
  78             if (IS_BUILDING_NATIVE_IMAGE || UseEncodedSnippets.getValue(options)) {
  79                 synchronized (HotSpotReplacementsImpl.class) {
  80                     if (snippetEncoder == null) {
  81                         snippetEncoder = new SymbolicSnippetEncoder(this);
  82                     }
  83                     snippetEncoder.registerMethodSubstitution(method, original);
  84                 }
  85             }
  86         }
  87     }
  88 
  89     @Override
  90     public StructuredGraph getIntrinsicGraph(ResolvedJavaMethod method, CompilationIdentifier compilationId, DebugContext debug) {
  91         if (IS_IN_NATIVE_IMAGE) {
  92             HotSpotReplacementsImpl replacements = (HotSpotReplacementsImpl) providers.getReplacements();
  93             InvocationPlugin plugin = replacements.getGraphBuilderPlugins().getInvocationPlugins().lookupInvocation(method);
  94             if (plugin instanceof MethodSubstitutionPlugin) {
  95                 MethodSubstitutionPlugin msp = (MethodSubstitutionPlugin) plugin;
  96                 return replacements.getMethodSubstitution(msp, method);
  97             }
  98             return null;
  99         }
 100         return super.getIntrinsicGraph(method, compilationId, debug);
 101     }
 102 
 103     @Override
 104     public void notifyNotInlined(GraphBuilderContext b, ResolvedJavaMethod method, Invoke invoke) {
 105         if (b.parsingIntrinsic() && snippetEncoder != null) {
 106             if (getIntrinsifyingPlugin(method) != null) {
 107                 snippetEncoder.addDelayedInvocationPluginMethod(method);
 108                 return;
 109             }
 110         }
 111         super.notifyNotInlined(b, method, invoke);
 112     }
 113 
 114     // When assertions are enabled, these fields are used to ensure all snippets are
 115     // registered during Graal initialization which in turn ensures that native image
 116     // building will not miss any snippets.
 117     @NativeImageReinitialize private EconomicSet<ResolvedJavaMethod> registeredSnippets = EconomicSet.create();
 118     private boolean snippetRegistrationClosed;
 119 
 120     @Override
 121     public void registerSnippet(ResolvedJavaMethod method, ResolvedJavaMethod original, Object receiver, boolean trackNodeSourcePosition) {
 122         if (!IS_IN_NATIVE_IMAGE) {
 123             assert !snippetRegistrationClosed : "Cannot register snippet after registration is closed: " + method.format("%H.%n(%p)");
 124             assert registeredSnippets.add(method) : "Cannot register snippet twice: " + method.format("%H.%n(%p)");
 125             if (IS_BUILDING_NATIVE_IMAGE || UseEncodedSnippets.getValue(options)) {
 126                 synchronized (HotSpotReplacementsImpl.class) {
 127                     if (snippetEncoder == null) {
 128                         snippetEncoder = new SymbolicSnippetEncoder(this);
 129                     }
 130                     snippetEncoder.registerSnippet(method, original, receiver, trackNodeSourcePosition);
 131                 }
 132             }
 133         }
 134     }
 135 
 136     @Override
 137     public void closeSnippetRegistration() {
 138         snippetRegistrationClosed = true;
 139     }
 140 
 141     static SymbolicSnippetEncoder.EncodedSnippets getEncodedSnippets() {
 142         return encodedSnippets;
 143     }
 144 
 145     public Set<ResolvedJavaMethod> getSnippetMethods() {
 146         if (snippetEncoder != null) {
 147             return snippetEncoder.getSnippetMethods();
 148         }
 149         return null;
 150     }
 151 
 152     static void setEncodedSnippets(SymbolicSnippetEncoder.EncodedSnippets encodedSnippets) {
 153         HotSpotReplacementsImpl.encodedSnippets = encodedSnippets;
 154     }
 155 
 156     public boolean encode() {
 157         SymbolicSnippetEncoder encoder = HotSpotReplacementsImpl.snippetEncoder;
 158         if (encoder != null) {
 159             return encoder.encode();
 160         }
 161         return false;
 162     }
 163 
 164     private static volatile SymbolicSnippetEncoder.EncodedSnippets encodedSnippets;
 165 
 166     @NativeImageReinitialize static SymbolicSnippetEncoder snippetEncoder;
 167 
 168     @Override
 169     public StructuredGraph getSnippet(ResolvedJavaMethod method, ResolvedJavaMethod recursiveEntry, Object[] args, boolean trackNodeSourcePosition, NodeSourcePosition replaceePosition) {
 170         StructuredGraph graph = getEncodedSnippet(method, args);
 171         if (graph != null) {
 172             return graph;
 173         }
 174 
 175         assert !IS_IN_NATIVE_IMAGE : "should be using encoded snippets";
 176         return super.getSnippet(method, recursiveEntry, args, trackNodeSourcePosition, replaceePosition);
 177     }
 178 
 179     public StructuredGraph getEncodedSnippet(ResolvedJavaMethod method, Object[] args) {
 180         if (IS_IN_NATIVE_IMAGE || UseEncodedSnippets.getValue(options)) {
 181             synchronized (HotSpotReplacementsImpl.class) {
 182                 if (!IS_IN_NATIVE_IMAGE && UseEncodedSnippets.getValue(options)) {
 183                     snippetEncoder.encode();
 184                 }
 185 
 186                 if (getEncodedSnippets() == null) {
 187                     throw GraalError.shouldNotReachHere("encoded snippets not found");
 188                 }
 189                 StructuredGraph graph = getEncodedSnippets().getEncodedSnippet(method, this, args);
 190                 if (graph == null) {
 191                     throw GraalError.shouldNotReachHere("snippet not found: " + method.format("%H.%n(%p)"));
 192                 }
 193                 return graph;
 194             }
 195         } else if (registeredSnippets != null) {
 196             assert registeredSnippets.contains(method) : "Asking for snippet method that was never registered: " + method.format("%H.%n(%p)");
 197         }
 198         return null;
 199     }
 200 
 201     public StructuredGraph getMethodSubstitution(MethodSubstitutionPlugin plugin, ResolvedJavaMethod original) {
 202         if (IS_IN_NATIVE_IMAGE || UseEncodedSnippets.getValue(options)) {
 203             if (getEncodedSnippets() == null) {
 204                 throw GraalError.shouldNotReachHere("encoded snippets not found");
 205             }
 206             return getEncodedSnippets().getMethodSubstitutionGraph(plugin, original, this);
 207         }
 208         return null;
 209     }
 210 
 211 }