summaryrefslogtreecommitdiffstats
path: root/runtime/mirror/class.cc
diff options
context:
space:
mode:
authorMingyao Yang <mingyao@google.com>2014-05-15 17:02:16 -0700
committerIan Rogers <irogers@google.com>2014-07-11 17:17:10 -0700
commit98d1cc8033251c93786e2fa8c59a2e555a9493be (patch)
treef0a76b8fff060ee484af09028da65a8339d57057 /runtime/mirror/class.cc
parentaebf3cda094f34cf846d19a7724bdc8005267c95 (diff)
downloadart-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.cc137
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