< prev index next >

src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/MonitorSnippets.java

Print this page




   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.replacements;
  26 
  27 import static jdk.vm.ci.code.MemoryBarriers.LOAD_STORE;
  28 import static jdk.vm.ci.code.MemoryBarriers.STORE_STORE;

  29 import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_VMCONFIG;

  30 import static org.graalvm.compiler.hotspot.nodes.BeginLockScopeNode.beginLockScope;
  31 import static org.graalvm.compiler.hotspot.nodes.EndLockScopeNode.endLockScope;
  32 import static org.graalvm.compiler.hotspot.nodes.VMErrorNode.vmError;
  33 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.DISPLACED_MARK_WORD_LOCATION;
  34 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.MARK_WORD_LOCATION;
  35 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.OBJECT_MONITOR_CXQ_LOCATION;
  36 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.OBJECT_MONITOR_ENTRY_LIST_LOCATION;
  37 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.OBJECT_MONITOR_OWNER_LOCATION;
  38 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.OBJECT_MONITOR_RECURSION_LOCATION;
  39 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.PROTOTYPE_MARK_WORD_LOCATION;
  40 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.ageMaskInPlace;
  41 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.biasedLockMaskInPlace;
  42 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.biasedLockPattern;
  43 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.config;
  44 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.epochMaskInPlace;
  45 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.loadWordFromObject;
  46 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.lockDisplacedMarkOffset;
  47 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.markOffset;
  48 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.monitorMask;
  49 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.objectMonitorCxqOffset;
  50 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.objectMonitorEntryListOffset;
  51 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.objectMonitorOwnerOffset;
  52 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.objectMonitorRecursionsOffset;
  53 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.pageSize;
  54 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.prototypeMarkWordOffset;
  55 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.registerAsWord;

  56 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.unlockedMask;
  57 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.useBiasedLocking;
  58 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.verifyOop;
  59 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.wordSize;
  60 import static org.graalvm.compiler.hotspot.replacements.HotspotSnippetsOptions.ProfileMonitors;
  61 import static org.graalvm.compiler.hotspot.replacements.HotspotSnippetsOptions.SimpleFastInflatedLocking;
  62 import static org.graalvm.compiler.hotspot.replacements.HotspotSnippetsOptions.TraceMonitorsMethodFilter;
  63 import static org.graalvm.compiler.hotspot.replacements.HotspotSnippetsOptions.TraceMonitorsTypeFilter;
  64 import static org.graalvm.compiler.hotspot.replacements.HotspotSnippetsOptions.VerifyBalancedMonitors;
  65 import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.FAST_PATH_PROBABILITY;
  66 import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.FREQUENT_PROBABILITY;
  67 import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.NOT_FREQUENT_PROBABILITY;
  68 import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.NOT_LIKELY_PROBABILITY;
  69 import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.SLOW_PATH_PROBABILITY;
  70 import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.VERY_FAST_PATH_PROBABILITY;
  71 import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.probability;

  72 import static org.graalvm.compiler.replacements.SnippetTemplate.DEFAULT_REPLACER;


  73 
  74 import java.util.List;
  75 
  76 import org.graalvm.compiler.api.replacements.Fold;
  77 import org.graalvm.compiler.api.replacements.Snippet;
  78 import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter;
  79 import org.graalvm.compiler.bytecode.Bytecode;
  80 import org.graalvm.compiler.bytecode.ResolvedJavaMethodBytecode;
  81 import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
  82 import org.graalvm.compiler.core.common.type.ObjectStamp;
  83 import org.graalvm.compiler.core.common.type.StampFactory;
  84 import org.graalvm.compiler.core.common.type.StampPair;
  85 import org.graalvm.compiler.debug.DebugHandlersFactory;
  86 import org.graalvm.compiler.graph.Node.ConstantNodeParameter;
  87 import org.graalvm.compiler.graph.Node.NodeIntrinsic;
  88 import org.graalvm.compiler.graph.iterators.NodeIterable;
  89 import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
  90 import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
  91 import org.graalvm.compiler.hotspot.meta.HotSpotRegistersProvider;
  92 import org.graalvm.compiler.hotspot.nodes.AcquiredCASLockNode;
  93 import org.graalvm.compiler.hotspot.nodes.CurrentLockNode;
  94 import org.graalvm.compiler.hotspot.nodes.FastAcquireBiasedLockNode;
  95 import org.graalvm.compiler.hotspot.nodes.MonitorCounterNode;
  96 import org.graalvm.compiler.hotspot.word.KlassPointer;
  97 import org.graalvm.compiler.nodes.BreakpointNode;
  98 import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind;
  99 import org.graalvm.compiler.nodes.ConstantNode;
 100 import org.graalvm.compiler.nodes.DeoptimizeNode;
 101 import org.graalvm.compiler.nodes.FrameState;
 102 import org.graalvm.compiler.nodes.InvokeNode;
 103 import org.graalvm.compiler.nodes.NamedLocationIdentity;
 104 import org.graalvm.compiler.nodes.NodeView;
 105 import org.graalvm.compiler.nodes.ReturnNode;
 106 import org.graalvm.compiler.nodes.StructuredGraph;
 107 import org.graalvm.compiler.nodes.ValueNode;
 108 import org.graalvm.compiler.nodes.debug.DynamicCounterNode;
 109 import org.graalvm.compiler.nodes.extended.ForeignCallNode;
 110 import org.graalvm.compiler.nodes.extended.MembarNode;
 111 import org.graalvm.compiler.nodes.java.MethodCallTargetNode;
 112 import org.graalvm.compiler.nodes.java.MonitorExitNode;


 202  *
 203  *  - the two lock bits are used to describe three states: locked/unlocked and monitor.
 204  *
 205  *    [ptr             | 00]  locked             ptr points to real header on stack
 206  *    [header      | 0 | 01]  unlocked           regular object header
 207  *    [ptr             | 10]  monitor            inflated lock (header is wapped out)
 208  *    [ptr             | 11]  marked             used by markSweep to mark an object
 209  *                                               not valid at any other time
 210  *
 211  *    We assume that stack/thread pointers have the lowest two bits cleared.
 212  * </pre>
 213  *
 214  * Note that {@code Thread::allocate} enforces {@code JavaThread} objects to be aligned
 215  * appropriately to comply with the layouts above.
 216  */
 217 public class MonitorSnippets implements Snippets {
 218 
 219     private static final boolean PROFILE_CONTEXT = false;
 220 
 221     @Fold
 222     static boolean doProfile(OptionValues options) {
 223         return ProfileMonitors.getValue(options);
 224     }
 225 
 226     @Snippet
 227     public static void monitorenter(Object object, KlassPointer hub, @ConstantParameter int lockDepth, @ConstantParameter Register threadRegister, @ConstantParameter Register stackPointerRegister,
 228                     @ConstantParameter boolean trace, @ConstantParameter OptionValues options, @ConstantParameter Counters counters) {
 229         verifyOop(object);
 230 
 231         // Load the mark word - this includes a null-check on object
 232         final Word mark = loadWordFromObject(object, markOffset(INJECTED_VMCONFIG));
 233 
 234         final Word lock = beginLockScope(lockDepth);
 235 
 236         Pointer objectPointer = Word.objectToTrackedPointer(object);
 237         trace(trace, "           object: 0x%016lx\n", objectPointer);
 238         trace(trace, "             lock: 0x%016lx\n", lock);
 239         trace(trace, "             mark: 0x%016lx\n", mark);
 240 
 241         incCounter(options);
 242 
 243         if (useBiasedLocking(INJECTED_VMCONFIG)) {
 244             if (tryEnterBiased(object, hub, lock, mark, threadRegister, trace, options, counters)) {
 245                 return;
 246             }
 247             // not biased, fall-through
 248         }
 249         if (inlineFastLockSupported(options) && probability(SLOW_PATH_PROBABILITY, mark.and(monitorMask(INJECTED_VMCONFIG)).notEqual(0))) {
 250             // Inflated case
 251             if (tryEnterInflated(object, lock, mark, threadRegister, trace, options, counters)) {
 252                 return;
 253             }
 254         } else {
 255             // Create the unlocked mark word pattern
 256             Word unlockedMark = mark.or(unlockedMask(INJECTED_VMCONFIG));
 257             trace(trace, "     unlockedMark: 0x%016lx\n", unlockedMark);
 258 
 259             // Copy this unlocked mark word into the lock slot on the stack
 260             lock.writeWord(lockDisplacedMarkOffset(INJECTED_VMCONFIG), unlockedMark, DISPLACED_MARK_WORD_LOCATION);
 261 
 262             // make sure previous store does not float below compareAndSwap
 263             MembarNode.memoryBarrier(STORE_STORE);
 264 
 265             // Test if the object's mark word is unlocked, and if so, store the
 266             // (address of) the lock slot into the object's mark word.
 267             Word currentMark = objectPointer.compareAndSwapWord(markOffset(INJECTED_VMCONFIG), unlockedMark, lock, MARK_WORD_LOCATION);
 268             if (probability(FAST_PATH_PROBABILITY, currentMark.equal(unlockedMark))) {
 269                 traceObject(trace, "+lock{cas}", object, true, options);
 270                 counters.lockCas.inc();
 271                 AcquiredCASLockNode.mark(object);
 272                 return;
 273             } else {
 274                 trace(trace, "      currentMark: 0x%016lx\n", currentMark);
 275                 // The mark word in the object header was not the same.
 276                 // Either the object is locked by another thread or is already locked
 277                 // by the current thread. The latter is true if the mark word
 278                 // is a stack pointer into the current thread's stack, i.e.:
 279                 //
 280                 // 1) (currentMark & aligned_mask) == 0
 281                 // 2) rsp <= currentMark
 282                 // 3) currentMark <= rsp + page_size
 283                 //
 284                 // These 3 tests can be done by evaluating the following expression:
 285                 //
 286                 // (currentMark - rsp) & (aligned_mask - page_size)
 287                 //
 288                 // assuming both the stack pointer and page_size have their least
 289                 // significant 2 bits cleared and page_size is a power of 2
 290                 final Word alignedMask = WordFactory.unsigned(wordSize() - 1);
 291                 final Word stackPointer = registerAsWord(stackPointerRegister).add(config(INJECTED_VMCONFIG).stackBias);
 292                 if (probability(FAST_PATH_PROBABILITY, currentMark.subtract(stackPointer).and(alignedMask.subtract(pageSize())).equal(0))) {
 293                     // Recursively locked => write 0 to the lock slot
 294                     lock.writeWord(lockDisplacedMarkOffset(INJECTED_VMCONFIG), WordFactory.zero(), DISPLACED_MARK_WORD_LOCATION);
 295                     traceObject(trace, "+lock{cas:recursive}", object, true, options);
 296                     counters.lockCasRecursive.inc();
 297                     return;
 298                 }
 299                 traceObject(trace, "+lock{stub:failed-cas/stack}", object, true, options);
 300                 counters.lockStubFailedCas.inc();
 301             }
 302         }
 303         // slow-path runtime-call
 304         monitorenterStubC(MONITORENTER, object, lock);
 305     }
 306 
 307     private static boolean tryEnterBiased(Object object, KlassPointer hub, Word lock, Word mark, Register threadRegister, boolean trace, OptionValues options, Counters counters) {
 308         // See whether the lock is currently biased toward our thread and
 309         // whether the epoch is still valid.
 310         // Note that the runtime guarantees sufficient alignment of JavaThread
 311         // pointers to allow age to be placed into low bits.
 312         final Word biasableLockBits = mark.and(biasedLockMaskInPlace(INJECTED_VMCONFIG));
 313 
 314         // Check whether the bias pattern is present in the object's mark word
 315         // and the bias owner and the epoch are both still current.
 316         final Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(INJECTED_VMCONFIG), PROTOTYPE_MARK_WORD_LOCATION);
 317         final Word thread = registerAsWord(threadRegister);
 318         final Word tmp = prototypeMarkWord.or(thread).xor(mark).and(~ageMaskInPlace(INJECTED_VMCONFIG));
 319         trace(trace, "prototypeMarkWord: 0x%016lx\n", prototypeMarkWord);
 320         trace(trace, "           thread: 0x%016lx\n", thread);
 321         trace(trace, "              tmp: 0x%016lx\n", tmp);
 322         if (probability(FAST_PATH_PROBABILITY, tmp.equal(0))) {
 323             // Object is already biased to current thread -> done
 324             traceObject(trace, "+lock{bias:existing}", object, true, options);
 325             counters.lockBiasExisting.inc();
 326             FastAcquireBiasedLockNode.mark(object);
 327             return true;
 328         }
 329 
 330         // Now check to see whether biasing is enabled for this object
 331         if (probability(NOT_FREQUENT_PROBABILITY, biasableLockBits.equal(WordFactory.unsigned(biasedLockPattern(INJECTED_VMCONFIG))))) {
 332             Pointer objectPointer = Word.objectToTrackedPointer(object);
 333             // At this point we know that the mark word has the bias pattern and
 334             // that we are not the bias owner in the current epoch. We need to
 335             // figure out more details about the state of the mark word in order to
 336             // know what operations can be legally performed on the object's
 337             // mark word.
 338 
 339             // If the low three bits in the xor result aren't clear, that means
 340             // the prototype header is no longer biasable and we have to revoke
 341             // the bias on this object.
 342             if (probability(FREQUENT_PROBABILITY, tmp.and(biasedLockMaskInPlace(INJECTED_VMCONFIG)).equal(0))) {
 343                 // Biasing is still enabled for object's type. See whether the
 344                 // epoch of the current bias is still valid, meaning that the epoch
 345                 // bits of the mark word are equal to the epoch bits of the
 346                 // prototype mark word. (Note that the prototype mark word's epoch bits
 347                 // only change at a safepoint.) If not, attempt to rebias the object
 348                 // toward the current thread. Note that we must be absolutely sure
 349                 // that the current epoch is invalid in order to do this because
 350                 // otherwise the manipulations it performs on the mark word are
 351                 // illegal.
 352                 if (probability(FREQUENT_PROBABILITY, tmp.and(epochMaskInPlace(INJECTED_VMCONFIG)).equal(0))) {
 353                     // The epoch of the current bias is still valid but we know nothing
 354                     // about the owner; it might be set or it might be clear. Try to
 355                     // acquire the bias of the object using an atomic operation. If this
 356                     // fails we will go in to the runtime to revoke the object's bias.
 357                     // Note that we first construct the presumed unbiased header so we
 358                     // don't accidentally blow away another thread's valid bias.
 359                     Word unbiasedMark = mark.and(biasedLockMaskInPlace(INJECTED_VMCONFIG) | ageMaskInPlace(INJECTED_VMCONFIG) | epochMaskInPlace(INJECTED_VMCONFIG));
 360                     Word biasedMark = unbiasedMark.or(thread);
 361                     trace(trace, "     unbiasedMark: 0x%016lx\n", unbiasedMark);
 362                     trace(trace, "       biasedMark: 0x%016lx\n", biasedMark);
 363                     if (probability(VERY_FAST_PATH_PROBABILITY, objectPointer.logicCompareAndSwapWord(markOffset(INJECTED_VMCONFIG), unbiasedMark, biasedMark, MARK_WORD_LOCATION))) {
 364                         // Object is now biased to current thread -> done
 365                         traceObject(trace, "+lock{bias:acquired}", object, true, options);
 366                         counters.lockBiasAcquired.inc();
 367                         return true;
 368                     }
 369                     // If the biasing toward our thread failed, this means that another thread
 370                     // owns the bias and we need to revoke that bias. The revocation will occur
 371                     // in the interpreter runtime.
 372                     traceObject(trace, "+lock{stub:revoke}", object, true, options);
 373                     counters.lockStubRevoke.inc();
 374                 } else {
 375                     // At this point we know the epoch has expired, meaning that the
 376                     // current bias owner, if any, is actually invalid. Under these
 377                     // circumstances _only_, are we allowed to use the current mark word
 378                     // value as the comparison value when doing the CAS to acquire the
 379                     // bias in the current epoch. In other words, we allow transfer of
 380                     // the bias from one thread to another directly in this situation.
 381                     Word biasedMark = prototypeMarkWord.or(thread);
 382                     trace(trace, "       biasedMark: 0x%016lx\n", biasedMark);
 383                     if (probability(VERY_FAST_PATH_PROBABILITY, objectPointer.logicCompareAndSwapWord(markOffset(INJECTED_VMCONFIG), mark, biasedMark, MARK_WORD_LOCATION))) {
 384                         // Object is now biased to current thread -> done
 385                         traceObject(trace, "+lock{bias:transfer}", object, true, options);
 386                         counters.lockBiasTransfer.inc();
 387                         return true;
 388                     }
 389                     // If the biasing toward our thread failed, then another thread
 390                     // succeeded in biasing it toward itself and we need to revoke that
 391                     // bias. The revocation will occur in the runtime in the slow case.
 392                     traceObject(trace, "+lock{stub:epoch-expired}", object, true, options);
 393                     counters.lockStubEpochExpired.inc();
 394                 }
 395                 // slow-path runtime-call
 396                 monitorenterStubC(MONITORENTER, object, lock);
 397                 return true;
 398             } else {
 399                 // The prototype mark word doesn't have the bias bit set any
 400                 // more, indicating that objects of this data type are not supposed
 401                 // to be biased any more. We are going to try to reset the mark of
 402                 // this object to the prototype value and fall through to the
 403                 // CAS-based locking scheme. Note that if our CAS fails, it means
 404                 // that another thread raced us for the privilege of revoking the
 405                 // bias of this particular object, so it's okay to continue in the
 406                 // normal locking code.
 407                 Word result = objectPointer.compareAndSwapWord(markOffset(INJECTED_VMCONFIG), mark, prototypeMarkWord, MARK_WORD_LOCATION);
 408 
 409                 // Fall through to the normal CAS-based lock, because no matter what
 410                 // the result of the above CAS, some thread must have succeeded in
 411                 // removing the bias bit from the object's header.
 412 
 413                 if (ENABLE_BREAKPOINT) {
 414                     bkpt(object, mark, tmp, result);
 415                 }
 416                 counters.revokeBias.inc();
 417                 return false;
 418             }
 419         } else {
 420             // Biasing not enabled -> fall through to lightweight locking
 421             counters.unbiasable.inc();
 422             return false;
 423         }
 424     }
 425 
 426     @Fold
 427     public static boolean useFastInflatedLocking(OptionValues options) {
 428         return SimpleFastInflatedLocking.getValue(options);
 429     }
 430 
 431     private static boolean inlineFastLockSupported(OptionValues options) {
 432         return inlineFastLockSupported(INJECTED_VMCONFIG, options);
 433     }
 434 
 435     private static boolean inlineFastLockSupported(GraalHotSpotVMConfig config, OptionValues options) {
 436         return useFastInflatedLocking(options) && monitorMask(config) >= 0 && objectMonitorOwnerOffset(config) >= 0;
 437     }
 438 
 439     private static boolean tryEnterInflated(Object object, Word lock, Word mark, Register threadRegister, boolean trace, OptionValues options, Counters counters) {
 440         // write non-zero value to lock slot
 441         lock.writeWord(lockDisplacedMarkOffset(INJECTED_VMCONFIG), lock, DISPLACED_MARK_WORD_LOCATION);
 442         // mark is a pointer to the ObjectMonitor + monitorMask
 443         Word monitor = mark.subtract(monitorMask(INJECTED_VMCONFIG));
 444         int ownerOffset = objectMonitorOwnerOffset(INJECTED_VMCONFIG);
 445         Word owner = monitor.readWord(ownerOffset, OBJECT_MONITOR_OWNER_LOCATION);
 446         if (probability(FREQUENT_PROBABILITY, owner.equal(0))) {
 447             // it appears unlocked (owner == 0)
 448             if (probability(FREQUENT_PROBABILITY, monitor.logicCompareAndSwapWord(ownerOffset, owner, registerAsWord(threadRegister), OBJECT_MONITOR_OWNER_LOCATION))) {
 449                 // success
 450                 traceObject(trace, "+lock{inflated:cas}", object, true, options);
 451                 counters.inflatedCas.inc();
 452                 return true;
 453             } else {
 454                 traceObject(trace, "+lock{stub:inflated:failed-cas}", object, true, options);
 455                 counters.inflatedFailedCas.inc();
 456             }
 457         } else {
 458             traceObject(trace, "+lock{stub:inflated:owned}", object, true, options);
 459             counters.inflatedOwned.inc();
 460         }
 461         return false;
 462     }
 463 
 464     /**
 465      * Calls straight out to the monitorenter stub.
 466      */
 467     @Snippet
 468     public static void monitorenterStub(Object object, @ConstantParameter int lockDepth, @ConstantParameter boolean trace, @ConstantParameter OptionValues options) {
 469         verifyOop(object);
 470         incCounter(options);
 471         if (object == null) {
 472             DeoptimizeNode.deopt(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.NullCheckException);
 473         }
 474         // BeginLockScope nodes do not read from object so a use of object
 475         // cannot float about the null check above
 476         final Word lock = beginLockScope(lockDepth);
 477         traceObject(trace, "+lock{stub}", object, true, options);
 478         monitorenterStubC(MONITORENTER, object, lock);
 479     }
 480 
 481     @Snippet
 482     public static void monitorexit(Object object, @ConstantParameter int lockDepth, @ConstantParameter Register threadRegister, @ConstantParameter boolean trace,
 483                     @ConstantParameter OptionValues options, @ConstantParameter Counters counters) {
 484         trace(trace, "           object: 0x%016lx\n", Word.objectToTrackedPointer(object));
 485         final Word mark = loadWordFromObject(object, markOffset(INJECTED_VMCONFIG));
 486         if (useBiasedLocking(INJECTED_VMCONFIG)) {
 487             // Check for biased locking unlock case, which is a no-op
 488             // Note: we do not have to check the thread ID for two reasons.
 489             // First, the interpreter checks for IllegalMonitorStateException at
 490             // a higher level. Second, if the bias was revoked while we held the
 491             // lock, the object could not be rebiased toward another thread, so
 492             // the bias bit would be clear.
 493             trace(trace, "             mark: 0x%016lx\n", mark);
 494             if (probability(FREQUENT_PROBABILITY, mark.and(biasedLockMaskInPlace(INJECTED_VMCONFIG)).equal(WordFactory.unsigned(biasedLockPattern(INJECTED_VMCONFIG))))) {
 495                 endLockScope();
 496                 decCounter(options);
 497                 traceObject(trace, "-lock{bias}", object, false, options);
 498                 counters.unlockBias.inc();
 499                 return;
 500             }
 501         }
 502 
 503         final Word lock = CurrentLockNode.currentLock(lockDepth);
 504 
 505         // Load displaced mark
 506         final Word displacedMark = lock.readWord(lockDisplacedMarkOffset(INJECTED_VMCONFIG), DISPLACED_MARK_WORD_LOCATION);
 507         trace(trace, "    displacedMark: 0x%016lx\n", displacedMark);
 508 
 509         if (probability(NOT_LIKELY_PROBABILITY, displacedMark.equal(0))) {
 510             // Recursive locking => done
 511             traceObject(trace, "-lock{recursive}", object, false, options);
 512             counters.unlockCasRecursive.inc();
 513         } else {
 514             if (!tryExitInflated(object, mark, lock, threadRegister, trace, options, counters)) {
 515                 verifyOop(object);
 516                 // Test if object's mark word is pointing to the displaced mark word, and if so,
 517                 // restore
 518                 // the displaced mark in the object - if the object's mark word is not pointing to
 519                 // the displaced mark word, do unlocking via runtime call.
 520                 Pointer objectPointer = Word.objectToTrackedPointer(object);
 521                 if (probability(VERY_FAST_PATH_PROBABILITY, objectPointer.logicCompareAndSwapWord(markOffset(INJECTED_VMCONFIG), lock, displacedMark, MARK_WORD_LOCATION))) {
 522                     traceObject(trace, "-lock{cas}", object, false, options);
 523                     counters.unlockCas.inc();
 524                 } else {
 525                     // The object's mark word was not pointing to the displaced header
 526                     traceObject(trace, "-lock{stub}", object, false, options);
 527                     counters.unlockStub.inc();
 528                     monitorexitStubC(MONITOREXIT, object, lock);
 529                 }
 530             }
 531         }
 532         endLockScope();
 533         decCounter(options);
 534     }
 535 
 536     private static boolean inlineFastUnlockSupported(OptionValues options) {
 537         return inlineFastUnlockSupported(INJECTED_VMCONFIG, options);
 538     }
 539 
 540     private static boolean inlineFastUnlockSupported(GraalHotSpotVMConfig config, OptionValues options) {
 541         return useFastInflatedLocking(options) && objectMonitorEntryListOffset(config) >= 0 && objectMonitorCxqOffset(config) >= 0 && monitorMask(config) >= 0 &&
 542                         objectMonitorOwnerOffset(config) >= 0 && objectMonitorRecursionsOffset(config) >= 0;
 543     }
 544 
 545     private static boolean tryExitInflated(Object object, Word mark, Word lock, Register threadRegister, boolean trace, OptionValues options, Counters counters) {
 546         if (!inlineFastUnlockSupported(options)) {
 547             return false;
 548         }
 549         if (probability(SLOW_PATH_PROBABILITY, mark.and(monitorMask(INJECTED_VMCONFIG)).notEqual(0))) {
 550             // Inflated case
 551             // mark is a pointer to the ObjectMonitor + monitorMask
 552             Word monitor = mark.subtract(monitorMask(INJECTED_VMCONFIG));
 553             int ownerOffset = objectMonitorOwnerOffset(INJECTED_VMCONFIG);
 554             Word owner = monitor.readWord(ownerOffset, OBJECT_MONITOR_OWNER_LOCATION);
 555             int recursionsOffset = objectMonitorRecursionsOffset(INJECTED_VMCONFIG);
 556             Word recursions = monitor.readWord(recursionsOffset, OBJECT_MONITOR_RECURSION_LOCATION);
 557             Word thread = registerAsWord(threadRegister);
 558             if (probability(FAST_PATH_PROBABILITY, owner.xor(thread).or(recursions).equal(0))) {
 559                 // owner == thread && recursions == 0
 560                 int cxqOffset = objectMonitorCxqOffset(INJECTED_VMCONFIG);
 561                 Word cxq = monitor.readWord(cxqOffset, OBJECT_MONITOR_CXQ_LOCATION);
 562                 int entryListOffset = objectMonitorEntryListOffset(INJECTED_VMCONFIG);
 563                 Word entryList = monitor.readWord(entryListOffset, OBJECT_MONITOR_ENTRY_LIST_LOCATION);
 564                 if (probability(FREQUENT_PROBABILITY, cxq.or(entryList).equal(0))) {
 565                     // cxq == 0 && entryList == 0
 566                     // Nobody is waiting, success
 567                     // release_store
 568                     MembarNode.memoryBarrier(LOAD_STORE | STORE_STORE);
 569                     monitor.writeWord(ownerOffset, WordFactory.zero());
 570                     traceObject(trace, "-lock{inflated:simple}", object, false, options);
 571                     counters.unlockInflatedSimple.inc();
 572                     return true;
 573                 }
 574             }
 575             counters.unlockStubInflated.inc();
 576             traceObject(trace, "-lock{stub:inflated}", object, false, options);
 577             monitorexitStubC(MONITOREXIT, object, lock);
 578             return true;
 579         }
 580         return false;
 581     }
 582 
 583     /**
 584      * Calls straight out to the monitorexit stub.
 585      */
 586     @Snippet
 587     public static void monitorexitStub(Object object, @ConstantParameter int lockDepth, @ConstantParameter boolean trace, @ConstantParameter OptionValues options) {
 588         verifyOop(object);
 589         traceObject(trace, "-lock{stub}", object, false, options);
 590         final Word lock = CurrentLockNode.currentLock(lockDepth);
 591         monitorexitStubC(MONITOREXIT, object, lock);
 592         endLockScope();
 593         decCounter(options);
 594     }
 595 
 596     public static void traceObject(boolean enabled, String action, Object object, boolean enter, OptionValues options) {
 597         if (doProfile(options)) {
 598             DynamicCounterNode.counter(enter ? "number of monitor enters" : "number of monitor exits", action, 1, PROFILE_CONTEXT);
 599         }
 600         if (enabled) {
 601             Log.print(action);
 602             Log.print(' ');
 603             Log.printlnObject(object);
 604         }
 605     }
 606 
 607     public static void trace(boolean enabled, String format, WordBase value) {
 608         if (enabled) {
 609             Log.printf(format, value.rawValue());
 610         }
 611     }
 612 
 613     /**
 614      * Leaving the breakpoint code in to provide an example of how to use the {@link BreakpointNode}
 615      * intrinsic.
 616      */
 617     private static final boolean ENABLE_BREAKPOINT = false;
 618 
 619     private static final LocationIdentity MONITOR_COUNTER_LOCATION = NamedLocationIdentity.mutable("MonitorCounter");
 620 
 621     @NodeIntrinsic(BreakpointNode.class)
 622     static native void bkpt(Object object, Word mark, Word tmp, Word value);
 623 
 624     @Fold
 625     static boolean verifyBalancedMonitors(OptionValues options) {
 626         return VerifyBalancedMonitors.getValue(options);
 627     }
 628 
 629     public static void incCounter(OptionValues options) {
 630         if (verifyBalancedMonitors(options)) {
 631             final Word counter = MonitorCounterNode.counter();
 632             final int count = counter.readInt(0, MONITOR_COUNTER_LOCATION);
 633             counter.writeInt(0, count + 1, MONITOR_COUNTER_LOCATION);
 634         }
 635     }
 636 
 637     public static void decCounter(OptionValues options) {
 638         if (verifyBalancedMonitors(options)) {
 639             final Word counter = MonitorCounterNode.counter();
 640             final int count = counter.readInt(0, MONITOR_COUNTER_LOCATION);
 641             counter.writeInt(0, count - 1, MONITOR_COUNTER_LOCATION);
 642         }
 643     }
 644 
 645     @Snippet
 646     private static void initCounter() {
 647         final Word counter = MonitorCounterNode.counter();
 648         counter.writeInt(0, 0, MONITOR_COUNTER_LOCATION);
 649     }
 650 
 651     @Snippet
 652     private static void checkCounter(@ConstantParameter String errMsg) {
 653         final Word counter = MonitorCounterNode.counter();
 654         final int count = counter.readInt(0, MONITOR_COUNTER_LOCATION);
 655         if (count != 0) {
 656             vmError(errMsg, count);
 657         }
 658     }


 733             this.useFastLocking = useFastLocking;
 734 
 735             this.counters = new Counters(factory);
 736         }
 737 
 738         public void lower(RawMonitorEnterNode monitorenterNode, HotSpotRegistersProvider registers, LoweringTool tool) {
 739             StructuredGraph graph = monitorenterNode.graph();
 740             checkBalancedMonitors(graph, tool);
 741 
 742             assert ((ObjectStamp) monitorenterNode.object().stamp(NodeView.DEFAULT)).nonNull();
 743 
 744             Arguments args;
 745             if (useFastLocking) {
 746                 args = new Arguments(monitorenter, graph.getGuardsStage(), tool.getLoweringStage());
 747                 args.add("object", monitorenterNode.object());
 748                 args.add("hub", monitorenterNode.getHub());
 749                 args.addConst("lockDepth", monitorenterNode.getMonitorId().getLockDepth());
 750                 args.addConst("threadRegister", registers.getThreadRegister());
 751                 args.addConst("stackPointerRegister", registers.getStackPointerRegister());
 752                 args.addConst("trace", isTracingEnabledForType(monitorenterNode.object()) || isTracingEnabledForMethod(graph));
 753                 args.addConst("options", graph.getOptions());
 754                 args.addConst("counters", counters);
 755             } else {
 756                 args = new Arguments(monitorenterStub, graph.getGuardsStage(), tool.getLoweringStage());
 757                 args.add("object", monitorenterNode.object());
 758                 args.addConst("lockDepth", monitorenterNode.getMonitorId().getLockDepth());
 759                 args.addConst("trace", isTracingEnabledForType(monitorenterNode.object()) || isTracingEnabledForMethod(graph));
 760                 args.addConst("options", graph.getOptions());
 761                 args.addConst("counters", counters);
 762             }
 763 
 764             template(monitorenterNode, args).instantiate(providers.getMetaAccess(), monitorenterNode, DEFAULT_REPLACER, args);
 765         }
 766 
 767         public void lower(MonitorExitNode monitorexitNode, HotSpotRegistersProvider registers, LoweringTool tool) {
 768             StructuredGraph graph = monitorexitNode.graph();
 769 
 770             Arguments args;
 771             if (useFastLocking) {
 772                 args = new Arguments(monitorexit, graph.getGuardsStage(), tool.getLoweringStage());
 773             } else {
 774                 args = new Arguments(monitorexitStub, graph.getGuardsStage(), tool.getLoweringStage());
 775             }
 776             args.add("object", monitorexitNode.object());
 777             args.addConst("lockDepth", monitorexitNode.getMonitorId().getLockDepth());
 778             args.addConst("threadRegister", registers.getThreadRegister());
 779             args.addConst("trace", isTracingEnabledForType(monitorexitNode.object()) || isTracingEnabledForMethod(graph));
 780             args.addConst("options", graph.getOptions());
 781             args.addConst("counters", counters);
 782 
 783             template(monitorexitNode, args).instantiate(providers.getMetaAccess(), monitorexitNode, DEFAULT_REPLACER, args);
 784         }
 785 
 786         public static boolean isTracingEnabledForType(ValueNode object) {
 787             ResolvedJavaType type = StampTool.typeOrNull(object.stamp(NodeView.DEFAULT));
 788             String filter = TraceMonitorsTypeFilter.getValue(object.getOptions());
 789             if (filter == null) {
 790                 return false;
 791             } else {
 792                 if (filter.length() == 0) {
 793                     return true;
 794                 }
 795                 if (type == null) {
 796                     return false;
 797                 }
 798                 return (type.getName().contains(filter));
 799             }
 800         }




   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.replacements;
  26 
  27 import static jdk.vm.ci.code.MemoryBarriers.LOAD_STORE;
  28 import static jdk.vm.ci.code.MemoryBarriers.STORE_STORE;
  29 import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_OPTIONVALUES;
  30 import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_VMCONFIG;
  31 import static org.graalvm.compiler.hotspot.nodes.AcquiredCASLockNode.mark;
  32 import static org.graalvm.compiler.hotspot.nodes.BeginLockScopeNode.beginLockScope;
  33 import static org.graalvm.compiler.hotspot.nodes.EndLockScopeNode.endLockScope;
  34 import static org.graalvm.compiler.hotspot.nodes.VMErrorNode.vmError;
  35 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.DISPLACED_MARK_WORD_LOCATION;
  36 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.MARK_WORD_LOCATION;
  37 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.OBJECT_MONITOR_CXQ_LOCATION;
  38 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.OBJECT_MONITOR_ENTRY_LIST_LOCATION;
  39 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.OBJECT_MONITOR_OWNER_LOCATION;
  40 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.OBJECT_MONITOR_RECURSION_LOCATION;
  41 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.PROTOTYPE_MARK_WORD_LOCATION;
  42 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.ageMaskInPlace;
  43 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.biasedLockMaskInPlace;
  44 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.biasedLockPattern;

  45 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.epochMaskInPlace;
  46 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.loadWordFromObject;
  47 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.lockDisplacedMarkOffset;
  48 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.markOffset;
  49 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.monitorMask;
  50 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.objectMonitorCxqOffset;
  51 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.objectMonitorEntryListOffset;
  52 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.objectMonitorOwnerOffset;
  53 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.objectMonitorRecursionsOffset;
  54 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.pageSize;
  55 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.prototypeMarkWordOffset;
  56 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.registerAsWord;
  57 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.stackBias;
  58 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.unlockedMask;
  59 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.useBiasedLocking;
  60 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.verifyOop;
  61 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.wordSize;
  62 import static org.graalvm.compiler.hotspot.replacements.HotspotSnippetsOptions.ProfileMonitors;
  63 import static org.graalvm.compiler.hotspot.replacements.HotspotSnippetsOptions.SimpleFastInflatedLocking;
  64 import static org.graalvm.compiler.hotspot.replacements.HotspotSnippetsOptions.TraceMonitorsMethodFilter;
  65 import static org.graalvm.compiler.hotspot.replacements.HotspotSnippetsOptions.TraceMonitorsTypeFilter;
  66 import static org.graalvm.compiler.hotspot.replacements.HotspotSnippetsOptions.VerifyBalancedMonitors;
  67 import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.FAST_PATH_PROBABILITY;
  68 import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.FREQUENT_PROBABILITY;
  69 import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.NOT_FREQUENT_PROBABILITY;
  70 import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.NOT_LIKELY_PROBABILITY;
  71 import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.SLOW_PATH_PROBABILITY;
  72 import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.VERY_FAST_PATH_PROBABILITY;
  73 import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.probability;
  74 import static org.graalvm.compiler.nodes.extended.MembarNode.memoryBarrier;
  75 import static org.graalvm.compiler.replacements.SnippetTemplate.DEFAULT_REPLACER;
  76 import static jdk.internal.vm.compiler.word.WordFactory.unsigned;
  77 import static jdk.internal.vm.compiler.word.WordFactory.zero;
  78 
  79 import java.util.List;
  80 
  81 import org.graalvm.compiler.api.replacements.Fold;
  82 import org.graalvm.compiler.api.replacements.Snippet;
  83 import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter;
  84 import org.graalvm.compiler.bytecode.Bytecode;
  85 import org.graalvm.compiler.bytecode.ResolvedJavaMethodBytecode;
  86 import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
  87 import org.graalvm.compiler.core.common.type.ObjectStamp;
  88 import org.graalvm.compiler.core.common.type.StampFactory;
  89 import org.graalvm.compiler.core.common.type.StampPair;
  90 import org.graalvm.compiler.debug.DebugHandlersFactory;
  91 import org.graalvm.compiler.graph.Node.ConstantNodeParameter;
  92 import org.graalvm.compiler.graph.Node.NodeIntrinsic;
  93 import org.graalvm.compiler.graph.iterators.NodeIterable;
  94 import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
  95 import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
  96 import org.graalvm.compiler.hotspot.meta.HotSpotRegistersProvider;

  97 import org.graalvm.compiler.hotspot.nodes.CurrentLockNode;
  98 import org.graalvm.compiler.hotspot.nodes.FastAcquireBiasedLockNode;
  99 import org.graalvm.compiler.hotspot.nodes.MonitorCounterNode;
 100 import org.graalvm.compiler.hotspot.word.KlassPointer;
 101 import org.graalvm.compiler.nodes.BreakpointNode;
 102 import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind;
 103 import org.graalvm.compiler.nodes.ConstantNode;
 104 import org.graalvm.compiler.nodes.DeoptimizeNode;
 105 import org.graalvm.compiler.nodes.FrameState;
 106 import org.graalvm.compiler.nodes.InvokeNode;
 107 import org.graalvm.compiler.nodes.NamedLocationIdentity;
 108 import org.graalvm.compiler.nodes.NodeView;
 109 import org.graalvm.compiler.nodes.ReturnNode;
 110 import org.graalvm.compiler.nodes.StructuredGraph;
 111 import org.graalvm.compiler.nodes.ValueNode;
 112 import org.graalvm.compiler.nodes.debug.DynamicCounterNode;
 113 import org.graalvm.compiler.nodes.extended.ForeignCallNode;
 114 import org.graalvm.compiler.nodes.extended.MembarNode;
 115 import org.graalvm.compiler.nodes.java.MethodCallTargetNode;
 116 import org.graalvm.compiler.nodes.java.MonitorExitNode;


 206  *
 207  *  - the two lock bits are used to describe three states: locked/unlocked and monitor.
 208  *
 209  *    [ptr             | 00]  locked             ptr points to real header on stack
 210  *    [header      | 0 | 01]  unlocked           regular object header
 211  *    [ptr             | 10]  monitor            inflated lock (header is wapped out)
 212  *    [ptr             | 11]  marked             used by markSweep to mark an object
 213  *                                               not valid at any other time
 214  *
 215  *    We assume that stack/thread pointers have the lowest two bits cleared.
 216  * </pre>
 217  *
 218  * Note that {@code Thread::allocate} enforces {@code JavaThread} objects to be aligned
 219  * appropriately to comply with the layouts above.
 220  */
 221 public class MonitorSnippets implements Snippets {
 222 
 223     private static final boolean PROFILE_CONTEXT = false;
 224 
 225     @Fold
 226     static boolean doProfile(@Fold.InjectedParameter OptionValues options) {
 227         return ProfileMonitors.getValue(options);
 228     }
 229 
 230     @Snippet
 231     public static void monitorenter(Object object, KlassPointer hub, @ConstantParameter int lockDepth, @ConstantParameter Register threadRegister, @ConstantParameter Register stackPointerRegister,
 232                     @ConstantParameter boolean trace, @ConstantParameter Counters counters) {
 233         verifyOop(object);
 234 
 235         // Load the mark word - this includes a null-check on object
 236         final Word mark = loadWordFromObject(object, markOffset(INJECTED_VMCONFIG));
 237 
 238         final Word lock = beginLockScope(lockDepth);
 239 
 240         Pointer objectPointer = Word.objectToTrackedPointer(object);
 241         trace(trace, "           object: 0x%016lx\n", objectPointer);
 242         trace(trace, "             lock: 0x%016lx\n", lock);
 243         trace(trace, "             mark: 0x%016lx\n", mark);
 244 
 245         incCounter();
 246 
 247         if (useBiasedLocking(INJECTED_VMCONFIG)) {
 248             if (tryEnterBiased(object, hub, lock, mark, threadRegister, trace, counters)) {
 249                 return;
 250             }
 251             // not biased, fall-through
 252         }
 253         if (inlineFastLockSupported() && probability(SLOW_PATH_PROBABILITY, mark.and(monitorMask(INJECTED_VMCONFIG)).notEqual(0))) {
 254             // Inflated case
 255             if (tryEnterInflated(object, lock, mark, threadRegister, trace, counters)) {
 256                 return;
 257             }
 258         } else {
 259             // Create the unlocked mark word pattern
 260             Word unlockedMark = mark.or(unlockedMask(INJECTED_VMCONFIG));
 261             trace(trace, "     unlockedMark: 0x%016lx\n", unlockedMark);
 262 
 263             // Copy this unlocked mark word into the lock slot on the stack
 264             lock.writeWord(lockDisplacedMarkOffset(INJECTED_VMCONFIG), unlockedMark, DISPLACED_MARK_WORD_LOCATION);
 265 
 266             // make sure previous store does not float below compareAndSwap
 267             MembarNode.memoryBarrier(STORE_STORE);
 268 
 269             // Test if the object's mark word is unlocked, and if so, store the
 270             // (address of) the lock slot into the object's mark word.
 271             Word currentMark = objectPointer.compareAndSwapWord(markOffset(INJECTED_VMCONFIG), unlockedMark, lock, MARK_WORD_LOCATION);
 272             if (probability(FAST_PATH_PROBABILITY, currentMark.equal(unlockedMark))) {
 273                 traceObject(trace, "+lock{cas}", object, true);
 274                 counters.lockCas.inc();
 275                 mark(object);
 276                 return;
 277             } else {
 278                 trace(trace, "      currentMark: 0x%016lx\n", currentMark);
 279                 // The mark word in the object header was not the same.
 280                 // Either the object is locked by another thread or is already locked
 281                 // by the current thread. The latter is true if the mark word
 282                 // is a stack pointer into the current thread's stack, i.e.:
 283                 //
 284                 // 1) (currentMark & aligned_mask) == 0
 285                 // 2) rsp <= currentMark
 286                 // 3) currentMark <= rsp + page_size
 287                 //
 288                 // These 3 tests can be done by evaluating the following expression:
 289                 //
 290                 // (currentMark - rsp) & (aligned_mask - page_size)
 291                 //
 292                 // assuming both the stack pointer and page_size have their least
 293                 // significant 2 bits cleared and page_size is a power of 2
 294                 final Word alignedMask = unsigned(wordSize() - 1);
 295                 final Word stackPointer = registerAsWord(stackPointerRegister).add(stackBias(INJECTED_VMCONFIG));
 296                 if (probability(FAST_PATH_PROBABILITY, currentMark.subtract(stackPointer).and(alignedMask.subtract(pageSize(INJECTED_VMCONFIG))).equal(0))) {
 297                     // Recursively locked => write 0 to the lock slot
 298                     lock.writeWord(lockDisplacedMarkOffset(INJECTED_VMCONFIG), zero(), DISPLACED_MARK_WORD_LOCATION);
 299                     traceObject(trace, "+lock{cas:recursive}", object, true);
 300                     counters.lockCasRecursive.inc();
 301                     return;
 302                 }
 303                 traceObject(trace, "+lock{stub:failed-cas/stack}", object, true);
 304                 counters.lockStubFailedCas.inc();
 305             }
 306         }
 307         // slow-path runtime-call
 308         monitorenterStubC(MONITORENTER, object, lock);
 309     }
 310 
 311     private static boolean tryEnterBiased(Object object, KlassPointer hub, Word lock, Word mark, Register threadRegister, boolean trace, Counters counters) {
 312         // See whether the lock is currently biased toward our thread and
 313         // whether the epoch is still valid.
 314         // Note that the runtime guarantees sufficient alignment of JavaThread
 315         // pointers to allow age to be placed into low bits.
 316         final Word biasableLockBits = mark.and(biasedLockMaskInPlace(INJECTED_VMCONFIG));
 317 
 318         // Check whether the bias pattern is present in the object's mark word
 319         // and the bias owner and the epoch are both still current.
 320         final Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(INJECTED_VMCONFIG), PROTOTYPE_MARK_WORD_LOCATION);
 321         final Word thread = registerAsWord(threadRegister);
 322         final Word tmp = prototypeMarkWord.or(thread).xor(mark).and(~ageMaskInPlace(INJECTED_VMCONFIG));
 323         trace(trace, "prototypeMarkWord: 0x%016lx\n", prototypeMarkWord);
 324         trace(trace, "           thread: 0x%016lx\n", thread);
 325         trace(trace, "              tmp: 0x%016lx\n", tmp);
 326         if (probability(FAST_PATH_PROBABILITY, tmp.equal(0))) {
 327             // Object is already biased to current thread -> done
 328             traceObject(trace, "+lock{bias:existing}", object, true);
 329             counters.lockBiasExisting.inc();
 330             FastAcquireBiasedLockNode.mark(object);
 331             return true;
 332         }
 333 
 334         // Now check to see whether biasing is enabled for this object
 335         if (probability(NOT_FREQUENT_PROBABILITY, biasableLockBits.equal(WordFactory.unsigned(biasedLockPattern(INJECTED_VMCONFIG))))) {
 336             Pointer objectPointer = Word.objectToTrackedPointer(object);
 337             // At this point we know that the mark word has the bias pattern and
 338             // that we are not the bias owner in the current epoch. We need to
 339             // figure out more details about the state of the mark word in order to
 340             // know what operations can be legally performed on the object's
 341             // mark word.
 342 
 343             // If the low three bits in the xor result aren't clear, that means
 344             // the prototype header is no longer biasable and we have to revoke
 345             // the bias on this object.
 346             if (probability(FREQUENT_PROBABILITY, tmp.and(biasedLockMaskInPlace(INJECTED_VMCONFIG)).equal(0))) {
 347                 // Biasing is still enabled for object's type. See whether the
 348                 // epoch of the current bias is still valid, meaning that the epoch
 349                 // bits of the mark word are equal to the epoch bits of the
 350                 // prototype mark word. (Note that the prototype mark word's epoch bits
 351                 // only change at a safepoint.) If not, attempt to rebias the object
 352                 // toward the current thread. Note that we must be absolutely sure
 353                 // that the current epoch is invalid in order to do this because
 354                 // otherwise the manipulations it performs on the mark word are
 355                 // illegal.
 356                 if (probability(FREQUENT_PROBABILITY, tmp.and(epochMaskInPlace(INJECTED_VMCONFIG)).equal(0))) {
 357                     // The epoch of the current bias is still valid but we know nothing
 358                     // about the owner; it might be set or it might be clear. Try to
 359                     // acquire the bias of the object using an atomic operation. If this
 360                     // fails we will go in to the runtime to revoke the object's bias.
 361                     // Note that we first construct the presumed unbiased header so we
 362                     // don't accidentally blow away another thread's valid bias.
 363                     Word unbiasedMark = mark.and(biasedLockMaskInPlace(INJECTED_VMCONFIG) | ageMaskInPlace(INJECTED_VMCONFIG) | epochMaskInPlace(INJECTED_VMCONFIG));
 364                     Word biasedMark = unbiasedMark.or(thread);
 365                     trace(trace, "     unbiasedMark: 0x%016lx\n", unbiasedMark);
 366                     trace(trace, "       biasedMark: 0x%016lx\n", biasedMark);
 367                     if (probability(VERY_FAST_PATH_PROBABILITY, objectPointer.logicCompareAndSwapWord(markOffset(INJECTED_VMCONFIG), unbiasedMark, biasedMark, MARK_WORD_LOCATION))) {
 368                         // Object is now biased to current thread -> done
 369                         traceObject(trace, "+lock{bias:acquired}", object, true);
 370                         counters.lockBiasAcquired.inc();
 371                         return true;
 372                     }
 373                     // If the biasing toward our thread failed, this means that another thread
 374                     // owns the bias and we need to revoke that bias. The revocation will occur
 375                     // in the interpreter runtime.
 376                     traceObject(trace, "+lock{stub:revoke}", object, true);
 377                     counters.lockStubRevoke.inc();
 378                 } else {
 379                     // At this point we know the epoch has expired, meaning that the
 380                     // current bias owner, if any, is actually invalid. Under these
 381                     // circumstances _only_, are we allowed to use the current mark word
 382                     // value as the comparison value when doing the CAS to acquire the
 383                     // bias in the current epoch. In other words, we allow transfer of
 384                     // the bias from one thread to another directly in this situation.
 385                     Word biasedMark = prototypeMarkWord.or(thread);
 386                     trace(trace, "       biasedMark: 0x%016lx\n", biasedMark);
 387                     if (probability(VERY_FAST_PATH_PROBABILITY, objectPointer.logicCompareAndSwapWord(markOffset(INJECTED_VMCONFIG), mark, biasedMark, MARK_WORD_LOCATION))) {
 388                         // Object is now biased to current thread -> done
 389                         traceObject(trace, "+lock{bias:transfer}", object, true);
 390                         counters.lockBiasTransfer.inc();
 391                         return true;
 392                     }
 393                     // If the biasing toward our thread failed, then another thread
 394                     // succeeded in biasing it toward itself and we need to revoke that
 395                     // bias. The revocation will occur in the runtime in the slow case.
 396                     traceObject(trace, "+lock{stub:epoch-expired}", object, true);
 397                     counters.lockStubEpochExpired.inc();
 398                 }
 399                 // slow-path runtime-call
 400                 monitorenterStubC(MONITORENTER, object, lock);
 401                 return true;
 402             } else {
 403                 // The prototype mark word doesn't have the bias bit set any
 404                 // more, indicating that objects of this data type are not supposed
 405                 // to be biased any more. We are going to try to reset the mark of
 406                 // this object to the prototype value and fall through to the
 407                 // CAS-based locking scheme. Note that if our CAS fails, it means
 408                 // that another thread raced us for the privilege of revoking the
 409                 // bias of this particular object, so it's okay to continue in the
 410                 // normal locking code.
 411                 Word result = objectPointer.compareAndSwapWord(markOffset(INJECTED_VMCONFIG), mark, prototypeMarkWord, MARK_WORD_LOCATION);
 412 
 413                 // Fall through to the normal CAS-based lock, because no matter what
 414                 // the result of the above CAS, some thread must have succeeded in
 415                 // removing the bias bit from the object's header.
 416 
 417                 if (ENABLE_BREAKPOINT) {
 418                     bkpt(object, mark, tmp, result);
 419                 }
 420                 counters.revokeBias.inc();
 421                 return false;
 422             }
 423         } else {
 424             // Biasing not enabled -> fall through to lightweight locking
 425             counters.unbiasable.inc();
 426             return false;
 427         }
 428     }
 429 
 430     @Fold
 431     public static boolean useFastInflatedLocking(@Fold.InjectedParameter OptionValues options) {
 432         return SimpleFastInflatedLocking.getValue(options);
 433     }
 434 
 435     private static boolean inlineFastLockSupported() {
 436         return inlineFastLockSupported(INJECTED_VMCONFIG, INJECTED_OPTIONVALUES);
 437     }
 438 
 439     private static boolean inlineFastLockSupported(GraalHotSpotVMConfig config, OptionValues options) {
 440         return useFastInflatedLocking(options) && monitorMask(config) >= 0 && objectMonitorOwnerOffset(config) >= 0;
 441     }
 442 
 443     private static boolean tryEnterInflated(Object object, Word lock, Word mark, Register threadRegister, boolean trace, Counters counters) {
 444         // write non-zero value to lock slot
 445         lock.writeWord(lockDisplacedMarkOffset(INJECTED_VMCONFIG), lock, DISPLACED_MARK_WORD_LOCATION);
 446         // mark is a pointer to the ObjectMonitor + monitorMask
 447         Word monitor = mark.subtract(monitorMask(INJECTED_VMCONFIG));
 448         int ownerOffset = objectMonitorOwnerOffset(INJECTED_VMCONFIG);
 449         Word owner = monitor.readWord(ownerOffset, OBJECT_MONITOR_OWNER_LOCATION);
 450         if (probability(FREQUENT_PROBABILITY, owner.equal(0))) {
 451             // it appears unlocked (owner == 0)
 452             if (probability(FREQUENT_PROBABILITY, monitor.logicCompareAndSwapWord(ownerOffset, owner, registerAsWord(threadRegister), OBJECT_MONITOR_OWNER_LOCATION))) {
 453                 // success
 454                 traceObject(trace, "+lock{inflated:cas}", object, true);
 455                 counters.inflatedCas.inc();
 456                 return true;
 457             } else {
 458                 traceObject(trace, "+lock{stub:inflated:failed-cas}", object, true);
 459                 counters.inflatedFailedCas.inc();
 460             }
 461         } else {
 462             traceObject(trace, "+lock{stub:inflated:owned}", object, true);
 463             counters.inflatedOwned.inc();
 464         }
 465         return false;
 466     }
 467 
 468     /**
 469      * Calls straight out to the monitorenter stub.
 470      */
 471     @Snippet
 472     public static void monitorenterStub(Object object, @ConstantParameter int lockDepth, @ConstantParameter boolean trace) {
 473         verifyOop(object);
 474         incCounter();
 475         if (object == null) {
 476             DeoptimizeNode.deopt(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.NullCheckException);
 477         }
 478         // BeginLockScope nodes do not read from object so a use of object
 479         // cannot float about the null check above
 480         final Word lock = beginLockScope(lockDepth);
 481         traceObject(trace, "+lock{stub}", object, true);
 482         monitorenterStubC(MONITORENTER, object, lock);
 483     }
 484 
 485     @Snippet
 486     public static void monitorexit(Object object, @ConstantParameter int lockDepth, @ConstantParameter Register threadRegister, @ConstantParameter boolean trace,
 487                     @ConstantParameter Counters counters) {
 488         trace(trace, "           object: 0x%016lx\n", Word.objectToTrackedPointer(object));
 489         final Word mark = loadWordFromObject(object, markOffset(INJECTED_VMCONFIG));
 490         if (useBiasedLocking(INJECTED_VMCONFIG)) {
 491             // Check for biased locking unlock case, which is a no-op
 492             // Note: we do not have to check the thread ID for two reasons.
 493             // First, the interpreter checks for IllegalMonitorStateException at
 494             // a higher level. Second, if the bias was revoked while we held the
 495             // lock, the object could not be rebiased toward another thread, so
 496             // the bias bit would be clear.
 497             trace(trace, "             mark: 0x%016lx\n", mark);
 498             if (probability(FREQUENT_PROBABILITY, mark.and(biasedLockMaskInPlace(INJECTED_VMCONFIG)).equal(WordFactory.unsigned(biasedLockPattern(INJECTED_VMCONFIG))))) {
 499                 endLockScope();
 500                 decCounter();
 501                 traceObject(trace, "-lock{bias}", object, false);
 502                 counters.unlockBias.inc();
 503                 return;
 504             }
 505         }
 506 
 507         final Word lock = CurrentLockNode.currentLock(lockDepth);
 508 
 509         // Load displaced mark
 510         final Word displacedMark = lock.readWord(lockDisplacedMarkOffset(INJECTED_VMCONFIG), DISPLACED_MARK_WORD_LOCATION);
 511         trace(trace, "    displacedMark: 0x%016lx\n", displacedMark);
 512 
 513         if (probability(NOT_LIKELY_PROBABILITY, displacedMark.equal(0))) {
 514             // Recursive locking => done
 515             traceObject(trace, "-lock{recursive}", object, false);
 516             counters.unlockCasRecursive.inc();
 517         } else {
 518             if (!tryExitInflated(object, mark, lock, threadRegister, trace, counters)) {
 519                 verifyOop(object);
 520                 // Test if object's mark word is pointing to the displaced mark word, and if so,
 521                 // restore
 522                 // the displaced mark in the object - if the object's mark word is not pointing to
 523                 // the displaced mark word, do unlocking via runtime call.
 524                 Pointer objectPointer = Word.objectToTrackedPointer(object);
 525                 if (probability(VERY_FAST_PATH_PROBABILITY, objectPointer.logicCompareAndSwapWord(markOffset(INJECTED_VMCONFIG), lock, displacedMark, MARK_WORD_LOCATION))) {
 526                     traceObject(trace, "-lock{cas}", object, false);
 527                     counters.unlockCas.inc();
 528                 } else {
 529                     // The object's mark word was not pointing to the displaced header
 530                     traceObject(trace, "-lock{stub}", object, false);
 531                     counters.unlockStub.inc();
 532                     monitorexitStubC(MONITOREXIT, object, lock);
 533                 }
 534             }
 535         }
 536         endLockScope();
 537         decCounter();
 538     }
 539 
 540     private static boolean inlineFastUnlockSupported(OptionValues options) {
 541         return inlineFastUnlockSupported(INJECTED_VMCONFIG, options);
 542     }
 543 
 544     private static boolean inlineFastUnlockSupported(GraalHotSpotVMConfig config, OptionValues options) {
 545         return useFastInflatedLocking(options) && objectMonitorEntryListOffset(config) >= 0 && objectMonitorCxqOffset(config) >= 0 && monitorMask(config) >= 0 &&
 546                         objectMonitorOwnerOffset(config) >= 0 && objectMonitorRecursionsOffset(config) >= 0;
 547     }
 548 
 549     private static boolean tryExitInflated(Object object, Word mark, Word lock, Register threadRegister, boolean trace, Counters counters) {
 550         if (!inlineFastUnlockSupported(INJECTED_OPTIONVALUES)) {
 551             return false;
 552         }
 553         if (probability(SLOW_PATH_PROBABILITY, mark.and(monitorMask(INJECTED_VMCONFIG)).notEqual(0))) {
 554             // Inflated case
 555             // mark is a pointer to the ObjectMonitor + monitorMask
 556             Word monitor = mark.subtract(monitorMask(INJECTED_VMCONFIG));
 557             int ownerOffset = objectMonitorOwnerOffset(INJECTED_VMCONFIG);
 558             Word owner = monitor.readWord(ownerOffset, OBJECT_MONITOR_OWNER_LOCATION);
 559             int recursionsOffset = objectMonitorRecursionsOffset(INJECTED_VMCONFIG);
 560             Word recursions = monitor.readWord(recursionsOffset, OBJECT_MONITOR_RECURSION_LOCATION);
 561             Word thread = registerAsWord(threadRegister);
 562             if (probability(FAST_PATH_PROBABILITY, owner.xor(thread).or(recursions).equal(0))) {
 563                 // owner == thread && recursions == 0
 564                 int cxqOffset = objectMonitorCxqOffset(INJECTED_VMCONFIG);
 565                 Word cxq = monitor.readWord(cxqOffset, OBJECT_MONITOR_CXQ_LOCATION);
 566                 int entryListOffset = objectMonitorEntryListOffset(INJECTED_VMCONFIG);
 567                 Word entryList = monitor.readWord(entryListOffset, OBJECT_MONITOR_ENTRY_LIST_LOCATION);
 568                 if (probability(FREQUENT_PROBABILITY, cxq.or(entryList).equal(0))) {
 569                     // cxq == 0 && entryList == 0
 570                     // Nobody is waiting, success
 571                     // release_store
 572                     memoryBarrier(LOAD_STORE | STORE_STORE);
 573                     monitor.writeWord(ownerOffset, zero());
 574                     traceObject(trace, "-lock{inflated:simple}", object, false);
 575                     counters.unlockInflatedSimple.inc();
 576                     return true;
 577                 }
 578             }
 579             counters.unlockStubInflated.inc();
 580             traceObject(trace, "-lock{stub:inflated}", object, false);
 581             monitorexitStubC(MONITOREXIT, object, lock);
 582             return true;
 583         }
 584         return false;
 585     }
 586 
 587     /**
 588      * Calls straight out to the monitorexit stub.
 589      */
 590     @Snippet
 591     public static void monitorexitStub(Object object, @ConstantParameter int lockDepth, @ConstantParameter boolean trace) {
 592         verifyOop(object);
 593         traceObject(trace, "-lock{stub}", object, false);
 594         final Word lock = CurrentLockNode.currentLock(lockDepth);
 595         monitorexitStubC(MONITOREXIT, object, lock);
 596         endLockScope();
 597         decCounter();
 598     }
 599 
 600     public static void traceObject(boolean enabled, String action, Object object, boolean enter) {
 601         if (doProfile(INJECTED_OPTIONVALUES)) {
 602             DynamicCounterNode.counter(enter ? "number of monitor enters" : "number of monitor exits", action, 1, PROFILE_CONTEXT);
 603         }
 604         if (enabled) {
 605             Log.print(action);
 606             Log.print(' ');
 607             Log.printlnObject(object);
 608         }
 609     }
 610 
 611     public static void trace(boolean enabled, String format, WordBase value) {
 612         if (enabled) {
 613             Log.printf(format, value.rawValue());
 614         }
 615     }
 616 
 617     /**
 618      * Leaving the breakpoint code in to provide an example of how to use the {@link BreakpointNode}
 619      * intrinsic.
 620      */
 621     private static final boolean ENABLE_BREAKPOINT = false;
 622 
 623     private static final LocationIdentity MONITOR_COUNTER_LOCATION = NamedLocationIdentity.mutable("MonitorCounter");
 624 
 625     @NodeIntrinsic(BreakpointNode.class)
 626     static native void bkpt(Object object, Word mark, Word tmp, Word value);
 627 
 628     @Fold
 629     static boolean verifyBalancedMonitors(@Fold.InjectedParameter OptionValues options) {
 630         return VerifyBalancedMonitors.getValue(options);
 631     }
 632 
 633     static void incCounter() {
 634         if (verifyBalancedMonitors(INJECTED_OPTIONVALUES)) {
 635             final Word counter = MonitorCounterNode.counter();
 636             final int count = counter.readInt(0, MONITOR_COUNTER_LOCATION);
 637             counter.writeInt(0, count + 1, MONITOR_COUNTER_LOCATION);
 638         }
 639     }
 640 
 641     public static void decCounter() {
 642         if (verifyBalancedMonitors(INJECTED_OPTIONVALUES)) {
 643             final Word counter = MonitorCounterNode.counter();
 644             final int count = counter.readInt(0, MONITOR_COUNTER_LOCATION);
 645             counter.writeInt(0, count - 1, MONITOR_COUNTER_LOCATION);
 646         }
 647     }
 648 
 649     @Snippet
 650     private static void initCounter() {
 651         final Word counter = MonitorCounterNode.counter();
 652         counter.writeInt(0, 0, MONITOR_COUNTER_LOCATION);
 653     }
 654 
 655     @Snippet
 656     private static void checkCounter(@ConstantParameter String errMsg) {
 657         final Word counter = MonitorCounterNode.counter();
 658         final int count = counter.readInt(0, MONITOR_COUNTER_LOCATION);
 659         if (count != 0) {
 660             vmError(errMsg, count);
 661         }
 662     }


 737             this.useFastLocking = useFastLocking;
 738 
 739             this.counters = new Counters(factory);
 740         }
 741 
 742         public void lower(RawMonitorEnterNode monitorenterNode, HotSpotRegistersProvider registers, LoweringTool tool) {
 743             StructuredGraph graph = monitorenterNode.graph();
 744             checkBalancedMonitors(graph, tool);
 745 
 746             assert ((ObjectStamp) monitorenterNode.object().stamp(NodeView.DEFAULT)).nonNull();
 747 
 748             Arguments args;
 749             if (useFastLocking) {
 750                 args = new Arguments(monitorenter, graph.getGuardsStage(), tool.getLoweringStage());
 751                 args.add("object", monitorenterNode.object());
 752                 args.add("hub", monitorenterNode.getHub());
 753                 args.addConst("lockDepth", monitorenterNode.getMonitorId().getLockDepth());
 754                 args.addConst("threadRegister", registers.getThreadRegister());
 755                 args.addConst("stackPointerRegister", registers.getStackPointerRegister());
 756                 args.addConst("trace", isTracingEnabledForType(monitorenterNode.object()) || isTracingEnabledForMethod(graph));

 757                 args.addConst("counters", counters);
 758             } else {
 759                 args = new Arguments(monitorenterStub, graph.getGuardsStage(), tool.getLoweringStage());
 760                 args.add("object", monitorenterNode.object());
 761                 args.addConst("lockDepth", monitorenterNode.getMonitorId().getLockDepth());
 762                 args.addConst("trace", isTracingEnabledForType(monitorenterNode.object()) || isTracingEnabledForMethod(graph));

 763                 args.addConst("counters", counters);
 764             }
 765 
 766             template(monitorenterNode, args).instantiate(providers.getMetaAccess(), monitorenterNode, DEFAULT_REPLACER, args);
 767         }
 768 
 769         public void lower(MonitorExitNode monitorexitNode, HotSpotRegistersProvider registers, LoweringTool tool) {
 770             StructuredGraph graph = monitorexitNode.graph();
 771 
 772             Arguments args;
 773             if (useFastLocking) {
 774                 args = new Arguments(monitorexit, graph.getGuardsStage(), tool.getLoweringStage());
 775             } else {
 776                 args = new Arguments(monitorexitStub, graph.getGuardsStage(), tool.getLoweringStage());
 777             }
 778             args.add("object", monitorexitNode.object());
 779             args.addConst("lockDepth", monitorexitNode.getMonitorId().getLockDepth());
 780             args.addConst("threadRegister", registers.getThreadRegister());
 781             args.addConst("trace", isTracingEnabledForType(monitorexitNode.object()) || isTracingEnabledForMethod(graph));

 782             args.addConst("counters", counters);
 783 
 784             template(monitorexitNode, args).instantiate(providers.getMetaAccess(), monitorexitNode, DEFAULT_REPLACER, args);
 785         }
 786 
 787         public static boolean isTracingEnabledForType(ValueNode object) {
 788             ResolvedJavaType type = StampTool.typeOrNull(object.stamp(NodeView.DEFAULT));
 789             String filter = TraceMonitorsTypeFilter.getValue(object.getOptions());
 790             if (filter == null) {
 791                 return false;
 792             } else {
 793                 if (filter.length() == 0) {
 794                     return true;
 795                 }
 796                 if (type == null) {
 797                     return false;
 798                 }
 799                 return (type.getName().contains(filter));
 800             }
 801         }


< prev index next >