< prev index next >

src/hotspot/cpu/sparc/macroAssembler_sparc.cpp

Print this page
rev 51633 : imported patch 8210381


2631 // SPARC refworkload performance - specifically jetstream and scimark - are
2632 // extremely sensitive to the size of the code emitted by compiler_lock_object
2633 // and compiler_unlock_object.  Critically, the key factor is code size, not path
2634 // length.  (Simply experiments to pad CLO with unexecuted NOPs demonstrte the
2635 // effect).
2636 
2637 
2638 void MacroAssembler::compiler_lock_object(Register Roop, Register Rmark,
2639                                           Register Rbox, Register Rscratch,
2640                                           BiasedLockingCounters* counters,
2641                                           bool try_bias) {
2642    Address mark_addr(Roop, oopDesc::mark_offset_in_bytes());
2643 
2644    verify_oop(Roop);
2645    Label done ;
2646 
2647    if (counters != NULL) {
2648      inc_counter((address) counters->total_entry_count_addr(), Rmark, Rscratch);
2649    }
2650 
2651    if (EmitSync & 1) {
2652      mov(3, Rscratch);
2653      st_ptr(Rscratch, Rbox, BasicLock::displaced_header_offset_in_bytes());
2654      cmp(SP, G0);
2655      return ;
2656    }
2657 
2658    if (EmitSync & 2) {
2659 
2660      // Fetch object's markword
2661      ld_ptr(mark_addr, Rmark);
2662 
2663      if (try_bias) {
2664         biased_locking_enter(Roop, Rmark, Rscratch, done, NULL, counters);
2665      }
2666 
2667      // Save Rbox in Rscratch to be used for the cas operation
2668      mov(Rbox, Rscratch);
2669 
2670      // set Rmark to markOop | markOopDesc::unlocked_value
2671      or3(Rmark, markOopDesc::unlocked_value, Rmark);
2672 
2673      // Initialize the box.  (Must happen before we update the object mark!)
2674      st_ptr(Rmark, Rbox, BasicLock::displaced_header_offset_in_bytes());
2675 
2676      // compare object markOop with Rmark and if equal exchange Rscratch with object markOop
2677      assert(mark_addr.disp() == 0, "cas must take a zero displacement");
2678      cas_ptr(mark_addr.base(), Rmark, Rscratch);
2679 
2680      // if compare/exchange succeeded we found an unlocked object and we now have locked it
2681      // hence we are done
2682      cmp(Rmark, Rscratch);
2683      sub(Rscratch, STACK_BIAS, Rscratch);
2684      brx(Assembler::equal, false, Assembler::pt, done);
2685      delayed()->sub(Rscratch, SP, Rscratch);  //pull next instruction into delay slot
2686 
2687      // we did not find an unlocked object so see if this is a recursive case
2688      // sub(Rscratch, SP, Rscratch);
2689      assert(os::vm_page_size() > 0xfff, "page size too small - change the constant");
2690      andcc(Rscratch, 0xfffff003, Rscratch);
2691      st_ptr(Rscratch, Rbox, BasicLock::displaced_header_offset_in_bytes());
2692      bind (done);
2693      return ;
2694    }
2695 
2696    Label Egress ;
2697 
2698    if (EmitSync & 256) {
2699       Label IsInflated ;
2700 
2701       ld_ptr(mark_addr, Rmark);           // fetch obj->mark
2702       // Triage: biased, stack-locked, neutral, inflated
2703       if (try_bias) {
2704         biased_locking_enter(Roop, Rmark, Rscratch, done, NULL, counters);
2705         // Invariant: if control reaches this point in the emitted stream
2706         // then Rmark has not been modified.
2707       }
2708 
2709       // Store mark into displaced mark field in the on-stack basic-lock "box"
2710       // Critically, this must happen before the CAS
2711       // Maximize the ST-CAS distance to minimize the ST-before-CAS penalty.
2712       st_ptr(Rmark, Rbox, BasicLock::displaced_header_offset_in_bytes());
2713       andcc(Rmark, 2, G0);
2714       brx(Assembler::notZero, false, Assembler::pn, IsInflated);
2715       delayed()->
2716 
2717       // Try stack-lock acquisition.
2718       // Beware: the 1st instruction is in a delay slot
2719       mov(Rbox,  Rscratch);
2720       or3(Rmark, markOopDesc::unlocked_value, Rmark);
2721       assert(mark_addr.disp() == 0, "cas must take a zero displacement");
2722       cas_ptr(mark_addr.base(), Rmark, Rscratch);
2723       cmp(Rmark, Rscratch);
2724       brx(Assembler::equal, false, Assembler::pt, done);
2725       delayed()->sub(Rscratch, SP, Rscratch);
2726 
2727       // Stack-lock attempt failed - check for recursive stack-lock.
2728       // See the comments below about how we might remove this case.
2729       sub(Rscratch, STACK_BIAS, Rscratch);
2730       assert(os::vm_page_size() > 0xfff, "page size too small - change the constant");
2731       andcc(Rscratch, 0xfffff003, Rscratch);
2732       br(Assembler::always, false, Assembler::pt, done);
2733       delayed()-> st_ptr(Rscratch, Rbox, BasicLock::displaced_header_offset_in_bytes());
2734 
2735       bind(IsInflated);
2736       if (EmitSync & 64) {
2737          // If m->owner != null goto IsLocked
2738          // Pessimistic form: Test-and-CAS vs CAS
2739          // The optimistic form avoids RTS->RTO cache line upgrades.
2740          ld_ptr(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner), Rscratch);
2741          andcc(Rscratch, Rscratch, G0);
2742          brx(Assembler::notZero, false, Assembler::pn, done);
2743          delayed()->nop();
2744          // m->owner == null : it's unlocked.
2745       }
2746 
2747       // Try to CAS m->owner from null to Self
2748       // Invariant: if we acquire the lock then _recursions should be 0.
2749       add(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner), Rmark);
2750       mov(G2_thread, Rscratch);
2751       cas_ptr(Rmark, G0, Rscratch);
2752       cmp(Rscratch, G0);
2753       // Intentional fall-through into done
2754    } else {
2755       // Aggressively avoid the Store-before-CAS penalty
2756       // Defer the store into box->dhw until after the CAS
2757       Label IsInflated, Recursive ;
2758 
2759 // Anticipate CAS -- Avoid RTS->RTO upgrade
2760 // prefetch (mark_addr, Assembler::severalWritesAndPossiblyReads);
2761 
2762       ld_ptr(mark_addr, Rmark);           // fetch obj->mark
2763       // Triage: biased, stack-locked, neutral, inflated
2764 
2765       if (try_bias) {
2766         biased_locking_enter(Roop, Rmark, Rscratch, done, NULL, counters);
2767         // Invariant: if control reaches this point in the emitted stream
2768         // then Rmark has not been modified.
2769       }
2770       andcc(Rmark, 2, G0);
2771       brx(Assembler::notZero, false, Assembler::pn, IsInflated);
2772       delayed()->                         // Beware - dangling delay-slot
2773 
2774       // Try stack-lock acquisition.


2819         ba_short(done);
2820       } else {
2821         ba(done);
2822         delayed()->st_ptr(Rscratch, Rbox, BasicLock::displaced_header_offset_in_bytes());
2823       }
2824 
2825       bind   (IsInflated);
2826 
2827       // Try to CAS m->owner from null to Self
2828       // Invariant: if we acquire the lock then _recursions should be 0.
2829       add(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner), Rmark);
2830       mov(G2_thread, Rscratch);
2831       cas_ptr(Rmark, G0, Rscratch);
2832       andcc(Rscratch, Rscratch, G0);             // set ICCs for done: icc.zf iff success
2833       // set icc.zf : 1=success 0=failure
2834       // ST box->displaced_header = NonZero.
2835       // Any non-zero value suffices:
2836       //    markOopDesc::unused_mark(), G2_thread, RBox, RScratch, rsp, etc.
2837       st_ptr(Rbox, Rbox, BasicLock::displaced_header_offset_in_bytes());
2838       // Intentional fall-through into done
2839    }
2840 
2841    bind   (done);
2842 }
2843 
2844 void MacroAssembler::compiler_unlock_object(Register Roop, Register Rmark,
2845                                             Register Rbox, Register Rscratch,
2846                                             bool try_bias) {
2847    Address mark_addr(Roop, oopDesc::mark_offset_in_bytes());
2848 
2849    Label done ;
2850 
2851    if (EmitSync & 4) {
2852      cmp(SP, G0);
2853      return ;
2854    }
2855 
2856    if (EmitSync & 8) {
2857      if (try_bias) {
2858         biased_locking_exit(mark_addr, Rscratch, done);
2859      }
2860 
2861      // Test first if it is a fast recursive unlock
2862      ld_ptr(Rbox, BasicLock::displaced_header_offset_in_bytes(), Rmark);
2863      br_null_short(Rmark, Assembler::pt, done);
2864 
2865      // Check if it is still a light weight lock, this is is true if we see
2866      // the stack address of the basicLock in the markOop of the object
2867      assert(mark_addr.disp() == 0, "cas must take a zero displacement");
2868      cas_ptr(mark_addr.base(), Rbox, Rmark);
2869      ba(done);
2870      delayed()->cmp(Rbox, Rmark);
2871      bind(done);
2872      return ;
2873    }
2874 
2875    // Beware ... If the aggregate size of the code emitted by CLO and CUO is
2876    // is too large performance rolls abruptly off a cliff.
2877    // This could be related to inlining policies, code cache management, or
2878    // I$ effects.
2879    Label LStacked ;
2880 
2881    if (try_bias) {
2882       // TODO: eliminate redundant LDs of obj->mark
2883       biased_locking_exit(mark_addr, Rscratch, done);
2884    }
2885 
2886    ld_ptr(Roop, oopDesc::mark_offset_in_bytes(), Rmark);
2887    ld_ptr(Rbox, BasicLock::displaced_header_offset_in_bytes(), Rscratch);
2888    andcc(Rscratch, Rscratch, G0);
2889    brx(Assembler::zero, false, Assembler::pn, done);
2890    delayed()->nop();      // consider: relocate fetch of mark, above, into this DS
2891    andcc(Rmark, 2, G0);
2892    brx(Assembler::zero, false, Assembler::pt, LStacked);
2893    delayed()->nop();
2894 
2895    // It's inflated
2896    // Conceptually we need a #loadstore|#storestore "release" MEMBAR before
2897    // the ST of 0 into _owner which releases the lock.  This prevents loads
2898    // and stores within the critical section from reordering (floating)
2899    // past the store that releases the lock.  But TSO is a strong memory model
2900    // and that particular flavor of barrier is a noop, so we can safely elide it.
2901    // Note that we use 1-0 locking by default for the inflated case.  We
2902    // close the resultant (and rare) race by having contended threads in
2903    // monitorenter periodically poll _owner.
2904 
2905    if (EmitSync & 1024) {
2906      // Emit code to check that _owner == Self
2907      // We could fold the _owner test into subsequent code more efficiently
2908      // than using a stand-alone check, but since _owner checking is off by
2909      // default we don't bother. We also might consider predicating the
2910      // _owner==Self check on Xcheck:jni or running on a debug build.
2911      ld_ptr(Address(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)), Rscratch);
2912      orcc(Rscratch, G0, G0);
2913      brx(Assembler::notZero, false, Assembler::pn, done);
2914      delayed()->nop();
2915    }
2916 
2917    if (EmitSync & 512) {
2918      // classic lock release code absent 1-0 locking
2919      //   m->Owner = null;
2920      //   membar #storeload
2921      //   if (m->cxq|m->EntryList) == null goto Success
2922      //   if (m->succ != null) goto Success
2923      //   if CAS (&m->Owner,0,Self) != 0 goto Success
2924      //   goto SlowPath
2925      ld_ptr(Address(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions)), Rbox);
2926      orcc(Rbox, G0, G0);
2927      brx(Assembler::notZero, false, Assembler::pn, done);
2928      delayed()->nop();
2929      st_ptr(G0, Address(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)));
2930      if (os::is_MP()) { membar(StoreLoad); }
2931      ld_ptr(Address(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(EntryList)), Rscratch);
2932      ld_ptr(Address(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(cxq)), Rbox);
2933      orcc(Rbox, Rscratch, G0);
2934      brx(Assembler::zero, false, Assembler::pt, done);
2935      delayed()->
2936      ld_ptr(Address(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(succ)), Rscratch);
2937      andcc(Rscratch, Rscratch, G0);
2938      brx(Assembler::notZero, false, Assembler::pt, done);
2939      delayed()->andcc(G0, G0, G0);
2940      add(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner), Rmark);
2941      mov(G2_thread, Rscratch);
2942      cas_ptr(Rmark, G0, Rscratch);
2943      cmp(Rscratch, G0);
2944      // invert icc.zf and goto done
2945      brx(Assembler::notZero, false, Assembler::pt, done);
2946      delayed()->cmp(G0, G0);
2947      br(Assembler::always, false, Assembler::pt, done);
2948      delayed()->cmp(G0, 1);
2949    } else {
2950      // 1-0 form : avoids CAS and MEMBAR in the common case
2951      // Do not bother to ratify that m->Owner == Self.
2952      ld_ptr(Address(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions)), Rbox);
2953      orcc(Rbox, G0, G0);
2954      brx(Assembler::notZero, false, Assembler::pn, done);
2955      delayed()->
2956      ld_ptr(Address(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(EntryList)), Rscratch);
2957      ld_ptr(Address(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(cxq)), Rbox);
2958      orcc(Rbox, Rscratch, G0);
2959      if (EmitSync & 16384) {
2960        // As an optional optimization, if (EntryList|cxq) != null and _succ is null then
2961        // we should transfer control directly to the slow-path.
2962        // This test makes the reacquire operation below very infrequent.
2963        // The logic is equivalent to :
2964        //   if (cxq|EntryList) == null : Owner=null; goto Success
2965        //   if succ == null : goto SlowPath
2966        //   Owner=null; membar #storeload
2967        //   if succ != null : goto Success
2968        //   if CAS(&Owner,null,Self) != null goto Success
2969        //   goto SlowPath
2970        brx(Assembler::zero, true, Assembler::pt, done);
2971        delayed()->
2972        st_ptr(G0, Address(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)));
2973        ld_ptr(Address(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(succ)), Rscratch);
2974        andcc(Rscratch, Rscratch, G0) ;
2975        brx(Assembler::zero, false, Assembler::pt, done);
2976        delayed()->orcc(G0, 1, G0);
2977        st_ptr(G0, Address(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)));
2978      } else {
2979        brx(Assembler::zero, false, Assembler::pt, done);
2980        delayed()->
2981        st_ptr(G0, Address(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)));
2982      }
2983      if (os::is_MP()) { membar(StoreLoad); }
2984      // Check that _succ is (or remains) non-zero
2985      ld_ptr(Address(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(succ)), Rscratch);
2986      andcc(Rscratch, Rscratch, G0);
2987      brx(Assembler::notZero, false, Assembler::pt, done);
2988      delayed()->andcc(G0, G0, G0);
2989      add(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner), Rmark);
2990      mov(G2_thread, Rscratch);
2991      cas_ptr(Rmark, G0, Rscratch);
2992      cmp(Rscratch, G0);
2993      // invert icc.zf and goto done
2994      // A slightly better v8+/v9 idiom would be the following:
2995      //   movrnz Rscratch,1,Rscratch
2996      //   ba done
2997      //   xorcc Rscratch,1,G0
2998      // In v8+ mode the idiom would be valid IFF Rscratch was a G or O register
2999      brx(Assembler::notZero, false, Assembler::pt, done);
3000      delayed()->cmp(G0, G0);
3001      br(Assembler::always, false, Assembler::pt, done);
3002      delayed()->cmp(G0, 1);
3003    }
3004 
3005    bind   (LStacked);
3006    // Consider: we could replace the expensive CAS in the exit
3007    // path with a simple ST of the displaced mark value fetched from
3008    // the on-stack basiclock box.  That admits a race where a thread T2
3009    // in the slow lock path -- inflating with monitor M -- could race a
3010    // thread T1 in the fast unlock path, resulting in a missed wakeup for T2.
3011    // More precisely T1 in the stack-lock unlock path could "stomp" the
3012    // inflated mark value M installed by T2, resulting in an orphan
3013    // object monitor M and T2 becoming stranded.  We can remedy that situation
3014    // by having T2 periodically poll the object's mark word using timed wait
3015    // operations.  If T2 discovers that a stomp has occurred it vacates
3016    // the monitor M and wakes any other threads stranded on the now-orphan M.
3017    // In addition the monitor scavenger, which performs deflation,
3018    // would also need to check for orpan monitors and stranded threads.
3019    //
3020    // Finally, inflation is also used when T2 needs to assign a hashCode
3021    // to O and O is stack-locked by T1.  The "stomp" race could cause
3022    // an assigned hashCode value to be lost.  We can avoid that condition
3023    // and provide the necessary hashCode stability invariants by ensuring




2631 // SPARC refworkload performance - specifically jetstream and scimark - are
2632 // extremely sensitive to the size of the code emitted by compiler_lock_object
2633 // and compiler_unlock_object.  Critically, the key factor is code size, not path
2634 // length.  (Simply experiments to pad CLO with unexecuted NOPs demonstrte the
2635 // effect).
2636 
2637 
2638 void MacroAssembler::compiler_lock_object(Register Roop, Register Rmark,
2639                                           Register Rbox, Register Rscratch,
2640                                           BiasedLockingCounters* counters,
2641                                           bool try_bias) {
2642    Address mark_addr(Roop, oopDesc::mark_offset_in_bytes());
2643 
2644    verify_oop(Roop);
2645    Label done ;
2646 
2647    if (counters != NULL) {
2648      inc_counter((address) counters->total_entry_count_addr(), Rmark, Rscratch);
2649    }
2650 













































2651    Label Egress ;
2652 

























































2653    // Aggressively avoid the Store-before-CAS penalty
2654    // Defer the store into box->dhw until after the CAS
2655    Label IsInflated, Recursive ;
2656 
2657 // Anticipate CAS -- Avoid RTS->RTO upgrade
2658 // prefetch (mark_addr, Assembler::severalWritesAndPossiblyReads);
2659 
2660    ld_ptr(mark_addr, Rmark);           // fetch obj->mark
2661    // Triage: biased, stack-locked, neutral, inflated
2662 
2663    if (try_bias) {
2664      biased_locking_enter(Roop, Rmark, Rscratch, done, NULL, counters);
2665      // Invariant: if control reaches this point in the emitted stream
2666      // then Rmark has not been modified.
2667    }
2668    andcc(Rmark, 2, G0);
2669    brx(Assembler::notZero, false, Assembler::pn, IsInflated);
2670    delayed()->                         // Beware - dangling delay-slot
2671 
2672    // Try stack-lock acquisition.


2717      ba_short(done);
2718    } else {
2719      ba(done);
2720      delayed()->st_ptr(Rscratch, Rbox, BasicLock::displaced_header_offset_in_bytes());
2721    }
2722 
2723    bind   (IsInflated);
2724 
2725    // Try to CAS m->owner from null to Self
2726    // Invariant: if we acquire the lock then _recursions should be 0.
2727    add(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner), Rmark);
2728    mov(G2_thread, Rscratch);
2729    cas_ptr(Rmark, G0, Rscratch);
2730    andcc(Rscratch, Rscratch, G0);             // set ICCs for done: icc.zf iff success
2731    // set icc.zf : 1=success 0=failure
2732    // ST box->displaced_header = NonZero.
2733    // Any non-zero value suffices:
2734    //    markOopDesc::unused_mark(), G2_thread, RBox, RScratch, rsp, etc.
2735    st_ptr(Rbox, Rbox, BasicLock::displaced_header_offset_in_bytes());
2736    // Intentional fall-through into done

2737 
2738    bind   (done);
2739 }
2740 
2741 void MacroAssembler::compiler_unlock_object(Register Roop, Register Rmark,
2742                                             Register Rbox, Register Rscratch,
2743                                             bool try_bias) {
2744    Address mark_addr(Roop, oopDesc::mark_offset_in_bytes());
2745 
2746    Label done ;
2747 
























2748    // Beware ... If the aggregate size of the code emitted by CLO and CUO is
2749    // is too large performance rolls abruptly off a cliff.
2750    // This could be related to inlining policies, code cache management, or
2751    // I$ effects.
2752    Label LStacked ;
2753 
2754    if (try_bias) {
2755       // TODO: eliminate redundant LDs of obj->mark
2756       biased_locking_exit(mark_addr, Rscratch, done);
2757    }
2758 
2759    ld_ptr(Roop, oopDesc::mark_offset_in_bytes(), Rmark);
2760    ld_ptr(Rbox, BasicLock::displaced_header_offset_in_bytes(), Rscratch);
2761    andcc(Rscratch, Rscratch, G0);
2762    brx(Assembler::zero, false, Assembler::pn, done);
2763    delayed()->nop();      // consider: relocate fetch of mark, above, into this DS
2764    andcc(Rmark, 2, G0);
2765    brx(Assembler::zero, false, Assembler::pt, LStacked);
2766    delayed()->nop();
2767 
2768    // It's inflated
2769    // Conceptually we need a #loadstore|#storestore "release" MEMBAR before
2770    // the ST of 0 into _owner which releases the lock.  This prevents loads
2771    // and stores within the critical section from reordering (floating)
2772    // past the store that releases the lock.  But TSO is a strong memory model
2773    // and that particular flavor of barrier is a noop, so we can safely elide it.
2774    // Note that we use 1-0 locking by default for the inflated case.  We
2775    // close the resultant (and rare) race by having contended threads in
2776    // monitorenter periodically poll _owner.
2777 













































2778    // 1-0 form : avoids CAS and MEMBAR in the common case
2779    // Do not bother to ratify that m->Owner == Self.
2780    ld_ptr(Address(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions)), Rbox);
2781    orcc(Rbox, G0, G0);
2782    brx(Assembler::notZero, false, Assembler::pn, done);
2783    delayed()->
2784    ld_ptr(Address(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(EntryList)), Rscratch);
2785    ld_ptr(Address(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(cxq)), Rbox);
2786    orcc(Rbox, Rscratch, G0);




















2787    brx(Assembler::zero, false, Assembler::pt, done);
2788    delayed()->
2789    st_ptr(G0, Address(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)));
2790 
2791    if (os::is_MP()) { membar(StoreLoad); }
2792    // Check that _succ is (or remains) non-zero
2793    ld_ptr(Address(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(succ)), Rscratch);
2794    andcc(Rscratch, Rscratch, G0);
2795    brx(Assembler::notZero, false, Assembler::pt, done);
2796    delayed()->andcc(G0, G0, G0);
2797    add(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner), Rmark);
2798    mov(G2_thread, Rscratch);
2799    cas_ptr(Rmark, G0, Rscratch);
2800    cmp(Rscratch, G0);
2801    // invert icc.zf and goto done
2802    // A slightly better v8+/v9 idiom would be the following:
2803    //   movrnz Rscratch,1,Rscratch
2804    //   ba done
2805    //   xorcc Rscratch,1,G0
2806    // In v8+ mode the idiom would be valid IFF Rscratch was a G or O register
2807    brx(Assembler::notZero, false, Assembler::pt, done);
2808    delayed()->cmp(G0, G0);
2809    br(Assembler::always, false, Assembler::pt, done);
2810    delayed()->cmp(G0, 1);

2811 
2812    bind   (LStacked);
2813    // Consider: we could replace the expensive CAS in the exit
2814    // path with a simple ST of the displaced mark value fetched from
2815    // the on-stack basiclock box.  That admits a race where a thread T2
2816    // in the slow lock path -- inflating with monitor M -- could race a
2817    // thread T1 in the fast unlock path, resulting in a missed wakeup for T2.
2818    // More precisely T1 in the stack-lock unlock path could "stomp" the
2819    // inflated mark value M installed by T2, resulting in an orphan
2820    // object monitor M and T2 becoming stranded.  We can remedy that situation
2821    // by having T2 periodically poll the object's mark word using timed wait
2822    // operations.  If T2 discovers that a stomp has occurred it vacates
2823    // the monitor M and wakes any other threads stranded on the now-orphan M.
2824    // In addition the monitor scavenger, which performs deflation,
2825    // would also need to check for orpan monitors and stranded threads.
2826    //
2827    // Finally, inflation is also used when T2 needs to assign a hashCode
2828    // to O and O is stack-locked by T1.  The "stomp" race could cause
2829    // an assigned hashCode value to be lost.  We can avoid that condition
2830    // and provide the necessary hashCode stability invariants by ensuring


< prev index next >