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