485 |
490 |
486 return status_code; |
491 return status_code; |
487 } |
492 } |
488 |
493 |
489 |
494 |
490 static void clean_up_cached_monitor_info() { |
495 static void clean_up_cached_monitor_info(JavaThread* thread = NULL) { |
491 // Walk the thread list clearing out the cached monitors |
496 if (thread != NULL) { |
492 for (JavaThreadIteratorWithHandle jtiwh; JavaThread *thr = jtiwh.next(); ) { |
497 thread->set_cached_monitor_info(NULL); |
493 thr->set_cached_monitor_info(NULL); |
498 } else { |
494 } |
499 // Walk the thread list clearing out the cached monitors |
495 } |
500 for (JavaThreadIteratorWithHandle jtiwh; JavaThread *thr = jtiwh.next(); ) { |
496 |
501 thr->set_cached_monitor_info(NULL); |
497 |
502 } |
498 class VM_RevokeBias : public VM_Operation { |
503 } |
499 protected: |
504 } |
|
505 |
|
506 |
|
507 class VM_BulkRevokeBias : public VM_Operation { |
|
508 private: |
500 Handle* _obj; |
509 Handle* _obj; |
501 GrowableArray<Handle>* _objs; |
|
502 JavaThread* _requesting_thread; |
510 JavaThread* _requesting_thread; |
503 BiasedLocking::Condition _status_code; |
|
504 traceid _biased_locker_id; |
|
505 uint64_t _safepoint_id; |
|
506 |
|
507 public: |
|
508 VM_RevokeBias(Handle* obj, JavaThread* requesting_thread) |
|
509 : _obj(obj) |
|
510 , _objs(NULL) |
|
511 , _requesting_thread(requesting_thread) |
|
512 , _status_code(BiasedLocking::NOT_BIASED) |
|
513 , _biased_locker_id(0) |
|
514 , _safepoint_id(0) {} |
|
515 |
|
516 VM_RevokeBias(GrowableArray<Handle>* objs, JavaThread* requesting_thread) |
|
517 : _obj(NULL) |
|
518 , _objs(objs) |
|
519 , _requesting_thread(requesting_thread) |
|
520 , _status_code(BiasedLocking::NOT_BIASED) |
|
521 , _biased_locker_id(0) |
|
522 , _safepoint_id(0) {} |
|
523 |
|
524 virtual VMOp_Type type() const { return VMOp_RevokeBias; } |
|
525 |
|
526 virtual bool doit_prologue() { |
|
527 // Verify that there is actual work to do since the callers just |
|
528 // give us locked object(s). If we don't find any biased objects |
|
529 // there is nothing to do and we avoid a safepoint. |
|
530 if (_obj != NULL) { |
|
531 markOop mark = (*_obj)()->mark(); |
|
532 if (mark->has_bias_pattern()) { |
|
533 return true; |
|
534 } |
|
535 } else { |
|
536 for ( int i = 0 ; i < _objs->length(); i++ ) { |
|
537 markOop mark = (_objs->at(i))()->mark(); |
|
538 if (mark->has_bias_pattern()) { |
|
539 return true; |
|
540 } |
|
541 } |
|
542 } |
|
543 return false; |
|
544 } |
|
545 |
|
546 virtual void doit() { |
|
547 if (_obj != NULL) { |
|
548 log_info(biasedlocking)("Revoking bias with potentially per-thread safepoint:"); |
|
549 JavaThread* biased_locker = NULL; |
|
550 _status_code = revoke_bias((*_obj)(), false, false, _requesting_thread, &biased_locker); |
|
551 if (biased_locker != NULL) { |
|
552 _biased_locker_id = JFR_THREAD_ID(biased_locker); |
|
553 } |
|
554 _safepoint_id = SafepointSynchronize::safepoint_id(); |
|
555 clean_up_cached_monitor_info(); |
|
556 return; |
|
557 } else { |
|
558 log_info(biasedlocking)("Revoking bias with global safepoint:"); |
|
559 BiasedLocking::revoke_at_safepoint(_objs); |
|
560 } |
|
561 } |
|
562 |
|
563 BiasedLocking::Condition status_code() const { |
|
564 return _status_code; |
|
565 } |
|
566 |
|
567 traceid biased_locker() const { |
|
568 return _biased_locker_id; |
|
569 } |
|
570 |
|
571 uint64_t safepoint_id() const { |
|
572 return _safepoint_id; |
|
573 } |
|
574 }; |
|
575 |
|
576 |
|
577 class VM_BulkRevokeBias : public VM_RevokeBias { |
|
578 private: |
|
579 bool _bulk_rebias; |
511 bool _bulk_rebias; |
580 bool _attempt_rebias_of_object; |
512 bool _attempt_rebias_of_object; |
|
513 BiasedLocking::Condition _status_code; |
|
514 uint64_t _safepoint_id; |
581 |
515 |
582 public: |
516 public: |
583 VM_BulkRevokeBias(Handle* obj, JavaThread* requesting_thread, |
517 VM_BulkRevokeBias(Handle* obj, JavaThread* requesting_thread, |
584 bool bulk_rebias, |
518 bool bulk_rebias, |
585 bool attempt_rebias_of_object) |
519 bool attempt_rebias_of_object) |
586 : VM_RevokeBias(obj, requesting_thread) |
520 : _obj(obj) |
|
521 , _requesting_thread(requesting_thread) |
587 , _bulk_rebias(bulk_rebias) |
522 , _bulk_rebias(bulk_rebias) |
588 , _attempt_rebias_of_object(attempt_rebias_of_object) {} |
523 , _attempt_rebias_of_object(attempt_rebias_of_object) |
|
524 , _status_code(BiasedLocking::NOT_BIASED) |
|
525 , _safepoint_id(0) {} |
589 |
526 |
590 virtual VMOp_Type type() const { return VMOp_BulkRevokeBias; } |
527 virtual VMOp_Type type() const { return VMOp_BulkRevokeBias; } |
591 virtual bool doit_prologue() { return true; } |
|
592 |
528 |
593 virtual void doit() { |
529 virtual void doit() { |
594 _status_code = bulk_revoke_or_rebias_at_safepoint((*_obj)(), _bulk_rebias, _attempt_rebias_of_object, _requesting_thread); |
530 _status_code = BiasedLocking::bulk_revoke_or_rebias_at_safepoint((*_obj)(), _bulk_rebias, _attempt_rebias_of_object, _requesting_thread); |
595 _safepoint_id = SafepointSynchronize::safepoint_id(); |
531 _safepoint_id = SafepointSynchronize::safepoint_id(); |
596 clean_up_cached_monitor_info(); |
532 clean_up_cached_monitor_info(); |
597 } |
533 } |
598 |
534 |
599 bool is_bulk_rebias() const { |
535 bool is_bulk_rebias() const { |
600 return _bulk_rebias; |
536 return _bulk_rebias; |
601 } |
537 } |
|
538 |
|
539 BiasedLocking::Condition status_code() const { |
|
540 return _status_code; |
|
541 } |
|
542 |
|
543 uint64_t safepoint_id() const { |
|
544 return _safepoint_id; |
|
545 } |
602 }; |
546 }; |
|
547 |
|
548 |
|
549 class RevokeOneBias : public ThreadClosure { |
|
550 protected: |
|
551 Handle _obj; |
|
552 JavaThread* _requesting_thread; |
|
553 JavaThread* _biased_locker; |
|
554 BiasedLocking::Condition _status_code; |
|
555 traceid _biased_locker_id; |
|
556 |
|
557 public: |
|
558 RevokeOneBias(Handle obj, JavaThread* requesting_thread, JavaThread* biased_locker) |
|
559 : _obj(obj) |
|
560 , _requesting_thread(requesting_thread) |
|
561 , _biased_locker(biased_locker) |
|
562 , _status_code(BiasedLocking::NOT_BIASED) |
|
563 , _biased_locker_id(0) {} |
|
564 |
|
565 void do_thread(Thread* target) { |
|
566 assert(target == _biased_locker, "Wrong thread"); |
|
567 |
|
568 oop o = _obj(); |
|
569 markOop mark = o->mark(); |
|
570 |
|
571 if (!mark->has_bias_pattern()) { |
|
572 return; |
|
573 } |
|
574 |
|
575 markOop prototype = o->klass()->prototype_header(); |
|
576 if (!prototype->has_bias_pattern()) { |
|
577 // This object has a stale bias from before the handshake |
|
578 // was requested. If we fail this race, the object's bias |
|
579 // has been revoked by another thread so we simply return. |
|
580 markOop biased_value = mark; |
|
581 mark = o->cas_set_mark(markOopDesc::prototype()->set_age(mark->age()), mark); |
|
582 assert(!o->mark()->has_bias_pattern(), "even if we raced, should still be revoked"); |
|
583 if (biased_value == mark) { |
|
584 _status_code = BiasedLocking::BIAS_REVOKED; |
|
585 } |
|
586 return; |
|
587 } |
|
588 |
|
589 if (_biased_locker == mark->biased_locker()) { |
|
590 if (mark->bias_epoch() == prototype->bias_epoch()) { |
|
591 // Epoch is still valid. This means biaser could be currently |
|
592 // synchronized on this object. We must walk its stack looking |
|
593 // for monitor records associated with this object and change |
|
594 // them to be stack locks if any are found. |
|
595 ResourceMark rm; |
|
596 BiasedLocking::walk_stack_and_revoke(o, _biased_locker); |
|
597 _biased_locker->set_cached_monitor_info(NULL); |
|
598 assert(!o->mark()->has_bias_pattern(), "invariant"); |
|
599 _biased_locker_id = JFR_THREAD_ID(_biased_locker); |
|
600 _status_code = BiasedLocking::BIAS_REVOKED; |
|
601 return; |
|
602 } else { |
|
603 markOop biased_value = mark; |
|
604 mark = o->cas_set_mark(markOopDesc::prototype()->set_age(mark->age()), mark); |
|
605 if (mark == biased_value || !mark->has_bias_pattern()) { |
|
606 assert(!o->mark()->has_bias_pattern(), "should be revoked"); |
|
607 _status_code = (biased_value == mark) ? BiasedLocking::BIAS_REVOKED : BiasedLocking::NOT_BIASED; |
|
608 return; |
|
609 } |
|
610 } |
|
611 } |
|
612 |
|
613 _status_code = BiasedLocking::NOT_REVOKED; |
|
614 } |
|
615 |
|
616 BiasedLocking::Condition status_code() const { |
|
617 return _status_code; |
|
618 } |
|
619 |
|
620 traceid biased_locker() const { |
|
621 return _biased_locker_id; |
|
622 } |
|
623 }; |
|
624 |
603 |
625 |
604 static void post_self_revocation_event(EventBiasedLockSelfRevocation* event, Klass* k) { |
626 static void post_self_revocation_event(EventBiasedLockSelfRevocation* event, Klass* k) { |
605 assert(event != NULL, "invariant"); |
627 assert(event != NULL, "invariant"); |
606 assert(k != NULL, "invariant"); |
628 assert(k != NULL, "invariant"); |
607 assert(event->should_commit(), "invariant"); |
629 assert(event->should_commit(), "invariant"); |
608 event->set_lockClass(k); |
630 event->set_lockClass(k); |
609 event->commit(); |
631 event->commit(); |
610 } |
632 } |
611 |
633 |
612 static void post_revocation_event(EventBiasedLockRevocation* event, Klass* k, VM_RevokeBias* op) { |
634 static void post_revocation_event(EventBiasedLockRevocation* event, Klass* k, RevokeOneBias* op) { |
613 assert(event != NULL, "invariant"); |
635 assert(event != NULL, "invariant"); |
614 assert(k != NULL, "invariant"); |
636 assert(k != NULL, "invariant"); |
615 assert(op != NULL, "invariant"); |
637 assert(op != NULL, "invariant"); |
616 assert(event->should_commit(), "invariant"); |
638 assert(event->should_commit(), "invariant"); |
617 event->set_lockClass(k); |
639 event->set_lockClass(k); |
618 event->set_safepointId(op->safepoint_id()); |
640 event->set_safepointId(0); |
619 event->set_previousOwner(op->biased_locker()); |
641 event->set_previousOwner(op->biased_locker()); |
620 event->commit(); |
642 event->commit(); |
621 } |
643 } |
622 |
644 |
623 static void post_class_revocation_event(EventBiasedLockClassRevocation* event, Klass* k, VM_BulkRevokeBias* op) { |
645 static void post_class_revocation_event(EventBiasedLockClassRevocation* event, Klass* k, VM_BulkRevokeBias* op) { |
629 event->set_disableBiasing(!op->is_bulk_rebias()); |
651 event->set_disableBiasing(!op->is_bulk_rebias()); |
630 event->set_safepointId(op->safepoint_id()); |
652 event->set_safepointId(op->safepoint_id()); |
631 event->commit(); |
653 event->commit(); |
632 } |
654 } |
633 |
655 |
|
656 |
|
657 BiasedLocking::Condition BiasedLocking::single_revoke_with_handshake(Handle obj, JavaThread *requester, JavaThread *biaser) { |
|
658 |
|
659 EventBiasedLockRevocation event; |
|
660 if (PrintBiasedLockingStatistics) { |
|
661 Atomic::inc(handshakes_count_addr()); |
|
662 } |
|
663 log_info(biasedlocking, handshake)("JavaThread " INTPTR_FORMAT " handshaking JavaThread " |
|
664 INTPTR_FORMAT " to revoke object " INTPTR_FORMAT, p2i(requester), |
|
665 p2i(biaser), p2i(obj())); |
|
666 |
|
667 RevokeOneBias revoke(obj, requester, biaser); |
|
668 bool executed = Handshake::execute(&revoke, biaser); |
|
669 if (revoke.status_code() == NOT_REVOKED) { |
|
670 return NOT_REVOKED; |
|
671 } |
|
672 if (executed) { |
|
673 log_info(biasedlocking, handshake)("Handshake revocation for object " INTPTR_FORMAT " succeeded. Bias was %srevoked", |
|
674 p2i(obj()), (revoke.status_code() == BIAS_REVOKED ? "" : "already ")); |
|
675 if (event.should_commit() && revoke.status_code() == BIAS_REVOKED) { |
|
676 post_revocation_event(&event, obj->klass(), &revoke); |
|
677 } |
|
678 assert(!obj->mark()->has_bias_pattern(), "invariant"); |
|
679 return revoke.status_code(); |
|
680 } else { |
|
681 // Thread was not alive. |
|
682 // Grab Threads_lock before manually trying to revoke bias. This avoids race with a newly |
|
683 // created JavaThread (that happens to get the same memory address as biaser) synchronizing |
|
684 // on this object. |
|
685 { |
|
686 MutexLocker ml(Threads_lock); |
|
687 markOop mark = obj->mark(); |
|
688 // Check if somebody else was able to revoke it before biased thread exited. |
|
689 if (!mark->has_bias_pattern()) { |
|
690 return NOT_BIASED; |
|
691 } |
|
692 ThreadsListHandle tlh; |
|
693 markOop prototype = obj->klass()->prototype_header(); |
|
694 if (!prototype->has_bias_pattern() || (!tlh.includes(biaser) && biaser == mark->biased_locker() && |
|
695 prototype->bias_epoch() == mark->bias_epoch())) { |
|
696 obj->cas_set_mark(markOopDesc::prototype()->set_age(mark->age()), mark); |
|
697 if (event.should_commit()) { |
|
698 post_revocation_event(&event, obj->klass(), &revoke); |
|
699 } |
|
700 assert(!obj->mark()->has_bias_pattern(), "bias should be revoked by now"); |
|
701 return BIAS_REVOKED; |
|
702 } |
|
703 } |
|
704 } |
|
705 |
|
706 return NOT_REVOKED; |
|
707 } |
|
708 |
|
709 |
|
710 // Caller should have instantiated a ResourceMark object before calling this method |
|
711 void BiasedLocking::walk_stack_and_revoke(oop obj, JavaThread* biased_locker) { |
|
712 assert(!SafepointSynchronize::is_at_safepoint() || !ThreadLocalHandshakes, |
|
713 "if ThreadLocalHandshakes is enabled this should always be executed outside safepoints"); |
|
714 assert(Thread::current() == biased_locker || Thread::current()->is_VM_thread(), "wrong thread"); |
|
715 |
|
716 markOop mark = obj->mark(); |
|
717 assert(mark->biased_locker() == biased_locker && |
|
718 obj->klass()->prototype_header()->bias_epoch() == mark->bias_epoch(), "invariant"); |
|
719 |
|
720 log_trace(biasedlocking)("%s(" INTPTR_FORMAT ") revoking object " INTPTR_FORMAT ", mark " |
|
721 INTPTR_FORMAT ", type %s, prototype header " INTPTR_FORMAT |
|
722 ", biaser " INTPTR_FORMAT " %s", |
|
723 Thread::current()->is_VM_thread() ? "VMThread" : "JavaThread", |
|
724 p2i(Thread::current()), |
|
725 p2i(obj), |
|
726 p2i(mark), |
|
727 obj->klass()->external_name(), |
|
728 p2i(obj->klass()->prototype_header()), |
|
729 p2i(biased_locker), |
|
730 Thread::current()->is_VM_thread() ? "" : "(walking own stack)"); |
|
731 |
|
732 markOop unbiased_prototype = markOopDesc::prototype()->set_age(obj->mark()->age()); |
|
733 |
|
734 GrowableArray<MonitorInfo*>* cached_monitor_info = get_or_compute_monitor_info(biased_locker); |
|
735 BasicLock* highest_lock = NULL; |
|
736 for (int i = 0; i < cached_monitor_info->length(); i++) { |
|
737 MonitorInfo* mon_info = cached_monitor_info->at(i); |
|
738 if (oopDesc::equals(mon_info->owner(), obj)) { |
|
739 log_trace(biasedlocking)(" mon_info->owner (" PTR_FORMAT ") == obj (" PTR_FORMAT ")", |
|
740 p2i(mon_info->owner()), |
|
741 p2i(obj)); |
|
742 // Assume recursive case and fix up highest lock below |
|
743 markOop mark = markOopDesc::encode((BasicLock*) NULL); |
|
744 highest_lock = mon_info->lock(); |
|
745 highest_lock->set_displaced_header(mark); |
|
746 } else { |
|
747 log_trace(biasedlocking)(" mon_info->owner (" PTR_FORMAT ") != obj (" PTR_FORMAT ")", |
|
748 p2i(mon_info->owner()), |
|
749 p2i(obj)); |
|
750 } |
|
751 } |
|
752 if (highest_lock != NULL) { |
|
753 // Fix up highest lock to contain displaced header and point |
|
754 // object at it |
|
755 highest_lock->set_displaced_header(unbiased_prototype); |
|
756 // Reset object header to point to displaced mark. |
|
757 // Must release store the lock address for platforms without TSO |
|
758 // ordering (e.g. ppc). |
|
759 obj->release_set_mark(markOopDesc::encode(highest_lock)); |
|
760 assert(!obj->mark()->has_bias_pattern(), "illegal mark state: stack lock used bias bit"); |
|
761 log_info(biasedlocking)(" Revoked bias of currently-locked object"); |
|
762 } else { |
|
763 log_info(biasedlocking)(" Revoked bias of currently-unlocked object"); |
|
764 // Store the unlocked value into the object's header. |
|
765 obj->set_mark(unbiased_prototype); |
|
766 } |
|
767 |
|
768 assert(!obj->mark()->has_bias_pattern(), "must not be biased"); |
|
769 } |
|
770 |
|
771 |
634 BiasedLocking::Condition BiasedLocking::revoke_and_rebias(Handle obj, bool attempt_rebias, TRAPS) { |
772 BiasedLocking::Condition BiasedLocking::revoke_and_rebias(Handle obj, bool attempt_rebias, TRAPS) { |
635 assert(!SafepointSynchronize::is_at_safepoint(), "must not be called while at safepoint"); |
773 assert(!SafepointSynchronize::is_at_safepoint(), "must not be called while at safepoint"); |
636 |
774 |
637 // We can revoke the biases of anonymously-biased objects |
775 while (true) { |
638 // efficiently enough that we should not cause these revocations to |
776 // We can revoke the biases of anonymously-biased objects |
639 // update the heuristics because doing so may cause unwanted bulk |
777 // efficiently enough that we should not cause these revocations to |
640 // revocations (which are expensive) to occur. |
778 // update the heuristics because doing so may cause unwanted bulk |
641 markOop mark = obj->mark(); |
779 // revocations (which are expensive) to occur. |
642 if (mark->is_biased_anonymously() && !attempt_rebias) { |
780 markOop mark = obj->mark(); |
643 // We are probably trying to revoke the bias of this object due to |
781 if (mark->is_biased_anonymously() && !attempt_rebias) { |
644 // an identity hash code computation. Try to revoke the bias |
782 // We are probably trying to revoke the bias of this object due to |
645 // without a safepoint. This is possible if we can successfully |
783 // an identity hash code computation. Try to revoke the bias |
646 // compare-and-exchange an unbiased header into the mark word of |
784 // without a safepoint. This is possible if we can successfully |
647 // the object, meaning that no other thread has raced to acquire |
785 // compare-and-exchange an unbiased header into the mark word of |
648 // the bias of the object. |
786 // the object, meaning that no other thread has raced to acquire |
649 markOop biased_value = mark; |
787 // the bias of the object. |
650 markOop unbiased_prototype = markOopDesc::prototype()->set_age(mark->age()); |
|
651 markOop res_mark = obj->cas_set_mark(unbiased_prototype, mark); |
|
652 if (res_mark == biased_value) { |
|
653 return BIAS_REVOKED; |
|
654 } |
|
655 } else if (mark->has_bias_pattern()) { |
|
656 Klass* k = obj->klass(); |
|
657 markOop prototype_header = k->prototype_header(); |
|
658 if (!prototype_header->has_bias_pattern()) { |
|
659 // This object has a stale bias from before the bulk revocation |
|
660 // for this data type occurred. It's pointless to update the |
|
661 // heuristics at this point so simply update the header with a |
|
662 // CAS. If we fail this race, the object's bias has been revoked |
|
663 // by another thread so we simply return and let the caller deal |
|
664 // with it. |
|
665 markOop biased_value = mark; |
788 markOop biased_value = mark; |
666 markOop res_mark = obj->cas_set_mark(prototype_header, mark); |
789 markOop unbiased_prototype = markOopDesc::prototype()->set_age(mark->age()); |
667 assert(!obj->mark()->has_bias_pattern(), "even if we raced, should still be revoked"); |
790 markOop res_mark = obj->cas_set_mark(unbiased_prototype, mark); |
668 return BIAS_REVOKED; |
791 if (res_mark == biased_value) { |
669 } else if (prototype_header->bias_epoch() != mark->bias_epoch()) { |
792 return BIAS_REVOKED; |
670 // The epoch of this biasing has expired indicating that the |
793 } |
671 // object is effectively unbiased. Depending on whether we need |
794 mark = res_mark; // Refresh mark with the latest value. |
672 // to rebias or revoke the bias of this object we can do it |
795 } else if (mark->has_bias_pattern()) { |
673 // efficiently enough with a CAS that we shouldn't update the |
796 Klass* k = obj->klass(); |
674 // heuristics. This is normally done in the assembly code but we |
797 markOop prototype_header = k->prototype_header(); |
675 // can reach this point due to various points in the runtime |
798 if (!prototype_header->has_bias_pattern()) { |
676 // needing to revoke biases. |
799 // This object has a stale bias from before the bulk revocation |
677 if (attempt_rebias) { |
800 // for this data type occurred. It's pointless to update the |
678 assert(THREAD->is_Java_thread(), ""); |
801 // heuristics at this point so simply update the header with a |
679 markOop biased_value = mark; |
802 // CAS. If we fail this race, the object's bias has been revoked |
680 markOop rebiased_prototype = markOopDesc::encode((JavaThread*) THREAD, mark->age(), prototype_header->bias_epoch()); |
803 // by another thread so we simply return and let the caller deal |
681 markOop res_mark = obj->cas_set_mark(rebiased_prototype, mark); |
804 // with it. |
682 if (res_mark == biased_value) { |
805 obj->cas_set_mark(prototype_header->set_age(mark->age()), mark); |
683 return BIAS_REVOKED_AND_REBIASED; |
806 assert(!obj->mark()->has_bias_pattern(), "even if we raced, should still be revoked"); |
|
807 return BIAS_REVOKED; |
|
808 } else if (prototype_header->bias_epoch() != mark->bias_epoch()) { |
|
809 // The epoch of this biasing has expired indicating that the |
|
810 // object is effectively unbiased. Depending on whether we need |
|
811 // to rebias or revoke the bias of this object we can do it |
|
812 // efficiently enough with a CAS that we shouldn't update the |
|
813 // heuristics. This is normally done in the assembly code but we |
|
814 // can reach this point due to various points in the runtime |
|
815 // needing to revoke biases. |
|
816 markOop res_mark; |
|
817 if (attempt_rebias) { |
|
818 assert(THREAD->is_Java_thread(), ""); |
|
819 markOop biased_value = mark; |
|
820 markOop rebiased_prototype = markOopDesc::encode((JavaThread*) THREAD, mark->age(), prototype_header->bias_epoch()); |
|
821 res_mark = obj->cas_set_mark(rebiased_prototype, mark); |
|
822 if (res_mark == biased_value) { |
|
823 return BIAS_REVOKED_AND_REBIASED; |
|
824 } |
|
825 } else { |
|
826 markOop biased_value = mark; |
|
827 markOop unbiased_prototype = markOopDesc::prototype()->set_age(mark->age()); |
|
828 res_mark = obj->cas_set_mark(unbiased_prototype, mark); |
|
829 if (res_mark == biased_value) { |
|
830 return BIAS_REVOKED; |
|
831 } |
684 } |
832 } |
|
833 mark = res_mark; // Refresh mark with the latest value. |
|
834 } |
|
835 } |
|
836 |
|
837 HeuristicsResult heuristics = update_heuristics(obj()); |
|
838 if (heuristics == HR_NOT_BIASED) { |
|
839 return NOT_BIASED; |
|
840 } else if (heuristics == HR_SINGLE_REVOKE) { |
|
841 JavaThread *blt = mark->biased_locker(); |
|
842 assert(blt != NULL, "invariant"); |
|
843 if (blt == THREAD) { |
|
844 // A thread is trying to revoke the bias of an object biased |
|
845 // toward it, again likely due to an identity hash code |
|
846 // computation. We can again avoid a safepoint/handshake in this case |
|
847 // since we are only going to walk our own stack. There are no |
|
848 // races with revocations occurring in other threads because we |
|
849 // reach no safepoints in the revocation path. |
|
850 EventBiasedLockSelfRevocation event; |
|
851 ResourceMark rm; |
|
852 walk_stack_and_revoke(obj(), blt); |
|
853 blt->set_cached_monitor_info(NULL); |
|
854 assert(!obj->mark()->has_bias_pattern(), "invariant"); |
|
855 if (event.should_commit()) { |
|
856 post_self_revocation_event(&event, obj->klass()); |
|
857 } |
|
858 return BIAS_REVOKED; |
685 } else { |
859 } else { |
686 markOop biased_value = mark; |
860 BiasedLocking::Condition cond = single_revoke_with_handshake(obj, (JavaThread*)THREAD, blt); |
687 markOop unbiased_prototype = markOopDesc::prototype()->set_age(mark->age()); |
861 if (cond != NOT_REVOKED) { |
688 markOop res_mark = obj->cas_set_mark(unbiased_prototype, mark); |
862 return cond; |
689 if (res_mark == biased_value) { |
|
690 return BIAS_REVOKED; |
|
691 } |
863 } |
692 } |
864 } |
693 } |
865 } else { |
694 } |
866 assert((heuristics == HR_BULK_REVOKE) || |
695 |
867 (heuristics == HR_BULK_REBIAS), "?"); |
696 HeuristicsResult heuristics = update_heuristics(obj(), attempt_rebias); |
868 EventBiasedLockClassRevocation event; |
697 if (heuristics == HR_NOT_BIASED) { |
869 VM_BulkRevokeBias bulk_revoke(&obj, (JavaThread*)THREAD, |
698 return NOT_BIASED; |
870 (heuristics == HR_BULK_REBIAS), |
699 } else if (heuristics == HR_SINGLE_REVOKE) { |
871 attempt_rebias); |
700 Klass *k = obj->klass(); |
872 VMThread::execute(&bulk_revoke); |
701 markOop prototype_header = k->prototype_header(); |
|
702 if (mark->biased_locker() == THREAD && |
|
703 prototype_header->bias_epoch() == mark->bias_epoch()) { |
|
704 // A thread is trying to revoke the bias of an object biased |
|
705 // toward it, again likely due to an identity hash code |
|
706 // computation. We can again avoid a safepoint in this case |
|
707 // since we are only going to walk our own stack. There are no |
|
708 // races with revocations occurring in other threads because we |
|
709 // reach no safepoints in the revocation path. |
|
710 // Also check the epoch because even if threads match, another thread |
|
711 // can come in with a CAS to steal the bias of an object that has a |
|
712 // stale epoch. |
|
713 ResourceMark rm; |
|
714 log_info(biasedlocking)("Revoking bias by walking my own stack:"); |
|
715 EventBiasedLockSelfRevocation event; |
|
716 BiasedLocking::Condition cond = revoke_bias(obj(), false, false, (JavaThread*) THREAD, NULL); |
|
717 ((JavaThread*) THREAD)->set_cached_monitor_info(NULL); |
|
718 assert(cond == BIAS_REVOKED, "why not?"); |
|
719 if (event.should_commit()) { |
873 if (event.should_commit()) { |
720 post_self_revocation_event(&event, k); |
874 post_class_revocation_event(&event, obj->klass(), &bulk_revoke); |
721 } |
875 } |
722 return cond; |
876 return bulk_revoke.status_code(); |
723 } else { |
877 } |
724 EventBiasedLockRevocation event; |
878 } |
725 VM_RevokeBias revoke(&obj, (JavaThread*) THREAD); |
879 } |
726 VMThread::execute(&revoke); |
880 |
727 if (event.should_commit() && revoke.status_code() != NOT_BIASED) { |
881 // All objects in objs should be locked by biaser |
728 post_revocation_event(&event, k, &revoke); |
882 void BiasedLocking::revoke(GrowableArray<Handle>* objs, JavaThread *biaser) { |
729 } |
883 bool clean_my_cache = false; |
730 return revoke.status_code(); |
884 for (int i = 0; i < objs->length(); i++) { |
731 } |
885 oop obj = (objs->at(i))(); |
732 } |
886 markOop mark = obj->mark(); |
733 |
887 if (mark->has_bias_pattern()) { |
734 assert((heuristics == HR_BULK_REVOKE) || |
888 walk_stack_and_revoke(obj, biaser); |
735 (heuristics == HR_BULK_REBIAS), "?"); |
889 clean_my_cache = true; |
736 EventBiasedLockClassRevocation event; |
890 } |
737 VM_BulkRevokeBias bulk_revoke(&obj, (JavaThread*) THREAD, |
891 } |
738 (heuristics == HR_BULK_REBIAS), |
892 if (clean_my_cache) { |
739 attempt_rebias); |
893 clean_up_cached_monitor_info(biaser); |
740 VMThread::execute(&bulk_revoke); |
894 } |
741 if (event.should_commit()) { |
|
742 post_class_revocation_event(&event, obj->klass(), &bulk_revoke); |
|
743 } |
|
744 return bulk_revoke.status_code(); |
|
745 } |
|
746 |
|
747 |
|
748 void BiasedLocking::revoke(GrowableArray<Handle>* objs) { |
|
749 assert(!SafepointSynchronize::is_at_safepoint(), "must not be called while at safepoint"); |
|
750 if (objs->length() == 0) { |
|
751 return; |
|
752 } |
|
753 VM_RevokeBias revoke(objs, JavaThread::current()); |
|
754 VMThread::execute(&revoke); |
|
755 } |
895 } |
756 |
896 |
757 |
897 |
758 void BiasedLocking::revoke_at_safepoint(Handle h_obj) { |
898 void BiasedLocking::revoke_at_safepoint(Handle h_obj) { |
759 assert(SafepointSynchronize::is_at_safepoint(), "must only be called while at safepoint"); |
899 assert(SafepointSynchronize::is_at_safepoint(), "must only be called while at safepoint"); |
760 oop obj = h_obj(); |
900 oop obj = h_obj(); |
761 HeuristicsResult heuristics = update_heuristics(obj, false); |
901 HeuristicsResult heuristics = update_heuristics(obj); |
762 if (heuristics == HR_SINGLE_REVOKE) { |
902 if (heuristics == HR_SINGLE_REVOKE) { |
763 revoke_bias(obj, false, false, NULL, NULL); |
903 JavaThread* biased_locker = NULL; |
|
904 single_revoke_at_safepoint(obj, false, false, NULL, &biased_locker); |
|
905 if (biased_locker) { |
|
906 clean_up_cached_monitor_info(biased_locker); |
|
907 } |
764 } else if ((heuristics == HR_BULK_REBIAS) || |
908 } else if ((heuristics == HR_BULK_REBIAS) || |
765 (heuristics == HR_BULK_REVOKE)) { |
909 (heuristics == HR_BULK_REVOKE)) { |
766 bulk_revoke_or_rebias_at_safepoint(obj, (heuristics == HR_BULK_REBIAS), false, NULL); |
910 bulk_revoke_or_rebias_at_safepoint(obj, (heuristics == HR_BULK_REBIAS), false, NULL); |
767 } |
911 clean_up_cached_monitor_info(); |
768 clean_up_cached_monitor_info(); |
912 } |
769 } |
913 } |
770 |
914 |
771 |
915 |
772 void BiasedLocking::revoke_at_safepoint(GrowableArray<Handle>* objs) { |
916 void BiasedLocking::revoke_at_safepoint(GrowableArray<Handle>* objs) { |
773 assert(SafepointSynchronize::is_at_safepoint(), "must only be called while at safepoint"); |
917 assert(SafepointSynchronize::is_at_safepoint(), "must only be called while at safepoint"); |
774 int len = objs->length(); |
918 int len = objs->length(); |
775 for (int i = 0; i < len; i++) { |
919 for (int i = 0; i < len; i++) { |
776 oop obj = (objs->at(i))(); |
920 oop obj = (objs->at(i))(); |
777 HeuristicsResult heuristics = update_heuristics(obj, false); |
921 HeuristicsResult heuristics = update_heuristics(obj); |
778 if (heuristics == HR_SINGLE_REVOKE) { |
922 if (heuristics == HR_SINGLE_REVOKE) { |
779 revoke_bias(obj, false, false, NULL, NULL); |
923 single_revoke_at_safepoint(obj, false, false, NULL, NULL); |
780 } else if ((heuristics == HR_BULK_REBIAS) || |
924 } else if ((heuristics == HR_BULK_REBIAS) || |
781 (heuristics == HR_BULK_REVOKE)) { |
925 (heuristics == HR_BULK_REVOKE)) { |
782 bulk_revoke_or_rebias_at_safepoint(obj, (heuristics == HR_BULK_REBIAS), false, NULL); |
926 bulk_revoke_or_rebias_at_safepoint(obj, (heuristics == HR_BULK_REBIAS), false, NULL); |
783 } |
927 } |
784 } |
928 } |