Always access Thread state and flags as 32-bit location.
Rewrite access to Thread's state and flags to use 32-bit
atomic operations. Avoid `volatile` accesses that prevent
compiler optimizations.
Change `ThreadState` and `ThreadFlag` to `enum class`es.
Golem results for art-opt-cc (higher is better):
linux-ia32 before after
NativeDowncallStaticNormal 28.162 35.323 (+25.43%)
NativeDowncallStaticNormal6 26.447 32.951 (+24.59%)
NativeDowncallStaticNormalRefs6
NativeDowncallVirtualNormal 27.972 35.027 (+25.22%)
NativeDowncallVirtualNormal6 26.096 32.131 (+23.13%)
NativeDowncallVirtualNormalRefs6 25.922 31.873 (+22.95%)
linux-x64 before after
NativeDowncallStaticNormal 26.987 34.380 (+27.40%)
NativeDowncallStaticNormal6 25.424 31.096 (+22.31%)
NativeDowncallStaticNormalRefs6 25.086 30.602 (+21.99%)
NativeDowncallVirtualNormal 26.812 33.234 (+23.95%)
NativeDowncallVirtualNormal6 25.086 30.617 (+22.05%)
NativeDowncallVirtualNormalRefs6 25.086 30.602 (+21.99%)
linux-armv7 before after
NativeDowncallStaticNormal 7.2394 7.9523 (+9.848%)
NativeDowncallStaticNormal6 6.8527 7.4888 (+9.283%)
NativeDowncallStaticNormalRefs6 6.3976 6.9444 (+8.547%)
NativeDowncallVirtualNormal 7.2081 7.9130 (+9.779%)
NativeDowncallVirtualNormal6 6.8527 7.4888 (+9.283%)
NativeDowncallVirtualNormalRefs6 6.3168 6.8527 (+8.483%)
linux-armv8 before after
NativeDowncallStaticNormal 7.0389 7.5973 (+7.933%)
NativeDowncallStaticNormal6 6.8527 7.3783 (+7.670%)
NativeDowncallStaticNormalRefs6 6.2924 6.8226 (+8.427%)
NativeDowncallVirtualNormal 6.8527 7.3783 (+7.670%)
NativeDowncallVirtualNormal6 6.5604 7.0423 (+7.344%)
NativeDowncallVirtualNormalRefs6 6.1408 6.5329 (+6.386%)
Test: m test-art-host-gtest
Test: testrunner.py --host --optimizing
Test: run-gtests.sh
Test: testrunner.py --target --optimizing --interpreter
Bug: 172332525
Bug: 143299880
Change-Id: Ib55d457ad8f5d9e1159b681dfd279d1f9cfb2af7
diff --git a/adbconnection/adbconnection.cc b/adbconnection/adbconnection.cc
index cca4485..f9ebe40 100644
--- a/adbconnection/adbconnection.cc
+++ b/adbconnection/adbconnection.cc
@@ -183,7 +183,7 @@
static jobject CreateAdbConnectionThread(art::Thread* thr) {
JNIEnv* env = thr->GetJniEnv();
// Move to native state to talk with the jnienv api.
- art::ScopedThreadStateChange stsc(thr, art::kNative);
+ art::ScopedThreadStateChange stsc(thr, art::ThreadState::kNative);
ScopedLocalRef<jstring> thr_name(env, env->NewStringUTF(kAdbConnectionThreadName));
ScopedLocalRef<jobject> thr_group(
env,
@@ -528,9 +528,9 @@
void AdbConnectionState::RunPollLoop(art::Thread* self) {
DCHECK(IsDebuggingPossible() || art::Runtime::Current()->IsProfileableFromShell());
CHECK_NE(agent_name_, "");
- CHECK_EQ(self->GetState(), art::kNative);
+ CHECK_EQ(self->GetState(), art::ThreadState::kNative);
art::Locks::mutator_lock_->AssertNotHeld(self);
- self->SetState(art::kWaitingInMainDebuggerLoop);
+ self->SetState(art::ThreadState::kWaitingInMainDebuggerLoop);
// shutting_down_ set by StopDebuggerThreads
while (!shutting_down_) {
// First, connect to adbd if we haven't already.
diff --git a/cmdline/cmdline.h b/cmdline/cmdline.h
index 5821496..b8ca7d0 100644
--- a/cmdline/cmdline.h
+++ b/cmdline/cmdline.h
@@ -127,7 +127,7 @@
// Runtime::Create acquired the mutator_lock_ that is normally given away when we Runtime::Start,
// give it away now and then switch to a more manageable ScopedObjectAccess.
- Thread::Current()->TransitionFromRunnableToSuspended(kNative);
+ Thread::Current()->TransitionFromRunnableToSuspended(ThreadState::kNative);
return Runtime::Current();
}
diff --git a/compiler/jni/jni_compiler_test.cc b/compiler/jni/jni_compiler_test.cc
index 2f96d44..d63ae17 100644
--- a/compiler/jni/jni_compiler_test.cc
+++ b/compiler/jni/jni_compiler_test.cc
@@ -536,9 +536,9 @@
static void expectValidThreadState() {
// Normal JNI always transitions to "Native". Other JNIs stay in the "Runnable" state.
if (IsCurrentJniNormal()) {
- EXPECT_EQ(kNative, Thread::Current()->GetState());
+ EXPECT_EQ(ThreadState::kNative, Thread::Current()->GetState());
} else {
- EXPECT_EQ(kRunnable, Thread::Current()->GetState());
+ EXPECT_EQ(ThreadState::kRunnable, Thread::Current()->GetState());
}
}
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index 2cf2571..bcb5ac5 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -1994,7 +1994,8 @@
UseScratchRegisterScope temps(codegen_->GetVIXLAssembler());
Register temp = temps.AcquireW();
- __ Ldrh(temp, MemOperand(tr, Thread::ThreadFlagsOffset<kArm64PointerSize>().SizeValue()));
+ __ Ldr(temp, MemOperand(tr, Thread::ThreadFlagsOffset<kArm64PointerSize>().SizeValue()));
+ static_assert(static_cast<std::underlying_type_t<ThreadState>>(ThreadState::kRunnable) == 0u);
if (successor == nullptr) {
__ Cbnz(temp, slow_path->GetEntryLabel());
__ Bind(slow_path->GetReturnLabel());
diff --git a/compiler/optimizing/code_generator_arm_vixl.cc b/compiler/optimizing/code_generator_arm_vixl.cc
index 62c285d..aa06c5a 100644
--- a/compiler/optimizing/code_generator_arm_vixl.cc
+++ b/compiler/optimizing/code_generator_arm_vixl.cc
@@ -7181,7 +7181,8 @@
UseScratchRegisterScope temps(GetVIXLAssembler());
vixl32::Register temp = temps.Acquire();
GetAssembler()->LoadFromOffset(
- kLoadUnsignedHalfword, temp, tr, Thread::ThreadFlagsOffset<kArmPointerSize>().Int32Value());
+ kLoadWord, temp, tr, Thread::ThreadFlagsOffset<kArmPointerSize>().Int32Value());
+ static_assert(static_cast<std::underlying_type_t<ThreadState>>(ThreadState::kRunnable) == 0u);
if (successor == nullptr) {
__ CompareAndBranchIfNonZero(temp, slow_path->GetEntryLabel());
__ Bind(slow_path->GetReturnLabel());
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 11c15d6..758a471 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -6699,7 +6699,8 @@
DCHECK_EQ(slow_path->GetSuccessor(), successor);
}
- __ fs()->cmpw(Address::Absolute(Thread::ThreadFlagsOffset<kX86PointerSize>().Int32Value()),
+ static_assert(static_cast<std::underlying_type_t<ThreadState>>(ThreadState::kRunnable) == 0u);
+ __ fs()->cmpl(Address::Absolute(Thread::ThreadFlagsOffset<kX86PointerSize>().Int32Value()),
Immediate(0));
if (successor == nullptr) {
__ j(kNotEqual, slow_path->GetEntryLabel());
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index e601b40..c402e83 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -6016,7 +6016,8 @@
DCHECK_EQ(slow_path->GetSuccessor(), successor);
}
- __ gs()->cmpw(Address::Absolute(Thread::ThreadFlagsOffset<kX86_64PointerSize>().Int32Value(),
+ static_assert(static_cast<std::underlying_type_t<ThreadState>>(ThreadState::kRunnable) == 0u);
+ __ gs()->cmpl(Address::Absolute(Thread::ThreadFlagsOffset<kX86_64PointerSize>().Int32Value(),
/* no_rip= */ true),
Immediate(0));
if (successor == nullptr) {
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index 16abf9d..6d7a953 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -1043,7 +1043,7 @@
// All signature polymorphic methods are native.
DCHECK(method == nullptr || !method->IsSignaturePolymorphic());
// Go to native so that we don't block GC during compilation.
- ScopedThreadSuspension sts(soa.Self(), kNative);
+ ScopedThreadSuspension sts(soa.Self(), ThreadState::kNative);
// Try to compile a fully intrinsified implementation.
if (method != nullptr && UNLIKELY(method->IsIntrinsic())) {
DCHECK(compiler_options.IsBootImage());
@@ -1159,7 +1159,7 @@
compiling_class);
CodeVectorAllocator code_allocator(&allocator);
// Go to native so that we don't block GC during compilation.
- ScopedThreadSuspension sts(soa.Self(), kNative);
+ ScopedThreadSuspension sts(soa.Self(), ThreadState::kNative);
std::unique_ptr<CodeGenerator> codegen(
TryCompileIntrinsic(&allocator,
&arena_stack,
@@ -1328,7 +1328,7 @@
compiling_class);
// Go to native so that we don't block GC during compilation.
- ScopedThreadSuspension sts(self, kNative);
+ ScopedThreadSuspension sts(self, ThreadState::kNative);
codegen.reset(
TryCompile(&allocator,
&arena_stack,
diff --git a/compiler/utils/arm/jni_macro_assembler_arm_vixl.cc b/compiler/utils/arm/jni_macro_assembler_arm_vixl.cc
index bd8aa083..2b3c2dd 100644
--- a/compiler/utils/arm/jni_macro_assembler_arm_vixl.cc
+++ b/compiler/utils/arm/jni_macro_assembler_arm_vixl.cc
@@ -1053,11 +1053,12 @@
void ArmVIXLJNIMacroAssembler::SuspendCheck(JNIMacroLabel* label) {
UseScratchRegisterScope temps(asm_.GetVIXLAssembler());
vixl32::Register scratch = temps.Acquire();
- asm_.LoadFromOffset(kLoadUnsignedHalfword,
+ asm_.LoadFromOffset(kLoadWord,
scratch,
tr,
Thread::ThreadFlagsOffset<kArmPointerSize>().Int32Value());
+ static_assert(static_cast<std::underlying_type_t<ThreadState>>(ThreadState::kRunnable) == 0u);
___ Cmp(scratch, 0);
___ BPreferNear(ne, ArmVIXLJNIMacroLabel::Cast(label)->AsArm());
// TODO: think about using CBNZ here.
diff --git a/compiler/utils/arm64/jni_macro_assembler_arm64.cc b/compiler/utils/arm64/jni_macro_assembler_arm64.cc
index 561cbbd..e2d29fd 100644
--- a/compiler/utils/arm64/jni_macro_assembler_arm64.cc
+++ b/compiler/utils/arm64/jni_macro_assembler_arm64.cc
@@ -892,7 +892,8 @@
void Arm64JNIMacroAssembler::SuspendCheck(JNIMacroLabel* label) {
UseScratchRegisterScope temps(asm_.GetVIXLAssembler());
Register scratch = temps.AcquireW();
- ___ Ldrh(scratch, MEM_OP(reg_x(TR), Thread::ThreadFlagsOffset<kArm64PointerSize>().Int32Value()));
+ ___ Ldr(scratch, MEM_OP(reg_x(TR), Thread::ThreadFlagsOffset<kArm64PointerSize>().Int32Value()));
+ static_assert(static_cast<std::underlying_type_t<ThreadState>>(ThreadState::kRunnable) == 0u);
___ Cbnz(scratch, Arm64JNIMacroLabel::Cast(label)->AsArm64());
}
diff --git a/compiler/utils/x86/jni_macro_assembler_x86.cc b/compiler/utils/x86/jni_macro_assembler_x86.cc
index 7dff279..904cca4 100644
--- a/compiler/utils/x86/jni_macro_assembler_x86.cc
+++ b/compiler/utils/x86/jni_macro_assembler_x86.cc
@@ -590,7 +590,8 @@
}
void X86JNIMacroAssembler::SuspendCheck(JNIMacroLabel* label) {
- __ fs()->cmpw(Address::Absolute(Thread::ThreadFlagsOffset<kX86PointerSize>()), Immediate(0));
+ static_assert(static_cast<std::underlying_type_t<ThreadState>>(ThreadState::kRunnable) == 0u);
+ __ fs()->cmpl(Address::Absolute(Thread::ThreadFlagsOffset<kX86PointerSize>()), Immediate(0));
__ j(kNotEqual, X86JNIMacroLabel::Cast(label)->AsX86());
}
diff --git a/compiler/utils/x86_64/jni_macro_assembler_x86_64.cc b/compiler/utils/x86_64/jni_macro_assembler_x86_64.cc
index 2da1b47..2fb2797 100644
--- a/compiler/utils/x86_64/jni_macro_assembler_x86_64.cc
+++ b/compiler/utils/x86_64/jni_macro_assembler_x86_64.cc
@@ -672,7 +672,8 @@
}
void X86_64JNIMacroAssembler::SuspendCheck(JNIMacroLabel* label) {
- __ gs()->cmpw(Address::Absolute(Thread::ThreadFlagsOffset<kX86_64PointerSize>(), true),
+ static_assert(static_cast<std::underlying_type_t<ThreadState>>(ThreadState::kRunnable) == 0u);
+ __ gs()->cmpl(Address::Absolute(Thread::ThreadFlagsOffset<kX86_64PointerSize>(), true),
Immediate(0));
__ j(kNotEqual, X86_64JNIMacroLabel::Cast(label)->AsX86_64());
}
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index fe46552..217afa9 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -2680,7 +2680,7 @@
// Runtime::Create acquired the mutator_lock_ that is normally given away when we
// Runtime::Start, give it away now so that we don't starve GC.
- self->TransitionFromRunnableToSuspended(kNative);
+ self->TransitionFromRunnableToSuspended(ThreadState::kNative);
WatchDog::SetRuntime(runtime_.get());
diff --git a/dex2oat/driver/compiler_driver.cc b/dex2oat/driver/compiler_driver.cc
index 5429430..6939b0c 100644
--- a/dex2oat/driver/compiler_driver.cc
+++ b/dex2oat/driver/compiler_driver.cc
@@ -1426,7 +1426,7 @@
// Ensure we're suspended while we're blocked waiting for the other threads to finish (worker
// thread destructor's called below perform join).
- CHECK_NE(self->GetState(), kRunnable);
+ CHECK_NE(self->GetState(), ThreadState::kRunnable);
// Wait for all the worker threads to finish.
thread_pool_->Wait(self, true, false);
@@ -2537,7 +2537,7 @@
}
// Go to native so that we don't block GC during compilation.
- ScopedThreadSuspension sts(soa.Self(), kNative);
+ ScopedThreadSuspension sts(soa.Self(), ThreadState::kNative);
// Compile direct and virtual methods.
int64_t previous_method_idx = -1;
diff --git a/dex2oat/linker/image_write_read_test.cc b/dex2oat/linker/image_write_read_test.cc
index 2966f19..3e3dac1 100644
--- a/dex2oat/linker/image_write_read_test.cc
+++ b/dex2oat/linker/image_write_read_test.cc
@@ -80,7 +80,7 @@
runtime_.reset(Runtime::Current());
// Runtime::Create acquired the mutator_lock_ that is normally given away when we Runtime::Start,
// give it away now and then switch to a more managable ScopedObjectAccess.
- Thread::Current()->TransitionFromRunnableToSuspended(kNative);
+ Thread::Current()->TransitionFromRunnableToSuspended(ThreadState::kNative);
ScopedObjectAccess soa(Thread::Current());
ASSERT_TRUE(runtime_.get() != nullptr);
class_linker_ = runtime_->GetClassLinker();
diff --git a/dexoptanalyzer/dexoptanalyzer.cc b/dexoptanalyzer/dexoptanalyzer.cc
index 99e8286..0cc2cdb 100644
--- a/dexoptanalyzer/dexoptanalyzer.cc
+++ b/dexoptanalyzer/dexoptanalyzer.cc
@@ -284,7 +284,7 @@
}
// Runtime::Create acquired the mutator_lock_ that is normally given away when we
// Runtime::Start. Give it away now.
- Thread::Current()->TransitionFromRunnableToSuspended(kNative);
+ Thread::Current()->TransitionFromRunnableToSuspended(ThreadState::kNative);
return true;
}
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index 365d1e8..7e21f64 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -1831,7 +1831,7 @@
// Since FlushAllocStack() above resets the (active) allocation
// stack. Need to revoke the thread-local allocation stacks that
// point into it.
- ScopedThreadSuspension sts(self, kNative);
+ ScopedThreadSuspension sts(self, ThreadState::kNative);
ScopedSuspendAll ssa(__FUNCTION__);
heap->RevokeAllThreadLocalAllocationStacks(self);
}
diff --git a/openjdkjvm/OpenjdkJvm.cc b/openjdkjvm/OpenjdkJvm.cc
index 9b514af..a9fa0fc6c 100644
--- a/openjdkjvm/OpenjdkJvm.cc
+++ b/openjdkjvm/OpenjdkJvm.cc
@@ -367,7 +367,8 @@
jobject java_lock, jlong millis) {
art::ScopedFastNativeObjectAccess soa(env);
art::ObjPtr<art::mirror::Object> lock = soa.Decode<art::mirror::Object>(java_lock);
- art::Monitor::Wait(art::Thread::Current(), lock.Ptr(), millis, 0, true, art::kSleeping);
+ art::Monitor::Wait(
+ art::Thread::Current(), lock.Ptr(), millis, 0, true, art::ThreadState::kSleeping);
}
JNIEXPORT jobject JVM_CurrentThread(JNIEnv* env, jclass unused ATTRIBUTE_UNUSED) {
diff --git a/openjdkjvmti/deopt_manager.cc b/openjdkjvmti/deopt_manager.cc
index cf28a71..f30a21d 100644
--- a/openjdkjvmti/deopt_manager.cc
+++ b/openjdkjvmti/deopt_manager.cc
@@ -219,14 +219,14 @@
void DeoptManager::RemoveDeoptimizeAllMethods() {
art::Thread* self = art::Thread::Current();
- art::ScopedThreadSuspension sts(self, art::kSuspended);
+ art::ScopedThreadSuspension sts(self, art::ThreadState::kSuspended);
deoptimization_status_lock_.ExclusiveLock(self);
RemoveDeoptimizeAllMethodsLocked(self);
}
void DeoptManager::AddDeoptimizeAllMethods() {
art::Thread* self = art::Thread::Current();
- art::ScopedThreadSuspension sts(self, art::kSuspended);
+ art::ScopedThreadSuspension sts(self, art::ThreadState::kSuspended);
deoptimization_status_lock_.ExclusiveLock(self);
AddDeoptimizeAllMethodsLocked(self);
}
@@ -240,7 +240,7 @@
method = method->GetCanonicalMethod();
bool is_default = method->IsDefault();
- art::ScopedThreadSuspension sts(self, art::kSuspended);
+ art::ScopedThreadSuspension sts(self, art::ThreadState::kSuspended);
deoptimization_status_lock_.ExclusiveLock(self);
{
breakpoint_status_lock_.ExclusiveLock(self);
@@ -280,7 +280,7 @@
method = method->GetCanonicalMethod();
bool is_default = method->IsDefault();
- art::ScopedThreadSuspension sts(self, art::kSuspended);
+ art::ScopedThreadSuspension sts(self, art::ThreadState::kSuspended);
// Ideally we should do a ScopedSuspendAll right here to get the full mutator_lock_ that we might
// need but since that is very heavy we will instead just use a condition variable to make sure we
// don't race with ourselves.
@@ -452,7 +452,7 @@
void DeoptManager::RemoveDeoptimizationRequester() {
art::Thread* self = art::Thread::Current();
- art::ScopedThreadStateChange sts(self, art::kSuspended);
+ art::ScopedThreadStateChange sts(self, art::ThreadState::kSuspended);
deoptimization_status_lock_.ExclusiveLock(self);
DCHECK_GT(deopter_count_, 0u) << "Removing deoptimization requester without any being present";
deopter_count_--;
@@ -468,7 +468,7 @@
void DeoptManager::AddDeoptimizationRequester() {
art::Thread* self = art::Thread::Current();
- art::ScopedThreadStateChange stsc(self, art::kSuspended);
+ art::ScopedThreadStateChange stsc(self, art::ThreadState::kSuspended);
deoptimization_status_lock_.ExclusiveLock(self);
deopter_count_++;
if (deopter_count_ == 1) {
@@ -487,7 +487,7 @@
void DeoptManager::DeoptimizeThread(art::Thread* target) {
// We might or might not be running on the target thread (self) so get Thread::Current
// directly.
- art::ScopedThreadSuspension sts(art::Thread::Current(), art::kSuspended);
+ art::ScopedThreadSuspension sts(art::Thread::Current(), art::ThreadState::kSuspended);
art::gc::ScopedGCCriticalSection sgccs(art::Thread::Current(),
art::gc::GcCause::kGcCauseDebugger,
art::gc::CollectorType::kCollectorTypeDebugger);
diff --git a/openjdkjvmti/ti_class.cc b/openjdkjvmti/ti_class.cc
index 924a0d8..3345883 100644
--- a/openjdkjvmti/ti_class.cc
+++ b/openjdkjvmti/ti_class.cc
@@ -368,7 +368,7 @@
heap->IncrementDisableMovingGC(self);
}
{
- art::ScopedThreadSuspension sts(self, art::kWaitingForVisitObjects);
+ art::ScopedThreadSuspension sts(self, art::ThreadState::kWaitingForVisitObjects);
art::ScopedSuspendAll ssa("FixupTempClass");
art::mirror::Class* input = temp_klass.Get();
diff --git a/openjdkjvmti/ti_heap.cc b/openjdkjvmti/ti_heap.cc
index bd9d2dd..2a1d442 100644
--- a/openjdkjvmti/ti_heap.cc
+++ b/openjdkjvmti/ti_heap.cc
@@ -1403,7 +1403,7 @@
{
art::ScopedObjectAccess soa(self); // Now we know we have the shared lock.
art::jni::ScopedEnableSuspendAllJniIdQueries sjni; // make sure we can get JNI ids.
- art::ScopedThreadSuspension sts(self, art::kWaitingForVisitObjects);
+ art::ScopedThreadSuspension sts(self, art::ThreadState::kWaitingForVisitObjects);
art::ScopedSuspendAll ssa("FollowReferences");
art::ObjPtr<art::mirror::Class> class_filter = klass == nullptr
diff --git a/openjdkjvmti/ti_monitor.cc b/openjdkjvmti/ti_monitor.cc
index 2ca5057..f244cc1 100644
--- a/openjdkjvmti/ti_monitor.cc
+++ b/openjdkjvmti/ti_monitor.cc
@@ -376,39 +376,42 @@
switch (target_thread->GetState()) {
// These three we are actually currently waiting on a monitor and have sent the appropriate
// events (if anyone is listening).
- case art::kBlocked:
- case art::kTimedWaiting:
- case art::kWaiting: {
+ case art::ThreadState::kBlocked:
+ case art::ThreadState::kTimedWaiting:
+ case art::ThreadState::kWaiting: {
out_ = art::GcRoot<art::mirror::Object>(art::Monitor::GetContendedMonitor(target_thread));
return;
}
- case art::kTerminated:
- case art::kRunnable:
- case art::kSleeping:
- case art::kWaitingForLockInflation:
- case art::kWaitingForTaskProcessor:
- case art::kWaitingForGcToComplete:
- case art::kWaitingForCheckPointsToRun:
- case art::kWaitingPerformingGc:
- case art::kWaitingForDebuggerSend:
- case art::kWaitingForDebuggerToAttach:
- case art::kWaitingInMainDebuggerLoop:
- case art::kWaitingForDebuggerSuspension:
- case art::kWaitingForJniOnLoad:
- case art::kWaitingForSignalCatcherOutput:
- case art::kWaitingInMainSignalCatcherLoop:
- case art::kWaitingForDeoptimization:
- case art::kWaitingForMethodTracingStart:
- case art::kWaitingForVisitObjects:
- case art::kWaitingForGetObjectsAllocated:
- case art::kWaitingWeakGcRootRead:
- case art::kWaitingForGcThreadFlip:
- case art::kNativeForAbort:
- case art::kStarting:
- case art::kNative:
- case art::kSuspended: {
+ case art::ThreadState::kTerminated:
+ case art::ThreadState::kRunnable:
+ case art::ThreadState::kSleeping:
+ case art::ThreadState::kWaitingForLockInflation:
+ case art::ThreadState::kWaitingForTaskProcessor:
+ case art::ThreadState::kWaitingForGcToComplete:
+ case art::ThreadState::kWaitingForCheckPointsToRun:
+ case art::ThreadState::kWaitingPerformingGc:
+ case art::ThreadState::kWaitingForDebuggerSend:
+ case art::ThreadState::kWaitingForDebuggerToAttach:
+ case art::ThreadState::kWaitingInMainDebuggerLoop:
+ case art::ThreadState::kWaitingForDebuggerSuspension:
+ case art::ThreadState::kWaitingForJniOnLoad:
+ case art::ThreadState::kWaitingForSignalCatcherOutput:
+ case art::ThreadState::kWaitingInMainSignalCatcherLoop:
+ case art::ThreadState::kWaitingForDeoptimization:
+ case art::ThreadState::kWaitingForMethodTracingStart:
+ case art::ThreadState::kWaitingForVisitObjects:
+ case art::ThreadState::kWaitingForGetObjectsAllocated:
+ case art::ThreadState::kWaitingWeakGcRootRead:
+ case art::ThreadState::kWaitingForGcThreadFlip:
+ case art::ThreadState::kNativeForAbort:
+ case art::ThreadState::kStarting:
+ case art::ThreadState::kNative:
+ case art::ThreadState::kSuspended: {
// We aren't currently (explicitly) waiting for a monitor so just return null.
return;
+ case art::ThreadState::kObsoleteRunnable:
+ LOG(FATAL) << "UNREACHABLE"; // Obsolete value.
+ UNREACHABLE();
}
}
}
diff --git a/openjdkjvmti/ti_object.cc b/openjdkjvmti/ti_object.cc
index 344ae88..eb1140d 100644
--- a/openjdkjvmti/ti_object.cc
+++ b/openjdkjvmti/ti_object.cc
@@ -91,7 +91,7 @@
std::vector<jthread> notify_wait;
{
art::ScopedObjectAccess soa(self); // Now we know we have the shared lock.
- art::ScopedThreadSuspension sts(self, art::kNative);
+ art::ScopedThreadSuspension sts(self, art::ThreadState::kNative);
art::ScopedSuspendAll ssa("GetObjectMonitorUsage", /*long_suspend=*/false);
art::ObjPtr<art::mirror::Object> target(self->DecodeJObject(obj));
// This gets the list of threads trying to lock or wait on the monitor.
diff --git a/openjdkjvmti/ti_thread.cc b/openjdkjvmti/ti_thread.cc
index a9a6ee8..f31759e 100644
--- a/openjdkjvmti/ti_thread.cc
+++ b/openjdkjvmti/ti_thread.cc
@@ -174,7 +174,7 @@
static void WaitForSystemDaemonStart(art::Thread* self) REQUIRES_SHARED(art::Locks::mutator_lock_) {
{
- art::ScopedThreadStateChange strc(self, art::kNative);
+ art::ScopedThreadStateChange strc(self, art::ThreadState::kNative);
JNIEnv* jni = self->GetJniEnv();
jni->CallStaticVoidMethod(art::WellKnownClasses::java_lang_Daemons,
art::WellKnownClasses::java_lang_Daemons_waitForDaemonStart);
@@ -487,6 +487,7 @@
jvmti_state |= (JVMTI_THREAD_STATE_WAITING |
JVMTI_THREAD_STATE_WAITING_INDEFINITELY);
break;
+ case art::ThreadState::kObsoleteRunnable: // Obsolete value.
case art::ThreadState::kStarting:
case art::ThreadState::kTerminated:
// We only call this if we are alive so we shouldn't see either of these states.
@@ -539,6 +540,9 @@
case art::ThreadState::kWaitingForGcThreadFlip:
case art::ThreadState::kNativeForAbort:
return JVMTI_JAVA_LANG_THREAD_STATE_WAITING;
+
+ case art::ThreadState::kObsoleteRunnable:
+ break; // Obsolete value.
}
LOG(FATAL) << "Unreachable";
UNREACHABLE();
diff --git a/runtime/art_method.cc b/runtime/art_method.cc
index 9dda50c..5b1a476 100644
--- a/runtime/art_method.cc
+++ b/runtime/art_method.cc
@@ -319,7 +319,7 @@
if (kIsDebugBuild) {
self->AssertThreadSuspensionIsAllowable();
- CHECK_EQ(kRunnable, self->GetState());
+ CHECK_EQ(ThreadState::kRunnable, self->GetState());
CHECK_STREQ(GetInterfaceMethodIfProxy(kRuntimePointerSize)->GetShorty(), shorty);
}
diff --git a/runtime/cha.cc b/runtime/cha.cc
index 392b35c..03025dc 100644
--- a/runtime/cha.cc
+++ b/runtime/cha.cc
@@ -249,7 +249,7 @@
void WaitForThreadsToRunThroughCheckpoint(size_t threads_running_checkpoint) {
Thread* self = Thread::Current();
- ScopedThreadStateChange tsc(self, kWaitingForCheckPointsToRun);
+ ScopedThreadStateChange tsc(self, ThreadState::kWaitingForCheckPointsToRun);
barrier_.Increment(self, threads_running_checkpoint);
}
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 45562c4..5410bb0 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -2550,7 +2550,7 @@
}
{
// Handle wrapper deals with klass moving.
- ScopedThreadSuspension sts(self, kSuspended);
+ ScopedThreadSuspension sts(self, ThreadState::kSuspended);
if (index < kNumYieldIterations) {
sched_yield();
} else {
@@ -2935,7 +2935,7 @@
soa.Env(), soa.AddLocalReference<jobject>(class_loader.Get()));
ScopedLocalRef<jobject> result(soa.Env(), nullptr);
{
- ScopedThreadStateChange tsc(self, kNative);
+ ScopedThreadStateChange tsc(self, ThreadState::kNative);
ScopedLocalRef<jobject> class_name_object(
soa.Env(), soa.Env()->NewStringUTF(class_name_string.c_str()));
if (class_name_object.get() == nullptr) {
@@ -3228,7 +3228,7 @@
// We must be in the kRunnable state to prevent instrumentation from
// suspending all threads to update entrypoints while we are doing it
// for this class.
- DCHECK_EQ(self->GetState(), kRunnable);
+ DCHECK_EQ(self->GetState(), ThreadState::kRunnable);
Runtime::Current()->GetInstrumentation()->InstallStubsForClass(h_new_class.Get());
}
@@ -7439,7 +7439,7 @@
if (methods != old_methods && old_methods != nullptr) {
// Need to make sure the GC is not running since it could be scanning the methods we are
// about to overwrite.
- ScopedThreadStateChange tsc(self_, kSuspended);
+ ScopedThreadStateChange tsc(self_, ThreadState::kSuspended);
gc::ScopedGCCriticalSection gcs(self_,
gc::kGcCauseClassLinker,
gc::kCollectorTypeClassLinker);
diff --git a/runtime/common_runtime_test.cc b/runtime/common_runtime_test.cc
index 3f643e8..f949759 100644
--- a/runtime/common_runtime_test.cc
+++ b/runtime/common_runtime_test.cc
@@ -130,7 +130,7 @@
// Runtime::Create acquired the mutator_lock_ that is normally given away when we
// Runtime::Start, give it away now and then switch to a more managable ScopedObjectAccess.
- Thread::Current()->TransitionFromRunnableToSuspended(kNative);
+ Thread::Current()->TransitionFromRunnableToSuspended(ThreadState::kNative);
// Get the boot class path from the runtime so it can be used in tests.
boot_class_path_ = class_linker_->GetBootClassPath();
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index 2da3e41..af36531 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -268,7 +268,7 @@
VLOG(jdwp) << "Broadcasting DDM " << (connect ? "connect" : "disconnect") << "...";
Thread* self = Thread::Current();
- if (self->GetState() != kRunnable) {
+ if (self->GetState() != ThreadState::kRunnable) {
LOG(ERROR) << "DDM broadcast in thread state " << self->GetState();
/* try anyway? */
}
@@ -747,7 +747,7 @@
context.SetChunkOverhead(0);
// Need to acquire the mutator lock before the heap bitmap lock with exclusive access since
// RosAlloc's internal logic doesn't know to release and reacquire the heap bitmap lock.
- ScopedThreadSuspension sts(self, kSuspended);
+ ScopedThreadSuspension sts(self, ThreadState::kSuspended);
ScopedSuspendAll ssa(__FUNCTION__);
ReaderMutexLock mu(self, *Locks::heap_bitmap_lock_);
space->AsRosAllocSpace()->Walk(HeapChunkContext::HeapChunkJavaCallback, &context);
@@ -759,7 +759,7 @@
} else if (space->IsRegionSpace()) {
heap->IncrementDisableMovingGC(self);
{
- ScopedThreadSuspension sts(self, kSuspended);
+ ScopedThreadSuspension sts(self, ThreadState::kSuspended);
ScopedSuspendAll ssa(__FUNCTION__);
ReaderMutexLock mu(self, *Locks::heap_bitmap_lock_);
context.SetChunkOverhead(0);
diff --git a/runtime/entrypoints/quick/quick_jni_entrypoints.cc b/runtime/entrypoints/quick/quick_jni_entrypoints.cc
index 9507213..4fa37e5 100644
--- a/runtime/entrypoints/quick/quick_jni_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_jni_entrypoints.cc
@@ -66,7 +66,7 @@
}
// Transition out of runnable.
- self->TransitionFromRunnableToSuspended(kNative);
+ self->TransitionFromRunnableToSuspended(ThreadState::kNative);
}
// TODO: NO_THREAD_SAFETY_ANALYSIS due to different control paths depending on fast JNI.
diff --git a/runtime/fault_handler.cc b/runtime/fault_handler.cc
index 66fb3c7..f8bd213 100644
--- a/runtime/fault_handler.cc
+++ b/runtime/fault_handler.cc
@@ -309,7 +309,7 @@
}
ThreadState state = thread->GetState();
- if (state != kRunnable) {
+ if (state != ThreadState::kRunnable) {
VLOG(signals) << "not runnable";
return false;
}
diff --git a/runtime/gc/accounting/mod_union_table_test.cc b/runtime/gc/accounting/mod_union_table_test.cc
index 1cd719d..e42682a 100644
--- a/runtime/gc/accounting/mod_union_table_test.cc
+++ b/runtime/gc/accounting/mod_union_table_test.cc
@@ -188,7 +188,7 @@
"other space", 128 * KB, 4 * MB, 4 * MB, /*can_move_objects=*/ false));
ASSERT_TRUE(other_space.get() != nullptr);
{
- ScopedThreadSuspension sts(self, kSuspended);
+ ScopedThreadSuspension sts(self, ThreadState::kSuspended);
ScopedSuspendAll ssa("Add image space");
heap->AddSpace(other_space.get());
}
@@ -260,7 +260,7 @@
std::ostringstream oss2;
table->Dump(oss2);
// Remove the space we added so it doesn't persist to the next test.
- ScopedThreadSuspension sts(self, kSuspended);
+ ScopedThreadSuspension sts(self, ThreadState::kSuspended);
ScopedSuspendAll ssa("Add image space");
heap->RemoveSpace(other_space.get());
}
diff --git a/runtime/gc/collector/concurrent_copying.cc b/runtime/gc/collector/concurrent_copying.cc
index af02da8..3a60191 100644
--- a/runtime/gc/collector/concurrent_copying.cc
+++ b/runtime/gc/collector/concurrent_copying.cc
@@ -266,7 +266,9 @@
void Run(Thread* thread) override NO_THREAD_SAFETY_ANALYSIS {
// Note: self is not necessarily equal to thread since thread may be suspended.
Thread* self = Thread::Current();
- DCHECK(thread == self || thread->IsSuspended() || thread->GetState() == kWaitingPerformingGc)
+ DCHECK(thread == self ||
+ thread->IsSuspended() ||
+ thread->GetState() == ThreadState::kWaitingPerformingGc)
<< thread->GetState() << " thread " << thread << " self " << self;
// Switch to the read barrier entrypoints.
thread->SetReadBarrierEntrypoints();
@@ -307,7 +309,7 @@
if (barrier_count == 0) {
return;
}
- ScopedThreadStateChange tsc(self, kWaitingForCheckPointsToRun);
+ ScopedThreadStateChange tsc(self, ThreadState::kWaitingForCheckPointsToRun);
gc_barrier_->Increment(self, barrier_count);
}
@@ -462,7 +464,9 @@
void Run(Thread* thread) override REQUIRES_SHARED(Locks::mutator_lock_) {
// Note: self is not necessarily equal to thread since thread may be suspended.
Thread* self = Thread::Current();
- CHECK(thread == self || thread->IsSuspended() || thread->GetState() == kWaitingPerformingGc)
+ CHECK(thread == self ||
+ thread->IsSuspended() ||
+ thread->GetState() == ThreadState::kWaitingPerformingGc)
<< thread->GetState() << " thread " << thread << " self " << self;
thread->SetIsGcMarkingAndUpdateEntrypoints(true);
if (use_tlab_ && thread->HasTlab()) {
@@ -768,7 +772,7 @@
&thread_flip_visitor, &flip_callback, this, GetHeap()->GetGcPauseListener());
{
- ScopedThreadStateChange tsc(self, kWaitingForCheckPointsToRun);
+ ScopedThreadStateChange tsc(self, ThreadState::kWaitingForCheckPointsToRun);
gc_barrier_->Increment(self, barrier_count);
}
is_asserting_to_space_invariant_ = true;
@@ -980,7 +984,9 @@
void Run(Thread* thread) override NO_THREAD_SAFETY_ANALYSIS {
// Note: self is not necessarily equal to thread since thread may be suspended.
Thread* const self = Thread::Current();
- CHECK(thread == self || thread->IsSuspended() || thread->GetState() == kWaitingPerformingGc)
+ CHECK(thread == self ||
+ thread->IsSuspended() ||
+ thread->GetState() == ThreadState::kWaitingPerformingGc)
<< thread->GetState() << " thread " << thread << " self " << self;
// Revoke thread local mark stacks.
{
@@ -1047,7 +1053,7 @@
}
Locks::mutator_lock_->SharedUnlock(self);
{
- ScopedThreadStateChange tsc(self, kWaitingForCheckPointsToRun);
+ ScopedThreadStateChange tsc(self, ThreadState::kWaitingForCheckPointsToRun);
gc_barrier_->Increment(self, barrier_count);
}
Locks::mutator_lock_->SharedLock(self);
@@ -1718,7 +1724,9 @@
void Run(Thread* thread) override NO_THREAD_SAFETY_ANALYSIS {
// Note: self is not necessarily equal to thread since thread may be suspended.
Thread* self = Thread::Current();
- DCHECK(thread == self || thread->IsSuspended() || thread->GetState() == kWaitingPerformingGc)
+ DCHECK(thread == self ||
+ thread->IsSuspended() ||
+ thread->GetState() == ThreadState::kWaitingPerformingGc)
<< thread->GetState() << " thread " << thread << " self " << self;
// Disable the thread-local is_gc_marking flag.
// Note a thread that has just started right before this checkpoint may have already this flag
@@ -1771,7 +1779,7 @@
// Release locks then wait for all mutator threads to pass the barrier.
Locks::mutator_lock_->SharedUnlock(self);
{
- ScopedThreadStateChange tsc(self, kWaitingForCheckPointsToRun);
+ ScopedThreadStateChange tsc(self, ThreadState::kWaitingForCheckPointsToRun);
gc_barrier_->Increment(self, barrier_count);
}
Locks::mutator_lock_->SharedLock(self);
@@ -2075,7 +2083,7 @@
}
Locks::mutator_lock_->SharedUnlock(self);
{
- ScopedThreadStateChange tsc(self, kWaitingForCheckPointsToRun);
+ ScopedThreadStateChange tsc(self, ThreadState::kWaitingForCheckPointsToRun);
gc_barrier_->Increment(self, barrier_count);
}
Locks::mutator_lock_->SharedLock(self);
diff --git a/runtime/gc/collector/mark_sweep.cc b/runtime/gc/collector/mark_sweep.cc
index ebac36d..e3cd1ee 100644
--- a/runtime/gc/collector/mark_sweep.cc
+++ b/runtime/gc/collector/mark_sweep.cc
@@ -1163,7 +1163,9 @@
ScopedTrace trace("Marking thread roots");
// Note: self is not necessarily equal to thread since thread may be suspended.
Thread* const self = Thread::Current();
- CHECK(thread == self || thread->IsSuspended() || thread->GetState() == kWaitingPerformingGc)
+ CHECK(thread == self ||
+ thread->IsSuspended() ||
+ thread->GetState() == ThreadState::kWaitingPerformingGc)
<< thread->GetState() << " thread " << thread << " self " << self;
thread->VisitRoots(this, kVisitRootFlagAllRoots);
if (revoke_ros_alloc_thread_local_buffers_at_checkpoint_) {
@@ -1197,7 +1199,7 @@
Locks::heap_bitmap_lock_->ExclusiveUnlock(self);
Locks::mutator_lock_->SharedUnlock(self);
{
- ScopedThreadStateChange tsc(self, kWaitingForCheckPointsToRun);
+ ScopedThreadStateChange tsc(self, ThreadState::kWaitingForCheckPointsToRun);
gc_barrier_->Increment(self, barrier_count);
}
Locks::mutator_lock_->SharedLock(self);
diff --git a/runtime/gc/collector/semi_space.cc b/runtime/gc/collector/semi_space.cc
index d191031..0848f34 100644
--- a/runtime/gc/collector/semi_space.cc
+++ b/runtime/gc/collector/semi_space.cc
@@ -156,13 +156,13 @@
Locks::mutator_lock_->AssertExclusiveHeld(self_);
// Store the stack traces into the runtime fault string in case we Get a heap corruption
// related crash later.
- ThreadState old_state = self_->SetStateUnsafe(kRunnable);
+ ThreadState old_state = self_->SetStateUnsafe(ThreadState::kRunnable);
std::ostringstream oss;
Runtime* runtime = Runtime::Current();
runtime->GetThreadList()->DumpForSigQuit(oss);
runtime->GetThreadList()->DumpNativeStacks(oss);
runtime->SetFaultMessage(oss.str());
- CHECK_EQ(self_->SetStateUnsafe(old_state), kRunnable);
+ CHECK_EQ(self_->SetStateUnsafe(old_state), ThreadState::kRunnable);
}
// Revoke the thread local buffers since the GC may allocate into a RosAllocSpace and this helps
// to prevent fragmentation.
diff --git a/runtime/gc/heap-inl.h b/runtime/gc/heap-inl.h
index 50cfc6e..9017f30 100644
--- a/runtime/gc/heap-inl.h
+++ b/runtime/gc/heap-inl.h
@@ -57,7 +57,7 @@
CheckPreconditionsForAllocObject(klass, byte_count);
// Since allocation can cause a GC which will need to SuspendAll, make sure all allocations are
// done in the runnable state where suspension is expected.
- CHECK_EQ(self->GetState(), kRunnable);
+ CHECK_EQ(self->GetState(), ThreadState::kRunnable);
self->AssertThreadSuspensionIsAllowable();
self->AssertNoPendingException();
// Make sure to preserve klass.
diff --git a/runtime/gc/heap-visit-objects-inl.h b/runtime/gc/heap-visit-objects-inl.h
index b6ccb277..e20d981 100644
--- a/runtime/gc/heap-visit-objects-inl.h
+++ b/runtime/gc/heap-visit-objects-inl.h
@@ -50,7 +50,7 @@
// IncrementDisableMovingGC() and threads are suspended.
IncrementDisableMovingGC(self);
{
- ScopedThreadSuspension sts(self, kWaitingForVisitObjects);
+ ScopedThreadSuspension sts(self, ThreadState::kWaitingForVisitObjects);
ScopedSuspendAll ssa(__FUNCTION__);
VisitObjectsInternalRegionSpace(visitor);
VisitObjectsInternal(visitor);
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index cb2a648..100754a 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -942,7 +942,7 @@
void Heap::IncrementDisableMovingGC(Thread* self) {
// Need to do this holding the lock to prevent races where the GC is about to run / running when
// we attempt to disable it.
- ScopedThreadStateChange tsc(self, kWaitingForGcToComplete);
+ ScopedThreadStateChange tsc(self, ThreadState::kWaitingForGcToComplete);
MutexLock mu(self, *gc_complete_lock_);
++disable_moving_gc_count_;
if (IsMovingGc(collector_type_running_)) {
@@ -966,7 +966,7 @@
// counter. The global counter is incremented only once for a thread for the outermost enter.
return;
}
- ScopedThreadStateChange tsc(self, kWaitingForGcThreadFlip);
+ ScopedThreadStateChange tsc(self, ThreadState::kWaitingForGcThreadFlip);
MutexLock mu(self, *thread_flip_lock_);
thread_flip_cond_->CheckSafeToWait(self);
bool has_waited = false;
@@ -1013,7 +1013,7 @@
// Supposed to be called by GC. Set thread_flip_running_ to be true. If disable_thread_flip_count_
// > 0, block. Otherwise, go ahead.
CHECK(kUseReadBarrier);
- ScopedThreadStateChange tsc(self, kWaitingForGcThreadFlip);
+ ScopedThreadStateChange tsc(self, ThreadState::kWaitingForGcThreadFlip);
MutexLock mu(self, *thread_flip_lock_);
thread_flip_cond_->CheckSafeToWait(self);
bool has_waited = false;
@@ -1559,7 +1559,7 @@
// TODO: May also want to look for entirely empty pages maintained by SmallIrtAllocator.
Barrier barrier(0);
TrimIndirectReferenceTableClosure closure(&barrier);
- ScopedThreadStateChange tsc(self, kWaitingForCheckPointsToRun);
+ ScopedThreadStateChange tsc(self, ThreadState::kWaitingForCheckPointsToRun);
size_t barrier_count = Runtime::Current()->GetThreadList()->RunCheckpoint(&closure);
if (barrier_count != 0) {
barrier.Increment(self, barrier_count);
@@ -1569,7 +1569,7 @@
void Heap::StartGC(Thread* self, GcCause cause, CollectorType collector_type) {
// Need to do this before acquiring the locks since we don't want to get suspended while
// holding any locks.
- ScopedThreadStateChange tsc(self, kWaitingForGcToComplete);
+ ScopedThreadStateChange tsc(self, ThreadState::kWaitingForGcToComplete);
MutexLock mu(self, *gc_complete_lock_);
// Ensure there is only one GC at a time.
WaitForGcToCompleteLocked(cause, self);
@@ -2000,7 +2000,7 @@
size_t Heap::GetObjectsAllocated() const {
Thread* const self = Thread::Current();
- ScopedThreadStateChange tsc(self, kWaitingForGetObjectsAllocated);
+ ScopedThreadStateChange tsc(self, ThreadState::kWaitingForGetObjectsAllocated);
// Prevent GC running during GetObjectsAllocated since we may get a checkpoint request that tells
// us to suspend while we are doing SuspendAll. b/35232978
gc::ScopedGCCriticalSection gcs(Thread::Current(),
@@ -2085,10 +2085,10 @@
// Inc requested homogeneous space compaction.
count_requested_homogeneous_space_compaction_++;
// Store performed homogeneous space compaction at a new request arrival.
- ScopedThreadStateChange tsc(self, kWaitingPerformingGc);
+ ScopedThreadStateChange tsc(self, ThreadState::kWaitingPerformingGc);
Locks::mutator_lock_->AssertNotHeld(self);
{
- ScopedThreadStateChange tsc2(self, kWaitingForGcToComplete);
+ ScopedThreadStateChange tsc2(self, ThreadState::kWaitingForGcToComplete);
MutexLock mu(self, *gc_complete_lock_);
// Ensure there is only one GC at a time.
WaitForGcToCompleteLocked(kGcCauseHomogeneousSpaceCompact, self);
@@ -2641,7 +2641,7 @@
// here is full GC.
}
}
- ScopedThreadStateChange tsc(self, kWaitingPerformingGc);
+ ScopedThreadStateChange tsc(self, ThreadState::kWaitingPerformingGc);
Locks::mutator_lock_->AssertNotHeld(self);
if (self->IsHandlingStackOverflow()) {
// If we are throwing a stack overflow error we probably don't have enough remaining stack
@@ -2653,7 +2653,7 @@
bool compacting_gc;
{
gc_complete_lock_->AssertNotHeld(self);
- ScopedThreadStateChange tsc2(self, kWaitingForGcToComplete);
+ ScopedThreadStateChange tsc2(self, ThreadState::kWaitingForGcToComplete);
MutexLock mu(self, *gc_complete_lock_);
// Ensure there is only one GC at a time.
WaitForGcToCompleteLocked(gc_cause, self);
@@ -3437,7 +3437,7 @@
// reachable objects.
if (verify_pre_sweeping_heap_) {
TimingLogger::ScopedTiming t2("(Paused)PostSweepingVerifyHeapReferences", timings);
- CHECK_NE(self->GetState(), kRunnable);
+ CHECK_NE(self->GetState(), ThreadState::kRunnable);
{
WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
// Swapping bound bitmaps does nothing.
@@ -3501,7 +3501,7 @@
}
collector::GcType Heap::WaitForGcToComplete(GcCause cause, Thread* self) {
- ScopedThreadStateChange tsc(self, kWaitingForGcToComplete);
+ ScopedThreadStateChange tsc(self, ThreadState::kWaitingForGcToComplete);
MutexLock mu(self, *gc_complete_lock_);
return WaitForGcToCompleteLocked(cause, self);
}
diff --git a/runtime/gc/space/dlmalloc_space.cc b/runtime/gc/space/dlmalloc_space.cc
index 7564c89..4f7cc71 100644
--- a/runtime/gc/space/dlmalloc_space.cc
+++ b/runtime/gc/space/dlmalloc_space.cc
@@ -367,7 +367,7 @@
// lock, temporarily release the shared access to the mutator
// lock here by transitioning to the suspended state.
Locks::mutator_lock_->AssertSharedHeld(self);
- ScopedThreadSuspension sts(self, kSuspended);
+ ScopedThreadSuspension sts(self, ThreadState::kSuspended);
Walk(MSpaceChunkCallback, &max_contiguous_allocation);
if (failed_alloc_bytes > max_contiguous_allocation) {
os << "; failed due to fragmentation (largest possible contiguous allocation "
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index fefba27..fe387e2 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -1008,7 +1008,7 @@
if (use_parallel) {
ScopedTrace trace("Waiting for workers");
// Go to native since we don't want to suspend while holding the mutator lock.
- ScopedThreadSuspension sts(Thread::Current(), kNative);
+ ScopedThreadSuspension sts(Thread::Current(), ThreadState::kNative);
pool->Wait(self, true, false);
}
const uint64_t time = NanoTime() - start;
diff --git a/runtime/gc/space/rosalloc_space.cc b/runtime/gc/space/rosalloc_space.cc
index fc9cad0..80430bd 100644
--- a/runtime/gc/space/rosalloc_space.cc
+++ b/runtime/gc/space/rosalloc_space.cc
@@ -396,7 +396,7 @@
// The mutators are not suspended yet and we have a shared access
// to the mutator lock. Temporarily release the shared access by
// transitioning to the suspend state, and suspend the mutators.
- ScopedThreadSuspension sts(self, kSuspended);
+ ScopedThreadSuspension sts(self, ThreadState::kSuspended);
InspectAllRosAllocWithSuspendAll(callback, arg, do_null_callback_at_end);
} else {
// The mutators are not suspended yet. Suspend the mutators.
diff --git a/runtime/gc/space/space_create_test.cc b/runtime/gc/space/space_create_test.cc
index 4849d6c..25bc12e 100644
--- a/runtime/gc/space/space_create_test.cc
+++ b/runtime/gc/space/space_create_test.cc
@@ -168,7 +168,7 @@
gc::Heap* heap = Runtime::Current()->GetHeap();
space::Space* old_space = space;
{
- ScopedThreadSuspension sts(self, kSuspended);
+ ScopedThreadSuspension sts(self, ThreadState::kSuspended);
ScopedSuspendAll ssa("Add image space");
heap->RemoveSpace(old_space);
}
diff --git a/runtime/gc/space/space_test.h b/runtime/gc/space/space_test.h
index e40ee50..4b01e83 100644
--- a/runtime/gc/space/space_test.h
+++ b/runtime/gc/space/space_test.h
@@ -46,7 +46,7 @@
heap->RevokeAllThreadLocalBuffers();
}
{
- ScopedThreadStateChange sts(Thread::Current(), kSuspended);
+ ScopedThreadStateChange sts(Thread::Current(), ThreadState::kSuspended);
ScopedSuspendAll ssa("Add image space");
heap->AddSpace(space);
}
@@ -237,7 +237,7 @@
size_t free_increment = 96;
while (true) {
{
- ScopedThreadStateChange tsc(self, kNative);
+ ScopedThreadStateChange tsc(self, ThreadState::kNative);
// Give the space a haircut.
space->Trim();
}
diff --git a/runtime/gc/task_processor.cc b/runtime/gc/task_processor.cc
index 64e8322..494cf2b 100644
--- a/runtime/gc/task_processor.cc
+++ b/runtime/gc/task_processor.cc
@@ -39,14 +39,14 @@
}
void TaskProcessor::AddTask(Thread* self, HeapTask* task) {
- ScopedThreadStateChange tsc(self, kWaitingForTaskProcessor);
+ ScopedThreadStateChange tsc(self, ThreadState::kWaitingForTaskProcessor);
MutexLock mu(self, lock_);
tasks_.insert(task);
cond_.Signal(self);
}
HeapTask* TaskProcessor::GetTask(Thread* self) {
- ScopedThreadStateChange tsc(self, kWaitingForTaskProcessor);
+ ScopedThreadStateChange tsc(self, ThreadState::kWaitingForTaskProcessor);
MutexLock mu(self, lock_);
while (true) {
if (tasks_.empty()) {
diff --git a/runtime/instrumentation_test.cc b/runtime/instrumentation_test.cc
index d35847e..cfca51e 100644
--- a/runtime/instrumentation_test.cc
+++ b/runtime/instrumentation_test.cc
@@ -187,7 +187,7 @@
void CheckConfigureStubs(const char* key, Instrumentation::InstrumentationLevel level) {
ScopedObjectAccess soa(Thread::Current());
instrumentation::Instrumentation* instr = Runtime::Current()->GetInstrumentation();
- ScopedThreadSuspension sts(soa.Self(), kSuspended);
+ ScopedThreadSuspension sts(soa.Self(), ThreadState::kSuspended);
gc::ScopedGCCriticalSection gcs(soa.Self(),
gc::kGcCauseInstrumentation,
gc::kCollectorTypeInstrumentation);
@@ -216,7 +216,7 @@
instrumentation::Instrumentation* instr = Runtime::Current()->GetInstrumentation();
TestInstrumentationListener listener;
{
- ScopedThreadSuspension sts(soa.Self(), kSuspended);
+ ScopedThreadSuspension sts(soa.Self(), ThreadState::kSuspended);
ScopedSuspendAll ssa("Add instrumentation listener");
instr->AddListener(&listener, instrumentation_event);
}
@@ -240,7 +240,7 @@
listener.Reset();
{
- ScopedThreadSuspension sts(soa.Self(), kSuspended);
+ ScopedThreadSuspension sts(soa.Self(), ThreadState::kSuspended);
ScopedSuspendAll ssa("Remove instrumentation listener");
instr->RemoveListener(&listener, instrumentation_event);
}
@@ -263,7 +263,7 @@
REQUIRES_SHARED(Locks::mutator_lock_) {
Runtime* runtime = Runtime::Current();
instrumentation::Instrumentation* instrumentation = runtime->GetInstrumentation();
- ScopedThreadSuspension sts(self, kSuspended);
+ ScopedThreadSuspension sts(self, ThreadState::kSuspended);
gc::ScopedGCCriticalSection gcs(self,
gc::kGcCauseInstrumentation,
gc::kCollectorTypeInstrumentation);
@@ -279,7 +279,7 @@
REQUIRES_SHARED(Locks::mutator_lock_) {
Runtime* runtime = Runtime::Current();
instrumentation::Instrumentation* instrumentation = runtime->GetInstrumentation();
- ScopedThreadSuspension sts(self, kSuspended);
+ ScopedThreadSuspension sts(self, ThreadState::kSuspended);
gc::ScopedGCCriticalSection gcs(self,
gc::kGcCauseInstrumentation,
gc::kCollectorTypeInstrumentation);
@@ -294,7 +294,7 @@
REQUIRES_SHARED(Locks::mutator_lock_) {
Runtime* runtime = Runtime::Current();
instrumentation::Instrumentation* instrumentation = runtime->GetInstrumentation();
- ScopedThreadSuspension sts(self, kSuspended);
+ ScopedThreadSuspension sts(self, ThreadState::kSuspended);
gc::ScopedGCCriticalSection gcs(self,
gc::kGcCauseInstrumentation,
gc::kCollectorTypeInstrumentation);
@@ -309,7 +309,7 @@
REQUIRES_SHARED(Locks::mutator_lock_) {
Runtime* runtime = Runtime::Current();
instrumentation::Instrumentation* instrumentation = runtime->GetInstrumentation();
- ScopedThreadSuspension sts(self, kSuspended);
+ ScopedThreadSuspension sts(self, ThreadState::kSuspended);
gc::ScopedGCCriticalSection gcs(self,
gc::kGcCauseInstrumentation,
gc::kCollectorTypeInstrumentation);
@@ -324,7 +324,7 @@
REQUIRES_SHARED(Locks::mutator_lock_) {
Runtime* runtime = Runtime::Current();
instrumentation::Instrumentation* instrumentation = runtime->GetInstrumentation();
- ScopedThreadSuspension sts(self, kSuspended);
+ ScopedThreadSuspension sts(self, ThreadState::kSuspended);
gc::ScopedGCCriticalSection gcs(self,
gc::kGcCauseInstrumentation,
gc::kCollectorTypeInstrumentation);
@@ -336,7 +336,7 @@
REQUIRES_SHARED(Locks::mutator_lock_) {
Runtime* runtime = Runtime::Current();
instrumentation::Instrumentation* instrumentation = runtime->GetInstrumentation();
- ScopedThreadSuspension sts(self, kSuspended);
+ ScopedThreadSuspension sts(self, ThreadState::kSuspended);
gc::ScopedGCCriticalSection gcs(self,
gc::kGcCauseInstrumentation,
gc::kCollectorTypeInstrumentation);
diff --git a/runtime/intern_table.cc b/runtime/intern_table.cc
index 6af0455..25c45cb 100644
--- a/runtime/intern_table.cc
+++ b/runtime/intern_table.cc
@@ -187,7 +187,7 @@
void InternTable::WaitUntilAccessible(Thread* self) {
Locks::intern_table_lock_->ExclusiveUnlock(self);
{
- ScopedThreadSuspension sts(self, kWaitingWeakGcRootRead);
+ ScopedThreadSuspension sts(self, ThreadState::kWaitingWeakGcRootRead);
MutexLock mu(self, *Locks::intern_table_lock_);
while ((!kUseReadBarrier && weak_root_state_ == gc::kWeakRootStateNoReadsOrWrites) ||
(kUseReadBarrier && !self->GetWeakRefAccessEnabled())) {
diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc
index 299892e..0cce09e 100644
--- a/runtime/interpreter/interpreter.cc
+++ b/runtime/interpreter/interpreter.cc
@@ -61,7 +61,7 @@
soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
jobject jresult;
{
- ScopedThreadStateChange tsc(self, kNative);
+ ScopedThreadStateChange tsc(self, ThreadState::kNative);
jresult = fn(soa.Env(), klass.get());
}
result->SetL(soa.Decode<mirror::Object>(jresult));
@@ -70,28 +70,28 @@
fntype* const fn = reinterpret_cast<fntype*>(method->GetEntryPointFromJni());
ScopedLocalRef<jclass> klass(soa.Env(),
soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
- ScopedThreadStateChange tsc(self, kNative);
+ ScopedThreadStateChange tsc(self, ThreadState::kNative);
fn(soa.Env(), klass.get());
} else if (shorty == "Z") {
using fntype = jboolean(JNIEnv*, jclass);
fntype* const fn = reinterpret_cast<fntype*>(method->GetEntryPointFromJni());
ScopedLocalRef<jclass> klass(soa.Env(),
soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
- ScopedThreadStateChange tsc(self, kNative);
+ ScopedThreadStateChange tsc(self, ThreadState::kNative);
result->SetZ(fn(soa.Env(), klass.get()));
} else if (shorty == "BI") {
using fntype = jbyte(JNIEnv*, jclass, jint);
fntype* const fn = reinterpret_cast<fntype*>(method->GetEntryPointFromJni());
ScopedLocalRef<jclass> klass(soa.Env(),
soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
- ScopedThreadStateChange tsc(self, kNative);
+ ScopedThreadStateChange tsc(self, ThreadState::kNative);
result->SetB(fn(soa.Env(), klass.get(), args[0]));
} else if (shorty == "II") {
using fntype = jint(JNIEnv*, jclass, jint);
fntype* const fn = reinterpret_cast<fntype*>(method->GetEntryPointFromJni());
ScopedLocalRef<jclass> klass(soa.Env(),
soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
- ScopedThreadStateChange tsc(self, kNative);
+ ScopedThreadStateChange tsc(self, ThreadState::kNative);
result->SetI(fn(soa.Env(), klass.get(), args[0]));
} else if (shorty == "LL") {
using fntype = jobject(JNIEnv*, jclass, jobject);
@@ -102,7 +102,7 @@
soa.AddLocalReference<jobject>(ObjArg(args[0])));
jobject jresult;
{
- ScopedThreadStateChange tsc(self, kNative);
+ ScopedThreadStateChange tsc(self, ThreadState::kNative);
jresult = fn(soa.Env(), klass.get(), arg0.get());
}
result->SetL(soa.Decode<mirror::Object>(jresult));
@@ -111,7 +111,7 @@
fntype* const fn = reinterpret_cast<fntype*>(method->GetEntryPointFromJni());
ScopedLocalRef<jclass> klass(soa.Env(),
soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
- ScopedThreadStateChange tsc(self, kNative);
+ ScopedThreadStateChange tsc(self, ThreadState::kNative);
result->SetI(fn(soa.Env(), klass.get(), args[0], args[1]));
} else if (shorty == "ILI") {
using fntype = jint(JNIEnv*, jclass, jobject, jint);
@@ -121,7 +121,7 @@
soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
ScopedLocalRef<jobject> arg0(soa.Env(),
soa.AddLocalReference<jobject>(ObjArg(args[0])));
- ScopedThreadStateChange tsc(self, kNative);
+ ScopedThreadStateChange tsc(self, ThreadState::kNative);
result->SetI(fn(soa.Env(), klass.get(), arg0.get(), args[1]));
} else if (shorty == "SIZ") {
using fntype = jshort(JNIEnv*, jclass, jint, jboolean);
@@ -129,14 +129,14 @@
reinterpret_cast<fntype*>(const_cast<void*>(method->GetEntryPointFromJni()));
ScopedLocalRef<jclass> klass(soa.Env(),
soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
- ScopedThreadStateChange tsc(self, kNative);
+ ScopedThreadStateChange tsc(self, ThreadState::kNative);
result->SetS(fn(soa.Env(), klass.get(), args[0], args[1]));
} else if (shorty == "VIZ") {
using fntype = void(JNIEnv*, jclass, jint, jboolean);
fntype* const fn = reinterpret_cast<fntype*>(method->GetEntryPointFromJni());
ScopedLocalRef<jclass> klass(soa.Env(),
soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
- ScopedThreadStateChange tsc(self, kNative);
+ ScopedThreadStateChange tsc(self, ThreadState::kNative);
fn(soa.Env(), klass.get(), args[0], args[1]);
} else if (shorty == "ZLL") {
using fntype = jboolean(JNIEnv*, jclass, jobject, jobject);
@@ -147,7 +147,7 @@
soa.AddLocalReference<jobject>(ObjArg(args[0])));
ScopedLocalRef<jobject> arg1(soa.Env(),
soa.AddLocalReference<jobject>(ObjArg(args[1])));
- ScopedThreadStateChange tsc(self, kNative);
+ ScopedThreadStateChange tsc(self, ThreadState::kNative);
result->SetZ(fn(soa.Env(), klass.get(), arg0.get(), arg1.get()));
} else if (shorty == "ZILL") {
using fntype = jboolean(JNIEnv*, jclass, jint, jobject, jobject);
@@ -158,7 +158,7 @@
soa.AddLocalReference<jobject>(ObjArg(args[1])));
ScopedLocalRef<jobject> arg2(soa.Env(),
soa.AddLocalReference<jobject>(ObjArg(args[2])));
- ScopedThreadStateChange tsc(self, kNative);
+ ScopedThreadStateChange tsc(self, ThreadState::kNative);
result->SetZ(fn(soa.Env(), klass.get(), args[0], arg1.get(), arg2.get()));
} else if (shorty == "VILII") {
using fntype = void(JNIEnv*, jclass, jint, jobject, jint, jint);
@@ -167,7 +167,7 @@
soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
ScopedLocalRef<jobject> arg1(soa.Env(),
soa.AddLocalReference<jobject>(ObjArg(args[1])));
- ScopedThreadStateChange tsc(self, kNative);
+ ScopedThreadStateChange tsc(self, ThreadState::kNative);
fn(soa.Env(), klass.get(), args[0], arg1.get(), args[2], args[3]);
} else if (shorty == "VLILII") {
using fntype = void(JNIEnv*, jclass, jobject, jint, jobject, jint, jint);
@@ -178,7 +178,7 @@
soa.AddLocalReference<jobject>(ObjArg(args[0])));
ScopedLocalRef<jobject> arg2(soa.Env(),
soa.AddLocalReference<jobject>(ObjArg(args[2])));
- ScopedThreadStateChange tsc(self, kNative);
+ ScopedThreadStateChange tsc(self, ThreadState::kNative);
fn(soa.Env(), klass.get(), arg0.get(), args[1], arg2.get(), args[3], args[4]);
} else {
LOG(FATAL) << "Do something with static native method: " << method->PrettyMethod()
@@ -192,7 +192,7 @@
soa.AddLocalReference<jobject>(receiver));
jobject jresult;
{
- ScopedThreadStateChange tsc(self, kNative);
+ ScopedThreadStateChange tsc(self, ThreadState::kNative);
jresult = fn(soa.Env(), rcvr.get());
}
result->SetL(soa.Decode<mirror::Object>(jresult));
@@ -201,7 +201,7 @@
fntype* const fn = reinterpret_cast<fntype*>(method->GetEntryPointFromJni());
ScopedLocalRef<jobject> rcvr(soa.Env(),
soa.AddLocalReference<jobject>(receiver));
- ScopedThreadStateChange tsc(self, kNative);
+ ScopedThreadStateChange tsc(self, ThreadState::kNative);
fn(soa.Env(), rcvr.get());
} else if (shorty == "LL") {
using fntype = jobject(JNIEnv*, jobject, jobject);
@@ -212,17 +212,17 @@
soa.AddLocalReference<jobject>(ObjArg(args[0])));
jobject jresult;
{
- ScopedThreadStateChange tsc(self, kNative);
+ ScopedThreadStateChange tsc(self, ThreadState::kNative);
jresult = fn(soa.Env(), rcvr.get(), arg0.get());
}
result->SetL(soa.Decode<mirror::Object>(jresult));
- ScopedThreadStateChange tsc(self, kNative);
+ ScopedThreadStateChange tsc(self, ThreadState::kNative);
} else if (shorty == "III") {
using fntype = jint(JNIEnv*, jobject, jint, jint);
fntype* const fn = reinterpret_cast<fntype*>(method->GetEntryPointFromJni());
ScopedLocalRef<jobject> rcvr(soa.Env(),
soa.AddLocalReference<jobject>(receiver));
- ScopedThreadStateChange tsc(self, kNative);
+ ScopedThreadStateChange tsc(self, ThreadState::kNative);
result->SetI(fn(soa.Env(), rcvr.get(), args[0], args[1]));
} else {
LOG(FATAL) << "Do something with native method: " << method->PrettyMethod()
diff --git a/runtime/interpreter/mterp/arm64ng/main.S b/runtime/interpreter/mterp/arm64ng/main.S
index ffd1b13..53792c0 100644
--- a/runtime/interpreter/mterp/arm64ng/main.S
+++ b/runtime/interpreter/mterp/arm64ng/main.S
@@ -309,8 +309,8 @@
add x2, x2, #-1
strh w2, [x0, #ART_METHOD_HOTNESS_COUNT_OFFSET]
// Otherwise, do a suspend check.
- ldr x0, [xSELF, #THREAD_FLAGS_OFFSET]
- ands x0, x0, #THREAD_SUSPEND_OR_CHECKPOINT_REQUEST
+ ldr w0, [xSELF, #THREAD_FLAGS_OFFSET]
+ tst w0, #THREAD_SUSPEND_OR_CHECKPOINT_REQUEST
b.eq 1b
EXPORT_PC
bl art_quick_test_suspend
@@ -435,8 +435,8 @@
cbz w2, 2f
add x2, x2, #-1
strh w2, [x0, #ART_METHOD_HOTNESS_COUNT_OFFSET]
- ldr x0, [xSELF, #THREAD_FLAGS_OFFSET]
- tst x0, #THREAD_SUSPEND_OR_CHECKPOINT_REQUEST
+ ldr w0, [xSELF, #THREAD_FLAGS_OFFSET]
+ tst w0, #THREAD_SUSPEND_OR_CHECKPOINT_REQUEST
b.ne 3f
1:
FETCH_INST
diff --git a/runtime/interpreter/mterp/armng/main.S b/runtime/interpreter/mterp/armng/main.S
index e21c64f..e26d922 100644
--- a/runtime/interpreter/mterp/armng/main.S
+++ b/runtime/interpreter/mterp/armng/main.S
@@ -318,7 +318,7 @@
strh r2, [r0, #ART_METHOD_HOTNESS_COUNT_OFFSET]
// Otherwise, do a suspend check.
ldr r0, [rSELF, #THREAD_FLAGS_OFFSET]
- ands r0, r0, #THREAD_SUSPEND_OR_CHECKPOINT_REQUEST
+ tst r0, #THREAD_SUSPEND_OR_CHECKPOINT_REQUEST
beq 1b
EXPORT_PC
bl art_quick_test_suspend
diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc
index 3fcb10a..5cf08f9 100644
--- a/runtime/jit/jit_code_cache.cc
+++ b/runtime/jit/jit_code_cache.cc
@@ -568,7 +568,7 @@
if (IsWeakAccessEnabled(self)) {
return;
}
- ScopedThreadSuspension sts(self, kWaitingWeakGcRootRead);
+ ScopedThreadSuspension sts(self, ThreadState::kWaitingWeakGcRootRead);
MutexLock mu(self, *Locks::jit_lock_);
while (!IsWeakAccessEnabled(self)) {
inline_cache_cond_.Wait(self);
@@ -625,7 +625,7 @@
while (collection_in_progress_) {
Locks::jit_lock_->Unlock(self);
{
- ScopedThreadSuspension sts(self, kSuspended);
+ ScopedThreadSuspension sts(self, ThreadState::kSuspended);
MutexLock mu(self, *Locks::jit_lock_);
WaitForPotentialCollectionToComplete(self);
}
@@ -943,7 +943,7 @@
while (true) {
bool at_max_capacity = false;
{
- ScopedThreadSuspension sts(self, kSuspended);
+ ScopedThreadSuspension sts(self, ThreadState::kSuspended);
MutexLock mu(self, *Locks::jit_lock_);
WaitForPotentialCollectionToComplete(self);
ScopedCodeCacheWrite ccw(*region);
@@ -1069,7 +1069,7 @@
threads_running_checkpoint = Runtime::Current()->GetThreadList()->RunCheckpoint(&closure);
// Now that we have run our checkpoint, move to a suspended state and wait
// for other threads to run the checkpoint.
- ScopedThreadSuspension sts(self, kSuspended);
+ ScopedThreadSuspension sts(self, ThreadState::kSuspended);
if (threads_running_checkpoint != 0) {
barrier.Increment(self, threads_running_checkpoint);
}
@@ -1100,7 +1100,7 @@
ScopedTrace trace(__FUNCTION__);
// Wait for an existing collection, or let everyone know we are starting one.
{
- ScopedThreadSuspension sts(self, kSuspended);
+ ScopedThreadSuspension sts(self, ThreadState::kSuspended);
MutexLock mu(self, *Locks::jit_lock_);
if (!garbage_collect_code_) {
private_region_.IncreaseCodeCacheCapacity();
diff --git a/runtime/jit/profile_saver.cc b/runtime/jit/profile_saver.cc
index a5cb81b..cea654f 100644
--- a/runtime/jit/profile_saver.cc
+++ b/runtime/jit/profile_saver.cc
@@ -788,7 +788,7 @@
// Release the mutator lock. We shall need to re-acquire the lock for a moment to
// destroy the `VariableSizedHandleScope` inside the `helper` which shall be
// conveniently handled by destroying `sts`, then `helper` and then `soa`.
- ScopedThreadSuspension sts(self, kNative);
+ ScopedThreadSuspension sts(self, ThreadState::kNative);
// Get back to the previous thread priority. We shall not increase the priority
// for the short time we need to re-acquire mutator lock for `helper` destructor.
sdp.reset();
diff --git a/runtime/jni/java_vm_ext.cc b/runtime/jni/java_vm_ext.cc
index 053afc9..dd45c32 100644
--- a/runtime/jni/java_vm_ext.cc
+++ b/runtime/jni/java_vm_ext.cc
@@ -285,7 +285,7 @@
const char* shorty = m->GetShorty();
{
// Go to suspended since dlsym may block for a long time if other threads are using dlopen.
- ScopedThreadSuspension sts(self, kNative);
+ ScopedThreadSuspension sts(self, ThreadState::kNative);
void* native_code = FindNativeMethodInternal(self,
declaring_class_loader_allocator,
shorty,
@@ -353,7 +353,7 @@
}
}
}
- ScopedThreadSuspension sts(self, kNative);
+ ScopedThreadSuspension sts(self, ThreadState::kNative);
// Do this without holding the jni libraries lock to prevent possible deadlocks.
UnloadLibraries(self->GetJniEnv()->GetVm(), unload_libraries);
for (auto library : unload_libraries) {
@@ -575,7 +575,7 @@
check_jni_abort_hook_(check_jni_abort_hook_data_, os.str());
} else {
// Ensure that we get a native stack trace for this thread.
- ScopedThreadSuspension sts(self, kNative);
+ ScopedThreadSuspension sts(self, ThreadState::kNative);
LOG(FATAL) << os.str();
UNREACHABLE();
}
diff --git a/runtime/mirror/object-inl.h b/runtime/mirror/object-inl.h
index 2476b13..c679fde 100644
--- a/runtime/mirror/object-inl.h
+++ b/runtime/mirror/object-inl.h
@@ -100,7 +100,7 @@
}
inline void Object::Wait(Thread* self, int64_t ms, int32_t ns) {
- Monitor::Wait(self, this, ms, ns, true, kTimedWaiting);
+ Monitor::Wait(self, this, ms, ns, true, ThreadState::kTimedWaiting);
}
inline uint32_t Object::GetMarkBit() {
diff --git a/runtime/monitor.cc b/runtime/monitor.cc
index f2189e1..0cad79b 100644
--- a/runtime/monitor.cc
+++ b/runtime/monitor.cc
@@ -515,7 +515,8 @@
}
self->SetMonitorEnterObject(GetObject().Ptr());
{
- ScopedThreadSuspension tsc(self, kBlocked); // Change to blocked and give up mutator_lock_.
+ // Change to blocked and give up mutator_lock_.
+ ScopedThreadSuspension tsc(self, ThreadState::kBlocked);
// Acquire monitor_lock_ without mutator_lock_, expecting to block this time.
// We already tried spinning above. The shutdown procedure currently assumes we stop
@@ -827,7 +828,9 @@
void Monitor::Wait(Thread* self, int64_t ms, int32_t ns,
bool interruptShouldThrow, ThreadState why) {
DCHECK(self != nullptr);
- DCHECK(why == kTimedWaiting || why == kWaiting || why == kSleeping);
+ DCHECK(why == ThreadState::kTimedWaiting ||
+ why == ThreadState::kWaiting ||
+ why == ThreadState::kSleeping);
// Make sure that we hold the lock.
if (owner_.load(std::memory_order_relaxed) != self) {
@@ -837,8 +840,8 @@
// We need to turn a zero-length timed wait into a regular wait because
// Object.wait(0, 0) is defined as Object.wait(0), which is defined as Object.wait().
- if (why == kTimedWaiting && (ms == 0 && ns == 0)) {
- why = kWaiting;
+ if (why == ThreadState::kTimedWaiting && (ms == 0 && ns == 0)) {
+ why = ThreadState::kWaiting;
}
// Enforce the timeout range.
@@ -900,10 +903,10 @@
was_interrupted = true;
} else {
// Wait for a notification or a timeout to occur.
- if (why == kWaiting) {
+ if (why == ThreadState::kWaiting) {
self->GetWaitConditionVariable()->Wait(self);
} else {
- DCHECK(why == kTimedWaiting || why == kSleeping) << why;
+ DCHECK(why == ThreadState::kTimedWaiting || why == ThreadState::kSleeping) << why;
timed_out = self->GetWaitConditionVariable()->TimedWait(self, ms, ns);
}
was_interrupted = self->IsInterrupted();
@@ -1065,7 +1068,7 @@
bool timed_out;
Thread* owner;
{
- ScopedThreadSuspension sts(self, kWaitingForLockInflation);
+ ScopedThreadSuspension sts(self, ThreadState::kWaitingForLockInflation);
owner = thread_list->SuspendThreadByThreadId(owner_thread_id,
SuspendReason::kInternal,
&timed_out);
@@ -1388,9 +1391,9 @@
ThreadState state = thread->GetState();
switch (state) {
- case kWaiting:
- case kTimedWaiting:
- case kSleeping:
+ case ThreadState::kWaiting:
+ case ThreadState::kTimedWaiting:
+ case ThreadState::kSleeping:
{
Thread* self = Thread::Current();
MutexLock mu(self, *thread->GetWaitMutex());
@@ -1401,8 +1404,8 @@
}
break;
- case kBlocked:
- case kWaitingForLockInflation:
+ case ThreadState::kBlocked:
+ case ThreadState::kWaitingForLockInflation:
{
ObjPtr<mirror::Object> lock_object = thread->GetMonitorEnterObject();
if (lock_object != nullptr) {
diff --git a/runtime/monitor_objects_stack_visitor.cc b/runtime/monitor_objects_stack_visitor.cc
index 61f4159..2e75e37 100644
--- a/runtime/monitor_objects_stack_visitor.cc
+++ b/runtime/monitor_objects_stack_visitor.cc
@@ -47,16 +47,16 @@
&monitor_object,
&lock_owner_tid);
switch (state) {
- case kWaiting:
- case kTimedWaiting:
+ case ThreadState::kWaiting:
+ case ThreadState::kTimedWaiting:
VisitWaitingObject(monitor_object, state);
break;
- case kSleeping:
+ case ThreadState::kSleeping:
VisitSleepingObject(monitor_object);
break;
- case kBlocked:
- case kWaitingForLockInflation:
+ case ThreadState::kBlocked:
+ case ThreadState::kWaitingForLockInflation:
VisitBlockedOnObject(monitor_object, state, lock_owner_tid);
break;
diff --git a/runtime/monitor_test.cc b/runtime/monitor_test.cc
index 8ddd50f..66008f3 100644
--- a/runtime/monitor_test.cc
+++ b/runtime/monitor_test.cc
@@ -265,7 +265,7 @@
}
// Need to drop the mutator lock to allow barriers.
- ScopedThreadSuspension sts(soa.Self(), kNative);
+ ScopedThreadSuspension sts(soa.Self(), ThreadState::kNative);
ThreadPool thread_pool(pool_name, 3);
thread_pool.AddTask(self, new CreateTask(test, create_sleep, c_millis, c_expected));
if (interrupt) {
@@ -361,7 +361,7 @@
// Test failure case.
thread_pool.AddTask(self, new TryLockTask(obj1));
thread_pool.StartWorkers(self);
- ScopedThreadSuspension sts(self, kSuspended);
+ ScopedThreadSuspension sts(self, ThreadState::kSuspended);
thread_pool.Wait(Thread::Current(), /*do_work=*/false, /*may_hold_locks=*/false);
}
// Test that the trylock actually locks the object.
diff --git a/runtime/native/dalvik_system_VMStack.cc b/runtime/native/dalvik_system_VMStack.cc
index e88516e..71078c9 100644
--- a/runtime/native/dalvik_system_VMStack.cc
+++ b/runtime/native/dalvik_system_VMStack.cc
@@ -55,7 +55,7 @@
return nullptr;
}
// Suspend thread to build stack trace.
- ScopedThreadSuspension sts(soa.Self(), kNative);
+ ScopedThreadSuspension sts(soa.Self(), ThreadState::kNative);
ThreadList* thread_list = Runtime::Current()->GetThreadList();
bool timed_out;
Thread* thread = thread_list->SuspendThreadByPeer(peer,
diff --git a/runtime/native/java_lang_Thread.cc b/runtime/native/java_lang_Thread.cc
index c3b4fe0..570c554 100644
--- a/runtime/native/java_lang_Thread.cc
+++ b/runtime/native/java_lang_Thread.cc
@@ -71,41 +71,43 @@
const jint kJavaTerminated = 5;
ScopedObjectAccess soa(env);
- ThreadState internal_thread_state = (has_been_started ? kTerminated : kStarting);
+ ThreadState internal_thread_state =
+ (has_been_started ? ThreadState::kTerminated : ThreadState::kStarting);
MutexLock mu(soa.Self(), *Locks::thread_list_lock_);
Thread* thread = Thread::FromManagedThread(soa, java_thread);
if (thread != nullptr) {
internal_thread_state = thread->GetState();
}
switch (internal_thread_state) {
- case kTerminated: return kJavaTerminated;
- case kRunnable: return kJavaRunnable;
- case kTimedWaiting: return kJavaTimedWaiting;
- case kSleeping: return kJavaTimedWaiting;
- case kBlocked: return kJavaBlocked;
- case kWaiting: return kJavaWaiting;
- case kStarting: return kJavaNew;
- case kNative: return kJavaRunnable;
- case kWaitingForTaskProcessor: return kJavaWaiting;
- case kWaitingForLockInflation: return kJavaWaiting;
- case kWaitingForGcToComplete: return kJavaWaiting;
- case kWaitingPerformingGc: return kJavaWaiting;
- case kWaitingForCheckPointsToRun: return kJavaWaiting;
- case kWaitingForDebuggerSend: return kJavaWaiting;
- case kWaitingForDebuggerToAttach: return kJavaWaiting;
- case kWaitingInMainDebuggerLoop: return kJavaWaiting;
- case kWaitingForDebuggerSuspension: return kJavaWaiting;
- case kWaitingForDeoptimization: return kJavaWaiting;
- case kWaitingForGetObjectsAllocated: return kJavaWaiting;
- case kWaitingForJniOnLoad: return kJavaWaiting;
- case kWaitingForSignalCatcherOutput: return kJavaWaiting;
- case kWaitingInMainSignalCatcherLoop: return kJavaWaiting;
- case kWaitingForMethodTracingStart: return kJavaWaiting;
- case kWaitingForVisitObjects: return kJavaWaiting;
- case kWaitingWeakGcRootRead: return kJavaRunnable;
- case kWaitingForGcThreadFlip: return kJavaWaiting;
- case kNativeForAbort: return kJavaWaiting;
- case kSuspended: return kJavaRunnable;
+ case ThreadState::kTerminated: return kJavaTerminated;
+ case ThreadState::kRunnable: return kJavaRunnable;
+ case ThreadState::kObsoleteRunnable: break; // Obsolete value.
+ case ThreadState::kTimedWaiting: return kJavaTimedWaiting;
+ case ThreadState::kSleeping: return kJavaTimedWaiting;
+ case ThreadState::kBlocked: return kJavaBlocked;
+ case ThreadState::kWaiting: return kJavaWaiting;
+ case ThreadState::kStarting: return kJavaNew;
+ case ThreadState::kNative: return kJavaRunnable;
+ case ThreadState::kWaitingForTaskProcessor: return kJavaWaiting;
+ case ThreadState::kWaitingForLockInflation: return kJavaWaiting;
+ case ThreadState::kWaitingForGcToComplete: return kJavaWaiting;
+ case ThreadState::kWaitingPerformingGc: return kJavaWaiting;
+ case ThreadState::kWaitingForCheckPointsToRun: return kJavaWaiting;
+ case ThreadState::kWaitingForDebuggerSend: return kJavaWaiting;
+ case ThreadState::kWaitingForDebuggerToAttach: return kJavaWaiting;
+ case ThreadState::kWaitingInMainDebuggerLoop: return kJavaWaiting;
+ case ThreadState::kWaitingForDebuggerSuspension: return kJavaWaiting;
+ case ThreadState::kWaitingForDeoptimization: return kJavaWaiting;
+ case ThreadState::kWaitingForGetObjectsAllocated: return kJavaWaiting;
+ case ThreadState::kWaitingForJniOnLoad: return kJavaWaiting;
+ case ThreadState::kWaitingForSignalCatcherOutput: return kJavaWaiting;
+ case ThreadState::kWaitingInMainSignalCatcherLoop: return kJavaWaiting;
+ case ThreadState::kWaitingForMethodTracingStart: return kJavaWaiting;
+ case ThreadState::kWaitingForVisitObjects: return kJavaWaiting;
+ case ThreadState::kWaitingWeakGcRootRead: return kJavaRunnable;
+ case ThreadState::kWaitingForGcThreadFlip: return kJavaWaiting;
+ case ThreadState::kNativeForAbort: return kJavaWaiting;
+ case ThreadState::kSuspended: return kJavaRunnable;
// Don't add a 'default' here so the compiler can spot incompatible enum changes.
}
LOG(ERROR) << "Unexpected thread state: " << internal_thread_state;
@@ -180,7 +182,7 @@
static void Thread_sleep(JNIEnv* env, jclass, jobject java_lock, jlong ms, jint ns) {
ScopedFastNativeObjectAccess soa(env);
ObjPtr<mirror::Object> lock = soa.Decode<mirror::Object>(java_lock);
- Monitor::Wait(Thread::Current(), lock.Ptr(), ms, ns, true, kSleeping);
+ Monitor::Wait(Thread::Current(), lock.Ptr(), ms, ns, true, ThreadState::kSleeping);
}
/*
diff --git a/runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc b/runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc
index f74e120..081ec20 100644
--- a/runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc
+++ b/runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc
@@ -109,38 +109,40 @@
TS_WAIT = 4, // (in Object.wait())
};
switch (state) {
- case kBlocked:
+ case ThreadState::kBlocked:
return TS_MONITOR;
- case kNative:
- case kRunnable:
- case kSuspended:
+ case ThreadState::kNative:
+ case ThreadState::kRunnable:
+ case ThreadState::kSuspended:
return TS_RUNNING;
- case kSleeping:
+ case ThreadState::kObsoleteRunnable:
+ break; // Obsolete value.
+ case ThreadState::kSleeping:
return TS_SLEEPING;
- case kStarting:
- case kTerminated:
+ case ThreadState::kStarting:
+ case ThreadState::kTerminated:
return TS_ZOMBIE;
- case kTimedWaiting:
- case kWaitingForTaskProcessor:
- case kWaitingForLockInflation:
- case kWaitingForCheckPointsToRun:
- case kWaitingForDebuggerSend:
- case kWaitingForDebuggerSuspension:
- case kWaitingForDebuggerToAttach:
- case kWaitingForDeoptimization:
- case kWaitingForGcToComplete:
- case kWaitingForGetObjectsAllocated:
- case kWaitingForJniOnLoad:
- case kWaitingForMethodTracingStart:
- case kWaitingForSignalCatcherOutput:
- case kWaitingForVisitObjects:
- case kWaitingInMainDebuggerLoop:
- case kWaitingInMainSignalCatcherLoop:
- case kWaitingPerformingGc:
- case kWaitingWeakGcRootRead:
- case kWaitingForGcThreadFlip:
- case kNativeForAbort:
- case kWaiting:
+ case ThreadState::kTimedWaiting:
+ case ThreadState::kWaitingForTaskProcessor:
+ case ThreadState::kWaitingForLockInflation:
+ case ThreadState::kWaitingForCheckPointsToRun:
+ case ThreadState::kWaitingForDebuggerSend:
+ case ThreadState::kWaitingForDebuggerSuspension:
+ case ThreadState::kWaitingForDebuggerToAttach:
+ case ThreadState::kWaitingForDeoptimization:
+ case ThreadState::kWaitingForGcToComplete:
+ case ThreadState::kWaitingForGetObjectsAllocated:
+ case ThreadState::kWaitingForJniOnLoad:
+ case ThreadState::kWaitingForMethodTracingStart:
+ case ThreadState::kWaitingForSignalCatcherOutput:
+ case ThreadState::kWaitingForVisitObjects:
+ case ThreadState::kWaitingInMainDebuggerLoop:
+ case ThreadState::kWaitingInMainSignalCatcherLoop:
+ case ThreadState::kWaitingPerformingGc:
+ case ThreadState::kWaitingWeakGcRootRead:
+ case ThreadState::kWaitingForGcThreadFlip:
+ case ThreadState::kNativeForAbort:
+ case ThreadState::kWaiting:
return TS_WAIT;
// Don't add a 'default' here so the compiler can spot incompatible enum changes.
}
diff --git a/runtime/native/scoped_fast_native_object_access-inl.h b/runtime/native/scoped_fast_native_object_access-inl.h
index 20ff76e..0b8ad11 100644
--- a/runtime/native/scoped_fast_native_object_access-inl.h
+++ b/runtime/native/scoped_fast_native_object_access-inl.h
@@ -29,7 +29,7 @@
Locks::mutator_lock_->AssertSharedHeld(Self());
DCHECK((*Self()->GetManagedStack()->GetTopQuickFrame())->IsFastNative());
// Don't work with raw objects in non-runnable states.
- DCHECK_EQ(Self()->GetState(), kRunnable);
+ DCHECK_EQ(Self()->GetState(), ThreadState::kRunnable);
}
} // namespace art
diff --git a/runtime/oat.h b/runtime/oat.h
index 0b6bf7d..8a97cdd 100644
--- a/runtime/oat.h
+++ b/runtime/oat.h
@@ -32,8 +32,8 @@
class PACKED(4) OatHeader {
public:
static constexpr std::array<uint8_t, 4> kOatMagic { { 'o', 'a', 't', '\n' } };
- // Last oat version changed reason: JNI: Rewrite locking for synchronized methods.
- static constexpr std::array<uint8_t, 4> kOatVersion { { '2', '1', '3', '\0' } };
+ // Last oat version changed reason: Always access thread state and flags as a 32-bit location.
+ static constexpr std::array<uint8_t, 4> kOatVersion { { '2', '1', '4', '\0' } };
static constexpr const char* kDex2OatCmdLineKey = "dex2oat-cmdline";
static constexpr const char* kDebuggableKey = "debuggable";
diff --git a/runtime/oat_file_manager.cc b/runtime/oat_file_manager.cc
index 7166dd1..dfa4518 100644
--- a/runtime/oat_file_manager.cc
+++ b/runtime/oat_file_manager.cc
@@ -263,7 +263,7 @@
// Add image space has a race condition since other threads could be reading from the
// spaces array.
{
- ScopedThreadSuspension sts(self, kSuspended);
+ ScopedThreadSuspension sts(self, ThreadState::kSuspended);
gc::ScopedGCCriticalSection gcs(self,
gc::kGcCauseAddRemoveAppImageSpace,
gc::kCollectorTypeAddRemoveAppImageSpace);
@@ -290,7 +290,7 @@
LOG(INFO) << "Failed to add image file " << temp_error_msg;
dex_files.clear();
{
- ScopedThreadSuspension sts(self, kSuspended);
+ ScopedThreadSuspension sts(self, ThreadState::kSuspended);
gc::ScopedGCCriticalSection gcs(self,
gc::kGcCauseAddRemoveAppImageSpace,
gc::kCollectorTypeAddRemoveAppImageSpace);
diff --git a/runtime/object_lock.cc b/runtime/object_lock.cc
index 744bc42..9e02484 100644
--- a/runtime/object_lock.cc
+++ b/runtime/object_lock.cc
@@ -35,7 +35,7 @@
template <typename T>
void ObjectLock<T>::WaitIgnoringInterrupts() {
- Monitor::Wait(self_, obj_.Get(), 0, 0, false, kWaiting);
+ Monitor::Wait(self_, obj_.Get(), 0, 0, false, ThreadState::kWaiting);
}
template <typename T>
diff --git a/runtime/reflection.cc b/runtime/reflection.cc
index f642bcb..a7290a2 100644
--- a/runtime/reflection.cc
+++ b/runtime/reflection.cc
@@ -879,7 +879,7 @@
}
ScopedObjectAccessUnchecked soa(Thread::Current());
- DCHECK_EQ(soa.Self()->GetState(), kRunnable);
+ DCHECK_EQ(soa.Self()->GetState(), ThreadState::kRunnable);
ArgArray arg_array(shorty, 2);
JValue result;
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 0f6b521..bbc6492 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -654,7 +654,7 @@
{
// Ensure that we don't have multiple threads trying to abort at once,
// which would result in significantly worse diagnostics.
- ScopedThreadStateChange tsc(Thread::Current(), kNativeForAbort);
+ ScopedThreadStateChange tsc(Thread::Current(), ThreadState::kNativeForAbort);
Locks::abort_lock_->ExclusiveLock(Thread::Current());
}
@@ -718,7 +718,7 @@
void Runtime::CallExitHook(jint status) {
if (exit_ != nullptr) {
- ScopedThreadStateChange tsc(Thread::Current(), kNative);
+ ScopedThreadStateChange tsc(Thread::Current(), ThreadState::kNative);
exit_(status);
LOG(WARNING) << "Exit hook returned instead of exiting!";
}
@@ -883,7 +883,7 @@
// Restore main thread state to kNative as expected by native code.
Thread* self = Thread::Current();
- self->TransitionFromRunnableToSuspended(kNative);
+ self->TransitionFromRunnableToSuspended(ThreadState::kNative);
started_ = true;
@@ -990,7 +990,7 @@
finished_starting_ = true;
if (trace_config_.get() != nullptr && trace_config_->trace_file != "") {
- ScopedThreadStateChange tsc(self, kWaitingForMethodTracingStart);
+ ScopedThreadStateChange tsc(self, ThreadState::kWaitingForMethodTracingStart);
Trace::Start(trace_config_->trace_file.c_str(),
static_cast<int>(trace_config_->trace_file_size),
0,
@@ -1195,7 +1195,7 @@
Thread* self = Thread::Current();
// Must be in the kNative state for calling native methods.
- CHECK_EQ(self->GetState(), kNative);
+ CHECK_EQ(self->GetState(), ThreadState::kNative);
JNIEnv* env = self->GetJniEnv();
env->CallStaticVoidMethod(WellKnownClasses::java_lang_Daemons,
@@ -2086,7 +2086,7 @@
JNIEnv* env = self->GetJniEnv();
// Must be in the kNative state for calling native methods (JNI_OnLoad code).
- CHECK_EQ(self->GetState(), kNative);
+ CHECK_EQ(self->GetState(), ThreadState::kNative);
// Set up the native methods provided by the runtime itself.
RegisterRuntimeNativeMethods(env);
diff --git a/runtime/runtime_callbacks_test.cc b/runtime/runtime_callbacks_test.cc
index e49deae..7619750 100644
--- a/runtime/runtime_callbacks_test.cc
+++ b/runtime/runtime_callbacks_test.cc
@@ -55,7 +55,7 @@
Thread* self = Thread::Current();
ScopedObjectAccess soa(self);
- ScopedThreadSuspension sts(self, kWaitingForDebuggerToAttach);
+ ScopedThreadSuspension sts(self, ThreadState::kWaitingForDebuggerToAttach);
ScopedSuspendAll ssa("RuntimeCallbacksTest SetUp");
AddListener();
}
@@ -64,7 +64,7 @@
{
Thread* self = Thread::Current();
ScopedObjectAccess soa(self);
- ScopedThreadSuspension sts(self, kWaitingForDebuggerToAttach);
+ ScopedThreadSuspension sts(self, ThreadState::kWaitingForDebuggerToAttach);
ScopedSuspendAll ssa("RuntimeCallbacksTest TearDown");
RemoveListener();
}
@@ -523,7 +523,7 @@
/*ms=*/0,
/*ns=*/0,
/*interruptShouldThrow=*/false,
- /*why=*/kWaiting);
+ /*why=*/ThreadState::kWaiting);
}
}
ASSERT_TRUE(cb_.saw_wait_start_);
diff --git a/runtime/scoped_thread_state_change-inl.h b/runtime/scoped_thread_state_change-inl.h
index 04be224..d601952 100644
--- a/runtime/scoped_thread_state_change-inl.h
+++ b/runtime/scoped_thread_state_change-inl.h
@@ -34,7 +34,7 @@
: self_(self), thread_state_(new_thread_state), expected_has_no_thread_(false) {
if (UNLIKELY(self_ == nullptr)) {
// Value chosen arbitrarily and won't be used in the destructor since thread_ == null.
- old_thread_state_ = kTerminated;
+ old_thread_state_ = ThreadState::kTerminated;
Runtime* runtime = Runtime::Current();
CHECK(runtime == nullptr || !runtime->IsStarted() || runtime->IsShuttingDown(self_));
} else {
@@ -43,9 +43,9 @@
// in the suspend count (this will be handled in the runnable transitions).
old_thread_state_ = self->GetState();
if (old_thread_state_ != new_thread_state) {
- if (new_thread_state == kRunnable) {
+ if (new_thread_state == ThreadState::kRunnable) {
self_->TransitionFromSuspendedToRunnable();
- } else if (old_thread_state_ == kRunnable) {
+ } else if (old_thread_state_ == ThreadState::kRunnable) {
self_->TransitionFromRunnableToSuspended(new_thread_state);
} else {
// A suspended transition to another effectively suspended transition, ok to use Unsafe.
@@ -60,9 +60,9 @@
ScopedThreadChangeDestructorCheck();
} else {
if (old_thread_state_ != thread_state_) {
- if (old_thread_state_ == kRunnable) {
+ if (old_thread_state_ == ThreadState::kRunnable) {
self_->TransitionFromSuspendedToRunnable();
- } else if (thread_state_ == kRunnable) {
+ } else if (thread_state_ == ThreadState::kRunnable) {
self_->TransitionFromRunnableToSuspended(old_thread_state_);
} else {
// A suspended transition to another effectively suspended transition, ok to use Unsafe.
@@ -90,7 +90,7 @@
}
inline bool ScopedObjectAccessAlreadyRunnable::IsRunnable() const {
- return self_->GetState() == kRunnable;
+ return self_->GetState() == ThreadState::kRunnable;
}
inline ScopedObjectAccessAlreadyRunnable::ScopedObjectAccessAlreadyRunnable(JNIEnv* env)
@@ -102,13 +102,13 @@
vm_(env_ != nullptr ? env_->GetVm() : nullptr) {}
inline ScopedObjectAccessUnchecked::ScopedObjectAccessUnchecked(JNIEnv* env)
- : ScopedObjectAccessAlreadyRunnable(env), tsc_(Self(), kRunnable) {
+ : ScopedObjectAccessAlreadyRunnable(env), tsc_(Self(), ThreadState::kRunnable) {
Self()->VerifyStack();
Locks::mutator_lock_->AssertSharedHeld(Self());
}
inline ScopedObjectAccessUnchecked::ScopedObjectAccessUnchecked(Thread* self)
- : ScopedObjectAccessAlreadyRunnable(self), tsc_(self, kRunnable) {
+ : ScopedObjectAccessAlreadyRunnable(self), tsc_(self, ThreadState::kRunnable) {
Self()->VerifyStack();
Locks::mutator_lock_->AssertSharedHeld(Self());
}
diff --git a/runtime/scoped_thread_state_change.h b/runtime/scoped_thread_state_change.h
index 08cb5b4..7416d18 100644
--- a/runtime/scoped_thread_state_change.h
+++ b/runtime/scoped_thread_state_change.h
@@ -55,12 +55,12 @@
ScopedThreadStateChange() {}
Thread* const self_ = nullptr;
- const ThreadState thread_state_ = kTerminated;
+ const ThreadState thread_state_ = ThreadState::kTerminated;
private:
void ScopedThreadChangeDestructorCheck();
- ThreadState old_thread_state_ = kTerminated;
+ ThreadState old_thread_state_ = ThreadState::kTerminated;
const bool expected_has_no_thread_ = true;
friend class ScopedObjectAccessUnchecked;
diff --git a/runtime/signal_catcher.cc b/runtime/signal_catcher.cc
index f76a0d0..70cebaf 100644
--- a/runtime/signal_catcher.cc
+++ b/runtime/signal_catcher.cc
@@ -104,7 +104,7 @@
}
void SignalCatcher::Output(const std::string& s) {
- ScopedThreadStateChange tsc(Thread::Current(), kWaitingForSignalCatcherOutput);
+ ScopedThreadStateChange tsc(Thread::Current(), ThreadState::kWaitingForSignalCatcherOutput);
palette_status_t status = PaletteWriteCrashThreadStacks(s.data(), s.size());
if (status == PALETTE_STATUS_OK) {
LOG(INFO) << "Wrote stack traces to tombstoned";
@@ -149,7 +149,7 @@
}
int SignalCatcher::WaitForSignal(Thread* self, SignalSet& signals) {
- ScopedThreadStateChange tsc(self, kWaitingInMainSignalCatcherLoop);
+ ScopedThreadStateChange tsc(self, ThreadState::kWaitingInMainSignalCatcherLoop);
// Signals for sigwait() must be blocked but not ignored. We
// block signals like SIGQUIT for all threads, so the condition
@@ -177,7 +177,7 @@
!runtime->IsAotCompiler()));
Thread* self = Thread::Current();
- DCHECK_NE(self->GetState(), kRunnable);
+ DCHECK_NE(self->GetState(), ThreadState::kRunnable);
{
MutexLock mu(self, signal_catcher->lock_);
signal_catcher->thread_ = self;
diff --git a/runtime/thread-inl.h b/runtime/thread-inl.h
index f5bf5fb..3ac1292 100644
--- a/runtime/thread-inl.h
+++ b/runtime/thread-inl.h
@@ -52,11 +52,12 @@
inline void Thread::CheckSuspend() {
DCHECK_EQ(Thread::Current(), this);
for (;;) {
- if (ReadFlag(kCheckpointRequest)) {
+ StateAndFlags state_and_flags(tls32_.state_and_flags.load(std::memory_order_relaxed));
+ if (state_and_flags.IsFlagSet(ThreadFlag::kCheckpointRequest)) {
RunCheckpointFunction();
- } else if (ReadFlag(kSuspendRequest)) {
+ } else if (state_and_flags.IsFlagSet(ThreadFlag::kSuspendRequest)) {
FullSuspendCheck();
- } else if (ReadFlag(kEmptyCheckpointRequest)) {
+ } else if (state_and_flags.IsFlagSet(ThreadFlag::kEmptyCheckpointRequest)) {
RunEmptyCheckpoint();
} else {
break;
@@ -68,7 +69,7 @@
Thread* self = Thread::Current();
DCHECK_EQ(self, this);
for (;;) {
- if (ReadFlag(kEmptyCheckpointRequest)) {
+ if (ReadFlag(ThreadFlag::kEmptyCheckpointRequest)) {
RunEmptyCheckpoint();
// Check we hold only an expected mutex when accessing weak ref.
if (kIsDebugBuild) {
@@ -92,7 +93,7 @@
inline void Thread::CheckEmptyCheckpointFromMutex() {
DCHECK_EQ(Thread::Current(), this);
for (;;) {
- if (ReadFlag(kEmptyCheckpointRequest)) {
+ if (ReadFlag(ThreadFlag::kEmptyCheckpointRequest)) {
RunEmptyCheckpoint();
} else {
break;
@@ -103,21 +104,29 @@
inline ThreadState Thread::SetState(ThreadState new_state) {
// Should only be used to change between suspended states.
// Cannot use this code to change into or from Runnable as changing to Runnable should
- // fail if old_state_and_flags.suspend_request is true and changing from Runnable might
+ // fail if the `ThreadFlag::kSuspendRequest` is set and changing from Runnable might
// miss passing an active suspend barrier.
- DCHECK_NE(new_state, kRunnable);
+ DCHECK_NE(new_state, ThreadState::kRunnable);
if (kIsDebugBuild && this != Thread::Current()) {
std::string name;
GetThreadName(name);
LOG(FATAL) << "Thread \"" << name << "\"(" << this << " != Thread::Current()="
<< Thread::Current() << ") changing state to " << new_state;
}
- union StateAndFlags old_state_and_flags;
- old_state_and_flags.as_int = tls32_.state_and_flags.as_int;
- CHECK_NE(old_state_and_flags.as_struct.state, kRunnable) << new_state << " " << *this << " "
- << *Thread::Current();
- tls32_.state_and_flags.as_struct.state = new_state;
- return static_cast<ThreadState>(old_state_and_flags.as_struct.state);
+
+ while (true) {
+ StateAndFlags old_state_and_flags(tls32_.state_and_flags.load(std::memory_order_relaxed));
+ CHECK_NE(old_state_and_flags.GetState(), ThreadState::kRunnable)
+ << new_state << " " << *this << " " << *Thread::Current();
+ StateAndFlags new_state_and_flags = old_state_and_flags;
+ new_state_and_flags.SetState(new_state);
+ bool done =
+ tls32_.state_and_flags.CompareAndSetWeakRelaxed(old_state_and_flags.GetValue(),
+ new_state_and_flags.GetValue());
+ if (done) {
+ return static_cast<ThreadState>(old_state_and_flags.GetState());
+ }
+ }
}
inline bool Thread::IsThreadSuspensionAllowable() const {
@@ -182,31 +191,29 @@
}
inline void Thread::TransitionToSuspendedAndRunCheckpoints(ThreadState new_state) {
- DCHECK_NE(new_state, kRunnable);
- DCHECK_EQ(GetState(), kRunnable);
- union StateAndFlags old_state_and_flags;
- union StateAndFlags new_state_and_flags;
+ DCHECK_NE(new_state, ThreadState::kRunnable);
while (true) {
- old_state_and_flags.as_int = tls32_.state_and_flags.as_int;
- if (UNLIKELY((old_state_and_flags.as_struct.flags & kCheckpointRequest) != 0)) {
+ StateAndFlags old_state_and_flags(tls32_.state_and_flags.load(std::memory_order_relaxed));
+ DCHECK_EQ(old_state_and_flags.GetState(), ThreadState::kRunnable);
+ if (UNLIKELY(old_state_and_flags.IsFlagSet(ThreadFlag::kCheckpointRequest))) {
RunCheckpointFunction();
continue;
}
- if (UNLIKELY((old_state_and_flags.as_struct.flags & kEmptyCheckpointRequest) != 0)) {
+ if (UNLIKELY(old_state_and_flags.IsFlagSet(ThreadFlag::kEmptyCheckpointRequest))) {
RunEmptyCheckpoint();
continue;
}
// Change the state but keep the current flags (kCheckpointRequest is clear).
- DCHECK_EQ((old_state_and_flags.as_struct.flags & kCheckpointRequest), 0);
- DCHECK_EQ((old_state_and_flags.as_struct.flags & kEmptyCheckpointRequest), 0);
- new_state_and_flags.as_struct.flags = old_state_and_flags.as_struct.flags;
- new_state_and_flags.as_struct.state = new_state;
+ DCHECK(!old_state_and_flags.IsFlagSet(ThreadFlag::kCheckpointRequest));
+ DCHECK(!old_state_and_flags.IsFlagSet(ThreadFlag::kEmptyCheckpointRequest));
+ StateAndFlags new_state_and_flags = old_state_and_flags;
+ new_state_and_flags.SetState(new_state);
// CAS the value, ensuring that prior memory operations are visible to any thread
// that observes that we are suspended.
bool done =
- tls32_.state_and_flags.as_atomic_int.CompareAndSetWeakRelease(old_state_and_flags.as_int,
- new_state_and_flags.as_int);
+ tls32_.state_and_flags.CompareAndSetWeakRelease(old_state_and_flags.GetValue(),
+ new_state_and_flags.GetValue());
if (LIKELY(done)) {
break;
}
@@ -215,11 +222,12 @@
inline void Thread::PassActiveSuspendBarriers() {
while (true) {
- uint16_t current_flags = tls32_.state_and_flags.as_struct.flags;
- if (LIKELY((current_flags &
- (kCheckpointRequest | kEmptyCheckpointRequest | kActiveSuspendBarrier)) == 0)) {
+ StateAndFlags state_and_flags(tls32_.state_and_flags.load(std::memory_order_relaxed));
+ if (LIKELY(!state_and_flags.IsFlagSet(ThreadFlag::kCheckpointRequest) &&
+ !state_and_flags.IsFlagSet(ThreadFlag::kEmptyCheckpointRequest) &&
+ !state_and_flags.IsFlagSet(ThreadFlag::kActiveSuspendBarrier))) {
break;
- } else if ((current_flags & kActiveSuspendBarrier) != 0) {
+ } else if (state_and_flags.IsFlagSet(ThreadFlag::kActiveSuspendBarrier)) {
PassActiveSuspendBarriers(this);
} else {
// Impossible
@@ -241,38 +249,33 @@
}
inline ThreadState Thread::TransitionFromSuspendedToRunnable() {
- union StateAndFlags old_state_and_flags;
- old_state_and_flags.as_int = tls32_.state_and_flags.as_int;
- int16_t old_state = old_state_and_flags.as_struct.state;
- DCHECK_NE(static_cast<ThreadState>(old_state), kRunnable);
- do {
+ StateAndFlags old_state_and_flags(tls32_.state_and_flags.load(std::memory_order_relaxed));
+ ThreadState old_state = old_state_and_flags.GetState();
+ DCHECK_NE(old_state, ThreadState::kRunnable);
+ while (true) {
GetMutatorLock()->AssertNotHeld(this); // Otherwise we starve GC.
- old_state_and_flags.as_int = tls32_.state_and_flags.as_int;
- DCHECK_EQ(old_state_and_flags.as_struct.state, old_state);
- if (LIKELY(old_state_and_flags.as_struct.flags == 0)) {
- // Optimize for the return from native code case - this is the fast path.
- // Atomically change from suspended to runnable if no suspend request pending.
- union StateAndFlags new_state_and_flags;
- new_state_and_flags.as_int = old_state_and_flags.as_int;
- new_state_and_flags.as_struct.state = kRunnable;
-
+ // Optimize for the return from native code case - this is the fast path.
+ // Atomically change from suspended to runnable if no suspend request pending.
+ StateAndFlags new_state_and_flags = old_state_and_flags;
+ new_state_and_flags.SetState(ThreadState::kRunnable);
+ static_assert(static_cast<std::underlying_type_t<ThreadState>>(ThreadState::kRunnable) == 0u);
+ if (LIKELY(new_state_and_flags.GetValue() == 0u)) { // No flags set?
// CAS the value with a memory barrier.
- if (LIKELY(tls32_.state_and_flags.as_atomic_int.CompareAndSetWeakAcquire(
- old_state_and_flags.as_int,
- new_state_and_flags.as_int))) {
+ if (LIKELY(tls32_.state_and_flags.CompareAndSetWeakAcquire(old_state_and_flags.GetValue(),
+ new_state_and_flags.GetValue()))) {
// Mark the acquisition of a share of the mutator lock.
GetMutatorLock()->TransitionFromSuspendedToRunnable(this);
break;
}
- } else if ((old_state_and_flags.as_struct.flags & kActiveSuspendBarrier) != 0) {
+ } else if (old_state_and_flags.IsFlagSet(ThreadFlag::kActiveSuspendBarrier)) {
PassActiveSuspendBarriers(this);
- } else if ((old_state_and_flags.as_struct.flags &
- (kCheckpointRequest | kEmptyCheckpointRequest)) != 0) {
+ } else if (UNLIKELY(old_state_and_flags.IsFlagSet(ThreadFlag::kCheckpointRequest) ||
+ old_state_and_flags.IsFlagSet(ThreadFlag::kEmptyCheckpointRequest))) {
// Impossible
LOG(FATAL) << "Transitioning to runnable with checkpoint flag, "
- << " flags=" << old_state_and_flags.as_struct.flags
- << " state=" << old_state_and_flags.as_struct.state;
- } else if ((old_state_and_flags.as_struct.flags & kSuspendRequest) != 0) {
+ << " flags=" << new_state_and_flags.GetValue() // State set to kRunnable = 0.
+ << " state=" << old_state_and_flags.GetState();
+ } else if (old_state_and_flags.IsFlagSet(ThreadFlag::kSuspendRequest)) {
// Wait while our suspend count is non-zero.
// We pass null to the MutexLock as we may be in a situation where the
@@ -286,17 +289,22 @@
}
MutexLock mu(thread_to_pass, *Locks::thread_suspend_count_lock_);
ScopedTransitioningToRunnable scoped_transitioning_to_runnable(this);
- old_state_and_flags.as_int = tls32_.state_and_flags.as_int;
- DCHECK_EQ(old_state_and_flags.as_struct.state, old_state);
- while ((old_state_and_flags.as_struct.flags & kSuspendRequest) != 0) {
+ // Reload state and flags after locking the mutex.
+ old_state_and_flags.SetValue(tls32_.state_and_flags.load(std::memory_order_relaxed));
+ DCHECK_EQ(old_state, old_state_and_flags.GetState());
+ while (old_state_and_flags.IsFlagSet(ThreadFlag::kSuspendRequest)) {
// Re-check when Thread::resume_cond_ is notified.
Thread::resume_cond_->Wait(thread_to_pass);
- old_state_and_flags.as_int = tls32_.state_and_flags.as_int;
- DCHECK_EQ(old_state_and_flags.as_struct.state, old_state);
+ // Reload state and flags after waiting.
+ old_state_and_flags.SetValue(tls32_.state_and_flags.load(std::memory_order_relaxed));
+ DCHECK_EQ(old_state, old_state_and_flags.GetState());
}
DCHECK_EQ(GetSuspendCount(), 0);
}
- } while (true);
+ // Reload state and flags.
+ old_state_and_flags.SetValue(tls32_.state_and_flags.load(std::memory_order_relaxed));
+ DCHECK_EQ(old_state, old_state_and_flags.GetState());
+ }
// Run the flip function, if set.
Closure* flip_func = GetFlipFunction();
if (flip_func != nullptr) {
@@ -344,7 +352,7 @@
if (kIsDebugBuild) {
// Note: self is not necessarily equal to this thread since thread may be suspended.
Thread* self = Thread::Current();
- DCHECK(this == self || IsSuspended() || GetState() == kWaitingPerformingGc)
+ DCHECK(this == self || IsSuspended() || GetState() == ThreadState::kWaitingPerformingGc)
<< GetState() << " thread " << this << " self " << self;
}
tlsPtr_.thread_local_alloc_stack_end = nullptr;
diff --git a/runtime/thread.cc b/runtime/thread.cc
index 46aa38e..c7ce0de 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -1003,8 +1003,8 @@
self->InitStringEntryPoints();
- CHECK_NE(self->GetState(), kRunnable);
- self->SetState(kNative);
+ CHECK_NE(self->GetState(), ThreadState::kRunnable);
+ self->SetState(ThreadState::kNative);
// Run the action that is acting on the peer.
if (!peer_action(self)) {
@@ -1444,7 +1444,7 @@
return false;
}
- uint16_t flags = kSuspendRequest;
+ uint32_t flags = enum_cast<uint32_t>(ThreadFlag::kSuspendRequest);
if (delta > 0 && suspend_barrier != nullptr) {
uint32_t available_barrier = kMaxSuspendBarriers;
for (uint32_t i = 0; i < kMaxSuspendBarriers; ++i) {
@@ -1458,7 +1458,7 @@
return false;
}
tlsPtr_.active_suspend_barriers[available_barrier] = suspend_barrier;
- flags |= kActiveSuspendBarrier;
+ flags |= enum_cast<uint32_t>(ThreadFlag::kActiveSuspendBarrier);
}
tls32_.suspend_count += delta;
@@ -1471,10 +1471,10 @@
}
if (tls32_.suspend_count == 0) {
- AtomicClearFlag(kSuspendRequest);
+ AtomicClearFlag(ThreadFlag::kSuspendRequest);
} else {
// Two bits might be set simultaneously.
- tls32_.state_and_flags.as_atomic_int.fetch_or(flags, std::memory_order_seq_cst);
+ tls32_.state_and_flags.fetch_or(flags, std::memory_order_seq_cst);
TriggerSuspend();
}
return true;
@@ -1488,7 +1488,7 @@
AtomicInteger* pass_barriers[kMaxSuspendBarriers];
{
MutexLock mu(self, *Locks::thread_suspend_count_lock_);
- if (!ReadFlag(kActiveSuspendBarrier)) {
+ if (!ReadFlag(ThreadFlag::kActiveSuspendBarrier)) {
// quick exit test: the barriers have already been claimed - this is
// possible as there may be a race to claim and it doesn't matter
// who wins.
@@ -1503,7 +1503,7 @@
pass_barriers[i] = tlsPtr_.active_suspend_barriers[i];
tlsPtr_.active_suspend_barriers[i] = nullptr;
}
- AtomicClearFlag(kActiveSuspendBarrier);
+ AtomicClearFlag(ThreadFlag::kActiveSuspendBarrier);
}
uint32_t barrier_count = 0;
@@ -1530,7 +1530,7 @@
}
void Thread::ClearSuspendBarrier(AtomicInteger* target) {
- CHECK(ReadFlag(kActiveSuspendBarrier));
+ CHECK(ReadFlag(ThreadFlag::kActiveSuspendBarrier));
bool clear_flag = true;
for (uint32_t i = 0; i < kMaxSuspendBarriers; ++i) {
AtomicInteger* ptr = tlsPtr_.active_suspend_barriers[i];
@@ -1541,7 +1541,7 @@
}
}
if (LIKELY(clear_flag)) {
- AtomicClearFlag(kActiveSuspendBarrier);
+ AtomicClearFlag(ThreadFlag::kActiveSuspendBarrier);
}
}
@@ -1559,7 +1559,7 @@
} else {
// No overflow checkpoints. Clear the kCheckpointRequest flag
tlsPtr_.checkpoint_function = nullptr;
- AtomicClearFlag(kCheckpointRequest);
+ AtomicClearFlag(ThreadFlag::kCheckpointRequest);
}
}
// Outside the lock, run the checkpoint function.
@@ -1570,24 +1570,22 @@
void Thread::RunEmptyCheckpoint() {
DCHECK_EQ(Thread::Current(), this);
- AtomicClearFlag(kEmptyCheckpointRequest);
+ AtomicClearFlag(ThreadFlag::kEmptyCheckpointRequest);
Runtime::Current()->GetThreadList()->EmptyCheckpointBarrier()->Pass(this);
}
bool Thread::RequestCheckpoint(Closure* function) {
- union StateAndFlags old_state_and_flags;
- old_state_and_flags.as_int = tls32_.state_and_flags.as_int;
- if (old_state_and_flags.as_struct.state != kRunnable) {
+ StateAndFlags old_state_and_flags(tls32_.state_and_flags.load(std::memory_order_relaxed));
+ if (old_state_and_flags.GetState() != ThreadState::kRunnable) {
return false; // Fail, thread is suspended and so can't run a checkpoint.
}
// We must be runnable to request a checkpoint.
- DCHECK_EQ(old_state_and_flags.as_struct.state, kRunnable);
- union StateAndFlags new_state_and_flags;
- new_state_and_flags.as_int = old_state_and_flags.as_int;
- new_state_and_flags.as_struct.flags |= kCheckpointRequest;
- bool success = tls32_.state_and_flags.as_atomic_int.CompareAndSetStrongSequentiallyConsistent(
- old_state_and_flags.as_int, new_state_and_flags.as_int);
+ DCHECK_EQ(old_state_and_flags.GetState(), ThreadState::kRunnable);
+ StateAndFlags new_state_and_flags = old_state_and_flags;
+ new_state_and_flags.SetFlag(ThreadFlag::kCheckpointRequest);
+ bool success = tls32_.state_and_flags.CompareAndSetStrongSequentiallyConsistent(
+ old_state_and_flags.GetValue(), new_state_and_flags.GetValue());
if (success) {
// Succeeded setting checkpoint flag, now insert the actual checkpoint.
if (tlsPtr_.checkpoint_function == nullptr) {
@@ -1595,28 +1593,26 @@
} else {
checkpoint_overflow_.push_back(function);
}
- CHECK_EQ(ReadFlag(kCheckpointRequest), true);
+ CHECK(ReadFlag(ThreadFlag::kCheckpointRequest));
TriggerSuspend();
}
return success;
}
bool Thread::RequestEmptyCheckpoint() {
- union StateAndFlags old_state_and_flags;
- old_state_and_flags.as_int = tls32_.state_and_flags.as_int;
- if (old_state_and_flags.as_struct.state != kRunnable) {
+ StateAndFlags old_state_and_flags(tls32_.state_and_flags.load(std::memory_order_relaxed));
+ if (old_state_and_flags.GetState() != ThreadState::kRunnable) {
// If it's not runnable, we don't need to do anything because it won't be in the middle of a
// heap access (eg. the read barrier).
return false;
}
// We must be runnable to request a checkpoint.
- DCHECK_EQ(old_state_and_flags.as_struct.state, kRunnable);
- union StateAndFlags new_state_and_flags;
- new_state_and_flags.as_int = old_state_and_flags.as_int;
- new_state_and_flags.as_struct.flags |= kEmptyCheckpointRequest;
- bool success = tls32_.state_and_flags.as_atomic_int.CompareAndSetStrongSequentiallyConsistent(
- old_state_and_flags.as_int, new_state_and_flags.as_int);
+ DCHECK_EQ(old_state_and_flags.GetState(), ThreadState::kRunnable);
+ StateAndFlags new_state_and_flags = old_state_and_flags;
+ new_state_and_flags.SetFlag(ThreadFlag::kEmptyCheckpointRequest);
+ bool success = tls32_.state_and_flags.CompareAndSetStrongSequentiallyConsistent(
+ old_state_and_flags.GetValue(), new_state_and_flags.GetValue());
if (success) {
TriggerSuspend();
}
@@ -1776,7 +1772,7 @@
VLOG(threads) << this << " self-suspending";
// Make thread appear suspended to other threads, release mutator_lock_.
// Transition to suspended and back to runnable, re-acquire share on mutator_lock_.
- ScopedThreadSuspension(this, kSuspended); // NOLINT
+ ScopedThreadSuspension(this, ThreadState::kSuspended); // NOLINT
VLOG(threads) << this << " self-reviving";
}
@@ -1879,10 +1875,15 @@
if (thread != nullptr) {
auto suspend_log_fn = [&]() REQUIRES(Locks::thread_suspend_count_lock_) {
+ StateAndFlags state_and_flags(
+ thread->tls32_.state_and_flags.load(std::memory_order_relaxed));
+ static_assert(
+ static_cast<std::underlying_type_t<ThreadState>>(ThreadState::kRunnable) == 0u);
+ state_and_flags.SetState(ThreadState::kRunnable); // Clear state bits.
os << " | group=\"" << group_name << "\""
<< " sCount=" << thread->tls32_.suspend_count
<< " ucsCount=" << thread->tls32_.user_code_suspend_count
- << " flags=" << thread->tls32_.state_and_flags.as_struct.flags
+ << " flags=" << state_and_flags.GetValue()
<< " obj=" << reinterpret_cast<void*>(thread->tlsPtr_.opeer)
<< " self=" << reinterpret_cast<const void*>(thread) << "\n";
};
@@ -2058,11 +2059,11 @@
REQUIRES_SHARED(Locks::mutator_lock_) {
const char* msg;
switch (state) {
- case kBlocked:
+ case ThreadState::kBlocked:
msg = " - waiting to lock ";
break;
- case kWaitingForLockInflation:
+ case ThreadState::kWaitingForLockInflation:
msg = " - waiting for lock inflation of ";
break;
@@ -2116,12 +2117,14 @@
ThreadState state = thread->GetState();
// In native code somewhere in the VM (one of the kWaitingFor* states)? That's interesting.
- if (state > kWaiting && state < kStarting) {
+ if (state > ThreadState::kWaiting && state < ThreadState::kStarting) {
return true;
}
// In an Object.wait variant or Thread.sleep? That's not interesting.
- if (state == kTimedWaiting || state == kSleeping || state == kWaiting) {
+ if (state == ThreadState::kTimedWaiting ||
+ state == ThreadState::kSleeping ||
+ state == ThreadState::kWaiting) {
return false;
}
@@ -2305,8 +2308,10 @@
static_assert((sizeof(Thread) % 4) == 0U,
"art::Thread has a size which is not a multiple of 4.");
- tls32_.state_and_flags.as_struct.flags = 0;
- tls32_.state_and_flags.as_struct.state = kNative;
+ DCHECK_EQ(tls32_.state_and_flags.load(std::memory_order_relaxed), 0u);
+ StateAndFlags state_and_flags(0u);
+ state_and_flags.SetState(ThreadState::kNative);
+ tls32_.state_and_flags.store(state_and_flags.GetValue(), std::memory_order_relaxed);
tls32_.interrupted.store(false, std::memory_order_relaxed);
// Initialize with no permit; if the java Thread was unparked before being
// started, it will unpark itself before calling into java code.
@@ -2462,9 +2467,9 @@
delete tlsPtr_.jni_env;
tlsPtr_.jni_env = nullptr;
}
- CHECK_NE(GetState(), kRunnable);
- CHECK(!ReadFlag(kCheckpointRequest));
- CHECK(!ReadFlag(kEmptyCheckpointRequest));
+ CHECK_NE(GetState(), ThreadState::kRunnable);
+ CHECK(!ReadFlag(ThreadFlag::kCheckpointRequest));
+ CHECK(!ReadFlag(ThreadFlag::kEmptyCheckpointRequest));
CHECK(tlsPtr_.checkpoint_function == nullptr);
CHECK_EQ(checkpoint_overflow_.size(), 0u);
CHECK(tlsPtr_.flip_function == nullptr);
@@ -2476,7 +2481,7 @@
"Not all deoptimized frames have been consumed by the debugger.";
// We may be deleting a still born thread.
- SetStateUnsafe(kTerminated);
+ SetStateUnsafe(ThreadState::kTerminated);
delete wait_cond_;
delete wait_mutex_;
@@ -2503,7 +2508,7 @@
return;
}
ScopedLocalRef<jobject> peer(tlsPtr_.jni_env, soa.AddLocalReference<jobject>(tlsPtr_.opeer));
- ScopedThreadStateChange tsc(this, kNative);
+ ScopedThreadStateChange tsc(this, ThreadState::kNative);
// Get and clear the exception.
ScopedLocalRef<jthrowable> exception(tlsPtr_.jni_env, tlsPtr_.jni_env->ExceptionOccurred());
@@ -2526,7 +2531,7 @@
if (ogroup != nullptr) {
ScopedLocalRef<jobject> group(soa.Env(), soa.AddLocalReference<jobject>(ogroup));
ScopedLocalRef<jobject> peer(soa.Env(), soa.AddLocalReference<jobject>(tlsPtr_.opeer));
- ScopedThreadStateChange tsc(soa.Self(), kNative);
+ ScopedThreadStateChange tsc(soa.Self(), ThreadState::kNative);
tlsPtr_.jni_env->CallVoidMethod(group.get(),
WellKnownClasses::java_lang_ThreadGroup_removeThread,
peer.get());
@@ -4470,7 +4475,7 @@
std::string Thread::StateAndFlagsAsHexString() const {
std::stringstream result_stream;
- result_stream << std::hex << tls32_.state_and_flags.as_atomic_int.load();
+ result_stream << std::hex << tls32_.state_and_flags.load(std::memory_order_relaxed);
return result_stream.str();
}
diff --git a/runtime/thread.h b/runtime/thread.h
index 9478980..f1dd7b8 100644
--- a/runtime/thread.h
+++ b/runtime/thread.h
@@ -26,6 +26,8 @@
#include <string>
#include "base/atomic.h"
+#include "base/bit_field.h"
+#include "base/bit_utils.h"
#include "base/enums.h"
#include "base/locks.h"
#include "base/macros.h"
@@ -118,12 +120,21 @@
kMaxThreadPriority = 10,
};
-enum ThreadFlag {
- kSuspendRequest = 1, // If set implies that suspend_count_ > 0 and the Thread should enter the
- // safepoint handler.
- kCheckpointRequest = 2, // Request that the thread do some checkpoint work and then continue.
- kEmptyCheckpointRequest = 4, // Request that the thread do empty checkpoint and then continue.
- kActiveSuspendBarrier = 8, // Register that at least 1 suspend barrier needs to be passed.
+enum class ThreadFlag : uint32_t {
+ // If set, implies that suspend_count_ > 0 and the Thread should enter the safepoint handler.
+ kSuspendRequest = 1u << 0,
+
+ // Request that the thread do some checkpoint work and then continue.
+ kCheckpointRequest = 1u << 1,
+
+ // Request that the thread do empty checkpoint and then continue.
+ kEmptyCheckpointRequest = 1u << 2,
+
+ // Register that at least 1 suspend barrier needs to be passed.
+ kActiveSuspendBarrier = 1u << 3,
+
+ // Indicates the last flag. Used for checking that the flags do not overlap thread state.
+ kLastFlag = kActiveSuspendBarrier
};
enum class StackedShadowFrameType {
@@ -236,9 +247,8 @@
REQUIRES_SHARED(Locks::mutator_lock_);
ThreadState GetState() const {
- DCHECK_GE(tls32_.state_and_flags.as_struct.state, kTerminated);
- DCHECK_LE(tls32_.state_and_flags.as_struct.state, kSuspended);
- return static_cast<ThreadState>(tls32_.state_and_flags.as_struct.state);
+ StateAndFlags state_and_flags(tls32_.state_and_flags.load(std::memory_order_relaxed));
+ return state_and_flags.GetState();
}
ThreadState SetState(ThreadState new_state);
@@ -253,10 +263,9 @@
}
bool IsSuspended() const {
- union StateAndFlags state_and_flags;
- state_and_flags.as_int = tls32_.state_and_flags.as_atomic_int.load(std::memory_order_relaxed);
- return state_and_flags.as_struct.state != kRunnable &&
- (state_and_flags.as_struct.flags & kSuspendRequest) != 0;
+ StateAndFlags state_and_flags(tls32_.state_and_flags.load(std::memory_order_relaxed));
+ return state_and_flags.GetState() != ThreadState::kRunnable &&
+ state_and_flags.IsFlagSet(ThreadFlag::kSuspendRequest);
}
void DecrDefineClassCount() {
@@ -1097,19 +1106,23 @@
REQUIRES(Locks::thread_suspend_count_lock_);
bool ReadFlag(ThreadFlag flag) const {
- return (tls32_.state_and_flags.as_struct.flags & flag) != 0;
+ StateAndFlags state_and_flags(tls32_.state_and_flags.load(std::memory_order_relaxed));
+ return state_and_flags.IsFlagSet(flag);
}
bool TestAllFlags() const {
- return (tls32_.state_and_flags.as_struct.flags != 0);
+ StateAndFlags state_and_flags(tls32_.state_and_flags.load(std::memory_order_relaxed));
+ static_assert(static_cast<std::underlying_type_t<ThreadState>>(ThreadState::kRunnable) == 0u);
+ state_and_flags.SetState(ThreadState::kRunnable); // Clear state bits.
+ return state_and_flags.GetValue() != 0u;
}
void AtomicSetFlag(ThreadFlag flag) {
- tls32_.state_and_flags.as_atomic_int.fetch_or(flag, std::memory_order_seq_cst);
+ tls32_.state_and_flags.fetch_or(enum_cast<uint32_t>(flag), std::memory_order_seq_cst);
}
void AtomicClearFlag(ThreadFlag flag) {
- tls32_.state_and_flags.as_atomic_int.fetch_and(-1 ^ flag, std::memory_order_seq_cst);
+ tls32_.state_and_flags.fetch_and(~enum_cast<uint32_t>(flag), std::memory_order_seq_cst);
}
void ResetQuickAllocEntryPointsForThread();
@@ -1330,10 +1343,15 @@
jint thread_priority)
REQUIRES_SHARED(Locks::mutator_lock_);
- // Avoid use, callers should use SetState. Used only by SignalCatcher::HandleSigQuit and, ~Thread
+ // Avoid use, callers should use SetState.
+ // Used only by `Thread` destructor and stack trace collection in semi-space GC (currently
+ // disabled by `kStoreStackTraces = false`).
ThreadState SetStateUnsafe(ThreadState new_state) {
- ThreadState old_state = GetState();
- if (old_state == kRunnable && new_state != kRunnable) {
+ StateAndFlags old_state_and_flags(tls32_.state_and_flags.load(std::memory_order_relaxed));
+ ThreadState old_state = old_state_and_flags.GetState();
+ if (old_state == new_state) {
+ // Nothing to do.
+ } else if (old_state == ThreadState::kRunnable) {
// Need to run pending checkpoint and suspend barriers. Run checkpoints in runnable state in
// case they need to use a ScopedObjectAccess. If we are holding the mutator lock and a SOA
// attempts to TransitionFromSuspendedToRunnable, it results in a deadlock.
@@ -1341,7 +1359,18 @@
// Since we transitioned to a suspended state, check the pass barrier requests.
PassActiveSuspendBarriers();
} else {
- tls32_.state_and_flags.as_struct.state = new_state;
+ while (true) {
+ StateAndFlags new_state_and_flags = old_state_and_flags;
+ new_state_and_flags.SetState(new_state);
+ if (LIKELY(tls32_.state_and_flags.CompareAndSetWeakAcquire(
+ old_state_and_flags.GetValue(),
+ new_state_and_flags.GetValue()))) {
+ break;
+ }
+ // Reload state and flags.
+ old_state_and_flags.SetValue(tls32_.state_and_flags.load(std::memory_order_relaxed));
+ DCHECK_EQ(old_state, old_state_and_flags.GetState());
+ }
}
return old_state;
}
@@ -1440,29 +1469,61 @@
void ReleaseLongJumpContextInternal();
- // 32 bits of atomically changed state and flags. Keeping as 32 bits allows and atomic CAS to
- // change from being Suspended to Runnable without a suspend request occurring.
- union PACKED(4) StateAndFlags {
- StateAndFlags() {}
- struct PACKED(4) {
- // Bitfield of flag values. Must be changed atomically so that flag values aren't lost. See
- // ThreadFlag for bit field meanings.
- volatile uint16_t flags;
- // Holds the ThreadState. May be changed non-atomically between Suspended (ie not Runnable)
- // transitions. Changing to Runnable requires that the suspend_request be part of the atomic
- // operation. If a thread is suspended and a suspend_request is present, a thread may not
- // change to Runnable as a GC or other operation is in progress.
- volatile uint16_t state;
- } as_struct;
- AtomicInteger as_atomic_int;
- volatile int32_t as_int;
+ // Helper class for manipulating the 32 bits of atomically changed state and flags.
+ class StateAndFlags {
+ public:
+ explicit StateAndFlags(uint32_t value) :value_(value) {}
+
+ uint32_t GetValue() const {
+ return value_;
+ }
+
+ void SetValue(uint32_t value) {
+ value_ = value;
+ }
+
+ bool IsFlagSet(ThreadFlag flag) const {
+ return (value_ & enum_cast<uint32_t>(flag)) != 0u;
+ }
+
+ void SetFlag(ThreadFlag flag) {
+ value_ |= enum_cast<uint32_t>(flag);
+ }
+
+ void ClearFlag(ThreadFlag flag) {
+ value_ &= ~enum_cast<uint32_t>(flag);
+ }
+
+ ThreadState GetState() const {
+ ThreadState state = ThreadStateField::Decode(value_);
+ ValidateThreadState(state);
+ return state;
+ }
+
+ void SetState(ThreadState state) {
+ ValidateThreadState(state);
+ value_ = ThreadStateField::Update(state, value_);
+ }
private:
- // gcc does not handle struct with volatile member assignments correctly.
- // See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47409
- DISALLOW_COPY_AND_ASSIGN(StateAndFlags);
+ static void ValidateThreadState(ThreadState state) {
+ if (kIsDebugBuild && state != ThreadState::kRunnable) {
+ CHECK_GE(state, ThreadState::kTerminated);
+ CHECK_LE(state, ThreadState::kSuspended);
+ CHECK_NE(state, ThreadState::kObsoleteRunnable);
+ }
+ }
+
+ // The value holds thread flags and thread state.
+ uint32_t value_;
+
+ static constexpr size_t kThreadStateBitSize = BitSizeOf<std::underlying_type_t<ThreadState>>();
+ static constexpr size_t kThreadStatePosition = BitSizeOf<uint32_t>() - kThreadStateBitSize;
+ using ThreadStateField = BitField<ThreadState, kThreadStatePosition, kThreadStateBitSize>;
+ static_assert(
+ WhichPowerOf2(enum_cast<uint32_t>(ThreadFlag::kLastFlag)) < kThreadStatePosition);
};
- static_assert(sizeof(StateAndFlags) == sizeof(int32_t), "Weird state_and_flags size");
+ static_assert(sizeof(StateAndFlags) == sizeof(uint32_t), "Unexpected StateAndFlags size");
// Format state and flags as a hex string. For diagnostic output.
std::string StateAndFlagsAsHexString() const;
@@ -1502,7 +1563,8 @@
using bool32_t = uint32_t;
explicit tls_32bit_sized_values(bool is_daemon)
- : suspend_count(0),
+ : state_and_flags(0u),
+ suspend_count(0),
thin_lock_thread_id(0),
tid(0),
daemon(is_daemon),
@@ -1518,9 +1580,13 @@
make_visibly_initialized_counter(0),
define_class_counter(0) {}
- union StateAndFlags state_and_flags;
- static_assert(sizeof(union StateAndFlags) == sizeof(int32_t),
- "Size of state_and_flags and int32 are different");
+ // The state and flags field must be changed atomically so that flag values aren't lost.
+ // See `StateAndFlags` for bit assignments of `ThreadFlag` and `ThreadState` values.
+ // Keeping the state and flags together allows an atomic CAS to change from being
+ // Suspended to Runnable without a suspend request occurring.
+ Atomic<uint32_t> state_and_flags;
+ static_assert(sizeof(state_and_flags) == sizeof(uint32_t),
+ "Size of state_and_flags and uint32 are different");
// A non-zero value is used to tell the current thread to enter a safe point
// at the next poll.
diff --git a/runtime/thread_list.cc b/runtime/thread_list.cc
index 8a48300..f50dba8 100644
--- a/runtime/thread_list.cc
+++ b/runtime/thread_list.cc
@@ -222,7 +222,7 @@
void WaitForThreadsToRunThroughCheckpoint(size_t threads_running_checkpoint) {
Thread* self = Thread::Current();
- ScopedThreadStateChange tsc(self, kWaitingForCheckPointsToRun);
+ ScopedThreadStateChange tsc(self, ThreadState::kWaitingForCheckPointsToRun);
bool timed_out = barrier_.Increment(self, threads_running_checkpoint, kDumpWaitTimeout);
if (timed_out) {
// Avoid a recursive abort.
@@ -338,7 +338,7 @@
break;
} else {
// The thread is probably suspended, try to make sure that it stays suspended.
- if (thread->GetState() == kRunnable) {
+ if (thread->GetState() == ThreadState::kRunnable) {
// Spurious fail, try again.
continue;
}
@@ -419,7 +419,7 @@
}
break;
}
- if (thread->GetState() != kRunnable) {
+ if (thread->GetState() != ThreadState::kRunnable) {
// It's seen suspended, we are done because it must not be in the middle of a mutator
// heap access.
break;
@@ -434,7 +434,7 @@
Runtime::Current()->GetHeap()->GetReferenceProcessor()->BroadcastForSlowPath(self);
Runtime::Current()->BroadcastForNewSystemWeaks(/*broadcast_for_checkpoint=*/true);
{
- ScopedThreadStateChange tsc(self, kWaitingForCheckPointsToRun);
+ ScopedThreadStateChange tsc(self, ThreadState::kWaitingForCheckPointsToRun);
uint64_t total_wait_time = 0;
bool first_iter = true;
while (true) {
@@ -481,7 +481,7 @@
std::find(runnable_thread_ids.begin(), runnable_thread_ids.end(), tid) !=
runnable_thread_ids.end();
if (is_in_runnable_thread_ids &&
- thread->ReadFlag(kEmptyCheckpointRequest)) {
+ thread->ReadFlag(ThreadFlag::kEmptyCheckpointRequest)) {
// Found a runnable thread that hasn't responded to the empty checkpoint request.
// Assume it's stuck and safe to dump its stack.
thread->Dump(LOG_STREAM(FATAL_WITHOUT_ABORT),
@@ -514,7 +514,7 @@
Locks::mutator_lock_->AssertNotHeld(self);
Locks::thread_list_lock_->AssertNotHeld(self);
Locks::thread_suspend_count_lock_->AssertNotHeld(self);
- CHECK_NE(self->GetState(), kRunnable);
+ CHECK_NE(self->GetState(), ThreadState::kRunnable);
collector->GetHeap()->ThreadFlipBegin(self); // Sync with JNI critical calls.
@@ -557,7 +557,7 @@
// runnable (both cases waiting inside Thread::TransitionFromSuspendedToRunnable), or waiting
// for the thread flip to end at the JNI critical section entry (kWaitingForGcThreadFlip),
ThreadState state = thread->GetState();
- if ((state == kWaitingForGcThreadFlip || thread->IsTransitioningToRunnable()) &&
+ if ((state == ThreadState::kWaitingForGcThreadFlip || thread->IsTransitioningToRunnable()) &&
thread->GetSuspendCount() == 1) {
// The thread will resume right after the broadcast.
bool updated = thread->ModifySuspendCount(self, -1, nullptr, SuspendReason::kInternal);
@@ -667,7 +667,7 @@
Locks::thread_list_lock_->AssertNotHeld(self);
Locks::thread_suspend_count_lock_->AssertNotHeld(self);
if (kDebugLocking && self != nullptr) {
- CHECK_NE(self->GetState(), kRunnable);
+ CHECK_NE(self->GetState(), ThreadState::kRunnable);
}
// First request that all threads suspend, then wait for them to suspend before
@@ -1201,7 +1201,7 @@
{
MutexLock mu(self, *Locks::thread_list_lock_);
for (const auto& thread : list_) {
- if (thread != self && thread->GetState() == kRunnable) {
+ if (thread != self && thread->GetState() == ThreadState::kRunnable) {
if (!have_complained) {
LOG(WARNING) << "daemon thread not yet suspended: " << *thread;
have_complained = true;
@@ -1236,7 +1236,7 @@
// touching deallocated memory, but it also prevents mutexes from getting released. Thus we
// only do this once we're reasonably sure that no system mutexes are still held.
for (const auto& thread : list_) {
- DCHECK(thread == self || !all_suspended || thread->GetState() != kRunnable);
+ DCHECK(thread == self || !all_suspended || thread->GetState() != ThreadState::kRunnable);
// In the !all_suspended case, the target is probably sleeping.
thread->GetJniEnv()->SetRuntimeDeleted();
// Possibly contended Mutex acquisitions are unsafe after this.
@@ -1291,7 +1291,7 @@
void ThreadList::Unregister(Thread* self) {
DCHECK_EQ(self, Thread::Current());
- CHECK_NE(self->GetState(), kRunnable);
+ CHECK_NE(self->GetState(), ThreadState::kRunnable);
Locks::mutator_lock_->AssertNotHeld(self);
VLOG(threads) << "ThreadList::Unregister() " << *self;
diff --git a/runtime/thread_state.h b/runtime/thread_state.h
index 69b5b5d..e03df27 100644
--- a/runtime/thread_state.h
+++ b/runtime/thread_state.h
@@ -25,12 +25,18 @@
// When we refer to "a suspended state", or when function names mention "ToSuspended" or
// "FromSuspended", we mean any state other than kRunnable, i.e. any state in which the thread is
// guaranteed not to access the Java heap. The kSuspended state is merely one of these.
-enum ThreadState {
+enum class ThreadState : uint8_t {
+ // `kRunnable` was previously 67 but it is now set to 0 so that we do not need to extract
+ // flags from the thread's `state_and_flags` to check for any flag being set while Runnable.
+ // Note: All atomic accesses for a location should use the same data size,
+ // so the incorrect old approach of reading just 16 bits has been rewritten.
+
// Java
// Thread.State JDWP state
kTerminated = 66, // TERMINATED TS_ZOMBIE Thread.run has returned, but Thread* still around
- kRunnable, // RUNNABLE TS_RUNNING runnable
- kTimedWaiting, // TIMED_WAITING TS_WAIT in Object.wait() with a timeout
+ kRunnable = 0, // RUNNABLE TS_RUNNING runnable
+ kObsoleteRunnable = 67, // --- --- obsolete value
+ kTimedWaiting = 68, // TIMED_WAITING TS_WAIT in Object.wait() with a timeout
kSleeping, // TIMED_WAITING TS_SLEEPING in Thread.sleep()
kBlocked, // BLOCKED TS_MONITOR blocked on a monitor
kWaiting, // WAITING TS_WAIT in Object.wait()
diff --git a/test/566-polymorphic-inlining/polymorphic_inline.cc b/test/566-polymorphic-inlining/polymorphic_inline.cc
index 34ec3ff..02ba04c 100644
--- a/test/566-polymorphic-inlining/polymorphic_inline.cc
+++ b/test/566-polymorphic-inlining/polymorphic_inline.cc
@@ -42,7 +42,7 @@
header = OatQuickMethodHeader::FromEntryPoint(pc);
break;
} else {
- ScopedThreadSuspension sts(soa.Self(), kSuspended);
+ ScopedThreadSuspension sts(soa.Self(), ThreadState::kSuspended);
// Sleep to yield to the compiler thread.
usleep(1000);
}
diff --git a/test/597-deopt-new-string/deopt.cc b/test/597-deopt-new-string/deopt.cc
index fe229e4..572be28 100644
--- a/test/597-deopt-new-string/deopt.cc
+++ b/test/597-deopt-new-string/deopt.cc
@@ -30,7 +30,7 @@
JNIEnv* env,
jclass cls ATTRIBUTE_UNUSED) {
ScopedObjectAccess soa(env);
- ScopedThreadSuspension sts(Thread::Current(), kWaitingForDeoptimization);
+ ScopedThreadSuspension sts(Thread::Current(), ThreadState::kWaitingForDeoptimization);
gc::ScopedGCCriticalSection gcs(Thread::Current(),
gc::kGcCauseInstrumentation,
gc::kCollectorTypeInstrumentation);
@@ -49,7 +49,7 @@
JNIEnv* env,
jclass cls ATTRIBUTE_UNUSED) {
ScopedObjectAccess soa(env);
- ScopedThreadSuspension sts(Thread::Current(), kWaitingForDeoptimization);
+ ScopedThreadSuspension sts(Thread::Current(), ThreadState::kWaitingForDeoptimization);
gc::ScopedGCCriticalSection gcs(Thread::Current(),
gc::kGcCauseInstrumentation,
gc::kCollectorTypeInstrumentation);
diff --git a/test/706-checker-scheduler/src/Main.java b/test/706-checker-scheduler/src/Main.java
index 5a66fbb..d4d3923 100644
--- a/test/706-checker-scheduler/src/Main.java
+++ b/test/706-checker-scheduler/src/Main.java
@@ -605,7 +605,7 @@
/// CHECK: subs
/// CHECK: add
/// CHECK: adds
- /// CHECK: ldrh
+ /// CHECK: ldr
/// CHECK: cmp
/// CHECK: beq
@@ -613,7 +613,7 @@
/// CHECK: sub
/// CHECK: add
/// CHECK: add
- /// CHECK: ldrh
+ /// CHECK: ldr
/// CHECK: cbz
private static void testCrossItersDependencies() {
int[] data = {1, 2, 3, 0};
diff --git a/tools/cpp-define-generator/thread.def b/tools/cpp-define-generator/thread.def
index d472cc4..fff5755 100644
--- a/tools/cpp-define-generator/thread.def
+++ b/tools/cpp-define-generator/thread.def
@@ -22,9 +22,9 @@
ASM_DEFINE(THREAD_CARD_TABLE_OFFSET,
art::Thread::CardTableOffset<art::kRuntimePointerSize>().Int32Value())
ASM_DEFINE(THREAD_CHECKPOINT_REQUEST,
- art::kCheckpointRequest)
+ static_cast<uint32_t>(art::ThreadFlag::kCheckpointRequest))
ASM_DEFINE(THREAD_EMPTY_CHECKPOINT_REQUEST,
- art::kEmptyCheckpointRequest)
+ static_cast<uint32_t>(art::ThreadFlag::kEmptyCheckpointRequest))
ASM_DEFINE(THREAD_EXCEPTION_OFFSET,
art::Thread::ExceptionOffset<art::kRuntimePointerSize>().Int32Value())
ASM_DEFINE(THREAD_FLAGS_OFFSET,
@@ -56,9 +56,11 @@
ASM_DEFINE(THREAD_SELF_OFFSET,
art::Thread::SelfOffset<art::kRuntimePointerSize>().Int32Value())
ASM_DEFINE(THREAD_SUSPEND_OR_CHECKPOINT_REQUEST,
- art::kSuspendRequest | art::kCheckpointRequest | art::kEmptyCheckpointRequest)
+ static_cast<uint32_t>(art::ThreadFlag::kSuspendRequest) |
+ static_cast<uint32_t>(art::ThreadFlag::kCheckpointRequest) |
+ static_cast<uint32_t>(art::ThreadFlag::kEmptyCheckpointRequest))
ASM_DEFINE(THREAD_SUSPEND_REQUEST,
- art::kSuspendRequest)
+ static_cast<uint32_t>(art::ThreadFlag::kSuspendRequest))
ASM_DEFINE(THREAD_TOP_QUICK_FRAME_OFFSET,
art::Thread::TopOfManagedStackOffset<art::kRuntimePointerSize>().Int32Value())
ASM_DEFINE(THREAD_ALLOC_OBJECT_ENTRYPOINT_OFFSET,