Path: blob/aarch64-shenandoah-jdk8u272-b10/hotspot/src/share/vm/runtime/biasedLocking.cpp
32285 views
/*1* Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*22*/2324#include "precompiled.hpp"25#include "oops/klass.inline.hpp"26#include "oops/markOop.hpp"27#include "runtime/basicLock.hpp"28#include "runtime/biasedLocking.hpp"29#include "runtime/task.hpp"30#include "runtime/vframe.hpp"31#include "runtime/vmThread.hpp"32#include "runtime/vm_operations.hpp"33#include "jfr/support/jfrThreadId.hpp"34#include "jfr/jfrEvents.hpp"3536static bool _biased_locking_enabled = false;37BiasedLockingCounters BiasedLocking::_counters;3839static GrowableArray<Handle>* _preserved_oop_stack = NULL;40static GrowableArray<markOop>* _preserved_mark_stack = NULL;4142static void enable_biased_locking(Klass* k) {43k->set_prototype_header(markOopDesc::biased_locking_prototype());44}4546class VM_EnableBiasedLocking: public VM_Operation {47private:48bool _is_cheap_allocated;49public:50VM_EnableBiasedLocking(bool is_cheap_allocated) { _is_cheap_allocated = is_cheap_allocated; }51VMOp_Type type() const { return VMOp_EnableBiasedLocking; }52Mode evaluation_mode() const { return _is_cheap_allocated ? _async_safepoint : _safepoint; }53bool is_cheap_allocated() const { return _is_cheap_allocated; }5455void doit() {56// Iterate the system dictionary enabling biased locking for all57// currently loaded classes58SystemDictionary::classes_do(enable_biased_locking);59// Indicate that future instances should enable it as well60_biased_locking_enabled = true;6162if (TraceBiasedLocking) {63tty->print_cr("Biased locking enabled");64}65}6667bool allow_nested_vm_operations() const { return false; }68};697071// One-shot PeriodicTask subclass for enabling biased locking72class EnableBiasedLockingTask : public PeriodicTask {73public:74EnableBiasedLockingTask(size_t interval_time) : PeriodicTask(interval_time) {}7576virtual void task() {77// Use async VM operation to avoid blocking the Watcher thread.78// VM Thread will free C heap storage.79VM_EnableBiasedLocking *op = new VM_EnableBiasedLocking(true);80VMThread::execute(op);8182// Reclaim our storage and disenroll ourself83delete this;84}85};868788void BiasedLocking::init() {89// If biased locking is enabled, schedule a task to fire a few90// seconds into the run which turns on biased locking for all91// currently loaded classes as well as future ones. This is a92// workaround for startup time regressions due to a large number of93// safepoints being taken during VM startup for bias revocation.94// Ideally we would have a lower cost for individual bias revocation95// and not need a mechanism like this.96if (UseBiasedLocking) {97if (BiasedLockingStartupDelay > 0) {98EnableBiasedLockingTask* task = new EnableBiasedLockingTask(BiasedLockingStartupDelay);99task->enroll();100} else {101VM_EnableBiasedLocking op(false);102VMThread::execute(&op);103}104}105}106107108bool BiasedLocking::enabled() {109return _biased_locking_enabled;110}111112// Returns MonitorInfos for all objects locked on this thread in youngest to oldest order113static GrowableArray<MonitorInfo*>* get_or_compute_monitor_info(JavaThread* thread) {114GrowableArray<MonitorInfo*>* info = thread->cached_monitor_info();115if (info != NULL) {116return info;117}118119info = new GrowableArray<MonitorInfo*>();120121// It's possible for the thread to not have any Java frames on it,122// i.e., if it's the main thread and it's already returned from main()123if (thread->has_last_Java_frame()) {124RegisterMap rm(thread);125for (javaVFrame* vf = thread->last_java_vframe(&rm); vf != NULL; vf = vf->java_sender()) {126GrowableArray<MonitorInfo*> *monitors = vf->monitors();127if (monitors != NULL) {128int len = monitors->length();129// Walk monitors youngest to oldest130for (int i = len - 1; i >= 0; i--) {131MonitorInfo* mon_info = monitors->at(i);132if (mon_info->eliminated()) continue;133oop owner = mon_info->owner();134if (owner != NULL) {135info->append(mon_info);136}137}138}139}140}141142thread->set_cached_monitor_info(info);143return info;144}145146// After the call, *biased_locker will be set to obj->mark()->biased_locker() if biased_locker != NULL,147// AND it is a living thread. Otherwise it will not be updated, (i.e. the caller is responsible for initialization).148static BiasedLocking::Condition revoke_bias(oop obj, bool allow_rebias, bool is_bulk, JavaThread* requesting_thread, JavaThread** biased_locker) {149markOop mark = obj->mark();150if (!mark->has_bias_pattern()) {151if (TraceBiasedLocking) {152ResourceMark rm;153tty->print_cr(" (Skipping revocation of object of type %s because it's no longer biased)",154obj->klass()->external_name());155}156return BiasedLocking::NOT_BIASED;157}158159uint age = mark->age();160markOop biased_prototype = markOopDesc::biased_locking_prototype()->set_age(age);161markOop unbiased_prototype = markOopDesc::prototype()->set_age(age);162163if (TraceBiasedLocking && (Verbose || !is_bulk)) {164ResourceMark rm;165tty->print_cr("Revoking bias of object " INTPTR_FORMAT " , mark " INTPTR_FORMAT " , type %s , prototype header " INTPTR_FORMAT " , allow rebias %d , requesting thread " INTPTR_FORMAT,166p2i((void *)obj), (intptr_t) mark, obj->klass()->external_name(), (intptr_t) obj->klass()->prototype_header(), (allow_rebias ? 1 : 0), (intptr_t) requesting_thread);167}168169JavaThread* biased_thread = mark->biased_locker();170if (biased_thread == NULL) {171// Object is anonymously biased. We can get here if, for172// example, we revoke the bias due to an identity hash code173// being computed for an object.174if (!allow_rebias) {175obj->set_mark(unbiased_prototype);176}177if (TraceBiasedLocking && (Verbose || !is_bulk)) {178tty->print_cr(" Revoked bias of anonymously-biased object");179}180return BiasedLocking::BIAS_REVOKED;181}182183// Handle case where the thread toward which the object was biased has exited184bool thread_is_alive = false;185if (requesting_thread == biased_thread) {186thread_is_alive = true;187} else {188for (JavaThread* cur_thread = Threads::first(); cur_thread != NULL; cur_thread = cur_thread->next()) {189if (cur_thread == biased_thread) {190thread_is_alive = true;191break;192}193}194}195if (!thread_is_alive) {196if (allow_rebias) {197obj->set_mark(biased_prototype);198} else {199obj->set_mark(unbiased_prototype);200}201if (TraceBiasedLocking && (Verbose || !is_bulk)) {202tty->print_cr(" Revoked bias of object biased toward dead thread");203}204return BiasedLocking::BIAS_REVOKED;205}206207// Thread owning bias is alive.208// Check to see whether it currently owns the lock and, if so,209// write down the needed displaced headers to the thread's stack.210// Otherwise, restore the object's header either to the unlocked211// or unbiased state.212GrowableArray<MonitorInfo*>* cached_monitor_info = get_or_compute_monitor_info(biased_thread);213BasicLock* highest_lock = NULL;214for (int i = 0; i < cached_monitor_info->length(); i++) {215MonitorInfo* mon_info = cached_monitor_info->at(i);216if (mon_info->owner() == obj) {217if (TraceBiasedLocking && Verbose) {218tty->print_cr(" mon_info->owner (" PTR_FORMAT ") == obj (" PTR_FORMAT ")",219p2i((void *) mon_info->owner()),220p2i((void *) obj));221}222// Assume recursive case and fix up highest lock later223markOop mark = markOopDesc::encode((BasicLock*) NULL);224highest_lock = mon_info->lock();225highest_lock->set_displaced_header(mark);226} else {227if (TraceBiasedLocking && Verbose) {228tty->print_cr(" mon_info->owner (" PTR_FORMAT ") != obj (" PTR_FORMAT ")",229p2i((void *) mon_info->owner()),230p2i((void *) obj));231}232}233}234if (highest_lock != NULL) {235// Fix up highest lock to contain displaced header and point236// object at it237highest_lock->set_displaced_header(unbiased_prototype);238// Reset object header to point to displaced mark.239// Must release storing the lock address for platforms without TSO240// ordering (e.g. ppc).241obj->release_set_mark(markOopDesc::encode(highest_lock));242assert(!obj->mark()->has_bias_pattern(), "illegal mark state: stack lock used bias bit");243if (TraceBiasedLocking && (Verbose || !is_bulk)) {244tty->print_cr(" Revoked bias of currently-locked object");245}246} else {247if (TraceBiasedLocking && (Verbose || !is_bulk)) {248tty->print_cr(" Revoked bias of currently-unlocked object");249}250if (allow_rebias) {251obj->set_mark(biased_prototype);252} else {253// Store the unlocked value into the object's header.254obj->set_mark(unbiased_prototype);255}256}257258#if INCLUDE_JFR259// If requested, return information on which thread held the bias260if (biased_locker != NULL) {261*biased_locker = biased_thread;262}263#endif // INCLUDE_JFR264265return BiasedLocking::BIAS_REVOKED;266}267268269enum HeuristicsResult {270HR_NOT_BIASED = 1,271HR_SINGLE_REVOKE = 2,272HR_BULK_REBIAS = 3,273HR_BULK_REVOKE = 4274};275276277static HeuristicsResult update_heuristics(oop o, bool allow_rebias) {278markOop mark = o->mark();279if (!mark->has_bias_pattern()) {280return HR_NOT_BIASED;281}282283// Heuristics to attempt to throttle the number of revocations.284// Stages:285// 1. Revoke the biases of all objects in the heap of this type,286// but allow rebiasing of those objects if unlocked.287// 2. Revoke the biases of all objects in the heap of this type288// and don't allow rebiasing of these objects. Disable289// allocation of objects of that type with the bias bit set.290Klass* k = o->klass();291jlong cur_time = os::javaTimeMillis();292jlong last_bulk_revocation_time = k->last_biased_lock_bulk_revocation_time();293int revocation_count = k->biased_lock_revocation_count();294if ((revocation_count >= BiasedLockingBulkRebiasThreshold) &&295(revocation_count < BiasedLockingBulkRevokeThreshold) &&296(last_bulk_revocation_time != 0) &&297(cur_time - last_bulk_revocation_time >= BiasedLockingDecayTime)) {298// This is the first revocation we've seen in a while of an299// object of this type since the last time we performed a bulk300// rebiasing operation. The application is allocating objects in301// bulk which are biased toward a thread and then handing them302// off to another thread. We can cope with this allocation303// pattern via the bulk rebiasing mechanism so we reset the304// klass's revocation count rather than allow it to increase305// monotonically. If we see the need to perform another bulk306// rebias operation later, we will, and if subsequently we see307// many more revocation operations in a short period of time we308// will completely disable biasing for this type.309k->set_biased_lock_revocation_count(0);310revocation_count = 0;311}312313// Make revocation count saturate just beyond BiasedLockingBulkRevokeThreshold314if (revocation_count <= BiasedLockingBulkRevokeThreshold) {315revocation_count = k->atomic_incr_biased_lock_revocation_count();316}317318if (revocation_count == BiasedLockingBulkRevokeThreshold) {319return HR_BULK_REVOKE;320}321322if (revocation_count == BiasedLockingBulkRebiasThreshold) {323return HR_BULK_REBIAS;324}325326return HR_SINGLE_REVOKE;327}328329330static BiasedLocking::Condition bulk_revoke_or_rebias_at_safepoint(oop o,331bool bulk_rebias,332bool attempt_rebias_of_object,333JavaThread* requesting_thread) {334assert(SafepointSynchronize::is_at_safepoint(), "must be done at safepoint");335336if (TraceBiasedLocking) {337tty->print_cr("* Beginning bulk revocation (kind == %s) because of object "338INTPTR_FORMAT " , mark " INTPTR_FORMAT " , type %s",339(bulk_rebias ? "rebias" : "revoke"),340p2i((void *) o), (intptr_t) o->mark(), o->klass()->external_name());341}342343jlong cur_time = os::javaTimeMillis();344o->klass()->set_last_biased_lock_bulk_revocation_time(cur_time);345346347Klass* k_o = o->klass();348Klass* klass = k_o;349350if (bulk_rebias) {351// Use the epoch in the klass of the object to implicitly revoke352// all biases of objects of this data type and force them to be353// reacquired. However, we also need to walk the stacks of all354// threads and update the headers of lightweight locked objects355// with biases to have the current epoch.356357// If the prototype header doesn't have the bias pattern, don't358// try to update the epoch -- assume another VM operation came in359// and reset the header to the unbiased state, which will360// implicitly cause all existing biases to be revoked361if (klass->prototype_header()->has_bias_pattern()) {362int prev_epoch = klass->prototype_header()->bias_epoch();363klass->set_prototype_header(klass->prototype_header()->incr_bias_epoch());364int cur_epoch = klass->prototype_header()->bias_epoch();365366// Now walk all threads' stacks and adjust epochs of any biased367// and locked objects of this data type we encounter368for (JavaThread* thr = Threads::first(); thr != NULL; thr = thr->next()) {369GrowableArray<MonitorInfo*>* cached_monitor_info = get_or_compute_monitor_info(thr);370for (int i = 0; i < cached_monitor_info->length(); i++) {371MonitorInfo* mon_info = cached_monitor_info->at(i);372oop owner = mon_info->owner();373markOop mark = owner->mark();374if ((owner->klass() == k_o) && mark->has_bias_pattern()) {375// We might have encountered this object already in the case of recursive locking376assert(mark->bias_epoch() == prev_epoch || mark->bias_epoch() == cur_epoch, "error in bias epoch adjustment");377owner->set_mark(mark->set_bias_epoch(cur_epoch));378}379}380}381}382383// At this point we're done. All we have to do is potentially384// adjust the header of the given object to revoke its bias.385revoke_bias(o, attempt_rebias_of_object && klass->prototype_header()->has_bias_pattern(), true, requesting_thread, NULL);386} else {387if (TraceBiasedLocking) {388ResourceMark rm;389tty->print_cr("* Disabling biased locking for type %s", klass->external_name());390}391392// Disable biased locking for this data type. Not only will this393// cause future instances to not be biased, but existing biased394// instances will notice that this implicitly caused their biases395// to be revoked.396klass->set_prototype_header(markOopDesc::prototype());397398// Now walk all threads' stacks and forcibly revoke the biases of399// any locked and biased objects of this data type we encounter.400for (JavaThread* thr = Threads::first(); thr != NULL; thr = thr->next()) {401GrowableArray<MonitorInfo*>* cached_monitor_info = get_or_compute_monitor_info(thr);402for (int i = 0; i < cached_monitor_info->length(); i++) {403MonitorInfo* mon_info = cached_monitor_info->at(i);404oop owner = mon_info->owner();405markOop mark = owner->mark();406if ((owner->klass() == k_o) && mark->has_bias_pattern()) {407revoke_bias(owner, false, true, requesting_thread, NULL);408}409}410}411412// Must force the bias of the passed object to be forcibly revoked413// as well to ensure guarantees to callers414revoke_bias(o, false, true, requesting_thread, NULL);415}416417if (TraceBiasedLocking) {418tty->print_cr("* Ending bulk revocation");419}420421BiasedLocking::Condition status_code = BiasedLocking::BIAS_REVOKED;422423if (attempt_rebias_of_object &&424o->mark()->has_bias_pattern() &&425klass->prototype_header()->has_bias_pattern()) {426markOop new_mark = markOopDesc::encode(requesting_thread, o->mark()->age(),427klass->prototype_header()->bias_epoch());428o->set_mark(new_mark);429status_code = BiasedLocking::BIAS_REVOKED_AND_REBIASED;430if (TraceBiasedLocking) {431tty->print_cr(" Rebiased object toward thread " INTPTR_FORMAT, (intptr_t) requesting_thread);432}433}434435assert(!o->mark()->has_bias_pattern() ||436(attempt_rebias_of_object && (o->mark()->biased_locker() == requesting_thread)),437"bug in bulk bias revocation");438439return status_code;440}441442443static void clean_up_cached_monitor_info() {444// Walk the thread list clearing out the cached monitors445for (JavaThread* thr = Threads::first(); thr != NULL; thr = thr->next()) {446thr->set_cached_monitor_info(NULL);447}448}449450451class VM_RevokeBias : public VM_Operation {452protected:453Handle* _obj;454GrowableArray<Handle>* _objs;455JavaThread* _requesting_thread;456BiasedLocking::Condition _status_code;457traceid _biased_locker_id;458459public:460VM_RevokeBias(Handle* obj, JavaThread* requesting_thread)461: _obj(obj)462, _objs(NULL)463, _requesting_thread(requesting_thread)464, _status_code(BiasedLocking::NOT_BIASED)465, _biased_locker_id(0) {}466467VM_RevokeBias(GrowableArray<Handle>* objs, JavaThread* requesting_thread)468: _obj(NULL)469, _objs(objs)470, _requesting_thread(requesting_thread)471, _status_code(BiasedLocking::NOT_BIASED)472, _biased_locker_id(0) {}473474virtual VMOp_Type type() const { return VMOp_RevokeBias; }475476virtual bool doit_prologue() {477// Verify that there is actual work to do since the callers just478// give us locked object(s). If we don't find any biased objects479// there is nothing to do and we avoid a safepoint.480if (_obj != NULL) {481markOop mark = (*_obj)()->mark();482if (mark->has_bias_pattern()) {483return true;484}485} else {486for ( int i = 0 ; i < _objs->length(); i++ ) {487markOop mark = (_objs->at(i))()->mark();488if (mark->has_bias_pattern()) {489return true;490}491}492}493return false;494}495496virtual void doit() {497if (_obj != NULL) {498if (TraceBiasedLocking) {499tty->print_cr("Revoking bias with potentially per-thread safepoint:");500}501502JavaThread* biased_locker = NULL;503_status_code = revoke_bias((*_obj)(), false, false, _requesting_thread, &biased_locker);504#if INCLUDE_JFR505if (biased_locker != NULL) {506_biased_locker_id = JFR_THREAD_ID(biased_locker);507}508#endif // INCLUDE_JFR509510clean_up_cached_monitor_info();511return;512} else {513if (TraceBiasedLocking) {514tty->print_cr("Revoking bias with global safepoint:");515}516BiasedLocking::revoke_at_safepoint(_objs);517}518}519520BiasedLocking::Condition status_code() const {521return _status_code;522}523524traceid biased_locker() const {525return _biased_locker_id;526}527};528529530class VM_BulkRevokeBias : public VM_RevokeBias {531private:532bool _bulk_rebias;533bool _attempt_rebias_of_object;534535public:536VM_BulkRevokeBias(Handle* obj, JavaThread* requesting_thread,537bool bulk_rebias,538bool attempt_rebias_of_object)539: VM_RevokeBias(obj, requesting_thread)540, _bulk_rebias(bulk_rebias)541, _attempt_rebias_of_object(attempt_rebias_of_object) {}542543virtual VMOp_Type type() const { return VMOp_BulkRevokeBias; }544virtual bool doit_prologue() { return true; }545546virtual void doit() {547_status_code = bulk_revoke_or_rebias_at_safepoint((*_obj)(), _bulk_rebias, _attempt_rebias_of_object, _requesting_thread);548clean_up_cached_monitor_info();549}550};551552553BiasedLocking::Condition BiasedLocking::revoke_and_rebias(Handle obj, bool attempt_rebias, TRAPS) {554assert(!SafepointSynchronize::is_at_safepoint(), "must not be called while at safepoint");555556// We can revoke the biases of anonymously-biased objects557// efficiently enough that we should not cause these revocations to558// update the heuristics because doing so may cause unwanted bulk559// revocations (which are expensive) to occur.560markOop mark = obj->mark();561if (mark->is_biased_anonymously() && !attempt_rebias) {562// We are probably trying to revoke the bias of this object due to563// an identity hash code computation. Try to revoke the bias564// without a safepoint. This is possible if we can successfully565// compare-and-exchange an unbiased header into the mark word of566// the object, meaning that no other thread has raced to acquire567// the bias of the object.568markOop biased_value = mark;569markOop unbiased_prototype = markOopDesc::prototype()->set_age(mark->age());570markOop res_mark = (markOop) Atomic::cmpxchg_ptr(unbiased_prototype, obj->mark_addr(), mark);571if (res_mark == biased_value) {572return BIAS_REVOKED;573}574} else if (mark->has_bias_pattern()) {575Klass* k = obj->klass();576markOop prototype_header = k->prototype_header();577if (!prototype_header->has_bias_pattern()) {578// This object has a stale bias from before the bulk revocation579// for this data type occurred. It's pointless to update the580// heuristics at this point so simply update the header with a581// CAS. If we fail this race, the object's bias has been revoked582// by another thread so we simply return and let the caller deal583// with it.584markOop biased_value = mark;585markOop res_mark = (markOop) Atomic::cmpxchg_ptr(prototype_header, obj->mark_addr(), mark);586assert(!(*(obj->mark_addr()))->has_bias_pattern(), "even if we raced, should still be revoked");587return BIAS_REVOKED;588} else if (prototype_header->bias_epoch() != mark->bias_epoch()) {589// The epoch of this biasing has expired indicating that the590// object is effectively unbiased. Depending on whether we need591// to rebias or revoke the bias of this object we can do it592// efficiently enough with a CAS that we shouldn't update the593// heuristics. This is normally done in the assembly code but we594// can reach this point due to various points in the runtime595// needing to revoke biases.596if (attempt_rebias) {597assert(THREAD->is_Java_thread(), "");598markOop biased_value = mark;599markOop rebiased_prototype = markOopDesc::encode((JavaThread*) THREAD, mark->age(), prototype_header->bias_epoch());600markOop res_mark = (markOop) Atomic::cmpxchg_ptr(rebiased_prototype, obj->mark_addr(), mark);601if (res_mark == biased_value) {602return BIAS_REVOKED_AND_REBIASED;603}604} else {605markOop biased_value = mark;606markOop unbiased_prototype = markOopDesc::prototype()->set_age(mark->age());607markOop res_mark = (markOop) Atomic::cmpxchg_ptr(unbiased_prototype, obj->mark_addr(), mark);608if (res_mark == biased_value) {609return BIAS_REVOKED;610}611}612}613}614615HeuristicsResult heuristics = update_heuristics(obj(), attempt_rebias);616if (heuristics == HR_NOT_BIASED) {617return NOT_BIASED;618} else if (heuristics == HR_SINGLE_REVOKE) {619Klass *k = obj->klass();620markOop prototype_header = k->prototype_header();621if (mark->biased_locker() == THREAD &&622prototype_header->bias_epoch() == mark->bias_epoch()) {623// A thread is trying to revoke the bias of an object biased624// toward it, again likely due to an identity hash code625// computation. We can again avoid a safepoint in this case626// since we are only going to walk our own stack. There are no627// races with revocations occurring in other threads because we628// reach no safepoints in the revocation path.629// Also check the epoch because even if threads match, another thread630// can come in with a CAS to steal the bias of an object that has a631// stale epoch.632ResourceMark rm;633if (TraceBiasedLocking) {634tty->print_cr("Revoking bias by walking my own stack:");635}636EventBiasedLockSelfRevocation event;637BiasedLocking::Condition cond = revoke_bias(obj(), false, false, (JavaThread*) THREAD, NULL);638((JavaThread*) THREAD)->set_cached_monitor_info(NULL);639assert(cond == BIAS_REVOKED, "why not?");640if (event.should_commit()) {641event.set_lockClass(k);642event.commit();643}644return cond;645} else {646EventBiasedLockRevocation event;647VM_RevokeBias revoke(&obj, (JavaThread*) THREAD);648VMThread::execute(&revoke);649if (event.should_commit() && (revoke.status_code() != NOT_BIASED)) {650event.set_lockClass(k);651// Subtract 1 to match the id of events committed inside the safepoint652event.set_safepointId(SafepointSynchronize::safepoint_counter() - 1);653event.set_previousOwner(revoke.biased_locker());654event.commit();655}656return revoke.status_code();657}658}659660assert((heuristics == HR_BULK_REVOKE) ||661(heuristics == HR_BULK_REBIAS), "?");662EventBiasedLockClassRevocation event;663VM_BulkRevokeBias bulk_revoke(&obj, (JavaThread*) THREAD,664(heuristics == HR_BULK_REBIAS),665attempt_rebias);666VMThread::execute(&bulk_revoke);667if (event.should_commit()) {668event.set_revokedClass(obj->klass());669event.set_disableBiasing((heuristics != HR_BULK_REBIAS));670// Subtract 1 to match the id of events committed inside the safepoint671event.set_safepointId(SafepointSynchronize::safepoint_counter() - 1);672event.commit();673}674return bulk_revoke.status_code();675}676677678void BiasedLocking::revoke(GrowableArray<Handle>* objs) {679assert(!SafepointSynchronize::is_at_safepoint(), "must not be called while at safepoint");680if (objs->length() == 0) {681return;682}683VM_RevokeBias revoke(objs, JavaThread::current());684VMThread::execute(&revoke);685}686687688void BiasedLocking::revoke_at_safepoint(Handle h_obj) {689assert(SafepointSynchronize::is_at_safepoint(), "must only be called while at safepoint");690oop obj = h_obj();691HeuristicsResult heuristics = update_heuristics(obj, false);692if (heuristics == HR_SINGLE_REVOKE) {693revoke_bias(obj, false, false, NULL, NULL);694} else if ((heuristics == HR_BULK_REBIAS) ||695(heuristics == HR_BULK_REVOKE)) {696bulk_revoke_or_rebias_at_safepoint(obj, (heuristics == HR_BULK_REBIAS), false, NULL);697}698clean_up_cached_monitor_info();699}700701702void BiasedLocking::revoke_at_safepoint(GrowableArray<Handle>* objs) {703assert(SafepointSynchronize::is_at_safepoint(), "must only be called while at safepoint");704int len = objs->length();705for (int i = 0; i < len; i++) {706oop obj = (objs->at(i))();707HeuristicsResult heuristics = update_heuristics(obj, false);708if (heuristics == HR_SINGLE_REVOKE) {709revoke_bias(obj, false, false, NULL, NULL);710} else if ((heuristics == HR_BULK_REBIAS) ||711(heuristics == HR_BULK_REVOKE)) {712bulk_revoke_or_rebias_at_safepoint(obj, (heuristics == HR_BULK_REBIAS), false, NULL);713}714}715clean_up_cached_monitor_info();716}717718719void BiasedLocking::preserve_marks() {720if (!UseBiasedLocking)721return;722723assert(SafepointSynchronize::is_at_safepoint(), "must only be called while at safepoint");724725assert(_preserved_oop_stack == NULL, "double initialization");726assert(_preserved_mark_stack == NULL, "double initialization");727728// In order to reduce the number of mark words preserved during GC729// due to the presence of biased locking, we reinitialize most mark730// words to the class's prototype during GC -- even those which have731// a currently valid bias owner. One important situation where we732// must not clobber a bias is when a biased object is currently733// locked. To handle this case we iterate over the currently-locked734// monitors in a prepass and, if they are biased, preserve their735// mark words here. This should be a relatively small set of objects736// especially compared to the number of objects in the heap.737_preserved_mark_stack = new (ResourceObj::C_HEAP, mtInternal) GrowableArray<markOop>(10, true);738_preserved_oop_stack = new (ResourceObj::C_HEAP, mtInternal) GrowableArray<Handle>(10, true);739740ResourceMark rm;741Thread* cur = Thread::current();742for (JavaThread* thread = Threads::first(); thread != NULL; thread = thread->next()) {743if (thread->has_last_Java_frame()) {744RegisterMap rm(thread);745for (javaVFrame* vf = thread->last_java_vframe(&rm); vf != NULL; vf = vf->java_sender()) {746GrowableArray<MonitorInfo*> *monitors = vf->monitors();747if (monitors != NULL) {748int len = monitors->length();749// Walk monitors youngest to oldest750for (int i = len - 1; i >= 0; i--) {751MonitorInfo* mon_info = monitors->at(i);752if (mon_info->owner_is_scalar_replaced()) continue;753oop owner = mon_info->owner();754if (owner != NULL) {755markOop mark = owner->mark();756if (mark->has_bias_pattern()) {757_preserved_oop_stack->push(Handle(cur, owner));758_preserved_mark_stack->push(mark);759}760}761}762}763}764}765}766}767768769void BiasedLocking::restore_marks() {770if (!UseBiasedLocking)771return;772773assert(_preserved_oop_stack != NULL, "double free");774assert(_preserved_mark_stack != NULL, "double free");775776int len = _preserved_oop_stack->length();777for (int i = 0; i < len; i++) {778Handle owner = _preserved_oop_stack->at(i);779markOop mark = _preserved_mark_stack->at(i);780owner->set_mark(mark);781}782783delete _preserved_oop_stack;784_preserved_oop_stack = NULL;785delete _preserved_mark_stack;786_preserved_mark_stack = NULL;787}788789790int* BiasedLocking::total_entry_count_addr() { return _counters.total_entry_count_addr(); }791int* BiasedLocking::biased_lock_entry_count_addr() { return _counters.biased_lock_entry_count_addr(); }792int* BiasedLocking::anonymously_biased_lock_entry_count_addr() { return _counters.anonymously_biased_lock_entry_count_addr(); }793int* BiasedLocking::rebiased_lock_entry_count_addr() { return _counters.rebiased_lock_entry_count_addr(); }794int* BiasedLocking::revoked_lock_entry_count_addr() { return _counters.revoked_lock_entry_count_addr(); }795int* BiasedLocking::fast_path_entry_count_addr() { return _counters.fast_path_entry_count_addr(); }796int* BiasedLocking::slow_path_entry_count_addr() { return _counters.slow_path_entry_count_addr(); }797798799// BiasedLockingCounters800801int BiasedLockingCounters::slow_path_entry_count() {802if (_slow_path_entry_count != 0) {803return _slow_path_entry_count;804}805int sum = _biased_lock_entry_count + _anonymously_biased_lock_entry_count +806_rebiased_lock_entry_count + _revoked_lock_entry_count +807_fast_path_entry_count;808809return _total_entry_count - sum;810}811812void BiasedLockingCounters::print_on(outputStream* st) {813tty->print_cr("# total entries: %d", _total_entry_count);814tty->print_cr("# biased lock entries: %d", _biased_lock_entry_count);815tty->print_cr("# anonymously biased lock entries: %d", _anonymously_biased_lock_entry_count);816tty->print_cr("# rebiased lock entries: %d", _rebiased_lock_entry_count);817tty->print_cr("# revoked lock entries: %d", _revoked_lock_entry_count);818tty->print_cr("# fast path lock entries: %d", _fast_path_entry_count);819tty->print_cr("# slow path lock entries: %d", slow_path_entry_count());820}821822823