1 /*
   2  * Copyright (c) 2015, 2020, 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.HotSpotBackend.BASE64_ENCODE_BLOCK;
  29 import static org.graalvm.compiler.hotspot.HotSpotBackend.GHASH_PROCESS_BLOCKS;
  30 import static org.graalvm.compiler.hotspot.meta.HotSpotAOTProfilingPlugin.Options.TieredAOT;
  31 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.JAVA_THREAD_THREAD_OBJECT_LOCATION;
  32 import static org.graalvm.compiler.java.BytecodeParserOptions.InlineDuringParsing;
  33 
  34 import java.lang.invoke.ConstantCallSite;
  35 import java.lang.invoke.MutableCallSite;
  36 import java.lang.invoke.VolatileCallSite;
  37 import java.lang.reflect.Array;
  38 import java.lang.reflect.Type;
  39 import java.math.BigInteger;
  40 import java.util.zip.CRC32;
  41 
  42 import jdk.internal.vm.compiler.collections.Pair;
  43 import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
  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.HotSpotGraalRuntimeProvider;
  51 import org.graalvm.compiler.hotspot.nodes.CurrentJavaThreadNode;
  52 import org.graalvm.compiler.hotspot.replacements.AESCryptSubstitutions;
  53 import org.graalvm.compiler.hotspot.replacements.ArraysSupportSubstitutions;
  54 import org.graalvm.compiler.hotspot.replacements.BigIntegerSubstitutions;
  55 import org.graalvm.compiler.hotspot.replacements.CRC32CSubstitutions;
  56 import org.graalvm.compiler.hotspot.replacements.CRC32Substitutions;
  57 import org.graalvm.compiler.hotspot.replacements.CallSiteTargetNode;
  58 import org.graalvm.compiler.hotspot.replacements.CipherBlockChainingSubstitutions;
  59 import org.graalvm.compiler.hotspot.replacements.ClassGetHubNode;
  60 import org.graalvm.compiler.hotspot.replacements.CounterModeSubstitutions;
  61 import org.graalvm.compiler.hotspot.replacements.DigestBaseSubstitutions;
  62 import org.graalvm.compiler.hotspot.replacements.FastNotifyNode;
  63 import org.graalvm.compiler.hotspot.replacements.HotSpotArraySubstitutions;
  64 import org.graalvm.compiler.hotspot.replacements.HotSpotClassSubstitutions;
  65 import org.graalvm.compiler.hotspot.replacements.IdentityHashCodeNode;
  66 import org.graalvm.compiler.hotspot.replacements.ObjectCloneNode;
  67 import org.graalvm.compiler.hotspot.replacements.ReflectionGetCallerClassNode;
  68 import org.graalvm.compiler.hotspot.replacements.ReflectionSubstitutions;
  69 import org.graalvm.compiler.hotspot.replacements.SHA2Substitutions;
  70 import org.graalvm.compiler.hotspot.replacements.SHA5Substitutions;
  71 import org.graalvm.compiler.hotspot.replacements.SHASubstitutions;
  72 import org.graalvm.compiler.hotspot.replacements.StringUTF16Substitutions;
  73 import org.graalvm.compiler.hotspot.replacements.ThreadSubstitutions;
  74 import org.graalvm.compiler.hotspot.word.HotSpotWordTypes;
  75 import org.graalvm.compiler.nodes.ComputeObjectAddressNode;
  76 import org.graalvm.compiler.nodes.ConstantNode;
  77 import org.graalvm.compiler.nodes.NamedLocationIdentity;
  78 import org.graalvm.compiler.nodes.NodeView;
  79 import org.graalvm.compiler.nodes.ValueNode;
  80 import org.graalvm.compiler.nodes.calc.AddNode;
  81 import org.graalvm.compiler.nodes.calc.IntegerConvertNode;
  82 import org.graalvm.compiler.nodes.calc.LeftShiftNode;
  83 import org.graalvm.compiler.nodes.extended.ForeignCallNode;
  84 import org.graalvm.compiler.nodes.graphbuilderconf.ForeignCallPlugin;
  85 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
  86 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
  87 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
  88 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin.Receiver;
  89 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
  90 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration;
  91 import org.graalvm.compiler.nodes.graphbuilderconf.NodeIntrinsicPluginFactory;
  92 import org.graalvm.compiler.nodes.memory.OnHeapMemoryAccess.BarrierType;
  93 import org.graalvm.compiler.nodes.memory.ReadNode;
  94 import org.graalvm.compiler.nodes.memory.address.AddressNode;
  95 import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
  96 import org.graalvm.compiler.nodes.spi.Replacements;
  97 import org.graalvm.compiler.nodes.util.GraphUtil;
  98 import org.graalvm.compiler.options.OptionValues;
  99 import org.graalvm.compiler.phases.tiers.CompilerConfiguration;
 100 import org.graalvm.compiler.replacements.InlineDuringParsingPlugin;
 101 import org.graalvm.compiler.replacements.MethodHandlePlugin;
 102 import org.graalvm.compiler.replacements.NodeIntrinsificationProvider;
 103 import org.graalvm.compiler.replacements.ReplacementsImpl;
 104 import org.graalvm.compiler.replacements.StandardGraphBuilderPlugins;
 105 import org.graalvm.compiler.replacements.arraycopy.ArrayCopyNode;
 106 import org.graalvm.compiler.serviceprovider.GraalServices;
 107 import org.graalvm.compiler.serviceprovider.JavaVersionUtil;
 108 import org.graalvm.compiler.word.WordOperationPlugin;
 109 import org.graalvm.compiler.word.WordTypes;
 110 import jdk.internal.vm.compiler.word.LocationIdentity;
 111 
 112 import jdk.vm.ci.code.CodeUtil;
 113 import jdk.vm.ci.code.TargetDescription;
 114 import jdk.vm.ci.hotspot.VMIntrinsicMethod;
 115 import jdk.vm.ci.meta.ConstantReflectionProvider;
 116 import jdk.vm.ci.meta.DeoptimizationAction;
 117 import jdk.vm.ci.meta.JavaKind;
 118 import jdk.vm.ci.meta.MetaAccessProvider;
 119 import jdk.vm.ci.meta.ResolvedJavaMethod;
 120 import jdk.vm.ci.services.Services;
 121 import sun.misc.Unsafe;
 122 
 123 /**
 124  * Defines the {@link Plugins} used when running on HotSpot.
 125  */
 126 public class HotSpotGraphBuilderPlugins {
 127 
 128     /**
 129      * Creates a {@link Plugins} object that should be used when running on HotSpot.
 130      *
 131      * @param constantReflection
 132      * @param snippetReflection
 133      * @param foreignCalls
 134      * @param options
 135      * @param target
 136      */
 137     public static Plugins create(HotSpotGraalRuntimeProvider graalRuntime,
 138                     CompilerConfiguration compilerConfiguration,
 139                     GraalHotSpotVMConfig config,
 140                     HotSpotWordTypes wordTypes,
 141                     MetaAccessProvider metaAccess,
 142                     ConstantReflectionProvider constantReflection,
 143                     SnippetReflectionProvider snippetReflection,
 144                     ForeignCallsProvider foreignCalls,
 145                     ReplacementsImpl replacements,
 146                     OptionValues options,
 147                     TargetDescription target) {
 148         InvocationPlugins invocationPlugins = new HotSpotInvocationPlugins(graalRuntime, config, compilerConfiguration);
 149 
 150         Plugins plugins = new Plugins(invocationPlugins);
 151         NodeIntrinsificationProvider nodeIntrinsificationProvider = new NodeIntrinsificationProvider(metaAccess, snippetReflection, foreignCalls, wordTypes, target);
 152         HotSpotWordOperationPlugin wordOperationPlugin = new HotSpotWordOperationPlugin(snippetReflection, wordTypes);
 153         HotSpotNodePlugin nodePlugin = new HotSpotNodePlugin(wordOperationPlugin, config, wordTypes);
 154 
 155         plugins.appendTypePlugin(nodePlugin);
 156         plugins.appendNodePlugin(nodePlugin);
 157         if (!GeneratePIC.getValue(options)) {
 158             plugins.appendNodePlugin(new MethodHandlePlugin(constantReflection.getMethodHandleAccess(), true));
 159         }
 160         plugins.appendInlineInvokePlugin(replacements);
 161         if (InlineDuringParsing.getValue(options)) {
 162             plugins.appendInlineInvokePlugin(new InlineDuringParsingPlugin());
 163         }
 164 
 165         if (GeneratePIC.getValue(options)) {
 166             plugins.setClassInitializationPlugin(new HotSpotAOTClassInitializationPlugin());
 167             if (TieredAOT.getValue(options)) {
 168                 plugins.setProfilingPlugin(new HotSpotAOTProfilingPlugin());
 169             }
 170         } else {
 171             if (config.instanceKlassInitThreadOffset != -1) {
 172                 plugins.setClassInitializationPlugin(new HotSpotJITClassInitializationPlugin());
 173             }
 174         }
 175 
 176         invocationPlugins.defer(new Runnable() {
 177 
 178             @Override
 179             public void run() {
 180                 registerObjectPlugins(invocationPlugins, options, config, replacements);
 181                 registerClassPlugins(plugins, config, replacements);
 182                 registerSystemPlugins(invocationPlugins, foreignCalls);
 183                 registerThreadPlugins(invocationPlugins, metaAccess, wordTypes, config, replacements);
 184                 if (!GeneratePIC.getValue(options)) {
 185                     registerCallSitePlugins(invocationPlugins);
 186                 }
 187                 registerReflectionPlugins(invocationPlugins, replacements);
 188                 registerConstantPoolPlugins(invocationPlugins, wordTypes, config, replacements);
 189                 registerAESPlugins(invocationPlugins, config, replacements);
 190                 registerCRC32Plugins(invocationPlugins, config, replacements);
 191                 registerCRC32CPlugins(invocationPlugins, config, replacements);
 192                 registerBigIntegerPlugins(invocationPlugins, config, replacements);
 193                 registerSHAPlugins(invocationPlugins, config, replacements);
 194                 registerGHASHPlugins(invocationPlugins, config, metaAccess, foreignCalls);
 195                 registerCounterModePlugins(invocationPlugins, config, replacements);
 196                 registerBase64Plugins(invocationPlugins, config, metaAccess, foreignCalls);
 197                 registerUnsafePlugins(invocationPlugins, config, replacements);
 198                 StandardGraphBuilderPlugins.registerInvocationPlugins(metaAccess, snippetReflection, invocationPlugins, replacements, true, false, true);
 199                 registerArrayPlugins(invocationPlugins, replacements);
 200                 registerStringPlugins(invocationPlugins, replacements);
 201                 registerArraysSupportPlugins(invocationPlugins, config, replacements);
 202 
 203                 for (NodeIntrinsicPluginFactory factory : GraalServices.load(NodeIntrinsicPluginFactory.class)) {
 204                     factory.registerPlugins(invocationPlugins, nodeIntrinsificationProvider);
 205                 }
 206             }
 207         });
 208         return plugins;
 209     }
 210 
 211     private static void registerObjectPlugins(InvocationPlugins plugins, OptionValues options, GraalHotSpotVMConfig config, Replacements replacements) {
 212         Registration r = new Registration(plugins, Object.class, replacements);
 213         if (!GeneratePIC.getValue(options)) {
 214             // FIXME: clone() requires speculation and requires a fix in here (to check that
 215             // b.getAssumptions() != null), and in ReplacementImpl.getSubstitution() where there is
 216             // an instantiation of IntrinsicGraphBuilder using a constructor that sets
 217             // AllowAssumptions to YES automatically. The former has to inherit the assumptions
 218             // settings from the root compile instead. So, for now, I'm disabling it for
 219             // GeneratePIC.
 220             r.register1("clone", Receiver.class, new InvocationPlugin() {
 221                 @Override
 222                 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
 223                     ValueNode object = receiver.get();
 224                     b.addPush(JavaKind.Object, new ObjectCloneNode(b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnStamp(b.getAssumptions()), object));
 225                     return true;
 226                 }
 227 
 228                 @Override
 229                 public boolean inlineOnly() {
 230                     return true;
 231                 }
 232             });
 233         }
 234         r.register1("hashCode", Receiver.class, new InvocationPlugin() {
 235             @Override
 236             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
 237                 ValueNode object = receiver.get();
 238                 b.addPush(JavaKind.Int, new IdentityHashCodeNode(object));
 239                 return true;
 240             }
 241 
 242             @Override
 243             public boolean inlineOnly() {
 244                 return true;
 245             }
 246         });
 247         if (config.inlineNotify()) {
 248             r.register1("notify", Receiver.class, new InvocationPlugin() {
 249                 @Override
 250                 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
 251                     ValueNode object = receiver.get();
 252                     b.add(new FastNotifyNode(object, false, b.bci()));
 253                     return true;
 254                 }
 255 
 256                 @Override
 257                 public boolean inlineOnly() {
 258                     return true;
 259                 }
 260             });
 261         }
 262         if (config.inlineNotifyAll()) {
 263             r.register1("notifyAll", Receiver.class, new InvocationPlugin() {
 264                 @Override
 265                 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
 266                     ValueNode object = receiver.get();
 267                     b.add(new FastNotifyNode(object, true, b.bci()));
 268                     return true;
 269                 }
 270 
 271                 @Override
 272                 public boolean inlineOnly() {
 273                     return true;
 274                 }
 275             });
 276         }
 277     }
 278 
 279     private static void registerClassPlugins(Plugins plugins, GraalHotSpotVMConfig config, Replacements replacements) {
 280         Registration r = new Registration(plugins.getInvocationPlugins(), Class.class, replacements);
 281 
 282         r.registerMethodSubstitution(HotSpotClassSubstitutions.class, "getModifiers", Receiver.class);
 283         r.registerMethodSubstitution(HotSpotClassSubstitutions.class, "isInterface", Receiver.class);
 284         r.registerMethodSubstitution(HotSpotClassSubstitutions.class, "isArray", Receiver.class);
 285         r.registerMethodSubstitution(HotSpotClassSubstitutions.class, "isPrimitive", Receiver.class);
 286         r.registerMethodSubstitution(HotSpotClassSubstitutions.class, "getSuperclass", Receiver.class);
 287 
 288         if (config.jvmAccIsHiddenClass != 0) {
 289             r.registerMethodSubstitution(HotSpotClassSubstitutions.class, "isHidden", Receiver.class);
 290         }
 291 
 292         if (config.getFieldOffset("ArrayKlass::_component_mirror", Integer.class, "oop", Integer.MAX_VALUE) != Integer.MAX_VALUE) {
 293             r.registerMethodSubstitution(HotSpotClassSubstitutions.class, "getComponentType", Receiver.class);
 294         }
 295     }
 296 
 297     private static void registerCallSitePlugins(InvocationPlugins plugins) {
 298         InvocationPlugin plugin = new InvocationPlugin() {
 299             @Override
 300             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
 301                 ValueNode callSite = receiver.get();
 302                 ValueNode folded = CallSiteTargetNode.tryFold(GraphUtil.originalValue(callSite, true), b.getMetaAccess(), b.getAssumptions());
 303                 if (folded != null) {
 304                     b.addPush(JavaKind.Object, folded);
 305                 } else {
 306                     b.addPush(JavaKind.Object, new CallSiteTargetNode(b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnStamp(b.getAssumptions()), callSite));
 307                 }
 308                 return true;
 309             }
 310 
 311             @Override
 312             public boolean inlineOnly() {
 313                 return true;
 314             }
 315         };
 316         plugins.register(plugin, ConstantCallSite.class, "getTarget", Receiver.class);
 317         plugins.register(plugin, MutableCallSite.class, "getTarget", Receiver.class);
 318         plugins.register(plugin, VolatileCallSite.class, "getTarget", Receiver.class);
 319     }
 320 
 321     private static void registerReflectionPlugins(InvocationPlugins plugins, Replacements replacements) {
 322         Registration r = new Registration(plugins, reflectionClass, replacements);
 323         r.register0("getCallerClass", new InvocationPlugin() {
 324             @Override
 325             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
 326                 b.addPush(JavaKind.Object, new ReflectionGetCallerClassNode(b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnStamp(b.getAssumptions())));
 327                 return true;
 328             }
 329 
 330             @Override
 331             public boolean inlineOnly() {
 332                 return true;
 333             }
 334         });
 335         r.registerMethodSubstitution(ReflectionSubstitutions.class, "getClassAccessFlags", Class.class);
 336     }
 337 
 338     private static void registerUnsafePlugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, Replacements replacements) {
 339         Registration r;
 340         if (JavaVersionUtil.JAVA_SPEC <= 8) {
 341             r = new Registration(plugins, Unsafe.class, replacements);
 342         } else {
 343             r = new Registration(plugins, "jdk.internal.misc.Unsafe", replacements);
 344         }
 345         String substituteMethodName = config.doingUnsafeAccessOffset != Integer.MAX_VALUE ? "copyMemoryGuarded" : "copyMemory";
 346         r.registerMethodSubstitution(HotSpotUnsafeSubstitutions.class, HotSpotUnsafeSubstitutions.copyMemoryName, substituteMethodName, Receiver.class, Object.class, long.class, Object.class,
 347                         long.class, long.class);
 348     }
 349 
 350     private static final LocationIdentity INSTANCE_KLASS_CONSTANTS = NamedLocationIdentity.immutable("InstanceKlass::_constants");
 351     private static final LocationIdentity CONSTANT_POOL_LENGTH = NamedLocationIdentity.immutable("ConstantPool::_length");
 352 
 353     /**
 354      * Emits a node to get the metaspace {@code ConstantPool} pointer given the value of the
 355      * {@code constantPoolOop} field in a ConstantPool value.
 356      *
 357      * @param constantPoolOop value of the {@code constantPoolOop} field in a ConstantPool value
 358      * @return a node representing the metaspace {@code ConstantPool} pointer associated with
 359      *         {@code constantPoolOop}
 360      */
 361     private static ValueNode getMetaspaceConstantPool(GraphBuilderContext b, ValueNode constantPoolOop, WordTypes wordTypes, GraalHotSpotVMConfig config) {
 362         // ConstantPool.constantPoolOop is in fact the holder class.
 363         ValueNode value = b.nullCheckedValue(constantPoolOop, DeoptimizationAction.None);
 364         ValueNode klass = b.add(ClassGetHubNode.create(value, b.getMetaAccess(), b.getConstantReflection(), false));
 365 
 366         boolean notCompressible = false;
 367         AddressNode constantsAddress = b.add(new OffsetAddressNode(klass, b.add(ConstantNode.forLong(config.instanceKlassConstantsOffset))));
 368         return WordOperationPlugin.readOp(b, wordTypes.getWordKind(), constantsAddress, INSTANCE_KLASS_CONSTANTS, BarrierType.NONE, notCompressible);
 369     }
 370 
 371     /**
 372      * Emits a node representing an element in a metaspace {@code ConstantPool}.
 373      *
 374      * @param constantPoolOop value of the {@code constantPoolOop} field in a ConstantPool value
 375      */
 376     private static boolean readMetaspaceConstantPoolElement(GraphBuilderContext b, ValueNode constantPoolOop, ValueNode index, JavaKind elementKind, WordTypes wordTypes, GraalHotSpotVMConfig config) {
 377         ValueNode constants = getMetaspaceConstantPool(b, constantPoolOop, wordTypes, config);
 378         int shift = CodeUtil.log2(wordTypes.getWordKind().getByteCount());
 379         ValueNode scaledIndex = b.add(new LeftShiftNode(IntegerConvertNode.convert(index, StampFactory.forKind(JavaKind.Long), NodeView.DEFAULT), b.add(ConstantNode.forInt(shift))));
 380         ValueNode offset = b.add(new AddNode(scaledIndex, b.add(ConstantNode.forLong(config.constantPoolSize))));
 381         AddressNode elementAddress = b.add(new OffsetAddressNode(constants, offset));
 382         boolean notCompressible = false;
 383         ValueNode elementValue = WordOperationPlugin.readOp(b, elementKind, elementAddress, NamedLocationIdentity.getArrayLocation(elementKind), BarrierType.NONE, notCompressible);
 384         b.addPush(elementKind, elementValue);
 385         return true;
 386     }
 387 
 388     private static void registerConstantPoolPlugins(InvocationPlugins plugins, WordTypes wordTypes, GraalHotSpotVMConfig config, Replacements replacements) {
 389         Registration r = new Registration(plugins, constantPoolClass, replacements);
 390 
 391         r.register2("getSize0", Receiver.class, Object.class, new InvocationPlugin() {
 392             @Override
 393             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode constantPoolOop) {
 394                 boolean notCompressible = false;
 395                 ValueNode constants = getMetaspaceConstantPool(b, constantPoolOop, wordTypes, config);
 396                 AddressNode lengthAddress = b.add(new OffsetAddressNode(constants, b.add(ConstantNode.forLong(config.constantPoolLengthOffset))));
 397                 ValueNode length = WordOperationPlugin.readOp(b, JavaKind.Int, lengthAddress, CONSTANT_POOL_LENGTH, BarrierType.NONE, notCompressible);
 398                 b.addPush(JavaKind.Int, length);
 399                 return true;
 400             }
 401         });
 402 
 403         r.register3("getIntAt0", Receiver.class, Object.class, int.class, new InvocationPlugin() {
 404             @Override
 405             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode constantPoolOop, ValueNode index) {
 406                 return readMetaspaceConstantPoolElement(b, constantPoolOop, index, JavaKind.Int, wordTypes, config);
 407             }
 408         });
 409         r.register3("getLongAt0", Receiver.class, Object.class, int.class, new InvocationPlugin() {
 410             @Override
 411             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode constantPoolOop, ValueNode index) {
 412                 return readMetaspaceConstantPoolElement(b, constantPoolOop, index, JavaKind.Long, wordTypes, config);
 413             }
 414         });
 415         r.register3("getFloatAt0", Receiver.class, Object.class, int.class, new InvocationPlugin() {
 416             @Override
 417             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode constantPoolOop, ValueNode index) {
 418                 return readMetaspaceConstantPoolElement(b, constantPoolOop, index, JavaKind.Float, wordTypes, config);
 419             }
 420         });
 421         r.register3("getDoubleAt0", Receiver.class, Object.class, int.class, new InvocationPlugin() {
 422             @Override
 423             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode constantPoolOop, ValueNode index) {
 424                 return readMetaspaceConstantPoolElement(b, constantPoolOop, index, JavaKind.Double, wordTypes, config);
 425             }
 426         });
 427     }
 428 
 429     private static void registerSystemPlugins(InvocationPlugins plugins, ForeignCallsProvider foreignCalls) {
 430         Registration r = new Registration(plugins, System.class);
 431         r.register0("currentTimeMillis", new ForeignCallPlugin(foreignCalls, HotSpotHostForeignCallsProvider.JAVA_TIME_MILLIS));
 432         r.register0("nanoTime", new ForeignCallPlugin(foreignCalls, HotSpotHostForeignCallsProvider.JAVA_TIME_NANOS));
 433         r.register1("identityHashCode", Object.class, new InvocationPlugin() {
 434             @Override
 435             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode object) {
 436                 b.addPush(JavaKind.Int, new IdentityHashCodeNode(object));
 437                 return true;
 438             }
 439 
 440             @Override
 441             public boolean inlineOnly() {
 442                 return true;
 443             }
 444         });
 445         r.register5("arraycopy", Object.class, int.class, Object.class, int.class, int.class, new InvocationPlugin() {
 446             @Override
 447             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode src, ValueNode srcPos, ValueNode dst, ValueNode dstPos, ValueNode length) {
 448                 b.add(new ArrayCopyNode(b.bci(), src, srcPos, dst, dstPos, length));
 449                 return true;
 450             }
 451 
 452             @Override
 453             public boolean inlineOnly() {
 454                 return true;
 455             }
 456         });
 457     }
 458 
 459     private static void registerArrayPlugins(InvocationPlugins plugins, Replacements replacements) {
 460         Registration r = new Registration(plugins, Array.class, replacements);
 461         r.setAllowOverwrite(true);
 462         r.registerMethodSubstitution(HotSpotArraySubstitutions.class, "newInstance", Class.class, int.class);
 463     }
 464 
 465     private static void registerStringPlugins(InvocationPlugins plugins, Replacements replacements) {
 466         if (JavaVersionUtil.JAVA_SPEC > 8) {
 467             final Registration utf16r = new Registration(plugins, "java.lang.StringUTF16", replacements);
 468             utf16r.registerMethodSubstitution(StringUTF16Substitutions.class, "toBytes", char[].class, int.class, int.class);
 469             utf16r.registerMethodSubstitution(StringUTF16Substitutions.class, "getChars", byte[].class, int.class, int.class, char[].class, int.class);
 470         }
 471     }
 472 
 473     private static void registerThreadPlugins(InvocationPlugins plugins, MetaAccessProvider metaAccess, WordTypes wordTypes, GraalHotSpotVMConfig config, Replacements replacements) {
 474         Registration r = new Registration(plugins, Thread.class, replacements);
 475         r.register0("currentThread", new InvocationPlugin() {
 476             @Override
 477             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
 478                 CurrentJavaThreadNode thread = b.add(new CurrentJavaThreadNode(wordTypes.getWordKind()));
 479                 ValueNode offset = b.add(ConstantNode.forLong(config.threadObjectOffset));
 480                 AddressNode address = b.add(new OffsetAddressNode(thread, offset));
 481                 // JavaThread::_threadObj is never compressed
 482                 ObjectStamp stamp = StampFactory.objectNonNull(TypeReference.create(b.getAssumptions(), metaAccess.lookupJavaType(Thread.class)));
 483                 b.addPush(JavaKind.Object, new ReadNode(address, JAVA_THREAD_THREAD_OBJECT_LOCATION, stamp, BarrierType.NONE));
 484                 return true;
 485             }
 486         });
 487 
 488         if (config.osThreadInterruptedOffset != Integer.MAX_VALUE) {
 489             r.registerMethodSubstitution(ThreadSubstitutions.class, "isInterrupted", Receiver.class, boolean.class);
 490         }
 491 
 492     }
 493 
 494     public static final String reflectionClass;
 495     public static final String constantPoolClass;
 496 
 497     static {
 498         if (JavaVersionUtil.JAVA_SPEC <= 8) {
 499             reflectionClass = "sun.reflect.Reflection";
 500             constantPoolClass = "sun.reflect.ConstantPool";
 501         } else {
 502             reflectionClass = "jdk.internal.reflect.Reflection";
 503             constantPoolClass = "jdk.internal.reflect.ConstantPool";
 504         }
 505     }
 506 
 507     public static String lookupIntrinsicName(GraalHotSpotVMConfig config, String className, String name1, String name2) {
 508         return selectIntrinsicName(config, className, name1, name2).getLeft();
 509     }
 510 
 511     /**
 512      * Returns a pair of Strings where the left one represents the matched intrinsic name and the
 513      * right one represents the mismatched intrinsic name.
 514      */
 515     public static Pair<String, String> selectIntrinsicName(GraalHotSpotVMConfig config, String className, String name1, String name2) {
 516         boolean foundName1 = false;
 517         boolean foundName2 = false;
 518         for (VMIntrinsicMethod intrinsic : config.getStore().getIntrinsics()) {
 519             if (className.equals(intrinsic.declaringClass)) {
 520                 if (name1.equals(intrinsic.name)) {
 521                     foundName1 = true;
 522                 } else if (name2.equals(intrinsic.name)) {
 523                     foundName2 = true;
 524                 }
 525             }
 526         }
 527         if (foundName1 && !foundName2) {
 528             return Pair.create(name1, name2);
 529         } else if (foundName2 && !foundName1) {
 530             return Pair.create(name2, name1);
 531         }
 532         throw GraalError.shouldNotReachHere();
 533     }
 534 
 535     public static boolean isIntrinsicName(GraalHotSpotVMConfig config, String className, String name) {
 536         for (VMIntrinsicMethod intrinsic : config.getStore().getIntrinsics()) {
 537             if (className.equals(intrinsic.declaringClass)) {
 538                 if (name.equals(intrinsic.name)) {
 539                     return true;
 540                 }
 541             }
 542         }
 543         return false;
 544     }
 545 
 546     private static void registerAESPlugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, Replacements replacements) {
 547         if (config.useAESIntrinsics) {
 548             assert config.aescryptEncryptBlockStub != 0L;
 549             assert config.aescryptDecryptBlockStub != 0L;
 550             assert config.cipherBlockChainingEncryptAESCryptStub != 0L;
 551             assert config.cipherBlockChainingDecryptAESCryptStub != 0L;
 552             String arch = config.osArch;
 553 
 554             Registration r = new Registration(plugins, "com.sun.crypto.provider.CipherBlockChaining", replacements);
 555 
 556             Pair<String, String> cbcEncryptName = selectIntrinsicName(config, "com/sun/crypto/provider/CipherBlockChaining", "implEncrypt", "encrypt");
 557             registerAndCheckMismatch(r, CipherBlockChainingSubstitutions.class, cbcEncryptName, Receiver.class, byte[].class, int.class, int.class,
 558                             byte[].class, int.class);
 559 
 560             Pair<String, String> cbcDecryptName = selectIntrinsicName(config, "com/sun/crypto/provider/CipherBlockChaining", "implDecrypt", "decrypt");
 561             registerAndCheckMismatch(r, CipherBlockChainingSubstitutions.class, cbcDecryptName, cbcDecryptName.getLeft(), Receiver.class, byte[].class, int.class, int.class,
 562                             byte[].class, int.class);
 563 
 564             r = new Registration(plugins, "com.sun.crypto.provider.AESCrypt", replacements);
 565 
 566             Pair<String, String> aesEncryptName = selectIntrinsicName(config, "com/sun/crypto/provider/AESCrypt", "implEncryptBlock", "encryptBlock");
 567             registerAndCheckMismatch(r, AESCryptSubstitutions.class, aesEncryptName, Receiver.class, byte[].class, int.class, byte[].class, int.class);
 568 
 569             Pair<String, String> aesDecryptName = selectIntrinsicName(config, "com/sun/crypto/provider/AESCrypt", "implDecryptBlock", "decryptBlock");
 570             registerAndCheckMismatch(r, AESCryptSubstitutions.class, aesDecryptName, aesDecryptName.getLeft(), Receiver.class, byte[].class, int.class, byte[].class, int.class);
 571         }
 572     }
 573 
 574     private static void registerAndCheckMismatch(Registration r, Class<?> substitutionClass, Pair<String, String> intrinsicNames, Type... argumentTypes) {
 575         try {
 576             r.registerMethodSubstitution(substitutionClass, intrinsicNames.getLeft(), argumentTypes);
 577         } catch (NoSuchMethodError e) {
 578             throw new GraalError(e, "Found method named '%s' instead of '%s' in class '%s'. This is most likely because the JVMCI JDK in %s was built on an incompatible base JDK.",
 579                             intrinsicNames.getRight(), intrinsicNames.getLeft(), r.getDeclaringType().getTypeName(), Services.getSavedProperties().get("java.home"));
 580         }
 581     }
 582 
 583     private static void registerAndCheckMismatch(Registration r, Class<?> substitutionClass, Pair<String, String> intrinsicNames, String substituteName, Type... argumentTypes) {
 584         try {
 585             r.registerMethodSubstitution(substitutionClass, intrinsicNames.getLeft(), substituteName, argumentTypes);
 586         } catch (NoSuchMethodError e) {
 587             throw new GraalError(e, "Found method named '%s' instead of '%s' in class '%s'. This is most likely because the JVMCI JDK in %s was built on an incompatible base JDK.",
 588                             intrinsicNames.getRight(), intrinsicNames.getLeft(), r.getDeclaringType().getTypeName(), Services.getSavedProperties().get("java.home"));
 589         }
 590     }
 591 
 592     private static void registerBigIntegerPlugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, Replacements replacements) {
 593         Registration r = new Registration(plugins, BigInteger.class, replacements);
 594         assert !config.useMultiplyToLenIntrinsic() || config.multiplyToLen != 0L;
 595         if (JavaVersionUtil.JAVA_SPEC <= 8) {
 596             r.registerConditionalMethodSubstitution(config.useMultiplyToLenIntrinsic(), BigIntegerSubstitutions.class, "multiplyToLen", "multiplyToLenStatic", int[].class, int.class, int[].class,
 597                             int.class, int[].class);
 598         } else {
 599             r.registerConditionalMethodSubstitution(config.useMultiplyToLenIntrinsic(), BigIntegerSubstitutions.class, "implMultiplyToLen", "multiplyToLenStatic", int[].class, int.class, int[].class,
 600                             int.class, int[].class);
 601         }
 602         r.registerConditionalMethodSubstitution(config.useMulAddIntrinsic(), BigIntegerSubstitutions.class, "implMulAdd", int[].class, int[].class, int.class, int.class, int.class);
 603         r.registerConditionalMethodSubstitution(config.useMontgomeryMultiplyIntrinsic(), BigIntegerSubstitutions.class, "implMontgomeryMultiply", int[].class, int[].class, int[].class, int.class,
 604                         long.class, int[].class);
 605         r.registerConditionalMethodSubstitution(config.useMontgomerySquareIntrinsic(), BigIntegerSubstitutions.class, "implMontgomerySquare", int[].class, int[].class, int.class, long.class,
 606                         int[].class);
 607         r.registerConditionalMethodSubstitution(config.useSquareToLenIntrinsic(), BigIntegerSubstitutions.class, "implSquareToLen", int[].class, int.class, int[].class, int.class);
 608     }
 609 
 610     private static void registerSHAPlugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, Replacements replacements) {
 611         boolean useSha1 = config.useSHA1Intrinsics();
 612         boolean useSha256 = config.useSHA256Intrinsics();
 613         boolean useSha512 = config.useSHA512Intrinsics();
 614 
 615         if (isIntrinsicName(config, "sun/security/provider/DigestBase", "implCompressMultiBlock0") && (useSha1 || useSha256 || useSha512)) {
 616             Registration r = new Registration(plugins, "sun.security.provider.DigestBase", replacements);
 617             r.registerMethodSubstitution(DigestBaseSubstitutions.class, "implCompressMultiBlock0", Receiver.class, byte[].class, int.class, int.class);
 618         }
 619 
 620         Pair<String, String> implCompressName = selectIntrinsicName(config, "sun/security/provider/SHA", "implCompress", "implCompress0");
 621         if (useSha1) {
 622             assert config.sha1ImplCompress != 0L;
 623             Registration r = new Registration(plugins, "sun.security.provider.SHA", replacements);
 624             registerAndCheckMismatch(r, SHASubstitutions.class, implCompressName, "implCompress0", Receiver.class, byte[].class, int.class);
 625         }
 626         if (useSha256) {
 627             assert config.sha256ImplCompress != 0L;
 628             Registration r = new Registration(plugins, "sun.security.provider.SHA2", replacements);
 629             registerAndCheckMismatch(r, SHA2Substitutions.class, implCompressName, "implCompress0", Receiver.class, byte[].class, int.class);
 630         }
 631         if (useSha512) {
 632             assert config.sha512ImplCompress != 0L;
 633             Registration r = new Registration(plugins, "sun.security.provider.SHA5", replacements);
 634             registerAndCheckMismatch(r, SHA5Substitutions.class, implCompressName, "implCompress0", Receiver.class, byte[].class, int.class);
 635         }
 636     }
 637 
 638     private static void registerGHASHPlugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, MetaAccessProvider metaAccess, ForeignCallsProvider foreignCalls) {
 639         if (config.useGHASHIntrinsics()) {
 640             assert config.ghashProcessBlocks != 0L;
 641             Registration r = new Registration(plugins, "com.sun.crypto.provider.GHASH");
 642             r.register5("processBlocks",
 643                             byte[].class,
 644                             int.class,
 645                             int.class,
 646                             long[].class,
 647                             long[].class,
 648                             new InvocationPlugin() {
 649                                 @Override
 650                                 public boolean apply(GraphBuilderContext b,
 651                                                 ResolvedJavaMethod targetMethod,
 652                                                 Receiver receiver,
 653                                                 ValueNode data,
 654                                                 ValueNode inOffset,
 655                                                 ValueNode blocks,
 656                                                 ValueNode state,
 657                                                 ValueNode hashSubkey) {
 658                                     int longArrayBaseOffset = metaAccess.getArrayBaseOffset(JavaKind.Long);
 659                                     int byteArrayBaseOffset = metaAccess.getArrayBaseOffset(JavaKind.Byte);
 660                                     ValueNode dataOffset = AddNode.create(ConstantNode.forInt(byteArrayBaseOffset), inOffset, NodeView.DEFAULT);
 661                                     ComputeObjectAddressNode dataAddress = b.add(new ComputeObjectAddressNode(data, dataOffset));
 662                                     ComputeObjectAddressNode stateAddress = b.add(new ComputeObjectAddressNode(state, ConstantNode.forInt(longArrayBaseOffset)));
 663                                     ComputeObjectAddressNode hashSubkeyAddress = b.add(new ComputeObjectAddressNode(hashSubkey, ConstantNode.forInt(longArrayBaseOffset)));
 664                                     b.add(new ForeignCallNode(foreignCalls, GHASH_PROCESS_BLOCKS, stateAddress, hashSubkeyAddress, dataAddress, blocks));
 665                                     return true;
 666                                 }
 667                             });
 668         }
 669     }
 670 
 671     private static void registerCounterModePlugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, Replacements replacements) {
 672         if (isIntrinsicName(config, "com/sun/crypto/provider/CounterMode", "implCrypt")) {
 673             assert !config.useAESCTRIntrinsics || config.counterModeAESCrypt != 0L;
 674             Registration r = new Registration(plugins, "com.sun.crypto.provider.CounterMode", replacements);
 675             r.registerConditionalMethodSubstitution(config.useAESCTRIntrinsics, CounterModeSubstitutions.class, "implCrypt", Receiver.class, byte[].class, int.class, int.class, byte[].class,
 676                             int.class);
 677         }
 678     }
 679 
 680     private static void registerBase64Plugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, MetaAccessProvider metaAccess, ForeignCallsProvider foreignCalls) {
 681         if (config.useBase64Intrinsics()) {
 682             Registration r = new Registration(plugins, "java.util.Base64$Encoder");
 683             r.register7("encodeBlock",
 684                             Receiver.class,
 685                             byte[].class,
 686                             int.class,
 687                             int.class,
 688                             byte[].class,
 689                             int.class,
 690                             boolean.class,
 691                             new InvocationPlugin() {
 692                                 @Override
 693                                 public boolean apply(GraphBuilderContext b,
 694                                                 ResolvedJavaMethod targetMethod,
 695                                                 Receiver receiver,
 696                                                 ValueNode src,
 697                                                 ValueNode sp,
 698                                                 ValueNode sl,
 699                                                 ValueNode dst,
 700                                                 ValueNode dp,
 701                                                 ValueNode isURL) {
 702                                     int byteArrayBaseOffset = metaAccess.getArrayBaseOffset(JavaKind.Byte);
 703                                     ComputeObjectAddressNode srcAddress = b.add(new ComputeObjectAddressNode(src, ConstantNode.forInt(byteArrayBaseOffset)));
 704                                     ComputeObjectAddressNode dstAddress = b.add(new ComputeObjectAddressNode(dst, ConstantNode.forInt(byteArrayBaseOffset)));
 705                                     b.add(new ForeignCallNode(foreignCalls, BASE64_ENCODE_BLOCK, srcAddress, sp, sl, dstAddress, dp, isURL));
 706                                     return true;
 707                                 }
 708                             });
 709         }
 710     }
 711 
 712     private static void registerCRC32Plugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, Replacements replacements) {
 713         Registration r = new Registration(plugins, CRC32.class, replacements);
 714         r.registerConditionalMethodSubstitution(config.useCRC32Intrinsics, CRC32Substitutions.class, "update", int.class, int.class);
 715         if (JavaVersionUtil.JAVA_SPEC <= 8) {
 716             r.registerConditionalMethodSubstitution(config.useCRC32Intrinsics, CRC32Substitutions.class, "updateBytes", int.class, byte[].class, int.class, int.class);
 717             r.registerConditionalMethodSubstitution(config.useCRC32Intrinsics, CRC32Substitutions.class, "updateByteBuffer", int.class, long.class, int.class, int.class);
 718         } else {
 719             r.registerConditionalMethodSubstitution(config.useCRC32Intrinsics, CRC32Substitutions.class, "updateBytes0", int.class, byte[].class, int.class, int.class);
 720             r.registerConditionalMethodSubstitution(config.useCRC32Intrinsics, CRC32Substitutions.class, "updateByteBuffer0", int.class, long.class, int.class, int.class);
 721         }
 722     }
 723 
 724     private static void registerCRC32CPlugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, Replacements replacements) {
 725         if (JavaVersionUtil.JAVA_SPEC > 8) {
 726             Registration r = new Registration(plugins, "java.util.zip.CRC32C", replacements);
 727             r.registerConditionalMethodSubstitution(config.useCRC32CIntrinsics, CRC32CSubstitutions.class, "updateBytes", int.class, byte[].class, int.class, int.class);
 728             r.registerConditionalMethodSubstitution(config.useCRC32CIntrinsics, CRC32CSubstitutions.class, "updateDirectByteBuffer", int.class, long.class, int.class, int.class);
 729         }
 730     }
 731 
 732     private static void registerArraysSupportPlugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, Replacements replacements) {
 733         if (JavaVersionUtil.JAVA_SPEC > 8) {
 734             Registration r = new Registration(plugins, "jdk.internal.util.ArraysSupport", replacements);
 735             r.registerConditionalMethodSubstitution(config.useVectorizedMismatchIntrinsic, ArraysSupportSubstitutions.class, "vectorizedMismatch", Object.class, long.class, Object.class, long.class,
 736                             int.class, int.class);
 737         }
 738     }
 739 }