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