diff options
author | Mingyao Yang <mingyao@google.com> | 2014-05-15 17:02:16 -0700 |
---|---|---|
committer | Ian Rogers <irogers@google.com> | 2014-07-11 17:17:10 -0700 |
commit | 98d1cc8033251c93786e2fa8c59a2e555a9493be (patch) | |
tree | f0a76b8fff060ee484af09028da65a8339d57057 /runtime/mirror/class.cc | |
parent | aebf3cda094f34cf846d19a7724bdc8005267c95 (diff) | |
download | art-98d1cc8033251c93786e2fa8c59a2e555a9493be.zip art-98d1cc8033251c93786e2fa8c59a2e555a9493be.tar.gz art-98d1cc8033251c93786e2fa8c59a2e555a9493be.tar.bz2 |
Improve performance of invokevirtual/invokeinterface with embedded imt/vtable
Add an embedded version of imt/vtable into class object. Both tables start at
fixed offset within class object so method/entry point can be loaded directly
from class object for invokeinterface/invokevirtual.
Bug: 8142917
Change-Id: I4240d58cfbe9250107c95c0708c036854c455968
Diffstat (limited to 'runtime/mirror/class.cc')
-rw-r--r-- | runtime/mirror/class.cc | 137 |
1 files changed, 99 insertions, 38 deletions
diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc index c6472c6..371e984 100644 --- a/runtime/mirror/class.cc +++ b/runtime/mirror/class.cc @@ -63,7 +63,8 @@ void Class::SetStatus(Status new_status, Thread* self) { ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); bool class_linker_initialized = class_linker != nullptr && class_linker->IsInitialized(); if (LIKELY(class_linker_initialized)) { - if (UNLIKELY(new_status <= old_status && new_status != kStatusError)) { + if (UNLIKELY(new_status <= old_status && new_status != kStatusError && + new_status != kStatusRetired)) { LOG(FATAL) << "Unexpected change back of class status for " << PrettyClass(this) << " " << old_status << " -> " << new_status; } @@ -113,11 +114,27 @@ void Class::SetStatus(Status new_status, Thread* self) { } else { SetField32Volatile<false>(OFFSET_OF_OBJECT_MEMBER(Class, status_), new_status); } - // Classes that are being resolved or initialized need to notify waiters that the class status - // changed. See ClassLinker::EnsureResolved and ClassLinker::WaitForInitializeClass. - if ((old_status >= kStatusResolved || new_status >= kStatusResolved) && - class_linker_initialized) { - NotifyAll(self); + + if (!class_linker_initialized) { + // When the class linker is being initialized its single threaded and by definition there can be + // no waiters. During initialization classes may appear temporary but won't be retired as their + // size was statically computed. + } else { + // Classes that are being resolved or initialized need to notify waiters that the class status + // changed. See ClassLinker::EnsureResolved and ClassLinker::WaitForInitializeClass. + if (IsTemp()) { + // Class is a temporary one, ensure that waiters for resolution get notified of retirement + // so that they can grab the new version of the class from the class linker's table. + CHECK_LT(new_status, kStatusResolved) << PrettyDescriptor(this); + if (new_status == kStatusRetired || new_status == kStatusError) { + NotifyAll(self); + } + } else { + CHECK_NE(new_status, kStatusRetired); + if (old_status >= kStatusResolved || new_status >= kStatusResolved) { + NotifyAll(self); + } + } } } @@ -217,35 +234,39 @@ void Class::DumpClass(std::ostream& os, int flags) { os << StringPrintf(" %2zd: %s (cl=%p)\n", i, PrettyClass(interface).c_str(), cl); } } - // After this point, this may have moved due to GetDirectInterface. - os << " vtable (" << h_this->NumVirtualMethods() << " entries, " - << (h_super.Get() != nullptr ? h_super->NumVirtualMethods() : 0) << " in super):\n"; - for (size_t i = 0; i < NumVirtualMethods(); ++i) { - os << StringPrintf(" %2zd: %s\n", i, - PrettyMethod(h_this->GetVirtualMethodDuringLinking(i)).c_str()); - } - os << " direct methods (" << h_this->NumDirectMethods() << " entries):\n"; - for (size_t i = 0; i < h_this->NumDirectMethods(); ++i) { - os << StringPrintf(" %2zd: %s\n", i, PrettyMethod(h_this->GetDirectMethod(i)).c_str()); - } - if (h_this->NumStaticFields() > 0) { - os << " static fields (" << h_this->NumStaticFields() << " entries):\n"; - if (h_this->IsResolved() || h_this->IsErroneous()) { - for (size_t i = 0; i < h_this->NumStaticFields(); ++i) { - os << StringPrintf(" %2zd: %s\n", i, PrettyField(h_this->GetStaticField(i)).c_str()); + if (!IsLoaded()) { + os << " class not yet loaded"; + } else { + // After this point, this may have moved due to GetDirectInterface. + os << " vtable (" << h_this->NumVirtualMethods() << " entries, " + << (h_super.Get() != nullptr ? h_super->NumVirtualMethods() : 0) << " in super):\n"; + for (size_t i = 0; i < NumVirtualMethods(); ++i) { + os << StringPrintf(" %2zd: %s\n", i, + PrettyMethod(h_this->GetVirtualMethodDuringLinking(i)).c_str()); + } + os << " direct methods (" << h_this->NumDirectMethods() << " entries):\n"; + for (size_t i = 0; i < h_this->NumDirectMethods(); ++i) { + os << StringPrintf(" %2zd: %s\n", i, PrettyMethod(h_this->GetDirectMethod(i)).c_str()); + } + if (h_this->NumStaticFields() > 0) { + os << " static fields (" << h_this->NumStaticFields() << " entries):\n"; + if (h_this->IsResolved() || h_this->IsErroneous()) { + for (size_t i = 0; i < h_this->NumStaticFields(); ++i) { + os << StringPrintf(" %2zd: %s\n", i, PrettyField(h_this->GetStaticField(i)).c_str()); + } + } else { + os << " <not yet available>"; } - } else { - os << " <not yet available>"; } - } - if (h_this->NumInstanceFields() > 0) { - os << " instance fields (" << h_this->NumInstanceFields() << " entries):\n"; - if (h_this->IsResolved() || h_this->IsErroneous()) { - for (size_t i = 0; i < h_this->NumInstanceFields(); ++i) { - os << StringPrintf(" %2zd: %s\n", i, PrettyField(h_this->GetInstanceField(i)).c_str()); + if (h_this->NumInstanceFields() > 0) { + os << " instance fields (" << h_this->NumInstanceFields() << " entries):\n"; + if (h_this->IsResolved() || h_this->IsErroneous()) { + for (size_t i = 0; i < h_this->NumInstanceFields(); ++i) { + os << StringPrintf(" %2zd: %s\n", i, PrettyField(h_this->GetInstanceField(i)).c_str()); + } + } else { + os << " <not yet available>"; } - } else { - os << " <not yet available>"; } } } @@ -721,9 +742,7 @@ uint32_t Class::NumDirectInterfaces() { } else if (IsArrayClass()) { return 2; } else if (IsProxyClass()) { - mirror::SynthesizedProxyClass* proxy_class= - reinterpret_cast<mirror::SynthesizedProxyClass*>(this); - mirror::ObjectArray<mirror::Class>* interfaces = proxy_class->GetInterfaces(); + mirror::ObjectArray<mirror::Class>* interfaces = GetInterfaces(); return interfaces != nullptr ? interfaces->GetLength() : 0; } else { const DexFile::TypeList* interfaces = GetInterfaceTypeList(); @@ -753,9 +772,7 @@ mirror::Class* Class::GetDirectInterface(Thread* self, Handle<mirror::Class> kla return class_linker->FindSystemClass(self, "Ljava/io/Serializable;"); } } else if (klass->IsProxyClass()) { - mirror::SynthesizedProxyClass* proxy_class = - reinterpret_cast<mirror::SynthesizedProxyClass*>(klass.Get()); - mirror::ObjectArray<mirror::Class>* interfaces = proxy_class->GetInterfaces(); + mirror::ObjectArray<mirror::Class>* interfaces = klass.Get()->GetInterfaces(); DCHECK(interfaces != nullptr); return interfaces->Get(idx); } else { @@ -798,5 +815,49 @@ const DexFile::TypeList* Class::GetInterfaceTypeList() { return GetDexFile().GetInterfacesList(*class_def); } +void Class::PopulateEmbeddedImtAndVTable() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + ObjectArray<ArtMethod>* table = GetImTable(); + if (table != nullptr) { + for (uint32_t i = 0; i < kImtSize; i++) { + SetEmbeddedImTableEntry(i, table->Get(i)); + } + } + + table = GetVTableDuringLinking(); + CHECK(table != nullptr); + for (int32_t i = 0; i < table->GetLength(); i++) { + SetEmbeddedVTableEntry(i, table->Get(i)); + } +} + +Class* Class::CopyOf(Thread* self, int32_t new_length) { + DCHECK_GE(new_length, static_cast<int32_t>(sizeof(Class))); + // We may get copied by a compacting GC. + StackHandleScope<1> hs(self); + Handle<mirror::Class> h_this(hs.NewHandle(this)); + gc::Heap* heap = Runtime::Current()->GetHeap(); + InitializeClassVisitor visitor(new_length); + + mirror::Object* new_class = + kMovingClasses ? heap->AllocObject<true>(self, java_lang_Class_, new_length, visitor) + : heap->AllocNonMovableObject<true>(self, java_lang_Class_, new_length, visitor); + if (UNLIKELY(new_class == nullptr)) { + CHECK(self->IsExceptionPending()); // Expect an OOME. + return NULL; + } + + mirror::Class* new_class_obj = new_class->AsClass(); + memcpy(new_class_obj, h_this.Get(), sizeof(Class)); + + new_class_obj->SetStatus(kStatusResolving, self); + new_class_obj->PopulateEmbeddedImtAndVTable(); + // Correct some fields. + new_class_obj->SetLockWord(LockWord(), false); + new_class_obj->SetClassSize(new_length); + + Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(new_class_obj); + return new_class_obj; +} + } // namespace mirror } // namespace art |