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