1 /*
   2  * Copyright (c) 2015, 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.meta;
  26 
  27 import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
  28 import static org.graalvm.compiler.hotspot.meta.HotSpotAOTProfilingPlugin.Options.TieredAOT;
  29 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.JAVA_THREAD_THREAD_OBJECT_LOCATION;
  30 import static org.graalvm.compiler.java.BytecodeParserOptions.InlineDuringParsing;
  31 import static org.graalvm.compiler.serviceprovider.GraalServices.Java8OrEarlier;
  32 
  33 import java.lang.invoke.ConstantCallSite;
  34 import java.lang.invoke.MutableCallSite;
  35 import java.lang.invoke.VolatileCallSite;
  36 import java.lang.reflect.Array;
  37 import java.lang.reflect.Method;
  38 import java.lang.reflect.Modifier;
  39 import java.math.BigInteger;
  40 import java.util.zip.CRC32;
  41 
  42 import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
  43 import org.graalvm.compiler.bytecode.BytecodeProvider;
  44 import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
  45 import org.graalvm.compiler.core.common.type.ObjectStamp;
  46 import org.graalvm.compiler.core.common.type.StampFactory;
  47 import org.graalvm.compiler.core.common.type.TypeReference;
  48 import org.graalvm.compiler.debug.GraalError;
  49 import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
  50 import org.graalvm.compiler.hotspot.nodes.CurrentJavaThreadNode;
  51 import org.graalvm.compiler.hotspot.replacements.AESCryptSubstitutions;
  52 import org.graalvm.compiler.hotspot.replacements.BigIntegerSubstitutions;
  53 import org.graalvm.compiler.hotspot.replacements.CRC32CSubstitutions;
  54 import org.graalvm.compiler.hotspot.replacements.CRC32Substitutions;
  55 import org.graalvm.compiler.hotspot.replacements.CallSiteTargetNode;
  56 import org.graalvm.compiler.hotspot.replacements.CipherBlockChainingSubstitutions;
  57 import org.graalvm.compiler.hotspot.replacements.ClassGetHubNode;
  58 import org.graalvm.compiler.hotspot.replacements.HotSpotArraySubstitutions;
  59 import org.graalvm.compiler.hotspot.replacements.HotSpotClassSubstitutions;
  60 import org.graalvm.compiler.hotspot.replacements.IdentityHashCodeNode;
  61 import org.graalvm.compiler.hotspot.replacements.ObjectCloneNode;
  62 import org.graalvm.compiler.hotspot.replacements.ObjectSubstitutions;
  63 import org.graalvm.compiler.hotspot.replacements.ReflectionGetCallerClassNode;
  64 import org.graalvm.compiler.hotspot.replacements.ReflectionSubstitutions;
  65 import org.graalvm.compiler.hotspot.replacements.SHA2Substitutions;
  66 import org.graalvm.compiler.hotspot.replacements.SHA5Substitutions;
  67 import org.graalvm.compiler.hotspot.replacements.SHASubstitutions;
  68 import org.graalvm.compiler.hotspot.replacements.ThreadSubstitutions;
  69 import org.graalvm.compiler.replacements.arraycopy.ArrayCopyNode;
  70 import org.graalvm.compiler.hotspot.word.HotSpotWordTypes;
  71 import org.graalvm.compiler.nodes.ConstantNode;
  72 import org.graalvm.compiler.nodes.NamedLocationIdentity;
  73 import org.graalvm.compiler.nodes.NodeView;
  74 import org.graalvm.compiler.nodes.ValueNode;
  75 import org.graalvm.compiler.nodes.calc.AddNode;
  76 import org.graalvm.compiler.nodes.calc.IntegerConvertNode;
  77 import org.graalvm.compiler.nodes.calc.LeftShiftNode;
  78 import org.graalvm.compiler.nodes.graphbuilderconf.ForeignCallPlugin;
  79 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
  80 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
  81 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
  82 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin.Receiver;
  83 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
  84 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration;
  85 import org.graalvm.compiler.nodes.graphbuilderconf.NodeIntrinsicPluginFactory;
  86 import org.graalvm.compiler.nodes.memory.HeapAccess.BarrierType;
  87 import org.graalvm.compiler.nodes.memory.ReadNode;
  88 import org.graalvm.compiler.nodes.memory.address.AddressNode;
  89 import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
  90 import org.graalvm.compiler.nodes.util.GraphUtil;
  91 import org.graalvm.compiler.options.OptionValues;
  92 import org.graalvm.compiler.phases.tiers.CompilerConfiguration;
  93 import org.graalvm.compiler.replacements.InlineDuringParsingPlugin;
  94 import org.graalvm.compiler.replacements.MethodHandlePlugin;
  95 import org.graalvm.compiler.replacements.NodeIntrinsificationProvider;
  96 import org.graalvm.compiler.replacements.ReplacementsImpl;
  97 import org.graalvm.compiler.replacements.StandardGraphBuilderPlugins;
  98 import org.graalvm.compiler.serviceprovider.GraalServices;
  99 import org.graalvm.compiler.word.WordOperationPlugin;
 100 import org.graalvm.compiler.word.WordTypes;
 101 import jdk.internal.vm.compiler.word.LocationIdentity;
 102 
 103 import jdk.vm.ci.code.CodeUtil;
 104 import jdk.vm.ci.meta.ConstantReflectionProvider;
 105 import jdk.vm.ci.meta.DeoptimizationAction;
 106 import jdk.vm.ci.meta.JavaKind;
 107 import jdk.vm.ci.meta.MetaAccessProvider;
 108 import jdk.vm.ci.meta.ResolvedJavaMethod;
 109 import sun.misc.Unsafe;
 110 
 111 /**
 112  * Defines the {@link Plugins} used when running on HotSpot.
 113  */
 114 public class HotSpotGraphBuilderPlugins {
 115 
 116     /**
 117      * Creates a {@link Plugins} object that should be used when running on HotSpot.
 118      *
 119      * @param constantReflection
 120      * @param snippetReflection
 121      * @param foreignCalls
 122      */
 123     public static Plugins create(CompilerConfiguration compilerConfiguration, GraalHotSpotVMConfig config, HotSpotWordTypes wordTypes, MetaAccessProvider metaAccess,
 124                     ConstantReflectionProvider constantReflection, SnippetReflectionProvider snippetReflection, ForeignCallsProvider foreignCalls, ReplacementsImpl replacements) {
 125         InvocationPlugins invocationPlugins = new HotSpotInvocationPlugins(config, compilerConfiguration);
 126 
 127         Plugins plugins = new Plugins(invocationPlugins);
 128         NodeIntrinsificationProvider nodeIntrinsificationProvider = new NodeIntrinsificationProvider(metaAccess, snippetReflection, foreignCalls, wordTypes);
 129         HotSpotWordOperationPlugin wordOperationPlugin = new HotSpotWordOperationPlugin(snippetReflection, wordTypes);
 130         HotSpotNodePlugin nodePlugin = new HotSpotNodePlugin(wordOperationPlugin);
 131 
 132         plugins.appendTypePlugin(nodePlugin);
 133         plugins.appendNodePlugin(nodePlugin);
 134         OptionValues options = replacements.getOptions();
 135         if (!GeneratePIC.getValue(options)) {
 136             plugins.appendNodePlugin(new MethodHandlePlugin(constantReflection.getMethodHandleAccess(), true));
 137         }
 138         plugins.appendInlineInvokePlugin(replacements);
 139         if (InlineDuringParsing.getValue(options)) {
 140             plugins.appendInlineInvokePlugin(new InlineDuringParsingPlugin());
 141         }
 142 
 143         if (GeneratePIC.getValue(options)) {
 144             plugins.setClassInitializationPlugin(new HotSpotClassInitializationPlugin());
 145             if (TieredAOT.getValue(options)) {
 146                 plugins.setProfilingPlugin(new HotSpotAOTProfilingPlugin());
 147             }
 148         }
 149 
 150         invocationPlugins.defer(new Runnable() {
 151 
 152             @Override
 153             public void run() {
 154                 BytecodeProvider replacementBytecodeProvider = replacements.getDefaultReplacementBytecodeProvider();
 155                 registerObjectPlugins(invocationPlugins, options, config, replacementBytecodeProvider);
 156                 registerClassPlugins(plugins, config, replacementBytecodeProvider);
 157                 registerSystemPlugins(invocationPlugins, foreignCalls);
 158                 registerThreadPlugins(invocationPlugins, metaAccess, wordTypes, config, replacementBytecodeProvider);
 159                 if (!GeneratePIC.getValue(options)) {
 160                     registerCallSitePlugins(invocationPlugins);
 161                 }
 162                 registerReflectionPlugins(invocationPlugins, replacementBytecodeProvider);
 163                 registerConstantPoolPlugins(invocationPlugins, wordTypes, config, replacementBytecodeProvider);
 164                 registerAESPlugins(invocationPlugins, config, replacementBytecodeProvider);
 165                 registerCRC32Plugins(invocationPlugins, config, replacementBytecodeProvider);
 166                 registerCRC32CPlugins(invocationPlugins, config, replacementBytecodeProvider);
 167                 registerBigIntegerPlugins(invocationPlugins, config, replacementBytecodeProvider);
 168                 registerSHAPlugins(invocationPlugins, config, replacementBytecodeProvider);
 169                 registerUnsafePlugins(invocationPlugins, replacementBytecodeProvider);
 170                 StandardGraphBuilderPlugins.registerInvocationPlugins(metaAccess, snippetReflection, invocationPlugins, replacementBytecodeProvider, true, false);
 171                 registerArrayPlugins(invocationPlugins, replacementBytecodeProvider);
 172 
 173                 for (NodeIntrinsicPluginFactory factory : GraalServices.load(NodeIntrinsicPluginFactory.class)) {
 174                     factory.registerPlugins(invocationPlugins, nodeIntrinsificationProvider);
 175                 }
 176             }
 177         });
 178         return plugins;
 179     }
 180 
 181     private static void registerObjectPlugins(InvocationPlugins plugins, OptionValues options, GraalHotSpotVMConfig config, BytecodeProvider bytecodeProvider) {
 182         Registration r = new Registration(plugins, Object.class, bytecodeProvider);
 183         if (!GeneratePIC.getValue(options)) {
 184             // FIXME: clone() requires speculation and requires a fix in here (to check that
 185             // b.getAssumptions() != null), and in ReplacementImpl.getSubstitution() where there is
 186             // an instantiation of IntrinsicGraphBuilder using a constructor that sets
 187             // AllowAssumptions to YES automatically. The former has to inherit the assumptions
 188             // settings from the root compile instead. So, for now, I'm disabling it for
 189             // GeneratePIC.
 190             r.register1("clone", Receiver.class, new InvocationPlugin() {
 191                 @Override
 192                 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
 193                     ValueNode object = receiver.get();
 194                     b.addPush(JavaKind.Object, new ObjectCloneNode(b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnStamp(b.getAssumptions()), object));
 195                     return true;
 196                 }
 197 
 198                 @Override
 199                 public boolean inlineOnly() {
 200                     return true;
 201                 }
 202             });
 203         }
 204         r.registerMethodSubstitution(ObjectSubstitutions.class, "hashCode", Receiver.class);
 205         if (config.inlineNotify()) {
 206             r.registerMethodSubstitution(ObjectSubstitutions.class, "notify", Receiver.class);
 207         }
 208         if (config.inlineNotifyAll()) {
 209             r.registerMethodSubstitution(ObjectSubstitutions.class, "notifyAll", Receiver.class);
 210         }
 211     }
 212 
 213     private static void registerClassPlugins(Plugins plugins, GraalHotSpotVMConfig config, BytecodeProvider bytecodeProvider) {
 214         Registration r = new Registration(plugins.getInvocationPlugins(), Class.class, bytecodeProvider);
 215 
 216         r.registerMethodSubstitution(HotSpotClassSubstitutions.class, "getModifiers", Receiver.class);
 217         r.registerMethodSubstitution(HotSpotClassSubstitutions.class, "isInterface", Receiver.class);
 218         r.registerMethodSubstitution(HotSpotClassSubstitutions.class, "isArray", Receiver.class);
 219         r.registerMethodSubstitution(HotSpotClassSubstitutions.class, "isPrimitive", Receiver.class);
 220         r.registerMethodSubstitution(HotSpotClassSubstitutions.class, "getSuperclass", Receiver.class);
 221 
 222         if (config.getFieldOffset("ArrayKlass::_component_mirror", Integer.class, "oop", Integer.MAX_VALUE) != Integer.MAX_VALUE) {
 223             r.registerMethodSubstitution(HotSpotClassSubstitutions.class, "getComponentType", Receiver.class);
 224         }
 225     }
 226 
 227     private static void registerCallSitePlugins(InvocationPlugins plugins) {
 228         InvocationPlugin plugin = new InvocationPlugin() {
 229             @Override
 230             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
 231                 ValueNode callSite = receiver.get();
 232                 ValueNode folded = CallSiteTargetNode.tryFold(GraphUtil.originalValue(callSite), b.getMetaAccess(), b.getAssumptions());
 233                 if (folded != null) {
 234                     b.addPush(JavaKind.Object, folded);
 235                 } else {
 236                     b.addPush(JavaKind.Object, new CallSiteTargetNode(b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnStamp(b.getAssumptions()), callSite));
 237                 }
 238                 return true;
 239             }
 240 
 241             @Override
 242             public boolean inlineOnly() {
 243                 return true;
 244             }
 245         };
 246         plugins.register(plugin, ConstantCallSite.class, "getTarget", Receiver.class);
 247         plugins.register(plugin, MutableCallSite.class, "getTarget", Receiver.class);
 248         plugins.register(plugin, VolatileCallSite.class, "getTarget", Receiver.class);
 249     }
 250 
 251     private static void registerReflectionPlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider) {
 252         Registration r = new Registration(plugins, reflectionClass, bytecodeProvider);
 253         r.register0("getCallerClass", new InvocationPlugin() {
 254             @Override
 255             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
 256                 b.addPush(JavaKind.Object, new ReflectionGetCallerClassNode(b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnStamp(b.getAssumptions())));
 257                 return true;
 258             }
 259 
 260             @Override
 261             public boolean inlineOnly() {
 262                 return true;
 263             }
 264         });
 265         r.registerMethodSubstitution(ReflectionSubstitutions.class, "getClassAccessFlags", Class.class);
 266     }
 267 
 268     private static void registerUnsafePlugins(InvocationPlugins plugins, BytecodeProvider replacementBytecodeProvider) {
 269         Registration r;
 270         if (Java8OrEarlier) {
 271             r = new Registration(plugins, Unsafe.class, replacementBytecodeProvider);
 272         } else {
 273             r = new Registration(plugins, "jdk.internal.misc.Unsafe", replacementBytecodeProvider);
 274         }
 275         r.registerMethodSubstitution(HotSpotUnsafeSubstitutions.class, HotSpotUnsafeSubstitutions.copyMemoryName, "copyMemory", Receiver.class, Object.class, long.class, Object.class, long.class,
 276                         long.class);
 277     }
 278 
 279     private static final LocationIdentity INSTANCE_KLASS_CONSTANTS = NamedLocationIdentity.immutable("InstanceKlass::_constants");
 280     private static final LocationIdentity CONSTANT_POOL_LENGTH = NamedLocationIdentity.immutable("ConstantPool::_length");
 281 
 282     /**
 283      * Emits a node to get the metaspace {@code ConstantPool} pointer given the value of the
 284      * {@code constantPoolOop} field in a ConstantPool value.
 285      *
 286      * @param constantPoolOop value of the {@code constantPoolOop} field in a ConstantPool value
 287      * @return a node representing the metaspace {@code ConstantPool} pointer associated with
 288      *         {@code constantPoolOop}
 289      */
 290     private static ValueNode getMetaspaceConstantPool(GraphBuilderContext b, ValueNode constantPoolOop, WordTypes wordTypes, GraalHotSpotVMConfig config) {
 291         // ConstantPool.constantPoolOop is in fact the holder class.
 292         ValueNode value = b.nullCheckedValue(constantPoolOop, DeoptimizationAction.None);
 293         ValueNode klass = b.add(ClassGetHubNode.create(value, b.getMetaAccess(), b.getConstantReflection(), false));
 294 
 295         boolean notCompressible = false;
 296         AddressNode constantsAddress = b.add(new OffsetAddressNode(klass, b.add(ConstantNode.forLong(config.instanceKlassConstantsOffset))));
 297         return WordOperationPlugin.readOp(b, wordTypes.getWordKind(), constantsAddress, INSTANCE_KLASS_CONSTANTS, BarrierType.NONE, notCompressible);
 298     }
 299 
 300     /**
 301      * Emits a node representing an element in a metaspace {@code ConstantPool}.
 302      *
 303      * @param constantPoolOop value of the {@code constantPoolOop} field in a ConstantPool value
 304      */
 305     private static boolean readMetaspaceConstantPoolElement(GraphBuilderContext b, ValueNode constantPoolOop, ValueNode index, JavaKind elementKind, WordTypes wordTypes, GraalHotSpotVMConfig config) {
 306         ValueNode constants = getMetaspaceConstantPool(b, constantPoolOop, wordTypes, config);
 307         int shift = CodeUtil.log2(wordTypes.getWordKind().getByteCount());
 308         ValueNode scaledIndex = b.add(new LeftShiftNode(IntegerConvertNode.convert(index, StampFactory.forKind(JavaKind.Long), NodeView.DEFAULT), b.add(ConstantNode.forInt(shift))));
 309         ValueNode offset = b.add(new AddNode(scaledIndex, b.add(ConstantNode.forLong(config.constantPoolSize))));
 310         AddressNode elementAddress = b.add(new OffsetAddressNode(constants, offset));
 311         boolean notCompressible = false;
 312         ValueNode elementValue = WordOperationPlugin.readOp(b, elementKind, elementAddress, NamedLocationIdentity.getArrayLocation(elementKind), BarrierType.NONE, notCompressible);
 313         b.addPush(elementKind, elementValue);
 314         return true;
 315     }
 316 
 317     private static void registerConstantPoolPlugins(InvocationPlugins plugins, WordTypes wordTypes, GraalHotSpotVMConfig config, BytecodeProvider bytecodeProvider) {
 318         Registration r = new Registration(plugins, constantPoolClass, bytecodeProvider);
 319 
 320         r.register2("getSize0", Receiver.class, Object.class, new InvocationPlugin() {
 321             @Override
 322             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode constantPoolOop) {
 323                 boolean notCompressible = false;
 324                 ValueNode constants = getMetaspaceConstantPool(b, constantPoolOop, wordTypes, config);
 325                 AddressNode lengthAddress = b.add(new OffsetAddressNode(constants, b.add(ConstantNode.forLong(config.constantPoolLengthOffset))));
 326                 ValueNode length = WordOperationPlugin.readOp(b, JavaKind.Int, lengthAddress, CONSTANT_POOL_LENGTH, BarrierType.NONE, notCompressible);
 327                 b.addPush(JavaKind.Int, length);
 328                 return true;
 329             }
 330         });
 331 
 332         r.register3("getIntAt0", Receiver.class, Object.class, int.class, new InvocationPlugin() {
 333             @Override
 334             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode constantPoolOop, ValueNode index) {
 335                 return readMetaspaceConstantPoolElement(b, constantPoolOop, index, JavaKind.Int, wordTypes, config);
 336             }
 337         });
 338         r.register3("getLongAt0", Receiver.class, Object.class, int.class, new InvocationPlugin() {
 339             @Override
 340             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode constantPoolOop, ValueNode index) {
 341                 return readMetaspaceConstantPoolElement(b, constantPoolOop, index, JavaKind.Long, wordTypes, config);
 342             }
 343         });
 344         r.register3("getFloatAt0", Receiver.class, Object.class, int.class, new InvocationPlugin() {
 345             @Override
 346             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode constantPoolOop, ValueNode index) {
 347                 return readMetaspaceConstantPoolElement(b, constantPoolOop, index, JavaKind.Float, wordTypes, config);
 348             }
 349         });
 350         r.register3("getDoubleAt0", Receiver.class, Object.class, int.class, new InvocationPlugin() {
 351             @Override
 352             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode constantPoolOop, ValueNode index) {
 353                 return readMetaspaceConstantPoolElement(b, constantPoolOop, index, JavaKind.Double, wordTypes, config);
 354             }
 355         });
 356     }
 357 
 358     private static void registerSystemPlugins(InvocationPlugins plugins, ForeignCallsProvider foreignCalls) {
 359         Registration r = new Registration(plugins, System.class);
 360         r.register0("currentTimeMillis", new ForeignCallPlugin(foreignCalls, HotSpotHostForeignCallsProvider.JAVA_TIME_MILLIS));
 361         r.register0("nanoTime", new ForeignCallPlugin(foreignCalls, HotSpotHostForeignCallsProvider.JAVA_TIME_NANOS));
 362         r.register1("identityHashCode", Object.class, new InvocationPlugin() {
 363             @Override
 364             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode object) {
 365                 b.addPush(JavaKind.Int, new IdentityHashCodeNode(object));
 366                 return true;
 367             }
 368 
 369             @Override
 370             public boolean inlineOnly() {
 371                 return true;
 372             }
 373         });
 374         r.register5("arraycopy", Object.class, int.class, Object.class, int.class, int.class, new InvocationPlugin() {
 375             @Override
 376             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode src, ValueNode srcPos, ValueNode dst, ValueNode dstPos, ValueNode length) {
 377                 b.add(new ArrayCopyNode(b.bci(), src, srcPos, dst, dstPos, length));
 378                 return true;
 379             }
 380 
 381             @Override
 382             public boolean inlineOnly() {
 383                 return true;
 384             }
 385         });
 386     }
 387 
 388     private static void registerArrayPlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider) {
 389         Registration r = new Registration(plugins, Array.class, bytecodeProvider);
 390         r.setAllowOverwrite(true);
 391         r.registerMethodSubstitution(HotSpotArraySubstitutions.class, "newInstance", Class.class, int.class);
 392     }
 393 
 394     private static void registerThreadPlugins(InvocationPlugins plugins, MetaAccessProvider metaAccess, WordTypes wordTypes, GraalHotSpotVMConfig config, BytecodeProvider bytecodeProvider) {
 395         Registration r = new Registration(plugins, Thread.class, bytecodeProvider);
 396         r.register0("currentThread", new InvocationPlugin() {
 397             @Override
 398             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
 399                 CurrentJavaThreadNode thread = b.add(new CurrentJavaThreadNode(wordTypes.getWordKind()));
 400                 ValueNode offset = b.add(ConstantNode.forLong(config.threadObjectOffset));
 401                 AddressNode address = b.add(new OffsetAddressNode(thread, offset));
 402                 // JavaThread::_threadObj is never compressed
 403                 ObjectStamp stamp = StampFactory.objectNonNull(TypeReference.create(b.getAssumptions(), metaAccess.lookupJavaType(Thread.class)));
 404                 b.addPush(JavaKind.Object, new ReadNode(address, JAVA_THREAD_THREAD_OBJECT_LOCATION, stamp, BarrierType.NONE));
 405                 return true;
 406             }
 407         });
 408 
 409         r.registerMethodSubstitution(ThreadSubstitutions.class, "isInterrupted", Receiver.class, boolean.class);
 410     }
 411 
 412     public static final String cbcEncryptName;
 413     public static final String cbcDecryptName;
 414     public static final String aesEncryptName;
 415     public static final String aesDecryptName;
 416 
 417     public static final String reflectionClass;
 418     public static final String constantPoolClass;
 419 
 420     static {
 421         if (Java8OrEarlier) {
 422             cbcEncryptName = "encrypt";
 423             cbcDecryptName = "decrypt";
 424             aesEncryptName = "encryptBlock";
 425             aesDecryptName = "decryptBlock";
 426             reflectionClass = "sun.reflect.Reflection";
 427             constantPoolClass = "sun.reflect.ConstantPool";
 428         } else {
 429             cbcEncryptName = "implEncrypt";
 430             cbcDecryptName = "implDecrypt";
 431             aesEncryptName = "implEncryptBlock";
 432             aesDecryptName = "implDecryptBlock";
 433             reflectionClass = "jdk.internal.reflect.Reflection";
 434             constantPoolClass = "jdk.internal.reflect.ConstantPool";
 435         }
 436     }
 437 
 438     private static void registerAESPlugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, BytecodeProvider bytecodeProvider) {
 439         if (config.useAESIntrinsics) {
 440             assert config.aescryptEncryptBlockStub != 0L;
 441             assert config.aescryptDecryptBlockStub != 0L;
 442             assert config.cipherBlockChainingEncryptAESCryptStub != 0L;
 443             assert config.cipherBlockChainingDecryptAESCryptStub != 0L;
 444             String arch = config.osArch;
 445             String decryptSuffix = arch.equals("sparc") ? "WithOriginalKey" : "";
 446             Registration r = new Registration(plugins, "com.sun.crypto.provider.CipherBlockChaining", bytecodeProvider);
 447             r.registerMethodSubstitution(CipherBlockChainingSubstitutions.class, cbcEncryptName, Receiver.class, byte[].class, int.class, int.class, byte[].class, int.class);
 448             r.registerMethodSubstitution(CipherBlockChainingSubstitutions.class, cbcDecryptName, cbcDecryptName + decryptSuffix, Receiver.class, byte[].class, int.class, int.class, byte[].class,
 449                             int.class);
 450             r = new Registration(plugins, "com.sun.crypto.provider.AESCrypt", bytecodeProvider);
 451             r.registerMethodSubstitution(AESCryptSubstitutions.class, aesEncryptName, Receiver.class, byte[].class, int.class, byte[].class, int.class);
 452             r.registerMethodSubstitution(AESCryptSubstitutions.class, aesDecryptName, aesDecryptName + decryptSuffix, Receiver.class, byte[].class, int.class, byte[].class, int.class);
 453         }
 454     }
 455 
 456     private static void registerBigIntegerPlugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, BytecodeProvider bytecodeProvider) {
 457         Registration r = new Registration(plugins, BigInteger.class, bytecodeProvider);
 458         if (config.useMultiplyToLenIntrinsic()) {
 459             assert config.multiplyToLen != 0L;
 460             if (Java8OrEarlier) {
 461                 try {
 462                     Method m = BigInteger.class.getDeclaredMethod("multiplyToLen", int[].class, int.class, int[].class, int.class, int[].class);
 463                     if (Modifier.isStatic(m.getModifiers())) {
 464                         r.registerMethodSubstitution(BigIntegerSubstitutions.class, "multiplyToLen", "multiplyToLenStatic", int[].class, int.class, int[].class, int.class,
 465                                         int[].class);
 466                     } else {
 467                         r.registerMethodSubstitution(BigIntegerSubstitutions.class, "multiplyToLen", Receiver.class, int[].class, int.class, int[].class, int.class,
 468                                         int[].class);
 469                     }
 470                 } catch (NoSuchMethodException | SecurityException e) {
 471                     throw new GraalError(e);
 472                 }
 473             } else {
 474                 r.registerMethodSubstitution(BigIntegerSubstitutions.class, "implMultiplyToLen", "multiplyToLenStatic", int[].class, int.class, int[].class, int.class,
 475                                 int[].class);
 476             }
 477         }
 478         if (config.useMulAddIntrinsic()) {
 479             r.registerMethodSubstitution(BigIntegerSubstitutions.class, "implMulAdd", int[].class, int[].class, int.class, int.class, int.class);
 480         }
 481         if (config.useMontgomeryMultiplyIntrinsic()) {
 482             r.registerMethodSubstitution(BigIntegerSubstitutions.class, "implMontgomeryMultiply", int[].class, int[].class, int[].class, int.class, long.class, int[].class);
 483         }
 484         if (config.useMontgomerySquareIntrinsic()) {
 485             r.registerMethodSubstitution(BigIntegerSubstitutions.class, "implMontgomerySquare", int[].class, int[].class, int.class, long.class, int[].class);
 486         }
 487         if (config.useSquareToLenIntrinsic()) {
 488             r.registerMethodSubstitution(BigIntegerSubstitutions.class, "implSquareToLen", int[].class, int.class, int[].class, int.class);
 489         }
 490     }
 491 
 492     private static void registerSHAPlugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, BytecodeProvider bytecodeProvider) {
 493         if (config.useSHA1Intrinsics()) {
 494             assert config.sha1ImplCompress != 0L;
 495             Registration r = new Registration(plugins, "sun.security.provider.SHA", bytecodeProvider);
 496             r.registerMethodSubstitution(SHASubstitutions.class, SHASubstitutions.implCompressName, "implCompress0", Receiver.class, byte[].class, int.class);
 497         }
 498         if (config.useSHA256Intrinsics()) {
 499             assert config.sha256ImplCompress != 0L;
 500             Registration r = new Registration(plugins, "sun.security.provider.SHA2", bytecodeProvider);
 501             r.registerMethodSubstitution(SHA2Substitutions.class, SHA2Substitutions.implCompressName, "implCompress0", Receiver.class, byte[].class, int.class);
 502         }
 503         if (config.useSHA512Intrinsics()) {
 504             assert config.sha512ImplCompress != 0L;
 505             Registration r = new Registration(plugins, "sun.security.provider.SHA5", bytecodeProvider);
 506             r.registerMethodSubstitution(SHA5Substitutions.class, SHA5Substitutions.implCompressName, "implCompress0", Receiver.class, byte[].class, int.class);
 507         }
 508     }
 509 
 510     private static void registerCRC32Plugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, BytecodeProvider bytecodeProvider) {
 511         if (config.useCRC32Intrinsics) {
 512             Registration r = new Registration(plugins, CRC32.class, bytecodeProvider);
 513             r.registerMethodSubstitution(CRC32Substitutions.class, "update", int.class, int.class);
 514             if (Java8OrEarlier) {
 515                 r.registerMethodSubstitution(CRC32Substitutions.class, "updateBytes", int.class, byte[].class, int.class, int.class);
 516                 r.registerMethodSubstitution(CRC32Substitutions.class, "updateByteBuffer", int.class, long.class, int.class, int.class);
 517             } else {
 518                 r.registerMethodSubstitution(CRC32Substitutions.class, "updateBytes0", int.class, byte[].class, int.class, int.class);
 519                 r.registerMethodSubstitution(CRC32Substitutions.class, "updateByteBuffer0", int.class, long.class, int.class, int.class);
 520             }
 521         }
 522     }
 523 
 524     private static void registerCRC32CPlugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, BytecodeProvider bytecodeProvider) {
 525         if (config.useCRC32CIntrinsics) {
 526             Registration r = new Registration(plugins, "java.util.zip.CRC32C", bytecodeProvider);
 527             r.registerMethodSubstitution(CRC32CSubstitutions.class, "updateBytes", int.class, byte[].class, int.class, int.class);
 528             r.registerMethodSubstitution(CRC32CSubstitutions.class, "updateDirectByteBuffer", int.class, long.class, int.class, int.class);
 529         }
 530     }
 531 }