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 = arch.equals("sparc") ? "WithOriginalKey" : ""; 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 }