summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--build/Android.common_build.mk2
-rw-r--r--compiler/utils/arm64/assembler_arm64.cc2
-rw-r--r--runtime/arch/x86/thread_x86.cc2
-rw-r--r--runtime/asm_support.h15
-rw-r--r--runtime/base/mutex-inl.h4
-rw-r--r--runtime/entrypoints/quick/quick_trampoline_entrypoints.cc1
-rw-r--r--runtime/mem_map.cc31
-rw-r--r--runtime/thread.cc102
-rw-r--r--runtime/thread.h74
-rw-r--r--runtime/thread_list.cc2
10 files changed, 64 insertions, 171 deletions
diff --git a/build/Android.common_build.mk b/build/Android.common_build.mk
index fabaaec..b84154b 100644
--- a/build/Android.common_build.mk
+++ b/build/Android.common_build.mk
@@ -233,7 +233,7 @@ art_non_debug_cflags := \
# Cflags for debug ART and ART tools.
art_debug_cflags := \
- -O0 \
+ -O2 \
-DDYNAMIC_ANNOTATIONS_ENABLED=1 \
-DVIXL_DEBUG \
-UNDEBUG
diff --git a/compiler/utils/arm64/assembler_arm64.cc b/compiler/utils/arm64/assembler_arm64.cc
index f068571..7d98a30 100644
--- a/compiler/utils/arm64/assembler_arm64.cc
+++ b/compiler/utils/arm64/assembler_arm64.cc
@@ -526,7 +526,7 @@ void Arm64Assembler::JumpTo(ManagedRegister m_base, Offset offs, ManagedRegister
CHECK(scratch.IsXRegister()) << scratch;
// Remove base and scratch form the temp list - higher level API uses IP1, IP0.
vixl::UseScratchRegisterScope temps(vixl_masm_);
- temps.Exclude(reg_x(base.AsXRegister()));
+ temps.Exclude(reg_x(base.AsXRegister()), reg_x(scratch.AsXRegister()));
___ Ldr(reg_x(scratch.AsXRegister()), MEM_OP(reg_x(base.AsXRegister()), offs.Int32Value()));
___ Br(reg_x(scratch.AsXRegister()));
}
diff --git a/runtime/arch/x86/thread_x86.cc b/runtime/arch/x86/thread_x86.cc
index 56b0b79..b97c143 100644
--- a/runtime/arch/x86/thread_x86.cc
+++ b/runtime/arch/x86/thread_x86.cc
@@ -137,7 +137,7 @@ void Thread::InitCpu() {
}
void Thread::CleanupCpu() {
- MutexLock mu(nullptr, *Locks::modify_ldt_lock_);
+ MutexLock mu(this, *Locks::modify_ldt_lock_);
// Sanity check that reads from %fs point to this Thread*.
Thread* self_check;
diff --git a/runtime/asm_support.h b/runtime/asm_support.h
index 69b26eb..10ed0f4 100644
--- a/runtime/asm_support.h
+++ b/runtime/asm_support.h
@@ -89,11 +89,7 @@ ADD_TEST_EQ(THREAD_ID_OFFSET,
art::Thread::ThinLockIdOffset<__SIZEOF_POINTER__>().Int32Value())
// Offset of field Thread::tlsPtr_.card_table.
-#if defined(__LP64__)
-#define THREAD_CARD_TABLE_OFFSET 160
-#else
-#define THREAD_CARD_TABLE_OFFSET 144
-#endif
+#define THREAD_CARD_TABLE_OFFSET 128
ADD_TEST_EQ(THREAD_CARD_TABLE_OFFSET,
art::Thread::CardTableOffset<__SIZEOF_POINTER__>().Int32Value())
@@ -108,16 +104,11 @@ ADD_TEST_EQ(THREAD_TOP_QUICK_FRAME_OFFSET,
art::Thread::TopOfManagedStackOffset<__SIZEOF_POINTER__>().Int32Value())
// Offset of field Thread::tlsPtr_.managed_stack.top_quick_frame_.
-#if defined(__LP64__)
-#define THREAD_SELF_OFFSET 2112
-#else
-#define THREAD_SELF_OFFSET 1120
-#endif
-// (THREAD_CARD_TABLE_OFFSET + (9 * __SIZEOF_POINTER__))
+#define THREAD_SELF_OFFSET (THREAD_CARD_TABLE_OFFSET + (9 * __SIZEOF_POINTER__))
ADD_TEST_EQ(THREAD_SELF_OFFSET,
art::Thread::SelfOffset<__SIZEOF_POINTER__>().Int32Value())
-#define THREAD_LOCAL_POS_OFFSET (THREAD_CARD_TABLE_OFFSET + 31 * __SIZEOF_POINTER__)
+#define THREAD_LOCAL_POS_OFFSET (THREAD_CARD_TABLE_OFFSET + 147 * __SIZEOF_POINTER__)
ADD_TEST_EQ(THREAD_LOCAL_POS_OFFSET,
art::Thread::ThreadLocalPosOffset<__SIZEOF_POINTER__>().Int32Value())
#define THREAD_LOCAL_END_OFFSET (THREAD_LOCAL_POS_OFFSET + __SIZEOF_POINTER__)
diff --git a/runtime/base/mutex-inl.h b/runtime/base/mutex-inl.h
index 2ae3b19..87840e7 100644
--- a/runtime/base/mutex-inl.h
+++ b/runtime/base/mutex-inl.h
@@ -74,9 +74,7 @@ static inline void CheckUnattachedThread(LockLevel level) NO_THREAD_SAFETY_ANALY
// Ignore logging which may or may not have set up thread data structures.
level == kLoggingLock ||
// Avoid recursive death.
- level == kAbortLock ||
- // A MemMap may be created for thread objects
- level == kMemMapsLock) << level;
+ level == kAbortLock) << level;
}
}
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index 73db6ba..2ea5cb0 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -1949,7 +1949,6 @@ static TwoWordReturn artInvokeCommon(uint32_t method_idx, mirror::Object* this_o
ArtMethod* caller_method, Thread* self, ArtMethod** sp) {
ScopedQuickEntrypointChecks sqec(self);
DCHECK_EQ(*sp, Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsAndArgs));
- DCHECK(caller_method != nullptr);
ArtMethod* method = FindMethodFast(method_idx, this_object, caller_method, access_check, type);
if (UNLIKELY(method == nullptr)) {
const DexFile* dex_file = caller_method->GetDeclaringClass()->GetDexCache()->GetDexFile();
diff --git a/runtime/mem_map.cc b/runtime/mem_map.cc
index e13822a..6566060 100644
--- a/runtime/mem_map.cc
+++ b/runtime/mem_map.cc
@@ -511,29 +511,26 @@ MemMap::~MemMap() {
if (base_begin_ == nullptr && base_size_ == 0) {
return;
}
-
- // Remove it from maps_.
- {
- MutexLock mu(Thread::Current(), *Locks::mem_maps_lock_);
- bool found = false;
- DCHECK(maps_ != nullptr);
- for (auto it = maps_->lower_bound(base_begin_), end = maps_->end();
- it != end && it->first == base_begin_; ++it) {
- if (it->second == this) {
- found = true;
- maps_->erase(it);
- break;
- }
- }
- CHECK(found) << "MemMap not found";
- }
-
if (!reuse_) {
int result = munmap(base_begin_, base_size_);
if (result == -1) {
PLOG(FATAL) << "munmap failed";
}
}
+
+ // Remove it from maps_.
+ MutexLock mu(Thread::Current(), *Locks::mem_maps_lock_);
+ bool found = false;
+ DCHECK(maps_ != nullptr);
+ for (auto it = maps_->lower_bound(base_begin_), end = maps_->end();
+ it != end && it->first == base_begin_; ++it) {
+ if (it->second == this) {
+ found = true;
+ maps_->erase(it);
+ break;
+ }
+ }
+ CHECK(found) << "MemMap not found";
}
MemMap::MemMap(const std::string& name, uint8_t* begin, size_t size, void* base_begin,
diff --git a/runtime/thread.cc b/runtime/thread.cc
index a9173d5..6e8f89c 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -96,11 +96,9 @@ void InitEntryPoints(InterpreterEntryPoints* ipoints, JniEntryPoints* jpoints,
void Thread::InitTlsEntryPoints() {
// Insert a placeholder so we can easily tell if we call an unimplemented entry point.
- uintptr_t* begin = reinterpret_cast<uintptr_t*>(&tlsPtr_.quick_entrypoints);
- uintptr_t* end = reinterpret_cast<uintptr_t*>(
- reinterpret_cast<uint8_t*>(&tlsPtr_.interpreter_entrypoints) +
- sizeof(tlsPtr_.interpreter_entrypoints));
- DCHECK_LT(begin, end);
+ uintptr_t* begin = reinterpret_cast<uintptr_t*>(&tlsPtr_.interpreter_entrypoints);
+ uintptr_t* end = reinterpret_cast<uintptr_t*>(reinterpret_cast<uint8_t*>(&tlsPtr_.quick_entrypoints) +
+ sizeof(tlsPtr_.quick_entrypoints));
for (uintptr_t* it = begin; it != end; ++it) {
*it = reinterpret_cast<uintptr_t>(UnimplementedEntryPoint);
}
@@ -108,90 +106,7 @@ void Thread::InitTlsEntryPoints() {
&tlsPtr_.quick_entrypoints);
}
-static constexpr bool kUseWriteProtectScheme = true;
-
-static size_t GetProtectionOffset() {
- return RoundUp(QUICK_ENTRYPOINT_OFFSET(sizeof(void*), pInstanceofNonTrivial).Uint32Value(), 16);
-}
-
-// Allocate a thread. This might do some magic to use two pages.
-Thread* Thread::AllocateThread(bool is_daemon) {
- if (!kUseWriteProtectScheme) {
- return new Thread(is_daemon);
- }
-
- std::string error_msg;
- MemMap* mem_map = MemMap::MapAnonymous("some thread",
- nullptr,
- 2 * kPageSize,
- PROT_READ | PROT_WRITE,
- false,
- false,
- &error_msg);
- if (mem_map == nullptr) {
- PLOG(FATAL) << error_msg;
- }
-
- uint8_t* second_page_address = mem_map->Begin() + kPageSize;
- const uint32_t offset = GetProtectionOffset();
- uintptr_t start_address = reinterpret_cast<uintptr_t>(second_page_address) - offset;
- DCHECK_GE(start_address, reinterpret_cast<uintptr_t>(mem_map->Begin()) + sizeof(void*));
- void* start_address_ptr = reinterpret_cast<void*>(start_address);
- Thread* t = new (start_address_ptr) Thread(is_daemon);
-
- // Store a pointer to the MemMap at the bottom.
- *reinterpret_cast<MemMap**>(mem_map->Begin()) = mem_map;
-
- return t;
-}
-
-static void ProtectThread(Thread* thread) {
- if (!kUseWriteProtectScheme) {
- return;
- }
-
- uintptr_t thread_addr = reinterpret_cast<uintptr_t>(thread);
- DCHECK_EQ(RoundUp(thread_addr, kPageSize), thread_addr + GetProtectionOffset());
- void* page_address = reinterpret_cast<void*>(RoundUp(thread_addr, kPageSize));
- mprotect(page_address, kPageSize, PROT_READ);
-}
-
-static void UnprotectThread(Thread* thread) {
- if (!kUseWriteProtectScheme) {
- return;
- }
-
- uintptr_t thread_addr = reinterpret_cast<uintptr_t>(thread);
- DCHECK_EQ(RoundUp(thread_addr, kPageSize), thread_addr + GetProtectionOffset());
- void* page_address = reinterpret_cast<void*>(RoundUp(thread_addr, kPageSize));
- mprotect(page_address, kPageSize, PROT_READ | PROT_WRITE);
-}
-
-void Thread::DeleteThread(Thread* thread) {
- if (!kUseWriteProtectScheme) {
- delete thread;
- return;
- }
-
- if (thread == nullptr) {
- return;
- }
-
- UnprotectThread(thread);
- thread->~Thread();
-
- // There should be the MemMap* at the bottom.
- MemMap* mem_map =
- *reinterpret_cast<MemMap**>(RoundDown(reinterpret_cast<uintptr_t>(thread), kPageSize));
-
- delete mem_map;
-}
-
void Thread::InitStringEntryPoints() {
- // Ensure things are writable. This may be a late initialization of the entrypoints for the main
- // thread.
- UnprotectThread(this);
-
ScopedObjectAccess soa(this);
QuickEntryPoints* qpoints = &tlsPtr_.quick_entrypoints;
qpoints->pNewEmptyString = reinterpret_cast<void(*)()>(
@@ -226,9 +141,6 @@ void Thread::InitStringEntryPoints() {
soa.DecodeMethod(WellKnownClasses::java_lang_StringFactory_newStringFromStringBuffer));
qpoints->pNewStringFromStringBuilder = reinterpret_cast<void(*)()>(
soa.DecodeMethod(WellKnownClasses::java_lang_StringFactory_newStringFromStringBuilder));
-
- // This is a good time to protect things, now that all entrypoints are set.
- ProtectThread(this);
}
void Thread::ResetQuickAllocEntryPointsForThread() {
@@ -494,7 +406,7 @@ void Thread::CreateNativeThread(JNIEnv* env, jobject java_peer, size_t stack_siz
return;
}
- Thread* child_thread = AllocateThread(is_daemon);
+ Thread* child_thread = new Thread(is_daemon);
// Use global JNI ref to hold peer live while child thread starts.
child_thread->tlsPtr_.jpeer = env->NewGlobalRef(java_peer);
stack_size = FixStackSize(stack_size);
@@ -542,7 +454,7 @@ void Thread::CreateNativeThread(JNIEnv* env, jobject java_peer, size_t stack_siz
// Manually delete the global reference since Thread::Init will not have been run.
env->DeleteGlobalRef(child_thread->tlsPtr_.jpeer);
child_thread->tlsPtr_.jpeer = nullptr;
- DeleteThread(child_thread);
+ delete child_thread;
child_thread = nullptr;
// TODO: remove from thread group?
env->SetLongField(java_peer, WellKnownClasses::java_lang_Thread_nativePeer, 0);
@@ -613,11 +525,11 @@ Thread* Thread::Attach(const char* thread_name, bool as_daemon, jobject thread_g
return nullptr;
} else {
Runtime::Current()->StartThreadBirth();
- self = AllocateThread(as_daemon);
+ self = new Thread(as_daemon);
bool init_success = self->Init(runtime->GetThreadList(), runtime->GetJavaVM());
Runtime::Current()->EndThreadBirth();
if (!init_success) {
- DeleteThread(self);
+ delete self;
return nullptr;
}
}
diff --git a/runtime/thread.h b/runtime/thread.h
index eb1809d..0e71c08 100644
--- a/runtime/thread.h
+++ b/runtime/thread.h
@@ -531,8 +531,7 @@ class Thread {
private:
template<size_t pointer_size>
static ThreadOffset<pointer_size> ThreadOffsetFromTlsPtr(size_t tls_ptr_offset) {
- size_t base = /* OFFSETOF_MEMBER(Thread, tlsPtr_); */
- pointer_size == 8u ? 160 : 144;
+ size_t base = OFFSETOF_MEMBER(Thread, tlsPtr_);
size_t scale;
size_t shrink;
if (pointer_size == sizeof(void*)) {
@@ -952,8 +951,6 @@ class Thread {
~Thread() LOCKS_EXCLUDED(Locks::mutator_lock_,
Locks::thread_suspend_count_lock_);
void Destroy();
- static Thread* AllocateThread(bool is_daemon);
- static void DeleteThread(Thread* thread);
void CreatePeer(const char* name, bool as_daemon, jobject thread_group);
@@ -1135,31 +1132,19 @@ class Thread {
RuntimeStats stats;
} tls64_;
- // Guards the 'interrupted_' and 'wait_monitor_' members.
- Mutex* wait_mutex_ DEFAULT_MUTEX_ACQUIRED_AFTER;
-
- // Condition variable waited upon during a wait.
- ConditionVariable* wait_cond_ GUARDED_BY(wait_mutex_);
- // Pointer to the monitor lock we're currently waiting on or null if not waiting.
- Monitor* wait_monitor_ GUARDED_BY(wait_mutex_);
-
- // Thread "interrupted" status; stays raised until queried or thrown.
- bool interrupted_ GUARDED_BY(wait_mutex_);
-
- struct PACKED(sizeof(void*)) tls_ptr_sized_values {
- tls_ptr_sized_values() : card_table(nullptr), exception(nullptr), stack_end(nullptr),
- managed_stack(), suspend_trigger(nullptr), jni_env(nullptr), tmp_jni_env(nullptr),
- opeer(nullptr), jpeer(nullptr), stack_begin(nullptr), stack_size(0),
- stack_trace_sample(nullptr), wait_next(nullptr), monitor_enter_object(nullptr),
- top_handle_scope(nullptr), class_loader_override(nullptr), long_jump_context(nullptr),
- instrumentation_stack(nullptr), debug_invoke_req(nullptr), single_step_control(nullptr),
- stacked_shadow_frame_record(nullptr), deoptimization_return_value_stack(nullptr),
- name(nullptr), pthread_self(0),
- last_no_thread_suspension_cause(nullptr), thread_local_start(nullptr),
- thread_local_pos(nullptr), thread_local_end(nullptr), thread_local_objects(0),
- thread_local_alloc_stack_top(nullptr), thread_local_alloc_stack_end(nullptr),
- nested_signal_state(nullptr), flip_function(nullptr), method_verifier(nullptr),
- self(nullptr) {
+ struct PACKED(4) tls_ptr_sized_values {
+ tls_ptr_sized_values() : card_table(nullptr), exception(nullptr), stack_end(nullptr),
+ managed_stack(), suspend_trigger(nullptr), jni_env(nullptr), tmp_jni_env(nullptr),
+ self(nullptr), opeer(nullptr), jpeer(nullptr), stack_begin(nullptr), stack_size(0),
+ stack_trace_sample(nullptr), wait_next(nullptr), monitor_enter_object(nullptr),
+ top_handle_scope(nullptr), class_loader_override(nullptr), long_jump_context(nullptr),
+ instrumentation_stack(nullptr), debug_invoke_req(nullptr), single_step_control(nullptr),
+ stacked_shadow_frame_record(nullptr), deoptimization_return_value_stack(nullptr),
+ name(nullptr), pthread_self(0),
+ last_no_thread_suspension_cause(nullptr), thread_local_start(nullptr),
+ thread_local_pos(nullptr), thread_local_end(nullptr), thread_local_objects(0),
+ thread_local_alloc_stack_top(nullptr), thread_local_alloc_stack_end(nullptr),
+ nested_signal_state(nullptr), flip_function(nullptr), method_verifier(nullptr) {
std::fill(held_mutexes, held_mutexes + kLockLevelCount, nullptr);
}
@@ -1187,6 +1172,11 @@ class Thread {
// created thread.
JNIEnvExt* tmp_jni_env;
+ // Initialized to "this". On certain architectures (such as x86) reading off of Thread::Current
+ // is easy but getting the address of Thread::Current is hard. This field can be read off of
+ // Thread::Current to give the address.
+ Thread* self;
+
// Our managed peer (an instance of java.lang.Thread). The jobject version is used during thread
// start up, until the thread is registered and the local opeer_ is used.
mirror::Object* opeer;
@@ -1248,6 +1238,12 @@ class Thread {
// Locks::thread_suspend_count_lock_.
Closure* checkpoint_functions[kMaxCheckpoints];
+ // Entrypoint function pointers.
+ // TODO: move this to more of a global offset table model to avoid per-thread duplication.
+ InterpreterEntryPoints interpreter_entrypoints;
+ JniEntryPoints jni_entrypoints;
+ QuickEntryPoints quick_entrypoints;
+
// Thread-local allocation pointer.
uint8_t* thread_local_start;
uint8_t* thread_local_pos;
@@ -1272,18 +1268,18 @@ class Thread {
// Current method verifier, used for root marking.
verifier::MethodVerifier* method_verifier;
+ } tlsPtr_;
- // Entrypoint function pointers.
- // TODO: move this to more of a global offset table model to avoid per-thread duplication.
- QuickEntryPoints quick_entrypoints;
- JniEntryPoints jni_entrypoints;
- InterpreterEntryPoints interpreter_entrypoints;
+ // Guards the 'interrupted_' and 'wait_monitor_' members.
+ Mutex* wait_mutex_ DEFAULT_MUTEX_ACQUIRED_AFTER;
- // Initialized to "this". On certain architectures (such as x86) reading off of Thread::Current
- // is easy but getting the address of Thread::Current is hard. This field can be read off of
- // Thread::Current to give the address.
- Thread* self;
- } tlsPtr_;
+ // Condition variable waited upon during a wait.
+ ConditionVariable* wait_cond_ GUARDED_BY(wait_mutex_);
+ // Pointer to the monitor lock we're currently waiting on or null if not waiting.
+ Monitor* wait_monitor_ GUARDED_BY(wait_mutex_);
+
+ // Thread "interrupted" status; stays raised until queried or thrown.
+ bool interrupted_ GUARDED_BY(wait_mutex_);
friend class Dbg; // For SetStateUnsafe.
friend class gc::collector::SemiSpace; // For getting stack traces.
diff --git a/runtime/thread_list.cc b/runtime/thread_list.cc
index 7d49112..b697b43 100644
--- a/runtime/thread_list.cc
+++ b/runtime/thread_list.cc
@@ -1148,7 +1148,7 @@ void ThreadList::Unregister(Thread* self) {
}
// We failed to remove the thread due to a suspend request, loop and try again.
}
- Thread::DeleteThread(self);
+ delete self;
// Release the thread ID after the thread is finished and deleted to avoid cases where we can
// temporarily have multiple threads with the same thread id. When this occurs, it causes