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             String decryptSuffix = "";
 554 
 555             Registration r = new Registration(plugins, "com.sun.crypto.provider.CipherBlockChaining", replacements);
 556 
 557             Pair<String, String> cbcEncryptName = selectIntrinsicName(config, "com/sun/crypto/provider/CipherBlockChaining", "implEncrypt", "encrypt");
 558             registerAndCheckMismatch(r, CipherBlockChainingSubstitutions.class, cbcEncryptName, Receiver.class, byte[].class, int.class, int.class,
 559                             byte[].class, int.class);
 560 
 561             Pair<String, String> cbcDecryptName = selectIntrinsicName(config, "com/sun/crypto/provider/CipherBlockChaining", "implDecrypt", "decrypt");
 562             registerAndCheckMismatch(r, CipherBlockChainingSubstitutions.class, cbcDecryptName, cbcDecryptName.getLeft() + decryptSuffix, Receiver.class, byte[].class, int.class, int.class,
 563                             byte[].class, int.class);
 564 
 565             r = new Registration(plugins, "com.sun.crypto.provider.AESCrypt", replacements);
 566 
 567             Pair<String, String> aesEncryptName = selectIntrinsicName(config, "com/sun/crypto/provider/AESCrypt", "implEncryptBlock", "encryptBlock");
 568             registerAndCheckMismatch(r, AESCryptSubstitutions.class, aesEncryptName, Receiver.class, byte[].class, int.class, byte[].class, int.class);
 569 
 570             Pair<String, String> aesDecryptName = selectIntrinsicName(config, "com/sun/crypto/provider/AESCrypt", "implDecryptBlock", "decryptBlock");
 571             registerAndCheckMismatch(r, AESCryptSubstitutions.class, aesDecryptName, aesDecryptName.getLeft() + decryptSuffix, Receiver.class, byte[].class, int.class, byte[].class, int.class);
 572         }
 573     }
 574 
 575     private static void registerAndCheckMismatch(Registration r, Class<?> substitutionClass, Pair<String, String> intrinsicNames, Type... argumentTypes) {
 576         try {
 577             r.registerMethodSubstitution(substitutionClass, intrinsicNames.getLeft(), argumentTypes);
 578         } catch (NoSuchMethodError e) {
 579             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.",
 580                             intrinsicNames.getRight(), intrinsicNames.getLeft(), r.getDeclaringType().getTypeName(), Services.getSavedProperties().get("java.home"));
 581         }
 582     }
 583 
 584     private static void registerAndCheckMismatch(Registration r, Class<?> substitutionClass, Pair<String, String> intrinsicNames, String substituteName, Type... argumentTypes) {
 585         try {
 586             r.registerMethodSubstitution(substitutionClass, intrinsicNames.getLeft(), substituteName, argumentTypes);
 587         } catch (NoSuchMethodError e) {
 588             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.",
 589                             intrinsicNames.getRight(), intrinsicNames.getLeft(), r.getDeclaringType().getTypeName(), Services.getSavedProperties().get("java.home"));
 590         }
 591     }
 592 
 593     private static void registerBigIntegerPlugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, Replacements replacements) {
 594         Registration r = new Registration(plugins, BigInteger.class, replacements);
 595         assert !config.useMultiplyToLenIntrinsic() || config.multiplyToLen != 0L;
 596         if (JavaVersionUtil.JAVA_SPEC <= 8) {
 597             r.registerConditionalMethodSubstitution(config.useMultiplyToLenIntrinsic(), BigIntegerSubstitutions.class, "multiplyToLen", "multiplyToLenStatic", int[].class, int.class, int[].class,
 598                             int.class, int[].class);
 599         } else {
 600             r.registerConditionalMethodSubstitution(config.useMultiplyToLenIntrinsic(), BigIntegerSubstitutions.class, "implMultiplyToLen", "multiplyToLenStatic", int[].class, int.class, int[].class,
 601                             int.class, int[].class);
 602         }
 603         r.registerConditionalMethodSubstitution(config.useMulAddIntrinsic(), BigIntegerSubstitutions.class, "implMulAdd", int[].class, int[].class, int.class, int.class, int.class);
 604         r.registerConditionalMethodSubstitution(config.useMontgomeryMultiplyIntrinsic(), BigIntegerSubstitutions.class, "implMontgomeryMultiply", int[].class, int[].class, int[].class, int.class,
 605                         long.class, int[].class);
 606         r.registerConditionalMethodSubstitution(config.useMontgomerySquareIntrinsic(), BigIntegerSubstitutions.class, "implMontgomerySquare", int[].class, int[].class, int.class, long.class,
 607                         int[].class);
 608         r.registerConditionalMethodSubstitution(config.useSquareToLenIntrinsic(), BigIntegerSubstitutions.class, "implSquareToLen", int[].class, int.class, int[].class, int.class);
 609     }
 610 
 611     private static void registerSHAPlugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, Replacements replacements) {
 612         boolean useSha1 = config.useSHA1Intrinsics();
 613         boolean useSha256 = config.useSHA256Intrinsics();
 614         boolean useSha512 = config.useSHA512Intrinsics();
 615 
 616         if (isIntrinsicName(config, "sun/security/provider/DigestBase", "implCompressMultiBlock0") && (useSha1 || useSha256 || useSha512)) {
 617             Registration r = new Registration(plugins, "sun.security.provider.DigestBase", replacements);
 618             r.registerMethodSubstitution(DigestBaseSubstitutions.class, "implCompressMultiBlock0", Receiver.class, byte[].class, int.class, int.class);
 619         }
 620 
 621         Pair<String, String> implCompressName = selectIntrinsicName(config, "sun/security/provider/SHA", "implCompress", "implCompress0");
 622         if (useSha1) {
 623             assert config.sha1ImplCompress != 0L;
 624             Registration r = new Registration(plugins, "sun.security.provider.SHA", replacements);
 625             registerAndCheckMismatch(r, SHASubstitutions.class, implCompressName, "implCompress0", Receiver.class, byte[].class, int.class);
 626         }
 627         if (useSha256) {
 628             assert config.sha256ImplCompress != 0L;
 629             Registration r = new Registration(plugins, "sun.security.provider.SHA2", replacements);
 630             registerAndCheckMismatch(r, SHA2Substitutions.class, implCompressName, "implCompress0", Receiver.class, byte[].class, int.class);
 631         }
 632         if (useSha512) {
 633             assert config.sha512ImplCompress != 0L;
 634             Registration r = new Registration(plugins, "sun.security.provider.SHA5", replacements);
 635             registerAndCheckMismatch(r, SHA5Substitutions.class, implCompressName, "implCompress0", Receiver.class, byte[].class, int.class);
 636         }
 637     }
 638 
 639     private static void registerGHASHPlugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, MetaAccessProvider metaAccess, ForeignCallsProvider foreignCalls) {
 640         if (config.useGHASHIntrinsics()) {
 641             assert config.ghashProcessBlocks != 0L;
 642             Registration r = new Registration(plugins, "com.sun.crypto.provider.GHASH");
 643             r.register5("processBlocks",
 644                             byte[].class,
 645                             int.class,
 646                             int.class,
 647                             long[].class,
 648                             long[].class,
 649                             new InvocationPlugin() {
 650                                 @Override
 651                                 public boolean apply(GraphBuilderContext b,
 652                                                 ResolvedJavaMethod targetMethod,
 653                                                 Receiver receiver,
 654                                                 ValueNode data,
 655                                                 ValueNode inOffset,
 656                                                 ValueNode blocks,
 657                                                 ValueNode state,
 658                                                 ValueNode hashSubkey) {
 659                                     int longArrayBaseOffset = metaAccess.getArrayBaseOffset(JavaKind.Long);
 660                                     int byteArrayBaseOffset = metaAccess.getArrayBaseOffset(JavaKind.Byte);
 661                                     ValueNode dataOffset = AddNode.create(ConstantNode.forInt(byteArrayBaseOffset), inOffset, NodeView.DEFAULT);
 662                                     ComputeObjectAddressNode dataAddress = b.add(new ComputeObjectAddressNode(data, dataOffset));
 663                                     ComputeObjectAddressNode stateAddress = b.add(new ComputeObjectAddressNode(state, ConstantNode.forInt(longArrayBaseOffset)));
 664                                     ComputeObjectAddressNode hashSubkeyAddress = b.add(new ComputeObjectAddressNode(hashSubkey, ConstantNode.forInt(longArrayBaseOffset)));
 665                                     b.add(new ForeignCallNode(foreignCalls, GHASH_PROCESS_BLOCKS, stateAddress, hashSubkeyAddress, dataAddress, blocks));
 666                                     return true;
 667                                 }
 668                             });
 669         }
 670     }
 671 
 672     private static void registerCounterModePlugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, Replacements replacements) {
 673         if (isIntrinsicName(config, "com/sun/crypto/provider/CounterMode", "implCrypt")) {
 674             assert !config.useAESCTRIntrinsics || config.counterModeAESCrypt != 0L;
 675             Registration r = new Registration(plugins, "com.sun.crypto.provider.CounterMode", replacements);
 676             r.registerConditionalMethodSubstitution(config.useAESCTRIntrinsics, CounterModeSubstitutions.class, "implCrypt", Receiver.class, byte[].class, int.class, int.class, byte[].class,
 677                             int.class);
 678         }
 679     }
 680 
 681     private static void registerBase64Plugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, MetaAccessProvider metaAccess, ForeignCallsProvider foreignCalls) {
 682         if (config.useBase64Intrinsics()) {
 683             Registration r = new Registration(plugins, "java.util.Base64$Encoder");
 684             r.register7("encodeBlock",
 685                             Receiver.class,
 686                             byte[].class,
 687                             int.class,
 688                             int.class,
 689                             byte[].class,
 690                             int.class,
 691                             boolean.class,
 692                             new InvocationPlugin() {
 693                                 @Override
 694                                 public boolean apply(GraphBuilderContext b,
 695                                                 ResolvedJavaMethod targetMethod,
 696                                                 Receiver receiver,
 697                                                 ValueNode src,
 698                                                 ValueNode sp,
 699                                                 ValueNode sl,
 700                                                 ValueNode dst,
 701                                                 ValueNode dp,
 702                                                 ValueNode isURL) {
 703                                     int byteArrayBaseOffset = metaAccess.getArrayBaseOffset(JavaKind.Byte);
 704                                     ComputeObjectAddressNode srcAddress = b.add(new ComputeObjectAddressNode(src, ConstantNode.forInt(byteArrayBaseOffset)));
 705                                     ComputeObjectAddressNode dstAddress = b.add(new ComputeObjectAddressNode(dst, ConstantNode.forInt(byteArrayBaseOffset)));
 706                                     b.add(new ForeignCallNode(foreignCalls, BASE64_ENCODE_BLOCK, srcAddress, sp, sl, dstAddress, dp, isURL));
 707                                     return true;
 708                                 }
 709                             });
 710         }
 711     }
 712 
 713     private static void registerCRC32Plugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, Replacements replacements) {
 714         Registration r = new Registration(plugins, CRC32.class, replacements);
 715         r.registerConditionalMethodSubstitution(config.useCRC32Intrinsics, CRC32Substitutions.class, "update", int.class, int.class);
 716         if (JavaVersionUtil.JAVA_SPEC <= 8) {
 717             r.registerConditionalMethodSubstitution(config.useCRC32Intrinsics, CRC32Substitutions.class, "updateBytes", int.class, byte[].class, int.class, int.class);
 718             r.registerConditionalMethodSubstitution(config.useCRC32Intrinsics, CRC32Substitutions.class, "updateByteBuffer", int.class, long.class, int.class, int.class);
 719         } else {
 720             r.registerConditionalMethodSubstitution(config.useCRC32Intrinsics, CRC32Substitutions.class, "updateBytes0", int.class, byte[].class, int.class, int.class);
 721             r.registerConditionalMethodSubstitution(config.useCRC32Intrinsics, CRC32Substitutions.class, "updateByteBuffer0", int.class, long.class, int.class, int.class);
 722         }
 723     }
 724 
 725     private static void registerCRC32CPlugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, Replacements replacements) {
 726         if (JavaVersionUtil.JAVA_SPEC > 8) {
 727             Registration r = new Registration(plugins, "java.util.zip.CRC32C", replacements);
 728             r.registerConditionalMethodSubstitution(config.useCRC32CIntrinsics, CRC32CSubstitutions.class, "updateBytes", int.class, byte[].class, int.class, int.class);
 729             r.registerConditionalMethodSubstitution(config.useCRC32CIntrinsics, CRC32CSubstitutions.class, "updateDirectByteBuffer", int.class, long.class, int.class, int.class);
 730         }
 731     }
 732 
 733     private static void registerArraysSupportPlugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, Replacements replacements) {
 734         if (JavaVersionUtil.JAVA_SPEC > 8) {
 735             Registration r = new Registration(plugins, "jdk.internal.util.ArraysSupport", replacements);
 736             r.registerConditionalMethodSubstitution(config.useVectorizedMismatchIntrinsic, ArraysSupportSubstitutions.class, "vectorizedMismatch", Object.class, long.class, Object.class, long.class,
 737                             int.class, int.class);
 738         }
 739     }
 740 }