1 /* 2 * Copyright (c) 2015, 2018, 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.replacements; 26 27 import static jdk.vm.ci.code.MemoryBarriers.JMM_POST_VOLATILE_READ; 28 import static jdk.vm.ci.code.MemoryBarriers.JMM_POST_VOLATILE_WRITE; 29 import static jdk.vm.ci.code.MemoryBarriers.JMM_PRE_VOLATILE_READ; 30 import static jdk.vm.ci.code.MemoryBarriers.JMM_PRE_VOLATILE_WRITE; 31 import static jdk.vm.ci.code.MemoryBarriers.LOAD_LOAD; 32 import static jdk.vm.ci.code.MemoryBarriers.LOAD_STORE; 33 import static jdk.vm.ci.code.MemoryBarriers.STORE_LOAD; 34 import static jdk.vm.ci.code.MemoryBarriers.STORE_STORE; 35 import static org.graalvm.compiler.nodes.NamedLocationIdentity.OFF_HEAP_LOCATION; 36 import static org.graalvm.compiler.serviceprovider.GraalServices.Java11OrEarlier; 37 import static org.graalvm.compiler.serviceprovider.GraalServices.Java8OrEarlier; 38 39 import java.lang.reflect.Array; 40 import java.lang.reflect.Field; 41 import java.util.Arrays; 42 43 import org.graalvm.compiler.api.directives.GraalDirectives; 44 import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; 45 import org.graalvm.compiler.bytecode.BytecodeProvider; 46 import org.graalvm.compiler.core.common.calc.Condition; 47 import org.graalvm.compiler.core.common.calc.Condition.CanonicalizedCondition; 48 import org.graalvm.compiler.core.common.calc.UnsignedMath; 49 import org.graalvm.compiler.core.common.type.ObjectStamp; 50 import org.graalvm.compiler.core.common.type.Stamp; 51 import org.graalvm.compiler.core.common.type.StampFactory; 52 import org.graalvm.compiler.core.common.type.TypeReference; 53 import org.graalvm.compiler.debug.GraalError; 54 import org.graalvm.compiler.graph.Edges; 55 import org.graalvm.compiler.graph.Node; 56 import org.graalvm.compiler.graph.NodeList; 57 import org.graalvm.compiler.java.IntegerExactOpSpeculation; 58 import org.graalvm.compiler.java.IntegerExactOpSpeculation.IntegerExactOp; 59 import org.graalvm.compiler.nodes.AbstractBeginNode; 60 import org.graalvm.compiler.nodes.BeginNode; 61 import org.graalvm.compiler.nodes.ConstantNode; 62 import org.graalvm.compiler.nodes.DeoptimizeNode; 63 import org.graalvm.compiler.nodes.EndNode; 64 import org.graalvm.compiler.nodes.FixedGuardNode; 65 import org.graalvm.compiler.nodes.FixedWithNextNode; 66 import org.graalvm.compiler.nodes.IfNode; 67 import org.graalvm.compiler.nodes.LogicNode; 68 import org.graalvm.compiler.nodes.MergeNode; 69 import org.graalvm.compiler.nodes.NodeView; 70 import org.graalvm.compiler.nodes.StateSplit; 71 import org.graalvm.compiler.nodes.StructuredGraph; 72 import org.graalvm.compiler.nodes.ValueNode; 73 import org.graalvm.compiler.nodes.ValuePhiNode; 74 import org.graalvm.compiler.nodes.calc.AbsNode; 75 import org.graalvm.compiler.nodes.calc.CompareNode; 76 import org.graalvm.compiler.nodes.calc.ConditionalNode; 77 import org.graalvm.compiler.nodes.calc.FloatEqualsNode; 78 import org.graalvm.compiler.nodes.calc.IntegerEqualsNode; 79 import org.graalvm.compiler.nodes.calc.IsNullNode; 80 import org.graalvm.compiler.nodes.calc.NarrowNode; 81 import org.graalvm.compiler.nodes.calc.ReinterpretNode; 82 import org.graalvm.compiler.nodes.calc.RightShiftNode; 83 import org.graalvm.compiler.nodes.calc.SignExtendNode; 84 import org.graalvm.compiler.nodes.calc.SqrtNode; 85 import org.graalvm.compiler.nodes.calc.UnsignedDivNode; 86 import org.graalvm.compiler.nodes.calc.UnsignedRemNode; 87 import org.graalvm.compiler.nodes.calc.ZeroExtendNode; 88 import org.graalvm.compiler.nodes.debug.BindToRegisterNode; 89 import org.graalvm.compiler.nodes.debug.BlackholeNode; 90 import org.graalvm.compiler.nodes.debug.ControlFlowAnchorNode; 91 import org.graalvm.compiler.nodes.debug.SpillRegistersNode; 92 import org.graalvm.compiler.nodes.extended.BoxNode; 93 import org.graalvm.compiler.nodes.extended.BranchProbabilityNode; 94 import org.graalvm.compiler.nodes.extended.BytecodeExceptionNode.BytecodeExceptionKind; 95 import org.graalvm.compiler.nodes.extended.GetClassNode; 96 import org.graalvm.compiler.nodes.extended.MembarNode; 97 import org.graalvm.compiler.nodes.extended.OpaqueNode; 98 import org.graalvm.compiler.nodes.extended.RawLoadNode; 99 import org.graalvm.compiler.nodes.extended.RawStoreNode; 100 import org.graalvm.compiler.nodes.extended.UnboxNode; 101 import org.graalvm.compiler.nodes.extended.UnsafeMemoryLoadNode; 102 import org.graalvm.compiler.nodes.extended.UnsafeMemoryStoreNode; 103 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; 104 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin; 105 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin.Receiver; 106 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins; 107 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration; 108 import org.graalvm.compiler.nodes.java.ClassIsAssignableFromNode; 109 import org.graalvm.compiler.nodes.java.DynamicNewArrayNode; 110 import org.graalvm.compiler.nodes.java.DynamicNewInstanceNode; 111 import org.graalvm.compiler.nodes.java.InstanceOfDynamicNode; 112 import org.graalvm.compiler.nodes.java.LoadFieldNode; 113 import org.graalvm.compiler.nodes.java.RegisterFinalizerNode; 114 import org.graalvm.compiler.nodes.java.UnsafeCompareAndExchangeNode; 115 import org.graalvm.compiler.nodes.java.UnsafeCompareAndSwapNode; 116 import org.graalvm.compiler.nodes.type.StampTool; 117 import org.graalvm.compiler.nodes.util.GraphUtil; 118 import org.graalvm.compiler.nodes.virtual.EnsureVirtualizedNode; 119 import org.graalvm.compiler.replacements.nodes.ProfileBooleanNode; 120 import org.graalvm.compiler.replacements.nodes.ReverseBytesNode; 121 import org.graalvm.compiler.replacements.nodes.VirtualizableInvokeMacroNode; 122 import org.graalvm.compiler.replacements.nodes.arithmetic.IntegerAddExactNode; 123 import org.graalvm.compiler.replacements.nodes.arithmetic.IntegerAddExactSplitNode; 124 import org.graalvm.compiler.replacements.nodes.arithmetic.IntegerExactArithmeticNode; 125 import org.graalvm.compiler.replacements.nodes.arithmetic.IntegerExactArithmeticSplitNode; 126 import org.graalvm.compiler.replacements.nodes.arithmetic.IntegerMulExactNode; 127 import org.graalvm.compiler.replacements.nodes.arithmetic.IntegerMulExactSplitNode; 128 import org.graalvm.compiler.replacements.nodes.arithmetic.IntegerSubExactNode; 129 import org.graalvm.compiler.replacements.nodes.arithmetic.IntegerSubExactSplitNode; 130 import jdk.internal.vm.compiler.word.LocationIdentity; 131 132 import jdk.vm.ci.code.BytecodePosition; 133 import jdk.vm.ci.meta.DeoptimizationAction; 134 import jdk.vm.ci.meta.DeoptimizationReason; 135 import jdk.vm.ci.meta.JavaConstant; 136 import jdk.vm.ci.meta.JavaKind; 137 import jdk.vm.ci.meta.MetaAccessProvider; 138 import jdk.vm.ci.meta.ResolvedJavaField; 139 import jdk.vm.ci.meta.ResolvedJavaMethod; 140 import jdk.vm.ci.meta.ResolvedJavaType; 141 import jdk.vm.ci.meta.SpeculationLog; 142 import jdk.vm.ci.meta.SpeculationLog.Speculation; 143 import jdk.vm.ci.meta.SpeculationLog.SpeculationReason; 144 import sun.misc.Unsafe; 145 146 /** 147 * Provides non-runtime specific {@link InvocationPlugin}s. 148 */ 149 public class StandardGraphBuilderPlugins { 150 registerInvocationPlugins(MetaAccessProvider metaAccess, SnippetReflectionProvider snippetReflection, InvocationPlugins plugins, BytecodeProvider bytecodeProvider, boolean allowDeoptimization, boolean explicitUnsafeNullChecks)151 public static void registerInvocationPlugins(MetaAccessProvider metaAccess, SnippetReflectionProvider snippetReflection, InvocationPlugins plugins, BytecodeProvider bytecodeProvider, 152 boolean allowDeoptimization, boolean explicitUnsafeNullChecks) { 153 registerObjectPlugins(plugins); 154 registerClassPlugins(plugins); 155 registerMathPlugins(plugins, allowDeoptimization); 156 registerStrictMathPlugins(plugins); 157 registerUnsignedMathPlugins(plugins); 158 registerStringPlugins(plugins, bytecodeProvider, snippetReflection); 159 registerCharacterPlugins(plugins); 160 registerShortPlugins(plugins); 161 registerIntegerLongPlugins(plugins, JavaKind.Int); 162 registerIntegerLongPlugins(plugins, JavaKind.Long); 163 registerFloatPlugins(plugins); 164 registerDoublePlugins(plugins); 165 registerArraysPlugins(plugins, bytecodeProvider); 166 registerArrayPlugins(plugins, bytecodeProvider); 167 registerUnsafePlugins(plugins, bytecodeProvider, explicitUnsafeNullChecks); 168 registerEdgesPlugins(metaAccess, plugins); 169 registerGraalDirectivesPlugins(plugins); 170 registerBoxingPlugins(plugins); 171 registerJMHBlackholePlugins(plugins, bytecodeProvider); 172 registerJFRThrowablePlugins(plugins, bytecodeProvider); 173 registerMethodHandleImplPlugins(plugins, snippetReflection, bytecodeProvider); 174 registerJcovCollectPlugins(plugins, bytecodeProvider); 175 } 176 177 private static final Field STRING_VALUE_FIELD; 178 private static final Field STRING_CODER_FIELD; 179 180 static { 181 Field coder = null; 182 try { 183 STRING_VALUE_FIELD = String.class.getDeclaredField("value"); 184 if (!Java8OrEarlier) { 185 coder = String.class.getDeclaredField("coder"); 186 } 187 } catch (NoSuchFieldException e) { 188 throw new GraalError(e); 189 } 190 STRING_CODER_FIELD = coder; 191 } 192 registerStringPlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider, SnippetReflectionProvider snippetReflection)193 private static void registerStringPlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider, SnippetReflectionProvider snippetReflection) { 194 final Registration r = new Registration(plugins, String.class, bytecodeProvider); 195 r.register1("hashCode", Receiver.class, new InvocationPlugin() { 196 @Override 197 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { 198 if (receiver.isConstant()) { 199 String s = snippetReflection.asObject(String.class, (JavaConstant) receiver.get().asConstant()); 200 b.addPush(JavaKind.Int, b.add(ConstantNode.forInt(s.hashCode()))); 201 return true; 202 } 203 return false; 204 } 205 }); 206 207 if (Java8OrEarlier) { 208 r.registerMethodSubstitution(StringSubstitutions.class, "equals", Receiver.class, Object.class); 209 210 r.register7("indexOf", char[].class, int.class, int.class, char[].class, int.class, int.class, int.class, new StringIndexOfConstantPlugin()); 211 212 Registration sr = new Registration(plugins, StringSubstitutions.class); 213 sr.register1("getValue", String.class, new InvocationPlugin() { 214 @Override 215 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { 216 ResolvedJavaField field = b.getMetaAccess().lookupJavaField(STRING_VALUE_FIELD); 217 b.addPush(JavaKind.Object, LoadFieldNode.create(b.getConstantFieldProvider(), b.getConstantReflection(), b.getMetaAccess(), 218 b.getOptions(), b.getAssumptions(), value, field, false, false)); 219 return true; 220 } 221 }); 222 } else { 223 r.registerMethodSubstitution(JDK9StringSubstitutions.class, "equals", Receiver.class, Object.class); 224 225 final Registration latin1r = new Registration(plugins, "java.lang.StringLatin1", bytecodeProvider); 226 latin1r.register5("indexOf", byte[].class, int.class, byte[].class, int.class, int.class, new StringLatin1IndexOfConstantPlugin()); 227 228 final Registration utf16r = new Registration(plugins, "java.lang.StringUTF16", bytecodeProvider); 229 utf16r.register5("indexOfUnsafe", byte[].class, int.class, byte[].class, int.class, int.class, new StringUTF16IndexOfConstantPlugin()); 230 231 Registration sr = new Registration(plugins, JDK9StringSubstitutions.class); 232 sr.register1("getValue", String.class, new InvocationPlugin() { 233 @Override 234 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { 235 ResolvedJavaField field = b.getMetaAccess().lookupJavaField(STRING_VALUE_FIELD); 236 b.addPush(JavaKind.Object, LoadFieldNode.create(b.getConstantFieldProvider(), b.getConstantReflection(), b.getMetaAccess(), 237 b.getOptions(), b.getAssumptions(), value, field, false, false)); 238 return true; 239 } 240 }); 241 sr.register1("getCoder", String.class, new InvocationPlugin() { 242 @Override 243 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { 244 ResolvedJavaField field = b.getMetaAccess().lookupJavaField(STRING_CODER_FIELD); 245 b.addPush(JavaKind.Int, LoadFieldNode.create(b.getConstantFieldProvider(), b.getConstantReflection(), b.getMetaAccess(), 246 b.getOptions(), b.getAssumptions(), value, field, false, false)); 247 return true; 248 } 249 }); 250 } 251 } 252 registerArraysPlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider)253 private static void registerArraysPlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider) { 254 Registration r = new Registration(plugins, Arrays.class, bytecodeProvider); 255 r.registerMethodSubstitution(ArraysSubstitutions.class, "equals", boolean[].class, boolean[].class); 256 r.registerMethodSubstitution(ArraysSubstitutions.class, "equals", byte[].class, byte[].class); 257 r.registerMethodSubstitution(ArraysSubstitutions.class, "equals", short[].class, short[].class); 258 r.registerMethodSubstitution(ArraysSubstitutions.class, "equals", char[].class, char[].class); 259 r.registerMethodSubstitution(ArraysSubstitutions.class, "equals", int[].class, int[].class); 260 r.registerMethodSubstitution(ArraysSubstitutions.class, "equals", long[].class, long[].class); 261 } 262 registerArrayPlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider)263 private static void registerArrayPlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider) { 264 Registration r = new Registration(plugins, Array.class, bytecodeProvider); 265 r.register2("newInstance", Class.class, int.class, new InvocationPlugin() { 266 @Override 267 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unused, ValueNode componentType, ValueNode length) { 268 b.addPush(JavaKind.Object, new DynamicNewArrayNode(componentType, length, true)); 269 return true; 270 } 271 }); 272 r.registerMethodSubstitution(ArraySubstitutions.class, "getLength", Object.class); 273 } 274 275 /** 276 * The intrinsic for {@link Math#sqrt(double)} is shared with {@link StrictMath#sqrt(double)}. 277 * 278 * @see "http://hg.openjdk.java.net/jdk/jdk/file/621efe32eb0b/src/hotspot/share/oops/method.cpp#l1504" 279 */ 280 static final class MathSqrtPlugin implements InvocationPlugin { 281 @Override apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value)282 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { 283 b.push(JavaKind.Double, b.append(SqrtNode.create(value, NodeView.DEFAULT))); 284 return true; 285 } 286 } 287 288 private abstract static class UnsafeCompareAndUpdatePluginsRegistrar { register(Registration r, String casPrefix, boolean explicitUnsafeNullChecks, JavaKind[] compareAndSwapTypes, boolean java11OrEarlier)289 public void register(Registration r, String casPrefix, boolean explicitUnsafeNullChecks, JavaKind[] compareAndSwapTypes, boolean java11OrEarlier) { 290 for (JavaKind kind : compareAndSwapTypes) { 291 Class<?> javaClass = kind == JavaKind.Object ? Object.class : kind.toJavaClass(); 292 String kindName = (kind == JavaKind.Object && !java11OrEarlier) ? "Reference" : kind.name(); 293 r.register5(casPrefix + kindName, Receiver.class, Object.class, long.class, javaClass, javaClass, new UnsafeAccessPlugin(returnKind(kind), explicitUnsafeNullChecks) { 294 @Override 295 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode object, ValueNode offset, ValueNode expected, ValueNode x) { 296 // Emits a null-check for the otherwise unused receiver 297 unsafe.get(); 298 createUnsafeAccess(object, b, (obj, loc) -> UnsafeCompareAndUpdatePluginsRegistrar.this.createNode(obj, offset, expected, x, kind, loc)); 299 return true; 300 } 301 }); 302 } 303 } 304 createNode(ValueNode object, ValueNode offset, ValueNode expected, ValueNode newValue, JavaKind kind, LocationIdentity identity)305 public abstract FixedWithNextNode createNode(ValueNode object, ValueNode offset, ValueNode expected, ValueNode newValue, JavaKind kind, LocationIdentity identity); 306 returnKind(JavaKind accessKind)307 public abstract JavaKind returnKind(JavaKind accessKind); 308 } 309 310 private static class UnsafeCompareAndSwapPluginsRegistrar extends UnsafeCompareAndUpdatePluginsRegistrar { 311 @Override createNode(ValueNode object, ValueNode offset, ValueNode expected, ValueNode newValue, JavaKind kind, LocationIdentity identity)312 public FixedWithNextNode createNode(ValueNode object, ValueNode offset, ValueNode expected, ValueNode newValue, JavaKind kind, LocationIdentity identity) { 313 return new UnsafeCompareAndSwapNode(object, offset, expected, newValue, kind, identity); 314 } 315 316 @Override returnKind(JavaKind accessKind)317 public JavaKind returnKind(JavaKind accessKind) { 318 return JavaKind.Boolean.getStackKind(); 319 } 320 } 321 322 private static UnsafeCompareAndSwapPluginsRegistrar unsafeCompareAndSwapPluginsRegistrar = new UnsafeCompareAndSwapPluginsRegistrar(); 323 324 private static class UnsafeCompareAndExchangePluginsRegistrar extends UnsafeCompareAndUpdatePluginsRegistrar { 325 @Override createNode(ValueNode object, ValueNode offset, ValueNode expected, ValueNode newValue, JavaKind kind, LocationIdentity identity)326 public FixedWithNextNode createNode(ValueNode object, ValueNode offset, ValueNode expected, ValueNode newValue, JavaKind kind, LocationIdentity identity) { 327 return new UnsafeCompareAndExchangeNode(object, offset, expected, newValue, kind, identity); 328 } 329 330 @Override returnKind(JavaKind accessKind)331 public JavaKind returnKind(JavaKind accessKind) { 332 if (accessKind.isNumericInteger()) { 333 return accessKind.getStackKind(); 334 } else { 335 return accessKind; 336 } 337 } 338 } 339 340 private static UnsafeCompareAndExchangePluginsRegistrar unsafeCompareAndExchangePluginsRegistrar = new UnsafeCompareAndExchangePluginsRegistrar(); 341 registerPlatformSpecificUnsafePlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider, boolean explicitUnsafeNullChecks, JavaKind[] supportedCasKinds)342 public static void registerPlatformSpecificUnsafePlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider, boolean explicitUnsafeNullChecks, JavaKind[] supportedCasKinds) { 343 registerPlatformSpecificUnsafePlugins(supportedCasKinds, new Registration(plugins, Unsafe.class), true, explicitUnsafeNullChecks); 344 if (!Java8OrEarlier) { 345 registerPlatformSpecificUnsafePlugins(supportedCasKinds, new Registration(plugins, "jdk.internal.misc.Unsafe", bytecodeProvider), false, explicitUnsafeNullChecks); 346 } 347 348 } 349 registerPlatformSpecificUnsafePlugins(JavaKind[] supportedCasKinds, Registration r, boolean java8OrEarlier, boolean explicitUnsafeNullChecks)350 private static void registerPlatformSpecificUnsafePlugins(JavaKind[] supportedCasKinds, Registration r, boolean java8OrEarlier, boolean explicitUnsafeNullChecks) { 351 if (java8OrEarlier) { 352 unsafeCompareAndSwapPluginsRegistrar.register(r, "compareAndSwap", explicitUnsafeNullChecks, new JavaKind[]{JavaKind.Int, JavaKind.Long, JavaKind.Object}, true); 353 } else { 354 unsafeCompareAndSwapPluginsRegistrar.register(r, "compareAndSet", explicitUnsafeNullChecks, supportedCasKinds, Java11OrEarlier); 355 unsafeCompareAndExchangePluginsRegistrar.register(r, "compareAndExchange", explicitUnsafeNullChecks, supportedCasKinds, Java11OrEarlier); 356 } 357 } 358 registerUnsafePlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider, boolean explicitUnsafeNullChecks)359 private static void registerUnsafePlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider, boolean explicitUnsafeNullChecks) { 360 registerUnsafePlugins(new Registration(plugins, Unsafe.class), true, explicitUnsafeNullChecks); 361 if (!Java8OrEarlier) { 362 registerUnsafePlugins(new Registration(plugins, "jdk.internal.misc.Unsafe", bytecodeProvider), false, explicitUnsafeNullChecks); 363 } 364 } 365 registerUnsafePlugins(Registration r, boolean sunMiscUnsafe, boolean explicitUnsafeNullChecks)366 private static void registerUnsafePlugins(Registration r, boolean sunMiscUnsafe, boolean explicitUnsafeNullChecks) { 367 for (JavaKind kind : JavaKind.values()) { 368 if ((kind.isPrimitive() && kind != JavaKind.Void) || kind == JavaKind.Object) { 369 Class<?> javaClass = kind == JavaKind.Object ? Object.class : kind.toJavaClass(); 370 String kindName = (kind == JavaKind.Object && !sunMiscUnsafe && !Java11OrEarlier) ? "Reference" : kind.name(); 371 String getName = "get" + kindName; 372 String putName = "put" + kindName; 373 // Object-based accesses 374 r.register3(getName, Receiver.class, Object.class, long.class, new UnsafeGetPlugin(kind, explicitUnsafeNullChecks)); 375 r.register4(putName, Receiver.class, Object.class, long.class, javaClass, new UnsafePutPlugin(kind, explicitUnsafeNullChecks)); 376 // Volatile object-based accesses 377 r.register3(getName + "Volatile", Receiver.class, Object.class, long.class, new UnsafeGetPlugin(kind, AccessKind.VOLATILE, explicitUnsafeNullChecks)); 378 r.register4(putName + "Volatile", Receiver.class, Object.class, long.class, javaClass, new UnsafePutPlugin(kind, AccessKind.VOLATILE, explicitUnsafeNullChecks)); 379 // Ordered object-based accesses 380 if (sunMiscUnsafe) { 381 if (kind == JavaKind.Int || kind == JavaKind.Long || kind == JavaKind.Object) { 382 r.register4("putOrdered" + kindName, Receiver.class, Object.class, long.class, javaClass, new UnsafePutPlugin(kind, AccessKind.RELEASE_ACQUIRE, explicitUnsafeNullChecks)); 383 } 384 } else { 385 r.register4("put" + kindName + "Release", Receiver.class, Object.class, long.class, javaClass, new UnsafePutPlugin(kind, AccessKind.RELEASE_ACQUIRE, explicitUnsafeNullChecks)); 386 r.register3("get" + kindName + "Acquire", Receiver.class, Object.class, long.class, new UnsafeGetPlugin(kind, AccessKind.RELEASE_ACQUIRE, explicitUnsafeNullChecks)); 387 r.register4("put" + kindName + "Opaque", Receiver.class, Object.class, long.class, javaClass, new UnsafePutPlugin(kind, AccessKind.OPAQUE, explicitUnsafeNullChecks)); 388 r.register3("get" + kindName + "Opaque", Receiver.class, Object.class, long.class, new UnsafeGetPlugin(kind, AccessKind.OPAQUE, explicitUnsafeNullChecks)); 389 } 390 if (kind != JavaKind.Boolean && kind != JavaKind.Object) { 391 // Raw accesses to memory addresses 392 r.register2(getName, Receiver.class, long.class, new UnsafeGetPlugin(kind, explicitUnsafeNullChecks)); 393 r.register3(putName, Receiver.class, long.class, kind.toJavaClass(), new UnsafePutPlugin(kind, explicitUnsafeNullChecks)); 394 } 395 } 396 } 397 398 // Accesses to native memory addresses. 399 r.register2("getAddress", Receiver.class, long.class, new UnsafeGetPlugin(JavaKind.Long, explicitUnsafeNullChecks)); 400 r.register3("putAddress", Receiver.class, long.class, long.class, new UnsafePutPlugin(JavaKind.Long, explicitUnsafeNullChecks)); 401 402 r.register2("allocateInstance", Receiver.class, Class.class, new InvocationPlugin() { 403 404 @Override 405 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode clazz) { 406 // Emits a null-check for the otherwise unused receiver 407 unsafe.get(); 408 b.addPush(JavaKind.Object, new DynamicNewInstanceNode(b.nullCheckedValue(clazz, DeoptimizationAction.None), true)); 409 return true; 410 } 411 412 }); 413 414 r.register1("loadFence", Receiver.class, new UnsafeFencePlugin(LOAD_LOAD | LOAD_STORE)); 415 r.register1("storeFence", Receiver.class, new UnsafeFencePlugin(STORE_STORE | LOAD_STORE)); 416 r.register1("fullFence", Receiver.class, new UnsafeFencePlugin(LOAD_LOAD | STORE_STORE | LOAD_STORE | STORE_LOAD)); 417 } 418 registerIntegerLongPlugins(InvocationPlugins plugins, JavaKind kind)419 private static void registerIntegerLongPlugins(InvocationPlugins plugins, JavaKind kind) { 420 Class<?> declaringClass = kind.toBoxedJavaClass(); 421 Class<?> type = kind.toJavaClass(); 422 Registration r = new Registration(plugins, declaringClass); 423 r.register1("reverseBytes", type, new InvocationPlugin() { 424 @Override 425 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { 426 b.push(kind, b.append(new ReverseBytesNode(value).canonical(null))); 427 return true; 428 } 429 }); 430 r.register2("divideUnsigned", type, type, new InvocationPlugin() { 431 @Override 432 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode dividend, ValueNode divisor) { 433 b.push(kind, b.append(UnsignedDivNode.create(dividend, divisor, null, NodeView.DEFAULT))); 434 return true; 435 } 436 }); 437 r.register2("remainderUnsigned", type, type, new InvocationPlugin() { 438 @Override 439 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode dividend, ValueNode divisor) { 440 b.push(kind, b.append(UnsignedRemNode.create(dividend, divisor, null, NodeView.DEFAULT))); 441 return true; 442 } 443 }); 444 } 445 registerCharacterPlugins(InvocationPlugins plugins)446 private static void registerCharacterPlugins(InvocationPlugins plugins) { 447 Registration r = new Registration(plugins, Character.class); 448 r.register1("reverseBytes", char.class, new InvocationPlugin() { 449 @Override 450 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { 451 // return (char) (Integer.reverse(i) >> 16); 452 ReverseBytesNode reverse = b.add(new ReverseBytesNode(value)); 453 RightShiftNode rightShift = b.add(new RightShiftNode(reverse, b.add(ConstantNode.forInt(16)))); 454 ZeroExtendNode charCast = b.add(new ZeroExtendNode(b.add(new NarrowNode(rightShift, 16)), 32)); 455 b.push(JavaKind.Char, b.append(charCast.canonical(null))); 456 return true; 457 } 458 }); 459 } 460 registerShortPlugins(InvocationPlugins plugins)461 private static void registerShortPlugins(InvocationPlugins plugins) { 462 Registration r = new Registration(plugins, Short.class); 463 r.register1("reverseBytes", short.class, new InvocationPlugin() { 464 @Override 465 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { 466 // return (short) (Integer.reverse(i) >> 16); 467 ReverseBytesNode reverse = b.add(new ReverseBytesNode(value)); 468 RightShiftNode rightShift = b.add(new RightShiftNode(reverse, b.add(ConstantNode.forInt(16)))); 469 SignExtendNode charCast = b.add(new SignExtendNode(b.add(new NarrowNode(rightShift, 16)), 32)); 470 b.push(JavaKind.Short, b.append(charCast.canonical(null))); 471 return true; 472 } 473 }); 474 } 475 registerFloatPlugins(InvocationPlugins plugins)476 private static void registerFloatPlugins(InvocationPlugins plugins) { 477 Registration r = new Registration(plugins, Float.class); 478 r.register1("floatToRawIntBits", float.class, new InvocationPlugin() { 479 @Override 480 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { 481 b.push(JavaKind.Int, b.append(ReinterpretNode.create(JavaKind.Int, value, NodeView.DEFAULT))); 482 return true; 483 } 484 }); 485 r.register1("floatToIntBits", float.class, new InvocationPlugin() { 486 @Override 487 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { 488 LogicNode notNan = b.append(FloatEqualsNode.create(value, value, NodeView.DEFAULT)); 489 ValueNode raw = b.append(ReinterpretNode.create(JavaKind.Int, value, NodeView.DEFAULT)); 490 ValueNode result = b.append(ConditionalNode.create(notNan, raw, ConstantNode.forInt(0x7fc00000), NodeView.DEFAULT)); 491 b.push(JavaKind.Int, result); 492 return true; 493 } 494 }); 495 r.register1("intBitsToFloat", int.class, new InvocationPlugin() { 496 @Override 497 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { 498 b.push(JavaKind.Float, b.append(ReinterpretNode.create(JavaKind.Float, value, NodeView.DEFAULT))); 499 return true; 500 } 501 }); 502 } 503 registerDoublePlugins(InvocationPlugins plugins)504 private static void registerDoublePlugins(InvocationPlugins plugins) { 505 Registration r = new Registration(plugins, Double.class); 506 r.register1("doubleToRawLongBits", double.class, new InvocationPlugin() { 507 @Override 508 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { 509 b.push(JavaKind.Long, b.append(ReinterpretNode.create(JavaKind.Long, value, NodeView.DEFAULT))); 510 return true; 511 } 512 }); 513 r.register1("doubleToLongBits", double.class, new InvocationPlugin() { 514 @Override 515 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { 516 LogicNode notNan = b.append(FloatEqualsNode.create(value, value, NodeView.DEFAULT)); 517 ValueNode raw = b.append(ReinterpretNode.create(JavaKind.Long, value, NodeView.DEFAULT)); 518 ValueNode result = b.append(ConditionalNode.create(notNan, raw, ConstantNode.forLong(0x7ff8000000000000L), NodeView.DEFAULT)); 519 b.push(JavaKind.Long, result); 520 return true; 521 } 522 }); 523 r.register1("longBitsToDouble", long.class, new InvocationPlugin() { 524 @Override 525 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { 526 b.push(JavaKind.Double, b.append(ReinterpretNode.create(JavaKind.Double, value, NodeView.DEFAULT))); 527 return true; 528 } 529 }); 530 } 531 createIntegerExactArithmeticNode(ValueNode x, ValueNode y, SpeculationReason speculation, IntegerExactOp op)532 private static ValueNode createIntegerExactArithmeticNode(ValueNode x, ValueNode y, SpeculationReason speculation, IntegerExactOp op) { 533 switch (op) { 534 case INTEGER_ADD_EXACT: 535 case INTEGER_INCREMENT_EXACT: 536 return new IntegerAddExactNode(x, y, speculation); 537 case INTEGER_SUBTRACT_EXACT: 538 case INTEGER_DECREMENT_EXACT: 539 return new IntegerSubExactNode(x, y, speculation); 540 case INTEGER_MULTIPLY_EXACT: 541 return new IntegerMulExactNode(x, y, speculation); 542 default: 543 throw GraalError.shouldNotReachHere("Unknown integer exact operation."); 544 } 545 } 546 createIntegerExactSplit(ValueNode x, ValueNode y, AbstractBeginNode exceptionEdge, IntegerExactOp op)547 private static IntegerExactArithmeticSplitNode createIntegerExactSplit(ValueNode x, ValueNode y, AbstractBeginNode exceptionEdge, IntegerExactOp op) { 548 switch (op) { 549 case INTEGER_ADD_EXACT: 550 case INTEGER_INCREMENT_EXACT: 551 return new IntegerAddExactSplitNode(x.stamp(NodeView.DEFAULT).unrestricted(), x, y, null, exceptionEdge); 552 case INTEGER_SUBTRACT_EXACT: 553 case INTEGER_DECREMENT_EXACT: 554 return new IntegerSubExactSplitNode(x.stamp(NodeView.DEFAULT).unrestricted(), x, y, null, exceptionEdge); 555 case INTEGER_MULTIPLY_EXACT: 556 return new IntegerMulExactSplitNode(x.stamp(NodeView.DEFAULT).unrestricted(), x, y, null, exceptionEdge); 557 default: 558 throw GraalError.shouldNotReachHere("Unknown integer exact operation."); 559 } 560 } 561 createIntegerExactOperation(GraphBuilderContext b, JavaKind kind, ValueNode x, ValueNode y, IntegerExactOp op)562 private static boolean createIntegerExactOperation(GraphBuilderContext b, JavaKind kind, ValueNode x, ValueNode y, IntegerExactOp op) { 563 BytecodeExceptionKind exceptionKind = kind == JavaKind.Int ? BytecodeExceptionKind.INTEGER_EXACT_OVERFLOW : BytecodeExceptionKind.LONG_EXACT_OVERFLOW; 564 AbstractBeginNode exceptionEdge = b.genExplicitExceptionEdge(exceptionKind); 565 if (exceptionEdge != null) { 566 IntegerExactArithmeticSplitNode split = b.addPush(kind, createIntegerExactSplit(x, y, exceptionEdge, op)); 567 split.setNext(b.add(new BeginNode())); 568 return true; 569 } 570 return false; 571 } 572 registerMathPlugins(InvocationPlugins plugins, boolean allowDeoptimization)573 private static void registerMathPlugins(InvocationPlugins plugins, boolean allowDeoptimization) { 574 Registration r = new Registration(plugins, Math.class); 575 if (allowDeoptimization) { 576 for (JavaKind kind : new JavaKind[]{JavaKind.Int, JavaKind.Long}) { 577 Class<?> type = kind.toJavaClass(); 578 579 r.register1("decrementExact", type, new InvocationPlugin() { 580 @Override 581 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x) { 582 ConstantNode y = b.add(ConstantNode.forIntegerKind(kind, 1)); 583 return createIntegerExactOperation(b, kind, x, y, IntegerExactOp.INTEGER_DECREMENT_EXACT); 584 } 585 }); 586 587 r.register1("incrementExact", type, new InvocationPlugin() { 588 @Override 589 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x) { 590 ConstantNode y = b.add(ConstantNode.forIntegerKind(kind, 1)); 591 return createIntegerExactOperation(b, kind, x, y, IntegerExactOp.INTEGER_INCREMENT_EXACT); 592 } 593 }); 594 595 r.register2("addExact", type, type, new InvocationPlugin() { 596 @Override 597 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) { 598 return createIntegerExactOperation(b, kind, x, y, IntegerExactOp.INTEGER_ADD_EXACT); 599 } 600 }); 601 602 r.register2("subtractExact", type, type, new InvocationPlugin() { 603 @Override 604 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) { 605 return createIntegerExactOperation(b, kind, x, y, IntegerExactOp.INTEGER_SUBTRACT_EXACT); 606 } 607 }); 608 609 r.register2("multiplyExact", type, type, new InvocationPlugin() { 610 @Override 611 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) { 612 return createIntegerExactOperation(b, kind, x, y, IntegerExactOp.INTEGER_MULTIPLY_EXACT); 613 } 614 }); 615 } 616 } 617 r.register1("abs", Float.TYPE, new InvocationPlugin() { 618 619 @Override 620 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { 621 b.push(JavaKind.Float, b.append(new AbsNode(value).canonical(null))); 622 return true; 623 } 624 }); 625 r.register1("abs", Double.TYPE, new InvocationPlugin() { 626 @Override 627 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { 628 b.push(JavaKind.Double, b.append(new AbsNode(value).canonical(null))); 629 return true; 630 } 631 }); 632 r.register1("sqrt", Double.TYPE, new MathSqrtPlugin()); 633 } 634 registerStrictMathPlugins(InvocationPlugins plugins)635 private static void registerStrictMathPlugins(InvocationPlugins plugins) { 636 Registration r = new Registration(plugins, StrictMath.class); 637 r.register1("sqrt", Double.TYPE, new MathSqrtPlugin()); 638 } 639 640 public static final class StringIndexOfConstantPlugin implements InvocationPlugin { 641 @Override inlineOnly()642 public boolean inlineOnly() { 643 return true; 644 } 645 646 @Override apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode source, ValueNode sourceOffset, ValueNode sourceCount, ValueNode target, ValueNode targetOffset, ValueNode targetCount, ValueNode origFromIndex)647 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode source, ValueNode sourceOffset, ValueNode sourceCount, 648 ValueNode target, ValueNode targetOffset, ValueNode targetCount, ValueNode origFromIndex) { 649 if (target.isConstant()) { 650 b.addPush(JavaKind.Int, new StringIndexOfNode(b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnStamp(b.getAssumptions()), source, sourceOffset, sourceCount, 651 target, targetOffset, targetCount, origFromIndex)); 652 return true; 653 } 654 return false; 655 } 656 } 657 658 public static final class StringLatin1IndexOfConstantPlugin implements InvocationPlugin { 659 @Override inlineOnly()660 public boolean inlineOnly() { 661 return true; 662 } 663 664 @Override apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode source, ValueNode sourceCount, ValueNode target, ValueNode targetCount, ValueNode origFromIndex)665 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, 666 ValueNode source, ValueNode sourceCount, ValueNode target, ValueNode targetCount, ValueNode origFromIndex) { 667 if (target.isConstant()) { 668 b.addPush(JavaKind.Int, new StringLatin1IndexOfNode(b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnStamp(b.getAssumptions()), 669 source, sourceCount, target, targetCount, origFromIndex)); 670 return true; 671 } 672 return false; 673 } 674 } 675 676 public static final class StringUTF16IndexOfConstantPlugin implements InvocationPlugin { 677 @Override inlineOnly()678 public boolean inlineOnly() { 679 return true; 680 } 681 682 @Override apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode source, ValueNode sourceCount, ValueNode target, ValueNode targetCount, ValueNode origFromIndex)683 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, 684 ValueNode source, ValueNode sourceCount, ValueNode target, ValueNode targetCount, ValueNode origFromIndex) { 685 if (target.isConstant()) { 686 b.addPush(JavaKind.Int, new StringUTF16IndexOfNode(b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnStamp(b.getAssumptions()), 687 source, sourceCount, target, targetCount, origFromIndex)); 688 return true; 689 } 690 return false; 691 } 692 } 693 694 public static class UnsignedMathPlugin implements InvocationPlugin { 695 private final Condition condition; 696 UnsignedMathPlugin(Condition condition)697 public UnsignedMathPlugin(Condition condition) { 698 this.condition = condition; 699 } 700 701 @Override apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y)702 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) { 703 CanonicalizedCondition canonical = condition.canonicalize(); 704 StructuredGraph graph = b.getGraph(); 705 706 ValueNode lhs = canonical.mustMirror() ? y : x; 707 ValueNode rhs = canonical.mustMirror() ? x : y; 708 709 ValueNode trueValue = ConstantNode.forBoolean(!canonical.mustNegate(), graph); 710 ValueNode falseValue = ConstantNode.forBoolean(canonical.mustNegate(), graph); 711 712 LogicNode compare = CompareNode.createCompareNode(graph, b.getConstantReflection(), b.getMetaAccess(), b.getOptions(), null, canonical.getCanonicalCondition(), lhs, rhs, NodeView.DEFAULT); 713 b.addPush(JavaKind.Boolean, new ConditionalNode(compare, trueValue, falseValue)); 714 return true; 715 } 716 } 717 registerUnsignedMathPlugins(InvocationPlugins plugins)718 private static void registerUnsignedMathPlugins(InvocationPlugins plugins) { 719 Registration r = new Registration(plugins, UnsignedMath.class); 720 r.register2("aboveThan", int.class, int.class, new UnsignedMathPlugin(Condition.AT)); 721 r.register2("aboveThan", long.class, long.class, new UnsignedMathPlugin(Condition.AT)); 722 r.register2("belowThan", int.class, int.class, new UnsignedMathPlugin(Condition.BT)); 723 r.register2("belowThan", long.class, long.class, new UnsignedMathPlugin(Condition.BT)); 724 r.register2("aboveOrEqual", int.class, int.class, new UnsignedMathPlugin(Condition.AE)); 725 r.register2("aboveOrEqual", long.class, long.class, new UnsignedMathPlugin(Condition.AE)); 726 r.register2("belowOrEqual", int.class, int.class, new UnsignedMathPlugin(Condition.BE)); 727 r.register2("belowOrEqual", long.class, long.class, new UnsignedMathPlugin(Condition.BE)); 728 } 729 registerBoxingPlugins(InvocationPlugins plugins)730 protected static void registerBoxingPlugins(InvocationPlugins plugins) { 731 for (JavaKind kind : JavaKind.values()) { 732 if (kind.isPrimitive() && kind != JavaKind.Void) { 733 new BoxPlugin(kind).register(plugins); 734 new UnboxPlugin(kind).register(plugins); 735 } 736 } 737 } 738 registerObjectPlugins(InvocationPlugins plugins)739 private static void registerObjectPlugins(InvocationPlugins plugins) { 740 Registration r = new Registration(plugins, Object.class); 741 r.register1("<init>", Receiver.class, new InvocationPlugin() { 742 @Override 743 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { 744 /* 745 * Object.<init> is a common instrumentation point so only perform this rewrite if 746 * the current definition is the normal empty method with a single return bytecode. 747 * The finalizer registration will instead be performed by the BytecodeParser. 748 */ 749 if (targetMethod.getCodeSize() == 1) { 750 ValueNode object = receiver.get(); 751 if (RegisterFinalizerNode.mayHaveFinalizer(object, b.getAssumptions())) { 752 b.add(new RegisterFinalizerNode(object)); 753 } 754 return true; 755 } 756 return false; 757 } 758 }); 759 r.register1("getClass", Receiver.class, new InvocationPlugin() { 760 @Override 761 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { 762 ValueNode object = receiver.get(); 763 ValueNode folded = GetClassNode.tryFold(b.getMetaAccess(), b.getConstantReflection(), NodeView.DEFAULT, GraphUtil.originalValue(object)); 764 if (folded != null) { 765 b.addPush(JavaKind.Object, folded); 766 } else { 767 Stamp stamp = StampFactory.objectNonNull(TypeReference.createTrusted(b.getAssumptions(), b.getMetaAccess().lookupJavaType(Class.class))); 768 b.addPush(JavaKind.Object, new GetClassNode(stamp, object)); 769 } 770 return true; 771 } 772 }); 773 } 774 registerClassPlugins(InvocationPlugins plugins)775 private static void registerClassPlugins(InvocationPlugins plugins) { 776 Registration r = new Registration(plugins, Class.class); 777 r.register2("isInstance", Receiver.class, Object.class, new InvocationPlugin() { 778 @Override 779 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver type, ValueNode object) { 780 LogicNode condition = b.append(InstanceOfDynamicNode.create(b.getAssumptions(), b.getConstantReflection(), type.get(), object, false)); 781 b.push(JavaKind.Boolean, b.append(new ConditionalNode(condition).canonical(null))); 782 return true; 783 } 784 }); 785 r.register2("isAssignableFrom", Receiver.class, Class.class, new InvocationPlugin() { 786 @Override 787 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver type, ValueNode otherType) { 788 ClassIsAssignableFromNode condition = b.append(new ClassIsAssignableFromNode(type.get(), otherType)); 789 b.push(JavaKind.Boolean, b.append(new ConditionalNode(condition).canonical(null))); 790 return true; 791 } 792 }); 793 794 r.register2("cast", Receiver.class, Object.class, new InvocationPlugin() { 795 @Override 796 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode object) { 797 b.genCheckcastDynamic(object, receiver.get()); 798 return true; 799 } 800 801 @Override 802 public boolean inlineOnly() { 803 return true; 804 } 805 }); 806 } 807 808 /** 809 * Substitutions for improving the performance of some critical methods in {@link Edges}. These 810 * substitutions improve the performance by forcing the relevant methods to be inlined 811 * (intrinsification being a special form of inlining) and removing a checked cast. 812 */ registerEdgesPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins)813 private static void registerEdgesPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) { 814 Registration r = new Registration(plugins, Edges.class); 815 for (Class<?> c : new Class<?>[]{Node.class, NodeList.class}) { 816 r.register2("get" + c.getSimpleName() + "Unsafe", Node.class, long.class, new InvocationPlugin() { 817 @Override 818 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode node, ValueNode offset) { 819 ObjectStamp stamp = StampFactory.object(TypeReference.createTrusted(b.getAssumptions(), metaAccess.lookupJavaType(c))); 820 RawLoadNode value = b.add(new RawLoadNode(stamp, node, offset, LocationIdentity.any(), JavaKind.Object)); 821 b.addPush(JavaKind.Object, value); 822 return true; 823 } 824 }); 825 r.register3("put" + c.getSimpleName() + "Unsafe", Node.class, long.class, c, new InvocationPlugin() { 826 @Override 827 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode node, ValueNode offset, ValueNode value) { 828 b.add(new RawStoreNode(node, offset, value, JavaKind.Object, LocationIdentity.any())); 829 return true; 830 } 831 }); 832 } 833 } 834 835 public static class BoxPlugin implements InvocationPlugin { 836 837 private final JavaKind kind; 838 BoxPlugin(JavaKind kind)839 BoxPlugin(JavaKind kind) { 840 this.kind = kind; 841 } 842 843 @Override apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value)844 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { 845 if (b.parsingIntrinsic()) { 846 ResolvedJavaMethod rootMethod = b.getGraph().method(); 847 if (b.getMetaAccess().lookupJavaType(BoxingSnippets.class).isAssignableFrom(rootMethod.getDeclaringClass())) { 848 // Disable invocation plugins for boxing snippets so that the 849 // original JDK methods are inlined 850 return false; 851 } 852 } 853 ResolvedJavaType resultType = b.getMetaAccess().lookupJavaType(kind.toBoxedJavaClass()); 854 b.addPush(JavaKind.Object, new BoxNode(value, resultType, kind)); 855 return true; 856 } 857 register(InvocationPlugins plugins)858 void register(InvocationPlugins plugins) { 859 plugins.register(this, kind.toBoxedJavaClass(), "valueOf", kind.toJavaClass()); 860 } 861 } 862 863 public static class UnboxPlugin implements InvocationPlugin { 864 865 private final JavaKind kind; 866 UnboxPlugin(JavaKind kind)867 UnboxPlugin(JavaKind kind) { 868 this.kind = kind; 869 } 870 871 @Override apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver)872 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { 873 if (b.parsingIntrinsic()) { 874 ResolvedJavaMethod rootMethod = b.getGraph().method(); 875 if (b.getMetaAccess().lookupJavaType(BoxingSnippets.class).isAssignableFrom(rootMethod.getDeclaringClass())) { 876 // Disable invocation plugins for unboxing snippets so that the 877 // original JDK methods are inlined 878 return false; 879 } 880 } 881 ValueNode valueNode = UnboxNode.create(b.getMetaAccess(), b.getConstantReflection(), receiver.get(), kind); 882 b.addPush(kind, valueNode); 883 return true; 884 } 885 register(InvocationPlugins plugins)886 void register(InvocationPlugins plugins) { 887 String name = kind.toJavaClass().getSimpleName() + "Value"; 888 plugins.register(this, kind.toBoxedJavaClass(), name, Receiver.class); 889 } 890 } 891 892 /** 893 * The new memory order modes (JDK9+) are defined with cumulative effect, from weakest to 894 * strongest: Plain, Opaque, Release/Acquire, and Volatile. The existing Plain and Volatile 895 * modes are defined compatibly with their pre-JDK 9 forms. Any guaranteed property of a weaker 896 * mode, plus more, holds for a stronger mode. (Conversely, implementations are allowed to use a 897 * stronger mode than requested for any access.) In JDK 9, these are provided without a full 898 * formal specification. 899 */ 900 enum AccessKind { 901 PLAIN(0, 0, 0, 0, false), 902 /** 903 * Opaque accesses are wrapped by dummy membars to avoid floating/hoisting, this is stronger 904 * than required since Opaque mode does not directly impose any ordering constraints with 905 * respect to other variables beyond Plain mode. 906 */ 907 OPAQUE(0, 0, 0, 0, true), 908 RELEASE_ACQUIRE(0, LOAD_LOAD | LOAD_STORE, LOAD_STORE | STORE_STORE, 0, true), 909 VOLATILE(JMM_PRE_VOLATILE_READ, JMM_POST_VOLATILE_READ, JMM_PRE_VOLATILE_WRITE, JMM_POST_VOLATILE_WRITE, true); 910 911 public final boolean emitBarriers; 912 public final int preReadBarriers; 913 public final int postReadBarriers; 914 public final int preWriteBarriers; 915 public final int postWriteBarriers; 916 AccessKind(int preReadBarriers, int postReadBarriers, int preWriteBarriers, int postWriteBarriers, boolean emitBarriers)917 AccessKind(int preReadBarriers, int postReadBarriers, int preWriteBarriers, int postWriteBarriers, boolean emitBarriers) { 918 this.emitBarriers = emitBarriers; 919 this.preReadBarriers = preReadBarriers; 920 this.postReadBarriers = postReadBarriers; 921 this.preWriteBarriers = preWriteBarriers; 922 this.postWriteBarriers = postWriteBarriers; 923 } 924 } 925 926 /** 927 * Unsafe access relative to null object is an access to off-heap memory. As linear pointer 928 * compression uses non-zero null, here null object must be replaced with zero constant. 929 */ 930 public abstract static class UnsafeAccessPlugin implements InvocationPlugin { 931 @FunctionalInterface 932 public interface UnsafeNodeConstructor { create(ValueNode value, LocationIdentity location)933 FixedWithNextNode create(ValueNode value, LocationIdentity location); 934 } 935 936 protected final JavaKind unsafeAccessKind; 937 private final boolean explicitUnsafeNullChecks; 938 UnsafeAccessPlugin(JavaKind kind, boolean explicitUnsafeNullChecks)939 public UnsafeAccessPlugin(JavaKind kind, boolean explicitUnsafeNullChecks) { 940 unsafeAccessKind = kind; 941 this.explicitUnsafeNullChecks = explicitUnsafeNullChecks; 942 } 943 createObjectAccessNode(ValueNode value, UnsafeNodeConstructor nodeConstructor)944 private static FixedWithNextNode createObjectAccessNode(ValueNode value, UnsafeNodeConstructor nodeConstructor) { 945 return nodeConstructor.create(value, LocationIdentity.ANY_LOCATION); 946 } 947 createMemoryAccessNode(StructuredGraph graph, UnsafeNodeConstructor nodeConstructor)948 private static FixedWithNextNode createMemoryAccessNode(StructuredGraph graph, UnsafeNodeConstructor nodeConstructor) { 949 return nodeConstructor.create(ConstantNode.forLong(0L, graph), OFF_HEAP_LOCATION); 950 } 951 isLoad(ValueNode node)952 private static boolean isLoad(ValueNode node) { 953 return node.getStackKind() != JavaKind.Void; 954 } 955 setResult(ValueNode node, GraphBuilderContext b)956 private void setResult(ValueNode node, GraphBuilderContext b) { 957 if (isLoad(node)) { 958 b.addPush(unsafeAccessKind, node); 959 } else { 960 b.add(node); 961 } 962 } 963 createUnsafeAccess(ValueNode value, GraphBuilderContext b, UnsafeNodeConstructor nodeConstructor)964 protected final void createUnsafeAccess(ValueNode value, GraphBuilderContext b, UnsafeNodeConstructor nodeConstructor) { 965 StructuredGraph graph = b.getGraph(); 966 graph.markUnsafeAccess(); 967 /* For unsafe access object pointers can only be stored in the heap */ 968 if (unsafeAccessKind == JavaKind.Object) { 969 setResult(createObjectAccessNode(value, nodeConstructor), b); 970 } else if (StampTool.isPointerAlwaysNull(value)) { 971 setResult(createMemoryAccessNode(graph, nodeConstructor), b); 972 } else if (!explicitUnsafeNullChecks || StampTool.isPointerNonNull(value)) { 973 setResult(createObjectAccessNode(value, nodeConstructor), b); 974 } else { 975 FixedWithNextNode objectAccess = graph.add(createObjectAccessNode(value, nodeConstructor)); 976 FixedWithNextNode memoryAccess = graph.add(createMemoryAccessNode(graph, nodeConstructor)); 977 FixedWithNextNode[] accessNodes = new FixedWithNextNode[]{objectAccess, memoryAccess}; 978 979 LogicNode condition = graph.addOrUniqueWithInputs(IsNullNode.create(value)); 980 b.add(new IfNode(condition, memoryAccess, objectAccess, 0.5)); 981 982 MergeNode merge = b.append(new MergeNode()); 983 for (FixedWithNextNode node : accessNodes) { 984 EndNode endNode = graph.add(new EndNode()); 985 node.setNext(endNode); 986 if (node instanceof StateSplit) { 987 if (isLoad(node)) { 988 /* 989 * Temporarily push the access node so that the frame state has the node 990 * on the expression stack. 991 */ 992 b.push(unsafeAccessKind, node); 993 } 994 b.setStateAfter((StateSplit) node); 995 if (isLoad(node)) { 996 ValueNode popped = b.pop(unsafeAccessKind); 997 assert popped == node; 998 } 999 } 1000 merge.addForwardEnd(endNode); 1001 } 1002 1003 if (isLoad(objectAccess)) { 1004 ValuePhiNode phi = new ValuePhiNode(objectAccess.stamp(NodeView.DEFAULT), merge, accessNodes); 1005 b.push(unsafeAccessKind, graph.addOrUnique(phi)); 1006 } 1007 b.setStateAfter(merge); 1008 } 1009 } 1010 } 1011 1012 public static class UnsafeGetPlugin extends UnsafeAccessPlugin { 1013 private final AccessKind accessKind; 1014 UnsafeGetPlugin(JavaKind returnKind, boolean explicitUnsafeNullChecks)1015 public UnsafeGetPlugin(JavaKind returnKind, boolean explicitUnsafeNullChecks) { 1016 this(returnKind, AccessKind.PLAIN, explicitUnsafeNullChecks); 1017 } 1018 UnsafeGetPlugin(JavaKind kind, AccessKind accessKind, boolean explicitUnsafeNullChecks)1019 public UnsafeGetPlugin(JavaKind kind, AccessKind accessKind, boolean explicitUnsafeNullChecks) { 1020 super(kind, explicitUnsafeNullChecks); 1021 this.accessKind = accessKind; 1022 } 1023 1024 @Override apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode address)1025 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode address) { 1026 // Emits a null-check for the otherwise unused receiver 1027 unsafe.get(); 1028 b.addPush(unsafeAccessKind, new UnsafeMemoryLoadNode(address, unsafeAccessKind, OFF_HEAP_LOCATION)); 1029 b.getGraph().markUnsafeAccess(); 1030 return true; 1031 } 1032 1033 @Override apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode object, ValueNode offset)1034 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode object, ValueNode offset) { 1035 // Emits a null-check for the otherwise unused receiver 1036 unsafe.get(); 1037 if (accessKind.emitBarriers) { 1038 b.add(new MembarNode(accessKind.preReadBarriers)); 1039 } 1040 createUnsafeAccess(object, b, (obj, loc) -> new RawLoadNode(obj, offset, unsafeAccessKind, loc)); 1041 if (accessKind.emitBarriers) { 1042 b.add(new MembarNode(accessKind.postReadBarriers)); 1043 } 1044 return true; 1045 } 1046 } 1047 1048 public static class UnsafePutPlugin extends UnsafeAccessPlugin { 1049 private final AccessKind accessKind; 1050 UnsafePutPlugin(JavaKind kind, boolean explicitUnsafeNullChecks)1051 public UnsafePutPlugin(JavaKind kind, boolean explicitUnsafeNullChecks) { 1052 this(kind, AccessKind.PLAIN, explicitUnsafeNullChecks); 1053 } 1054 UnsafePutPlugin(JavaKind kind, AccessKind accessKind, boolean explicitUnsafeNullChecks)1055 private UnsafePutPlugin(JavaKind kind, AccessKind accessKind, boolean explicitUnsafeNullChecks) { 1056 super(kind, explicitUnsafeNullChecks); 1057 this.accessKind = accessKind; 1058 } 1059 1060 @Override apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode address, ValueNode value)1061 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode address, ValueNode value) { 1062 assert !accessKind.emitBarriers : "Barriers for address based Unsafe put is not supported."; 1063 // Emits a null-check for the otherwise unused receiver 1064 unsafe.get(); 1065 b.add(new UnsafeMemoryStoreNode(address, value, unsafeAccessKind, OFF_HEAP_LOCATION)); 1066 b.getGraph().markUnsafeAccess(); 1067 return true; 1068 } 1069 1070 @Override apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode object, ValueNode offset, ValueNode value)1071 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode object, ValueNode offset, ValueNode value) { 1072 // Emits a null-check for the otherwise unused receiver 1073 unsafe.get(); 1074 if (accessKind.emitBarriers) { 1075 b.add(new MembarNode(accessKind.preWriteBarriers)); 1076 } 1077 ValueNode maskedValue = b.maskSubWordValue(value, unsafeAccessKind); 1078 createUnsafeAccess(object, b, (obj, loc) -> new RawStoreNode(obj, offset, maskedValue, unsafeAccessKind, loc)); 1079 if (accessKind.emitBarriers) { 1080 b.add(new MembarNode(accessKind.postWriteBarriers)); 1081 } 1082 return true; 1083 } 1084 } 1085 1086 public static class UnsafeFencePlugin implements InvocationPlugin { 1087 1088 private final int barriers; 1089 UnsafeFencePlugin(int barriers)1090 public UnsafeFencePlugin(int barriers) { 1091 this.barriers = barriers; 1092 } 1093 1094 @Override apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe)1095 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe) { 1096 // Emits a null-check for the otherwise unused receiver 1097 unsafe.get(); 1098 b.add(new MembarNode(barriers)); 1099 return true; 1100 } 1101 } 1102 1103 private static final class DirectiveSpeculationReason implements SpeculationLog.SpeculationReason { 1104 private final BytecodePosition pos; 1105 DirectiveSpeculationReason(BytecodePosition pos)1106 private DirectiveSpeculationReason(BytecodePosition pos) { 1107 this.pos = pos; 1108 } 1109 1110 @Override hashCode()1111 public int hashCode() { 1112 return pos.hashCode(); 1113 } 1114 1115 @Override equals(Object obj)1116 public boolean equals(Object obj) { 1117 return obj instanceof DirectiveSpeculationReason && ((DirectiveSpeculationReason) obj).pos.equals(this.pos); 1118 } 1119 } 1120 registerGraalDirectivesPlugins(InvocationPlugins plugins)1121 private static void registerGraalDirectivesPlugins(InvocationPlugins plugins) { 1122 Registration r = new Registration(plugins, GraalDirectives.class); 1123 r.register0("deoptimize", new InvocationPlugin() { 1124 @Override 1125 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { 1126 b.add(new DeoptimizeNode(DeoptimizationAction.None, DeoptimizationReason.TransferToInterpreter)); 1127 return true; 1128 } 1129 }); 1130 1131 r.register0("deoptimizeAndInvalidate", new InvocationPlugin() { 1132 @Override 1133 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { 1134 b.add(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TransferToInterpreter)); 1135 return true; 1136 } 1137 }); 1138 1139 r.register0("deoptimizeAndInvalidateWithSpeculation", new InvocationPlugin() { 1140 @Override 1141 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { 1142 GraalError.guarantee(b.getGraph().getSpeculationLog() != null, "A speculation log is need to use `deoptimizeAndInvalidateWithSpeculation`"); 1143 BytecodePosition pos = new BytecodePosition(null, b.getMethod(), b.bci()); 1144 DirectiveSpeculationReason reason = new DirectiveSpeculationReason(pos); 1145 Speculation speculation; 1146 if (b.getGraph().getSpeculationLog().maySpeculate(reason)) { 1147 speculation = b.getGraph().getSpeculationLog().speculate(reason); 1148 } else { 1149 speculation = SpeculationLog.NO_SPECULATION; 1150 } 1151 b.add(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TransferToInterpreter, speculation)); 1152 return true; 1153 } 1154 }); 1155 1156 r.register0("inCompiledCode", new InvocationPlugin() { 1157 @Override 1158 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { 1159 b.addPush(JavaKind.Boolean, ConstantNode.forBoolean(true)); 1160 return true; 1161 } 1162 }); 1163 1164 r.register0("controlFlowAnchor", new InvocationPlugin() { 1165 @Override 1166 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { 1167 b.add(new ControlFlowAnchorNode()); 1168 return true; 1169 } 1170 }); 1171 1172 r.register2("injectBranchProbability", double.class, boolean.class, new InvocationPlugin() { 1173 @Override 1174 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode probability, ValueNode condition) { 1175 b.addPush(JavaKind.Boolean, new BranchProbabilityNode(probability, condition)); 1176 return true; 1177 } 1178 }); 1179 1180 InvocationPlugin blackholePlugin = new InvocationPlugin() { 1181 @Override 1182 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { 1183 b.add(new BlackholeNode(value)); 1184 return true; 1185 } 1186 }; 1187 1188 InvocationPlugin bindToRegisterPlugin = new InvocationPlugin() { 1189 @Override 1190 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { 1191 b.add(new BindToRegisterNode(value)); 1192 return true; 1193 } 1194 }; 1195 for (JavaKind kind : JavaKind.values()) { 1196 if ((kind.isPrimitive() && kind != JavaKind.Void) || kind == JavaKind.Object) { 1197 Class<?> javaClass = kind == JavaKind.Object ? Object.class : kind.toJavaClass(); 1198 r.register1("blackhole", javaClass, blackholePlugin); 1199 r.register1("bindToRegister", javaClass, bindToRegisterPlugin); 1200 1201 r.register1("opaque", javaClass, new InvocationPlugin() { 1202 @Override 1203 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { 1204 b.addPush(kind, new OpaqueNode(value)); 1205 return true; 1206 } 1207 }); 1208 } 1209 } 1210 1211 InvocationPlugin spillPlugin = new InvocationPlugin() { 1212 @Override 1213 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { 1214 b.add(new SpillRegistersNode()); 1215 return true; 1216 } 1217 }; 1218 r.register0("spillRegisters", spillPlugin); 1219 1220 r.register1("guardingNonNull", Object.class, new InvocationPlugin() { 1221 @Override 1222 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { 1223 b.addPush(value.getStackKind(), b.nullCheckedValue(value)); 1224 return true; 1225 } 1226 }); 1227 1228 r.register1("ensureVirtualized", Object.class, new InvocationPlugin() { 1229 @Override 1230 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode object) { 1231 b.add(new EnsureVirtualizedNode(object, false)); 1232 return true; 1233 } 1234 }); 1235 r.register1("ensureVirtualizedHere", Object.class, new InvocationPlugin() { 1236 @Override 1237 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode object) { 1238 b.add(new EnsureVirtualizedNode(object, true)); 1239 return true; 1240 } 1241 }); 1242 } 1243 registerJMHBlackholePlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider)1244 private static void registerJMHBlackholePlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider) { 1245 InvocationPlugin blackholePlugin = new InvocationPlugin() { 1246 @Override 1247 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver blackhole, ValueNode value) { 1248 blackhole.get(); 1249 b.add(new BlackholeNode(value)); 1250 return true; 1251 } 1252 1253 @Override 1254 public boolean isDecorator() { 1255 return true; 1256 } 1257 }; 1258 String[] names = {"org.openjdk.jmh.infra.Blackhole", "org.openjdk.jmh.logic.BlackHole"}; 1259 for (String name : names) { 1260 Registration r = new Registration(plugins, name, bytecodeProvider); 1261 for (JavaKind kind : JavaKind.values()) { 1262 if ((kind.isPrimitive() && kind != JavaKind.Void) || kind == JavaKind.Object) { 1263 Class<?> javaClass = kind == JavaKind.Object ? Object.class : kind.toJavaClass(); 1264 r.registerOptional2("consume", Receiver.class, javaClass, blackholePlugin); 1265 } 1266 } 1267 r.registerOptional2("consume", Receiver.class, Object[].class, blackholePlugin); 1268 } 1269 } 1270 registerJFRThrowablePlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider)1271 private static void registerJFRThrowablePlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider) { 1272 Registration r = new Registration(plugins, "oracle.jrockit.jfr.jdkevents.ThrowableTracer", bytecodeProvider); 1273 r.register2("traceThrowable", Throwable.class, String.class, new InvocationPlugin() { 1274 @Override 1275 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode throwable, ValueNode message) { 1276 b.add(new VirtualizableInvokeMacroNode(b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnStamp(b.getAssumptions()), throwable, message)); 1277 return true; 1278 } 1279 1280 @Override 1281 public boolean inlineOnly() { 1282 return true; 1283 } 1284 }); 1285 } 1286 registerMethodHandleImplPlugins(InvocationPlugins plugins, SnippetReflectionProvider snippetReflection, BytecodeProvider bytecodeProvider)1287 private static void registerMethodHandleImplPlugins(InvocationPlugins plugins, SnippetReflectionProvider snippetReflection, BytecodeProvider bytecodeProvider) { 1288 Registration r = new Registration(plugins, "java.lang.invoke.MethodHandleImpl", bytecodeProvider); 1289 // In later JDKs this no longer exists and the usage is replace by Class.cast which is 1290 // already an intrinsic 1291 r.registerOptional2("castReference", Class.class, Object.class, new InvocationPlugin() { 1292 @Override 1293 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode javaClass, ValueNode object) { 1294 b.genCheckcastDynamic(object, javaClass); 1295 return true; 1296 } 1297 1298 @Override 1299 public boolean inlineOnly() { 1300 return true; 1301 } 1302 }); 1303 r.register2("profileBoolean", boolean.class, int[].class, new InvocationPlugin() { 1304 @Override 1305 public boolean inlineOnly() { 1306 return true; 1307 } 1308 1309 @Override 1310 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode result, ValueNode counters) { 1311 if (result.isConstant()) { 1312 b.push(JavaKind.Boolean, result); 1313 return true; 1314 } 1315 if (counters.isConstant()) { 1316 ValueNode newResult = result; 1317 int[] ctrs = snippetReflection.asObject(int[].class, (JavaConstant) counters.asConstant()); 1318 if (ctrs != null && ctrs.length == 2) { 1319 int falseCount = ctrs[0]; 1320 int trueCount = ctrs[1]; 1321 int totalCount = trueCount + falseCount; 1322 1323 if (totalCount == 0) { 1324 b.add(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TransferToInterpreter)); 1325 } else if (falseCount == 0 || trueCount == 0) { 1326 boolean expected = falseCount == 0; 1327 LogicNode condition = b.addWithInputs( 1328 IntegerEqualsNode.create(b.getConstantReflection(), b.getMetaAccess(), b.getOptions(), null, result, b.add(ConstantNode.forBoolean(!expected)), 1329 NodeView.DEFAULT)); 1330 b.append(new FixedGuardNode(condition, DeoptimizationReason.UnreachedCode, DeoptimizationAction.InvalidateReprofile, true)); 1331 newResult = b.add(ConstantNode.forBoolean(expected)); 1332 } else { 1333 // We cannot use BranchProbabilityNode here since there's no guarantee 1334 // the result of MethodHandleImpl.profileBoolean() is used as the 1335 // test in an `if` statement (as required by BranchProbabilityNode). 1336 } 1337 } 1338 b.addPush(JavaKind.Boolean, newResult); 1339 return true; 1340 } 1341 b.addPush(JavaKind.Boolean, 1342 new ProfileBooleanNode(snippetReflection, b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnStamp(b.getAssumptions()), result, counters)); 1343 return true; 1344 } 1345 }); 1346 } 1347 1348 /** 1349 * Registers a plugin to ignore {@code com.sun.tdk.jcov.runtime.Collect.hit} within an 1350 * intrinsic. 1351 */ registerJcovCollectPlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider)1352 private static void registerJcovCollectPlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider) { 1353 Registration r = new Registration(plugins, "com.sun.tdk.jcov.runtime.Collect", bytecodeProvider); 1354 r.register1("hit", int.class, new InvocationPlugin() { 1355 @Override 1356 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode object) { 1357 if (b.parsingIntrinsic()) { 1358 return true; 1359 } 1360 return false; 1361 } 1362 }); 1363 } 1364 } 1365