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
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 5180e34..85ce10a 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -55,6 +55,7 @@
#include "mirror/object_array-inl.h"
#include "mirror/proxy.h"
#include "mirror/stack_trace_element.h"
+#include "mirror/string-inl.h"
#include "object_utils.h"
#include "os.h"
#include "runtime.h"
@@ -207,7 +208,8 @@
heap->IncrementDisableMovingGC(self);
StackHandleScope<64> hs(self); // 64 is picked arbitrarily.
Handle<mirror::Class> java_lang_Class(hs.NewHandle(down_cast<mirror::Class*>(
- heap->AllocNonMovableObject<true>(self, nullptr, sizeof(mirror::ClassClass),
+ heap->AllocNonMovableObject<true>(self, nullptr,
+ mirror::Class::ClassClassSize(),
VoidFunctor()))));
CHECK(java_lang_Class.Get() != NULL);
mirror::Class::SetClassClass(java_lang_Class.Get());
@@ -215,43 +217,44 @@
if (kUseBakerOrBrooksReadBarrier) {
java_lang_Class->AssertReadBarrierPointer();
}
- java_lang_Class->SetClassSize(sizeof(mirror::ClassClass));
+ java_lang_Class->SetClassSize(mirror::Class::ClassClassSize());
heap->DecrementDisableMovingGC(self);
// AllocClass(mirror::Class*) can now be used
// Class[] is used for reflection support.
- Handle<mirror::Class> class_array_class(
- hs.NewHandle(AllocClass(self, java_lang_Class.Get(), sizeof(mirror::Class))));
+ Handle<mirror::Class> class_array_class(hs.NewHandle(
+ AllocClass(self, java_lang_Class.Get(), mirror::ObjectArray<mirror::Class>::ClassSize())));
class_array_class->SetComponentType(java_lang_Class.Get());
// java_lang_Object comes next so that object_array_class can be created.
- Handle<mirror::Class> java_lang_Object(
- hs.NewHandle(AllocClass(self, java_lang_Class.Get(), sizeof(mirror::Class))));
+ Handle<mirror::Class> java_lang_Object(hs.NewHandle(
+ AllocClass(self, java_lang_Class.Get(), mirror::Object::ClassSize())));
CHECK(java_lang_Object.Get() != NULL);
// backfill Object as the super class of Class.
java_lang_Class->SetSuperClass(java_lang_Object.Get());
java_lang_Object->SetStatus(mirror::Class::kStatusLoaded, self);
// Object[] next to hold class roots.
- Handle<mirror::Class> object_array_class(
- hs.NewHandle(AllocClass(self, java_lang_Class.Get(), sizeof(mirror::Class))));
+ Handle<mirror::Class> object_array_class(hs.NewHandle(
+ AllocClass(self, java_lang_Class.Get(), mirror::ObjectArray<mirror::Object>::ClassSize())));
object_array_class->SetComponentType(java_lang_Object.Get());
- // Setup the char class to be used for char[].
- Handle<mirror::Class> char_class(hs.NewHandle(AllocClass(self, java_lang_Class.Get(),
- sizeof(mirror::Class))));
+ // Setup the char (primitive) class to be used for char[].
+ Handle<mirror::Class> char_class(hs.NewHandle(
+ AllocClass(self, java_lang_Class.Get(), mirror::Class::PrimitiveClassSize())));
// Setup the char[] class to be used for String.
- Handle<mirror::Class> char_array_class(hs.NewHandle(AllocClass(self, java_lang_Class.Get(),
- sizeof(mirror::Class))));
+ Handle<mirror::Class> char_array_class(hs.NewHandle(
+ AllocClass(self, java_lang_Class.Get(),
+ mirror::Array::ClassSize())));
char_array_class->SetComponentType(char_class.Get());
mirror::CharArray::SetArrayClass(char_array_class.Get());
// Setup String.
- Handle<mirror::Class> java_lang_String(hs.NewHandle(AllocClass(self, java_lang_Class.Get(),
- sizeof(mirror::StringClass))));
+ Handle<mirror::Class> java_lang_String(hs.NewHandle(
+ AllocClass(self, java_lang_Class.Get(), mirror::String::ClassSize())));
mirror::String::SetClass(java_lang_String.Get());
- java_lang_String->SetObjectSize(sizeof(mirror::String));
+ java_lang_String->SetObjectSize(mirror::String::InstanceSize());
java_lang_String->SetStatus(mirror::Class::kStatusResolved, self);
// Create storage for root classes, save away our work so far (requires descriptors).
@@ -279,8 +282,8 @@
array_iftable_ = AllocIfTable(self, 2);
// Create int array type for AllocDexCache (done in AppendToBootClassPath).
- Handle<mirror::Class> int_array_class(
- hs.NewHandle(AllocClass(self, java_lang_Class.Get(), sizeof(mirror::Class))));
+ Handle<mirror::Class> int_array_class(hs.NewHandle(
+ AllocClass(self, java_lang_Class.Get(), mirror::Array::ClassSize())));
int_array_class->SetComponentType(GetClassRoot(kPrimitiveInt));
mirror::IntArray::SetArrayClass(int_array_class.Get());
SetClassRoot(kIntArrayClass, int_array_class.Get());
@@ -288,44 +291,47 @@
// now that these are registered, we can use AllocClass() and AllocObjectArray
// Set up DexCache. This cannot be done later since AppendToBootClassPath calls AllocDexCache.
- Handle<mirror::Class> java_lang_DexCache(
- hs.NewHandle(AllocClass(self, java_lang_Class.Get(), sizeof(mirror::DexCacheClass))));
+ Handle<mirror::Class> java_lang_DexCache(hs.NewHandle(
+ AllocClass(self, java_lang_Class.Get(), mirror::DexCache::ClassSize())));
SetClassRoot(kJavaLangDexCache, java_lang_DexCache.Get());
- java_lang_DexCache->SetObjectSize(sizeof(mirror::DexCache));
+ java_lang_DexCache->SetObjectSize(mirror::DexCache::InstanceSize());
java_lang_DexCache->SetStatus(mirror::Class::kStatusResolved, self);
// Constructor, Field, Method, and AbstractMethod are necessary so
// that FindClass can link members.
- Handle<mirror::Class> java_lang_reflect_ArtField(
- hs.NewHandle(AllocClass(self, java_lang_Class.Get(), sizeof(mirror::ArtFieldClass))));
+ Handle<mirror::Class> java_lang_reflect_ArtField(hs.NewHandle(
+ AllocClass(self, java_lang_Class.Get(), mirror::ArtField::ClassSize())));
CHECK(java_lang_reflect_ArtField.Get() != NULL);
- java_lang_reflect_ArtField->SetObjectSize(sizeof(mirror::ArtField));
+ java_lang_reflect_ArtField->SetObjectSize(mirror::ArtField::InstanceSize());
SetClassRoot(kJavaLangReflectArtField, java_lang_reflect_ArtField.Get());
java_lang_reflect_ArtField->SetStatus(mirror::Class::kStatusResolved, self);
mirror::ArtField::SetClass(java_lang_reflect_ArtField.Get());
- Handle<mirror::Class> java_lang_reflect_ArtMethod(
- hs.NewHandle(AllocClass(self, java_lang_Class.Get(), sizeof(mirror::ArtMethodClass))));
+ Handle<mirror::Class> java_lang_reflect_ArtMethod(hs.NewHandle(
+ AllocClass(self, java_lang_Class.Get(), mirror::ArtMethod::ClassSize())));
CHECK(java_lang_reflect_ArtMethod.Get() != NULL);
- java_lang_reflect_ArtMethod->SetObjectSize(sizeof(mirror::ArtMethod));
+ java_lang_reflect_ArtMethod->SetObjectSize(mirror::ArtMethod::InstanceSize());
SetClassRoot(kJavaLangReflectArtMethod, java_lang_reflect_ArtMethod.Get());
java_lang_reflect_ArtMethod->SetStatus(mirror::Class::kStatusResolved, self);
mirror::ArtMethod::SetClass(java_lang_reflect_ArtMethod.Get());
// Set up array classes for string, field, method
- Handle<mirror::Class> object_array_string(
- hs.NewHandle(AllocClass(self, java_lang_Class.Get(), sizeof(mirror::Class))));
+ Handle<mirror::Class> object_array_string(hs.NewHandle(
+ AllocClass(self, java_lang_Class.Get(),
+ mirror::ObjectArray<mirror::String>::ClassSize())));
object_array_string->SetComponentType(java_lang_String.Get());
SetClassRoot(kJavaLangStringArrayClass, object_array_string.Get());
- Handle<mirror::Class> object_array_art_method(
- hs.NewHandle(AllocClass(self, java_lang_Class.Get(), sizeof(mirror::Class))));
+ Handle<mirror::Class> object_array_art_method(hs.NewHandle(
+ AllocClass(self, java_lang_Class.Get(),
+ mirror::ObjectArray<mirror::ArtMethod>::ClassSize())));
object_array_art_method->SetComponentType(java_lang_reflect_ArtMethod.Get());
SetClassRoot(kJavaLangReflectArtMethodArrayClass, object_array_art_method.Get());
- Handle<mirror::Class> object_array_art_field(
- hs.NewHandle(AllocClass(self, java_lang_Class.Get(), sizeof(mirror::Class))));
+ Handle<mirror::Class> object_array_art_field(hs.NewHandle(
+ AllocClass(self, java_lang_Class.Get(),
+ mirror::ObjectArray<mirror::ArtField>::ClassSize())));
object_array_art_field->SetComponentType(java_lang_reflect_ArtField.Get());
SetClassRoot(kJavaLangReflectArtFieldArrayClass, object_array_art_field.Get());
@@ -359,16 +365,19 @@
java_lang_Object->SetStatus(mirror::Class::kStatusNotReady, self);
mirror::Class* Object_class = FindSystemClass(self, "Ljava/lang/Object;");
CHECK_EQ(java_lang_Object.Get(), Object_class);
- CHECK_EQ(java_lang_Object->GetObjectSize(), sizeof(mirror::Object));
+ CHECK_EQ(java_lang_Object->GetObjectSize(), mirror::Object::InstanceSize());
java_lang_String->SetStatus(mirror::Class::kStatusNotReady, self);
mirror::Class* String_class = FindSystemClass(self, "Ljava/lang/String;");
- CHECK_EQ(java_lang_String.Get(), String_class);
- CHECK_EQ(java_lang_String->GetObjectSize(), sizeof(mirror::String));
+ std::ostringstream os1, os2;
+ java_lang_String->DumpClass(os1, mirror::Class::kDumpClassFullDetail);
+ String_class->DumpClass(os2, mirror::Class::kDumpClassFullDetail);
+ CHECK_EQ(java_lang_String.Get(), String_class) << os1.str() << "\n\n" << os2.str();
+ CHECK_EQ(java_lang_String->GetObjectSize(), mirror::String::InstanceSize());
java_lang_DexCache->SetStatus(mirror::Class::kStatusNotReady, self);
mirror::Class* DexCache_class = FindSystemClass(self, "Ljava/lang/DexCache;");
CHECK_EQ(java_lang_String.Get(), String_class);
CHECK_EQ(java_lang_DexCache.Get(), DexCache_class);
- CHECK_EQ(java_lang_DexCache->GetObjectSize(), sizeof(mirror::DexCache));
+ CHECK_EQ(java_lang_DexCache->GetObjectSize(), mirror::DexCache::InstanceSize());
// Setup the primitive array type classes - can't be done until Object has a vtable.
SetClassRoot(kBooleanArrayClass, FindSystemClass(self, "[Z"));
@@ -476,7 +485,7 @@
// Setup the ClassLoader, verifying the object_size_.
mirror::Class* java_lang_ClassLoader = FindSystemClass(self, "Ljava/lang/ClassLoader;");
- CHECK_EQ(java_lang_ClassLoader->GetObjectSize(), sizeof(mirror::ClassLoader));
+ CHECK_EQ(java_lang_ClassLoader->GetObjectSize(), mirror::ClassLoader::InstanceSize());
SetClassRoot(kJavaLangClassLoader, java_lang_ClassLoader);
// Set up java.lang.Throwable, java.lang.ClassNotFoundException, and
@@ -1400,36 +1409,11 @@
return dex_cache.Get();
}
-// Used to initialize a class in the allocation code path to ensure it is guarded by a StoreStore
-// fence.
-class InitializeClassVisitor {
- public:
- explicit InitializeClassVisitor(uint32_t class_size) : class_size_(class_size) {
- }
-
- void operator()(mirror::Object* obj, size_t usable_size) const
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- DCHECK_LE(class_size_, usable_size);
- // Avoid AsClass as object is not yet in live bitmap or allocation stack.
- mirror::Class* klass = down_cast<mirror::Class*>(obj);
- // DCHECK(klass->IsClass());
- klass->SetClassSize(class_size_);
- klass->SetPrimitiveType(Primitive::kPrimNot); // Default to not being primitive.
- klass->SetDexClassDefIndex(DexFile::kDexNoIndex16); // Default to no valid class def index.
- klass->SetDexTypeIndex(DexFile::kDexNoIndex16); // Default to no valid type index.
- }
-
- private:
- const uint32_t class_size_;
-
- DISALLOW_COPY_AND_ASSIGN(InitializeClassVisitor);
-};
-
mirror::Class* ClassLinker::AllocClass(Thread* self, mirror::Class* java_lang_Class,
uint32_t class_size) {
DCHECK_GE(class_size, sizeof(mirror::Class));
gc::Heap* heap = Runtime::Current()->GetHeap();
- InitializeClassVisitor visitor(class_size);
+ mirror::Class::InitializeClassVisitor visitor(class_size);
mirror::Object* k = kMovingClasses ?
heap->AllocObject<true>(self, java_lang_Class, class_size, visitor) :
heap->AllocNonMovableObject<true>(self, java_lang_Class, class_size, visitor);
@@ -1460,9 +1444,33 @@
self, GetClassRoot(kJavaLangStackTraceElementArrayClass), length);
}
-static mirror::Class* EnsureResolved(Thread* self, mirror::Class* klass)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+mirror::Class* ClassLinker::EnsureResolved(Thread* self, const char* descriptor,
+ mirror::Class* klass) {
DCHECK(klass != NULL);
+
+ // For temporary classes we must wait for them to be retired.
+ if (init_done_ && klass->IsTemp()) {
+ CHECK(!klass->IsResolved());
+ if (klass->IsErroneous()) {
+ ThrowEarlierClassFailure(klass);
+ return nullptr;
+ }
+ StackHandleScope<1> hs(self);
+ Handle<mirror::Class> h_class(hs.NewHandle(klass));
+ ObjectLock<mirror::Class> lock(self, h_class);
+ // Loop and wait for the resolving thread to retire this class.
+ while (!h_class->IsRetired() && !h_class->IsErroneous()) {
+ lock.WaitIgnoringInterrupts();
+ }
+ if (h_class->IsErroneous()) {
+ ThrowEarlierClassFailure(h_class.Get());
+ return nullptr;
+ }
+ CHECK(h_class->IsRetired());
+ // Get the updated class from class table.
+ klass = LookupClass(descriptor, h_class.Get()->GetClassLoader());
+ }
+
// Wait for the class if it has not already been linked.
if (!klass->IsResolved() && !klass->IsErroneous()) {
StackHandleScope<1> hs(self);
@@ -1479,6 +1487,7 @@
lock.WaitIgnoringInterrupts();
}
}
+
if (klass->IsErroneous()) {
ThrowEarlierClassFailure(klass);
return nullptr;
@@ -1502,7 +1511,7 @@
// Find the class in the loaded classes table.
mirror::Class* klass = LookupClass(descriptor, class_loader.Get());
if (klass != NULL) {
- return EnsureResolved(self, klass);
+ return EnsureResolved(self, descriptor, klass);
}
// Class is not yet loaded.
if (descriptor[0] == '[') {
@@ -1576,8 +1585,10 @@
const DexFile& dex_file,
const DexFile::ClassDef& dex_class_def) {
Thread* self = Thread::Current();
- StackHandleScope<2> hs(self);
+ StackHandleScope<3> hs(self);
auto klass = hs.NewHandle<mirror::Class>(nullptr);
+ bool should_allocate = false;
+
// Load the class from the dex file.
if (UNLIKELY(!init_done_)) {
// finish up init of hand crafted class_roots_
@@ -1594,10 +1605,18 @@
} else if (strcmp(descriptor, "Ljava/lang/reflect/ArtMethod;") == 0) {
klass.Assign(GetClassRoot(kJavaLangReflectArtMethod));
} else {
- klass.Assign(AllocClass(self, SizeOfClass(dex_file, dex_class_def)));
+ should_allocate = true;
}
} else {
- klass.Assign(AllocClass(self, SizeOfClass(dex_file, dex_class_def)));
+ should_allocate = true;
+ }
+
+ if (should_allocate) {
+ // Allocate a class with the status of not ready.
+ // Interface object should get the right size here. Regular class will
+ // figure out the right size later and be replaced with one of the right
+ // size when the class becomes resolved.
+ klass.Assign(AllocClass(self, SizeOfClassWithoutEmbeddedTables(dex_file, dex_class_def)));
}
if (UNLIKELY(klass.Get() == NULL)) {
CHECK(self->IsExceptionPending()); // Expect an OOME.
@@ -1612,13 +1631,15 @@
}
ObjectLock<mirror::Class> lock(self, klass);
klass->SetClinitThreadId(self->GetTid());
+
// Add the newly loaded class to the loaded classes table.
mirror::Class* existing = InsertClass(descriptor, klass.Get(), Hash(descriptor));
if (existing != NULL) {
// We failed to insert because we raced with another thread. Calling EnsureResolved may cause
// this thread to block.
- return EnsureResolved(self, existing);
+ return EnsureResolved(self, descriptor, existing);
}
+
// Finish loading (if necessary) by finding parents
CHECK(!klass->IsLoaded());
if (!LoadSuperAndInterfaces(klass, dex_file)) {
@@ -1631,12 +1652,17 @@
CHECK(!klass->IsResolved());
// TODO: Use fast jobjects?
auto interfaces = hs.NewHandle<mirror::ObjectArray<mirror::Class>>(nullptr);
- if (!LinkClass(self, klass, interfaces)) {
+
+ mirror::Class* new_class = nullptr;
+ if (!LinkClass(self, descriptor, klass, interfaces, &new_class)) {
// Linking failed.
klass->SetStatus(mirror::Class::kStatusError, self);
return NULL;
}
- CHECK(klass->IsResolved());
+ CHECK(new_class != nullptr) << descriptor;
+ CHECK(new_class->IsResolved()) << descriptor;
+
+ Handle<mirror::Class> new_class_h(hs.NewHandle(new_class));
/*
* We send CLASS_PREPARE events to the debugger from here. The
@@ -1649,14 +1675,13 @@
* The class has been prepared and resolved but possibly not yet verified
* at this point.
*/
- Dbg::PostClassPrepare(klass.Get());
+ Dbg::PostClassPrepare(new_class_h.Get());
- return klass.Get();
+ return new_class_h.Get();
}
-// Precomputes size that will be needed for Class, matching LinkStaticFields
-uint32_t ClassLinker::SizeOfClass(const DexFile& dex_file,
- const DexFile::ClassDef& dex_class_def) {
+uint32_t ClassLinker::SizeOfClassWithoutEmbeddedTables(const DexFile& dex_file,
+ const DexFile::ClassDef& dex_class_def) {
const byte* class_data = dex_file.GetClassData(dex_class_def);
size_t num_ref = 0;
size_t num_32 = 0;
@@ -1675,24 +1700,7 @@
}
}
}
- // start with generic class data
- uint32_t size = sizeof(mirror::Class);
- // follow with reference fields which must be contiguous at start
- size += (num_ref * sizeof(uint32_t));
- // if there are 64-bit fields to add, make sure they are aligned
- if (num_64 != 0 && size != RoundUp(size, 8)) { // for 64-bit alignment
- if (num_32 != 0) {
- // use an available 32-bit field for padding
- num_32--;
- }
- size += sizeof(uint32_t); // either way, we are adding a word
- DCHECK_EQ(size, RoundUp(size, 8));
- }
- // tack on any 64-bit fields now that alignment is assured
- size += (num_64 * sizeof(uint64_t));
- // tack on any remaining 32-bit fields
- size += (num_32 * sizeof(uint32_t));
- return size;
+ return mirror::Class::ComputeClassSize(false, 0, num_32, num_64, num_ref);
}
OatFile::OatClass ClassLinker::GetOatClass(const DexFile& dex_file, uint16_t class_def_idx) {
@@ -2306,7 +2314,7 @@
}
mirror::Class* ClassLinker::CreatePrimitiveClass(Thread* self, Primitive::Type type) {
- mirror::Class* klass = AllocClass(self, sizeof(mirror::Class));
+ mirror::Class* klass = AllocClass(self, mirror::Class::PrimitiveClassSize());
if (UNLIKELY(klass == NULL)) {
return NULL;
}
@@ -2411,7 +2419,7 @@
}
}
if (new_class.Get() == nullptr) {
- new_class.Assign(AllocClass(self, sizeof(mirror::Class)));
+ new_class.Assign(AllocClass(self, mirror::Array::ClassSize()));
if (new_class.Get() == nullptr) {
return nullptr;
}
@@ -2424,6 +2432,8 @@
new_class->SetVTable(java_lang_Object->GetVTable());
new_class->SetPrimitiveType(Primitive::kPrimNot);
new_class->SetClassLoader(component_type->GetClassLoader());
+ new_class->SetStatus(mirror::Class::kStatusLoaded, self);
+ new_class->PopulateEmbeddedImtAndVTable();
new_class->SetStatus(mirror::Class::kStatusInitialized, self);
// don't need to set new_class->SetObjectSize(..)
// because Object::SizeOf delegates to Array::SizeOf
@@ -2517,7 +2527,8 @@
if (existing != NULL) {
return existing;
}
- if (kIsDebugBuild && klass->GetClassLoader() == NULL && dex_cache_image_class_lookup_required_) {
+ if (kIsDebugBuild && !klass->IsTemp() && klass->GetClassLoader() == NULL &&
+ dex_cache_image_class_lookup_required_) {
// Check a class loaded with the system class loader matches one in the image if the class
// is in the image.
existing = LookupClassFromImage(descriptor);
@@ -2533,6 +2544,50 @@
return NULL;
}
+mirror::Class* ClassLinker::UpdateClass(const char* descriptor, mirror::Class* klass,
+ size_t hash) {
+ WriterMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
+ mirror::Class* existing =
+ LookupClassFromTableLocked(descriptor, klass->GetClassLoader(), hash);
+
+ if (existing == nullptr) {
+ CHECK(klass->IsProxyClass());
+ return nullptr;
+ }
+
+ CHECK_NE(existing, klass) << descriptor;
+ CHECK(!existing->IsResolved()) << descriptor;
+ CHECK_EQ(klass->GetStatus(), mirror::Class::kStatusResolving) << descriptor;
+
+ for (auto it = class_table_.lower_bound(hash), end = class_table_.end(); it != end && it->first == hash;
+ ++it) {
+ mirror::Class* entry = it->second;
+ if (entry == existing) {
+ class_table_.erase(it);
+ break;
+ }
+ }
+
+ CHECK(!klass->IsTemp()) << descriptor;
+ if (kIsDebugBuild && klass->GetClassLoader() == nullptr &&
+ dex_cache_image_class_lookup_required_) {
+ // Check a class loaded with the system class loader matches one in the image if the class
+ // is in the image.
+ existing = LookupClassFromImage(descriptor);
+ if (existing != nullptr) {
+ CHECK(klass == existing) << descriptor;
+ }
+ }
+ VerifyObject(klass);
+
+ class_table_.insert(std::make_pair(hash, klass));
+ if (log_new_class_table_roots_) {
+ new_class_roots_.push_back(std::make_pair(hash, klass));
+ }
+
+ return existing;
+}
+
bool ClassLinker::RemoveClass(const char* descriptor, const mirror::ClassLoader* class_loader) {
size_t hash = Hash(descriptor);
WriterMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
@@ -2952,8 +3007,8 @@
jobjectArray methods, jobjectArray throws) {
Thread* self = soa.Self();
StackHandleScope<8> hs(self);
- Handle<mirror::Class> klass(hs.NewHandle(AllocClass(self, GetClassRoot(kJavaLangClass),
- sizeof(mirror::SynthesizedProxyClass))));
+ Handle<mirror::Class> klass(hs.NewHandle(
+ AllocClass(self, GetClassRoot(kJavaLangClass), sizeof(mirror::Class))));
if (klass.Get() == NULL) {
CHECK(self->IsExceptionPending()); // OOME.
return NULL;
@@ -3044,20 +3099,31 @@
klass->SetStatus(mirror::Class::kStatusLoaded, self); // Now effectively in the loaded state.
self->AssertNoPendingException();
+ std::string descriptor(GetDescriptorForProxy(klass.Get()));
+ mirror::Class* new_class = nullptr;
{
- ObjectLock<mirror::Class> lock(self, klass); // Must hold lock on object when resolved.
+ ObjectLock<mirror::Class> resolution_lock(self, klass); // Must hold lock on object when resolved.
// Link the fields and virtual methods, creating vtable and iftables
- Handle<mirror::ObjectArray<mirror::Class>> h_interfaces(
+ Handle<mirror::ObjectArray<mirror::Class> > h_interfaces(
hs.NewHandle(soa.Decode<mirror::ObjectArray<mirror::Class>*>(interfaces)));
- if (!LinkClass(self, klass, h_interfaces)) {
+ if (!LinkClass(self, descriptor.c_str(), klass, h_interfaces, &new_class)) {
klass->SetStatus(mirror::Class::kStatusError, self);
return nullptr;
}
+ }
- interfaces_sfield->SetObject<false>(
- klass.Get(), soa.Decode<mirror::ObjectArray<mirror::Class>*>(interfaces));
- throws_sfield->SetObject<false>(
- klass.Get(), soa.Decode<mirror::ObjectArray<mirror::ObjectArray<mirror::Class>>*>(throws));
+ CHECK(klass->IsRetired());
+ CHECK_NE(klass.Get(), new_class);
+ klass.Assign(new_class);
+
+ CHECK_EQ(interfaces_sfield->GetDeclaringClass(), new_class);
+ interfaces_sfield->SetObject<false>(klass.Get(), soa.Decode<mirror::ObjectArray<mirror::Class>*>(interfaces));
+ CHECK_EQ(throws_sfield->GetDeclaringClass(), new_class);
+ throws_sfield->SetObject<false>(klass.Get(), soa.Decode<mirror::ObjectArray<mirror::ObjectArray<mirror::Class> >*>(throws));
+
+ {
+ // Lock on klass is released. Lock new class object.
+ ObjectLock<mirror::Class> initialization_lock(self, klass);
klass->SetStatus(mirror::Class::kStatusInitialized, self);
}
@@ -3083,14 +3149,11 @@
decoded_name->ToModifiedUtf8().c_str()));
CHECK_EQ(PrettyField(klass->GetStaticField(1)), throws_field_name);
- mirror::SynthesizedProxyClass* synth_proxy_class =
- down_cast<mirror::SynthesizedProxyClass*>(klass.Get());
- CHECK_EQ(synth_proxy_class->GetInterfaces(),
+ CHECK_EQ(klass.Get()->GetInterfaces(),
soa.Decode<mirror::ObjectArray<mirror::Class>*>(interfaces));
- CHECK_EQ(synth_proxy_class->GetThrows(),
+ CHECK_EQ(klass.Get()->GetThrows(),
soa.Decode<mirror::ObjectArray<mirror::ObjectArray<mirror::Class>>*>(throws));
}
- std::string descriptor(GetDescriptorForProxy(klass.Get()));
mirror::Class* existing = InsertClass(descriptor.c_str(), klass.Get(), Hash(descriptor.c_str()));
CHECK(existing == nullptr);
return klass.Get();
@@ -3524,9 +3587,49 @@
}
}
-bool ClassLinker::LinkClass(Thread* self, Handle<mirror::Class> klass,
- Handle<mirror::ObjectArray<mirror::Class>> interfaces) {
+void ClassLinker::FixupTemporaryDeclaringClass(mirror::Class* temp_class, mirror::Class* new_class) {
+ mirror::ObjectArray<mirror::ArtField>* fields = new_class->GetIFields();
+ if (fields != nullptr) {
+ for (int index = 0; index < fields->GetLength(); index ++) {
+ if (fields->Get(index)->GetDeclaringClass() == temp_class) {
+ fields->Get(index)->SetDeclaringClass(new_class);
+ }
+ }
+ }
+
+ fields = new_class->GetSFields();
+ if (fields != nullptr) {
+ for (int index = 0; index < fields->GetLength(); index ++) {
+ if (fields->Get(index)->GetDeclaringClass() == temp_class) {
+ fields->Get(index)->SetDeclaringClass(new_class);
+ }
+ }
+ }
+
+ mirror::ObjectArray<mirror::ArtMethod>* methods = new_class->GetDirectMethods();
+ if (methods != nullptr) {
+ for (int index = 0; index < methods->GetLength(); index ++) {
+ if (methods->Get(index)->GetDeclaringClass() == temp_class) {
+ methods->Get(index)->SetDeclaringClass(new_class);
+ }
+ }
+ }
+
+ methods = new_class->GetVirtualMethods();
+ if (methods != nullptr) {
+ for (int index = 0; index < methods->GetLength(); index ++) {
+ if (methods->Get(index)->GetDeclaringClass() == temp_class) {
+ methods->Get(index)->SetDeclaringClass(new_class);
+ }
+ }
+ }
+}
+
+bool ClassLinker::LinkClass(Thread* self, const char* descriptor, Handle<mirror::Class> klass,
+ Handle<mirror::ObjectArray<mirror::Class>> interfaces,
+ mirror::Class** new_class) {
CHECK_EQ(mirror::Class::kStatusLoaded, klass->GetStatus());
+
if (!LinkSuperClass(klass)) {
return false;
}
@@ -3536,13 +3639,60 @@
if (!LinkInstanceFields(klass)) {
return false;
}
- if (!LinkStaticFields(klass)) {
+ size_t class_size;
+ if (!LinkStaticFields(klass, &class_size)) {
return false;
}
CreateReferenceInstanceOffsets(klass);
CreateReferenceStaticOffsets(klass);
CHECK_EQ(mirror::Class::kStatusLoaded, klass->GetStatus());
- klass->SetStatus(mirror::Class::kStatusResolved, self);
+
+ if (!klass->IsTemp() || (!init_done_ && klass->GetClassSize() == class_size)) {
+ // We don't need to retire this class as it has no embedded tables or it was created the
+ // correct size during class linker initialization.
+ CHECK_EQ(klass->GetClassSize(), class_size) << PrettyDescriptor(klass.Get());
+
+ if (klass->ShouldHaveEmbeddedImtAndVTable()) {
+ klass->PopulateEmbeddedImtAndVTable();
+ }
+
+ // This will notify waiters on klass that saw the not yet resolved
+ // class in the class_table_ during EnsureResolved.
+ klass->SetStatus(mirror::Class::kStatusResolved, self);
+ *new_class = klass.Get();
+ } else {
+ CHECK(!klass->IsResolved());
+ // Retire the temporary class and create the correctly sized resolved class.
+ *new_class = klass->CopyOf(self, class_size);
+ if (UNLIKELY(*new_class == NULL)) {
+ CHECK(self->IsExceptionPending()); // Expect an OOME.
+ klass->SetStatus(mirror::Class::kStatusError, self);
+ return false;
+ }
+
+ CHECK_EQ((*new_class)->GetClassSize(), class_size);
+ StackHandleScope<1> hs(self);
+ auto new_class_h = hs.NewHandleWrapper<mirror::Class>(new_class);
+ ObjectLock<mirror::Class> lock(self, new_class_h);
+
+ FixupTemporaryDeclaringClass(klass.Get(), new_class_h.Get());
+
+ mirror::Class* existing = UpdateClass(descriptor, new_class_h.Get(), Hash(descriptor));
+ CHECK(existing == NULL || existing == klass.Get());
+
+ // This will notify waiters on temp class that saw the not yet resolved class in the
+ // class_table_ during EnsureResolved.
+ klass->SetStatus(mirror::Class::kStatusRetired, self);
+
+ CHECK_EQ(new_class_h->GetStatus(), mirror::Class::kStatusResolving);
+ // This will notify waiters on new_class that saw the not yet resolved
+ // class in the class_table_ during EnsureResolved.
+ new_class_h->SetStatus(mirror::Class::kStatusResolved, self);
+
+ // Only embedded imt should be used from this point.
+ new_class_h->SetImTable(NULL);
+ // TODO: remove vtable and only use embedded vtable.
+ }
return true;
}
@@ -3563,6 +3713,7 @@
PrettyDescriptor(klass.Get()).c_str());
return false;
}
+ CHECK(super_class->IsResolved());
klass->SetSuperClass(super_class);
}
const DexFile::TypeList* interfaces = dex_file.GetInterfacesList(class_def);
@@ -3876,7 +4027,7 @@
// Allocate imtable
bool imtable_changed = false;
Handle<mirror::ObjectArray<mirror::ArtMethod>> imtable(
- hs.NewHandle(AllocArtMethodArray(self, kImtSize)));
+ hs.NewHandle(AllocArtMethodArray(self, mirror::Class::kImtSize)));
if (UNLIKELY(imtable.Get() == NULL)) {
CHECK(self->IsExceptionPending()); // OOME.
return false;
@@ -3923,7 +4074,7 @@
}
method_array->Set<false>(j, vtable_method);
// Place method in imt if entry is empty, place conflict otherwise.
- uint32_t imt_index = interface_method->GetDexMethodIndex() % kImtSize;
+ uint32_t imt_index = interface_method->GetDexMethodIndex() % mirror::Class::kImtSize;
if (imtable->Get(imt_index) == NULL) {
imtable->Set<false>(imt_index, vtable_method);
imtable_changed = true;
@@ -3961,7 +4112,7 @@
if (imtable_changed) {
// Fill in empty entries in interface method table with conflict.
mirror::ArtMethod* imt_conflict_method = runtime->GetImtConflictMethod();
- for (size_t i = 0; i < kImtSize; i++) {
+ for (size_t i = 0; i < mirror::Class::kImtSize; i++) {
if (imtable->Get(i) == NULL) {
imtable->Set<false>(i, imt_conflict_method);
}
@@ -4018,15 +4169,12 @@
bool ClassLinker::LinkInstanceFields(Handle<mirror::Class> klass) {
CHECK(klass.Get() != NULL);
- return LinkFields(klass, false);
+ return LinkFields(klass, false, nullptr);
}
-bool ClassLinker::LinkStaticFields(Handle<mirror::Class> klass) {
+bool ClassLinker::LinkStaticFields(Handle<mirror::Class> klass, size_t* class_size) {
CHECK(klass.Get() != NULL);
- size_t allocated_class_size = klass->GetClassSize();
- bool success = LinkFields(klass, true);
- CHECK_EQ(allocated_class_size, klass->GetClassSize());
- return success;
+ return LinkFields(klass, true, class_size);
}
struct LinkFieldsComparator {
@@ -4056,19 +4204,23 @@
}
};
-bool ClassLinker::LinkFields(Handle<mirror::Class> klass, bool is_static) {
+bool ClassLinker::LinkFields(Handle<mirror::Class> klass, bool is_static, size_t* class_size) {
size_t num_fields =
is_static ? klass->NumStaticFields() : klass->NumInstanceFields();
mirror::ObjectArray<mirror::ArtField>* fields =
is_static ? klass->GetSFields() : klass->GetIFields();
- // Initialize size and field_offset
- size_t size;
+ // Initialize field_offset
MemberOffset field_offset(0);
if (is_static) {
- size = klass->GetClassSize();
- field_offset = mirror::Class::FieldsOffset();
+ uint32_t base = sizeof(mirror::Class); // Static fields come after the class.
+ if (klass->ShouldHaveEmbeddedImtAndVTable()) {
+ // Static fields come after the embedded tables.
+ base = mirror::Class::ComputeClassSize(true, klass->GetVTableDuringLinking()->GetLength(),
+ 0, 0, 0);
+ }
+ field_offset = MemberOffset(base);
} else {
mirror::Class* super_class = klass->GetSuperClass();
if (super_class != NULL) {
@@ -4076,7 +4228,6 @@
<< PrettyClass(klass.Get()) << " " << PrettyClass(super_class);
field_offset = MemberOffset(super_class->GetObjectSize());
}
- size = field_offset.Uint32Value();
}
CHECK_EQ(num_fields == 0, fields == NULL) << PrettyClass(klass.Get());
@@ -4189,11 +4340,12 @@
DCHECK_EQ(num_fields, num_reference_fields) << PrettyClass(klass.Get());
}
}
- size = field_offset.Uint32Value();
+
+ size_t size = field_offset.Uint32Value();
// Update klass
if (is_static) {
klass->SetNumReferenceStaticFields(num_reference_fields);
- klass->SetClassSize(size);
+ *class_size = size;
} else {
klass->SetNumReferenceInstanceFields(num_reference_fields);
if (!klass->IsVariableSize()) {