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