< prev index next > src/hotspot/share/runtime/synchronizer.cpp
Print this page
bool volatile ObjectSynchronizer::_is_final_audit = false;
jlong ObjectSynchronizer::_last_async_deflation_time_ns = 0;
static uintx _no_progress_cnt = 0;
static bool _no_progress_skip_increment = false;
+ // These checks are required for wait, notify and exit to avoid inflating the monitor to
+ // find out this inline type object cannot be locked.
+ #define CHECK_THROW_NOSYNC_IMSE(obj) \
+ if (EnableValhalla && (obj)->mark().is_inline_type()) { \
+ JavaThread* THREAD = current; \
+ ResourceMark rm(THREAD); \
+ THROW_MSG(vmSymbols::java_lang_IllegalMonitorStateException(), obj->klass()->external_name()); \
+ }
+
+ #define CHECK_THROW_NOSYNC_IMSE_0(obj) \
+ if (EnableValhalla && (obj)->mark().is_inline_type()) { \
+ JavaThread* THREAD = current; \
+ ResourceMark rm(THREAD); \
+ THROW_MSG_0(vmSymbols::java_lang_IllegalMonitorStateException(), obj->klass()->external_name()); \
+ }
+
// =====================> Quick functions
// The quick_* forms are special fast-path variants used to improve
// performance. In the simplest case, a "quick_*" implementation could
// simply return false, in which case the caller will perform the necessary
bool ObjectSynchronizer::quick_notify(oopDesc* obj, JavaThread* current, bool all) {
assert(current->thread_state() == _thread_in_Java, "invariant");
NoSafepointVerifier nsv;
if (obj == nullptr) return false; // slow-path for invalid obj
+ assert(!EnableValhalla || !obj->klass()->is_inline_klass(), "monitor op on inline type");
const markWord mark = obj->mark();
if (LockingMode == LM_LIGHTWEIGHT) {
if (mark.is_fast_locked() && current->lock_stack().contains(cast_to_oop(obj))) {
// Degenerate notify
// Note that we can't safely call AsyncPrintJavaStack() from within
// quick_enter() as our thread state remains _in_Java.
bool ObjectSynchronizer::quick_enter_legacy(oop obj, BasicLock* lock, JavaThread* current) {
assert(current->thread_state() == _thread_in_Java, "invariant");
+ assert(!EnableValhalla || !obj->klass()->is_inline_klass(), "monitor op on inline type");
if (useHeavyMonitors()) {
return false; // Slow path
}
void ObjectSynchronizer::enter_for(Handle obj, BasicLock* lock, JavaThread* locking_thread) {
// When called with locking_thread != Thread::current() some mechanism must synchronize
// the locking_thread with respect to the current thread. Currently only used when
// deoptimizing and re-locking locks. See Deoptimization::relock_objects
assert(locking_thread == Thread::current() || locking_thread->is_obj_deopt_suspend(), "must be");
+ assert(!EnableValhalla || !obj->klass()->is_inline_klass(), "JITed code should never have locked an instance of a value class");
if (LockingMode == LM_LIGHTWEIGHT) {
return LightweightSynchronizer::enter_for(obj, lock, locking_thread);
}
}
}
}
void ObjectSynchronizer::enter_legacy(Handle obj, BasicLock* lock, JavaThread* current) {
+ assert(!EnableValhalla || !obj->klass()->is_inline_klass(), "This method should never be called on an instance of an inline class");
if (!enter_fast_impl(obj, lock, current)) {
// Inflated ObjectMonitor::enter is required
// An async deflation can race after the inflate() call and before
// enter() can make the ObjectMonitor busy. enter() returns false if
// The interpreter and compiler assembly code tries to lock using the fast path
// of this algorithm. Make sure to update that code if the following function is
// changed. The implementation is extremely sensitive to race condition. Be careful.
bool ObjectSynchronizer::enter_fast_impl(Handle obj, BasicLock* lock, JavaThread* locking_thread) {
+ guarantee(!EnableValhalla || !obj->klass()->is_inline_klass(), "Attempt to inflate inline type");
assert(LockingMode != LM_LIGHTWEIGHT, "Use LightweightSynchronizer");
if (obj->klass()->is_value_based()) {
handle_sync_on_value_based_class(obj, locking_thread);
}
void ObjectSynchronizer::exit_legacy(oop object, BasicLock* lock, JavaThread* current) {
assert(LockingMode != LM_LIGHTWEIGHT, "Use LightweightSynchronizer");
if (!useHeavyMonitors()) {
markWord mark = object->mark();
+ if (EnableValhalla && mark.is_inline_type()) {
+ return;
+ }
if (LockingMode == LM_LEGACY) {
markWord dhw = lock->displaced_header();
if (dhw.value() == 0) {
// If the displaced header is null, then this exit matches up with
// a recursive enter. No real work to do here except for diagnostics.
// -----------------------------------------------------------------------------
// JNI locks on java objects
// NOTE: must use heavy weight monitor to handle jni monitor enter
void ObjectSynchronizer::jni_enter(Handle obj, JavaThread* current) {
+ JavaThread* THREAD = current;
if (obj->klass()->is_value_based()) {
handle_sync_on_value_based_class(obj, current);
}
+ if (EnableValhalla && obj->klass()->is_inline_klass()) {
+ ResourceMark rm(THREAD);
+ const char* desc = "Cannot synchronize on an instance of value class ";
+ const char* className = obj->klass()->external_name();
+ size_t msglen = strlen(desc) + strlen(className) + 1;
+ char* message = NEW_RESOURCE_ARRAY(char, msglen);
+ assert(message != nullptr, "NEW_RESOURCE_ARRAY should have called vm_exit_out_of_memory and not return nullptr");
+ THROW_MSG(vmSymbols::java_lang_IdentityException(), className);
+ }
+
// the current locking is from JNI instead of Java code
current->set_current_pending_monitor_is_from_java(false);
// An async deflation can race after the inflate() call and before
// enter() can make the ObjectMonitor busy. enter() returns false if
// we have lost the race to async deflation and we simply try again.
}
// NOTE: must use heavy weight monitor to handle jni monitor exit
void ObjectSynchronizer::jni_exit(oop obj, TRAPS) {
JavaThread* current = THREAD;
+ CHECK_THROW_NOSYNC_IMSE(obj);
ObjectMonitor* monitor;
if (LockingMode == LM_LIGHTWEIGHT) {
monitor = LightweightSynchronizer::inflate_locked_or_imse(obj, inflate_cause_jni_exit, CHECK);
} else {
// Wait/Notify/NotifyAll
// NOTE: must use heavy weight monitor to handle wait()
int ObjectSynchronizer::wait(Handle obj, jlong millis, TRAPS) {
JavaThread* current = THREAD;
+ CHECK_THROW_NOSYNC_IMSE_0(obj);
if (millis < 0) {
THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "timeout value is negative");
}
ObjectMonitor* monitor;
}
void ObjectSynchronizer::notify(Handle obj, TRAPS) {
JavaThread* current = THREAD;
+ CHECK_THROW_NOSYNC_IMSE(obj);
markWord mark = obj->mark();
if (LockingMode == LM_LIGHTWEIGHT) {
if ((mark.is_fast_locked() && current->lock_stack().contains(obj()))) {
// Not inflated so there can't be any waiters to notify.
}
// NOTE: see comment of notify()
void ObjectSynchronizer::notifyall(Handle obj, TRAPS) {
JavaThread* current = THREAD;
+ CHECK_THROW_NOSYNC_IMSE(obj);
markWord mark = obj->mark();
if (LockingMode == LM_LIGHTWEIGHT) {
if ((mark.is_fast_locked() && current->lock_stack().contains(obj()))) {
// Not inflated so there can't be any waiters to notify.
}
}
}
intptr_t ObjectSynchronizer::FastHashCode(Thread* current, oop obj) {
+ if (EnableValhalla && obj->klass()->is_inline_klass()) {
+ // VM should be calling bootstrap method
+ ShouldNotReachHere();
+ }
if (UseObjectMonitorTable) {
// Since the monitor isn't in the object header, the hash can simply be
// installed in the object header.
return install_hash_code(current, obj);
}
}
}
bool ObjectSynchronizer::current_thread_holds_lock(JavaThread* current,
Handle h_obj) {
+ if (EnableValhalla && h_obj->mark().is_inline_type()) {
+ return false;
+ }
assert(current == JavaThread::current(), "Can only be called on current thread");
oop obj = h_obj();
markWord mark = read_stable_mark(obj);
assert(LockingMode != LM_LIGHTWEIGHT, "LM_LIGHTWEIGHT cannot use inflate_for");
return inflate_impl(obj, cause);
}
ObjectMonitor* ObjectSynchronizer::inflate_impl(oop object, const InflateCause cause) {
+ if (EnableValhalla) {
+ guarantee(!object->klass()->is_inline_klass(), "Attempt to inflate inline type");
+ }
assert(LockingMode != LM_LIGHTWEIGHT, "LM_LIGHTWEIGHT cannot use inflate_impl");
EventJavaMonitorInflate event;
for (;;) {
const markWord mark = object->mark_acquire();
< prev index next >