diff options
author | Ian Rogers <irogers@google.com> | 2014-09-10 14:44:24 -0700 |
---|---|---|
committer | Ian Rogers <irogers@google.com> | 2014-09-12 14:57:53 -0700 |
commit | 7b078e8c04f3e1451dbdd18543c8b9692b5b067e (patch) | |
tree | 414229c6b87eb20ea24c40780752da5a3999a49a /runtime/entrypoints | |
parent | f79ba17defbd9342e44ab9f3de0807054673d3c9 (diff) | |
download | art-7b078e8c04f3e1451dbdd18543c8b9692b5b067e.zip art-7b078e8c04f3e1451dbdd18543c8b9692b5b067e.tar.gz art-7b078e8c04f3e1451dbdd18543c8b9692b5b067e.tar.bz2 |
Compile time performance improvements focusing on interpret-only.
Reduce virtual method dispatch in the method verifier and make more code
inline-able.
Add a StringPiece with const char* equality operator to avoid redundant
StringPieces and strlens.
Remove back link from register line to verifier and pass as argument to reduce
size of RegisterLine.
Remove instruction length from instruction flags and compute from the
instruction, again to reduce size.
Add suspend checks to resolve and verify to allow for more easy monitor
inflation and reduce contention on Locks::thread_list_suspend_thread_lock_.
Change ThrowEarlierClassFailure to throw pre-allocated exception.
Avoid calls to Thread::Current() by passing self.
Template specialize IsValidClassName.
Make ANR reporting with SIGQUIT run using checkpoints rather than suspending
all threads. This makes the stack/lock analysis less lock error prone.
Extra Barrier assertions and condition variable time out is now returned as a
boolean both from Barrier and ConditionVariable::Wait.
2 threaded host x86-64 interpret-only numbers from 341 samples:
Before change: Avg 176.137ms 99% CI 3.468ms to 1060.770ms
After change: Avg 139.163% 99% CI 3.027ms to 838.257ms
Reduction in average compile time after change is 20.9%.
Slow-down without change is 26.5%.
Bug: 17471626 - Fix bug where RegTypeCache::JavaLangObject/String/Class/Throwable
could return unresolved type when class loading is disabled.
Bug: 17398101
Change-Id: Id59ce3cc520701c6ecf612f7152498107bc40684
Diffstat (limited to 'runtime/entrypoints')
8 files changed, 18 insertions, 42 deletions
diff --git a/runtime/entrypoints/entrypoint_utils-inl.h b/runtime/entrypoints/entrypoint_utils-inl.h index 38842cb..4ef7d74 100644 --- a/runtime/entrypoints/entrypoint_utils-inl.h +++ b/runtime/entrypoints/entrypoint_utils-inl.h @@ -79,7 +79,7 @@ static inline mirror::Class* CheckObjectAlloc(uint32_t type_idx, // has changed and to null-check the return value in case the // initialization fails. *slow_path = true; - if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(h_klass, true, true)) { + if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(self, h_klass, true, true)) { DCHECK(self->IsExceptionPending()); return nullptr; // Failure } else { @@ -107,7 +107,7 @@ static inline mirror::Class* CheckClassInitializedForObjectAlloc(mirror::Class* // has changed and to null-check the return value in case the // initialization fails. *slow_path = true; - if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(h_class, true, true)) { + if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(self, h_class, true, true)) { DCHECK(self->IsExceptionPending()); return nullptr; // Failure } @@ -324,7 +324,7 @@ static inline mirror::ArtField* FindFieldFromCode(uint32_t field_idx, mirror::Ar } else { StackHandleScope<1> hs(self); Handle<mirror::Class> h_class(hs.NewHandle(fields_class)); - if (LIKELY(class_linker->EnsureInitialized(h_class, true, true))) { + if (LIKELY(class_linker->EnsureInitialized(self, h_class, true, true))) { // Otherwise let's ensure the class is initialized before resolving the field. return resolved_field; } @@ -603,7 +603,7 @@ static inline mirror::Class* ResolveVerifyAndClinit(uint32_t type_idx, } StackHandleScope<1> hs(self); Handle<mirror::Class> h_class(hs.NewHandle(klass)); - if (!class_linker->EnsureInitialized(h_class, true, true)) { + if (!class_linker->EnsureInitialized(self, h_class, true, true)) { CHECK(self->IsExceptionPending()); return nullptr; // Failure - Indicate to caller to deliver exception } @@ -640,18 +640,6 @@ static inline void UnlockJniSynchronizedMethod(jobject locked, Thread* self) { } } -static inline void CheckSuspend(Thread* thread) { - for (;;) { - if (thread->ReadFlag(kCheckpointRequest)) { - thread->RunCheckpointFunction(); - } else if (thread->ReadFlag(kSuspendRequest)) { - thread->FullSuspendCheck(); - } else { - break; - } - } -} - template <typename INT_TYPE, typename FLOAT_TYPE> static inline INT_TYPE art_float_to_integral(FLOAT_TYPE f) { const INT_TYPE kMaxInt = static_cast<INT_TYPE>(std::numeric_limits<INT_TYPE>::max()); diff --git a/runtime/entrypoints/entrypoint_utils.h b/runtime/entrypoints/entrypoint_utils.h index 44c89ad..08edecf 100644 --- a/runtime/entrypoints/entrypoint_utils.h +++ b/runtime/entrypoints/entrypoint_utils.h @@ -174,8 +174,6 @@ static inline void UnlockJniSynchronizedMethod(jobject locked, Thread* self) void CheckReferenceResult(mirror::Object* o, Thread* self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); -static inline void CheckSuspend(Thread* thread) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - JValue InvokeProxyInvocationHandler(ScopedObjectAccessAlreadyRunnable& soa, const char* shorty, jobject rcvr_jobj, jobject interface_art_method_jobj, std::vector<jvalue>& args) diff --git a/runtime/entrypoints/interpreter/interpreter_entrypoints.cc b/runtime/entrypoints/interpreter/interpreter_entrypoints.cc index 64faf76..b617636 100644 --- a/runtime/entrypoints/interpreter/interpreter_entrypoints.cc +++ b/runtime/entrypoints/interpreter/interpreter_entrypoints.cc @@ -36,7 +36,8 @@ extern "C" void artInterpreterToCompiledCodeBridge(Thread* self, MethodHelper& m self->PushShadowFrame(shadow_frame); StackHandleScope<1> hs(self); Handle<mirror::Class> h_class(hs.NewHandle(declaringClass)); - if (UNLIKELY(!Runtime::Current()->GetClassLinker()->EnsureInitialized(h_class, true, true))) { + if (UNLIKELY(!Runtime::Current()->GetClassLinker()->EnsureInitialized(self, h_class, true, + true))) { self->PopShadowFrame(); DCHECK(self->IsExceptionPending()); return; diff --git a/runtime/entrypoints/portable/portable_thread_entrypoints.cc b/runtime/entrypoints/portable/portable_thread_entrypoints.cc index 23e1c36..7d5ccc2 100644 --- a/runtime/entrypoints/portable/portable_thread_entrypoints.cc +++ b/runtime/entrypoints/portable/portable_thread_entrypoints.cc @@ -14,11 +14,9 @@ * limitations under the License. */ -#include "entrypoints/entrypoint_utils-inl.h" -#include "mirror/art_method.h" -#include "mirror/object-inl.h" #include "verifier/dex_gc_map.h" #include "stack.h" +#include "thread-inl.h" namespace art { @@ -71,7 +69,7 @@ class ShadowFrameCopyVisitor : public StackVisitor { extern "C" void art_portable_test_suspend_from_code(Thread* self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - CheckSuspend(self); + self->CheckSuspend(); if (Runtime::Current()->GetInstrumentation()->ShouldPortableCodeDeoptimize()) { // Save out the shadow frame to the heap ShadowFrameCopyVisitor visitor(self); diff --git a/runtime/entrypoints/portable/portable_trampoline_entrypoints.cc b/runtime/entrypoints/portable/portable_trampoline_entrypoints.cc index 9f75b0f..7f6144b 100644 --- a/runtime/entrypoints/portable/portable_trampoline_entrypoints.cc +++ b/runtime/entrypoints/portable/portable_trampoline_entrypoints.cc @@ -215,7 +215,7 @@ extern "C" uint64_t artPortableToInterpreterBridge(mirror::ArtMethod* method, Th if (method->IsStatic() && !method->GetDeclaringClass()->IsInitialized()) { // Ensure static method's class is initialized. Handle<mirror::Class> h_class(hs.NewHandle(method->GetDeclaringClass())); - if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(h_class, true, true)) { + if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(self, h_class, true, true)) { DCHECK(Thread::Current()->IsExceptionPending()); self->PopManagedStackFragment(fragment); return 0; @@ -399,7 +399,7 @@ extern "C" const void* artPortableResolutionTrampoline(mirror::ArtMethod* called // Ensure that the called method's class is initialized. StackHandleScope<1> hs(self); Handle<mirror::Class> called_class(hs.NewHandle(called->GetDeclaringClass())); - linker->EnsureInitialized(called_class, true, true); + linker->EnsureInitialized(self, called_class, true, true); if (LIKELY(called_class->IsInitialized())) { code = called->GetEntryPointFromPortableCompiledCode(); // TODO: remove this after we solve the link issue. diff --git a/runtime/entrypoints/quick/quick_jni_entrypoints.cc b/runtime/entrypoints/quick/quick_jni_entrypoints.cc index 6537249..87f04bb 100644 --- a/runtime/entrypoints/quick/quick_jni_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_jni_entrypoints.cc @@ -14,15 +14,8 @@ * limitations under the License. */ -#include "dex_file-inl.h" -#include "entrypoints/entrypoint_utils-inl.h" -#include "mirror/art_method-inl.h" -#include "mirror/class-inl.h" -#include "mirror/object.h" #include "mirror/object-inl.h" -#include "mirror/object_array-inl.h" -#include "scoped_thread_state_change.h" -#include "thread.h" +#include "thread-inl.h" #include "verify_object-inl.h" namespace art { @@ -56,7 +49,7 @@ static void GoToRunnable(Thread* self) NO_THREAD_SAFETY_ANALYSIS { // In fast JNI mode we never transitioned out of runnable. Perform a suspend check if there // is a flag raised. DCHECK(Locks::mutator_lock_->IsSharedHeld(self)); - CheckSuspend(self); + self->CheckSuspend(); } } diff --git a/runtime/entrypoints/quick/quick_thread_entrypoints.cc b/runtime/entrypoints/quick/quick_thread_entrypoints.cc index 118cd7f..ea75fb6 100644 --- a/runtime/entrypoints/quick/quick_thread_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_thread_entrypoints.cc @@ -15,17 +15,15 @@ */ #include "callee_save_frame.h" -#include "entrypoints/entrypoint_utils-inl.h" -#include "thread.h" -#include "thread_list.h" +#include "thread-inl.h" namespace art { -extern "C" void artTestSuspendFromCode(Thread* thread, StackReference<mirror::ArtMethod>* sp) +extern "C" void artTestSuspendFromCode(Thread* self, StackReference<mirror::ArtMethod>* sp) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { // Called when suspend count check value is 0 and thread->suspend_count_ != 0 - FinishCalleeSaveFrameSetup(thread, sp, Runtime::kRefsOnly); - CheckSuspend(thread); + FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly); + self->CheckSuspend(); } } // namespace art diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc index dfd2e11..95dd8be 100644 --- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc @@ -496,7 +496,7 @@ extern "C" uint64_t artQuickToInterpreterBridge(mirror::ArtMethod* method, Threa // Ensure static method's class is initialized. StackHandleScope<1> hs(self); Handle<mirror::Class> h_class(hs.NewHandle(method->GetDeclaringClass())); - if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(h_class, true, true)) { + if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(self, h_class, true, true)) { DCHECK(Thread::Current()->IsExceptionPending()) << PrettyMethod(method); self->PopManagedStackFragment(fragment); return 0; @@ -808,7 +808,7 @@ extern "C" const void* artQuickResolutionTrampoline(mirror::ArtMethod* called, // Ensure that the called method's class is initialized. StackHandleScope<1> hs(soa.Self()); Handle<mirror::Class> called_class(hs.NewHandle(called->GetDeclaringClass())); - linker->EnsureInitialized(called_class, true, true); + linker->EnsureInitialized(soa.Self(), called_class, true, true); if (LIKELY(called_class->IsInitialized())) { code = called->GetEntryPointFromQuickCompiledCode(); } else if (called_class->IsInitializing()) { |