diff options
Diffstat (limited to 'runtime/class_linker.cc')
-rw-r--r-- | runtime/class_linker.cc | 1281 |
1 files changed, 697 insertions, 584 deletions
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index a028942c7..fb2debd63 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -26,8 +26,11 @@ #include <vector> #include "art_field-inl.h" +#include "art_method-inl.h" +#include "base/arena_allocator.h" #include "base/casts.h" #include "base/logging.h" +#include "base/scoped_arena_containers.h" #include "base/scoped_flock.h" #include "base/stl_util.h" #include "base/time_utils.h" @@ -54,7 +57,6 @@ #include "oat_file.h" #include "oat_file_assistant.h" #include "object_lock.h" -#include "mirror/art_method-inl.h" #include "mirror/class.h" #include "mirror/class-inl.h" #include "mirror/class_loader.h" @@ -94,9 +96,9 @@ static void ThrowNoClassDefFoundError(const char* fmt, ...) { va_end(args); } -static bool HasInitWithString(Thread* self, ClassLinker* class_linker, const char* descriptor) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - mirror::ArtMethod* method = self->GetCurrentMethod(nullptr); +bool ClassLinker::HasInitWithString( + Thread* self, ClassLinker* class_linker, const char* descriptor) { + ArtMethod* method = self->GetCurrentMethod(nullptr); StackHandleScope<1> hs(self); Handle<mirror::ClassLoader> class_loader(hs.NewHandle(method != nullptr ? method->GetDeclaringClass()->GetClassLoader() @@ -110,8 +112,8 @@ static bool HasInitWithString(Thread* self, ClassLinker* class_linker, const cha return false; } - mirror::ArtMethod* exception_init_method = - exception_class->FindDeclaredDirectMethod("<init>", "(Ljava/lang/String;)V"); + ArtMethod* exception_init_method = exception_class->FindDeclaredDirectMethod( + "<init>", "(Ljava/lang/String;)V", image_pointer_size_); return exception_init_method != nullptr; } @@ -275,46 +277,51 @@ ClassLinker::ClassLinker(InternTable* intern_table) quick_to_interpreter_bridge_trampoline_(nullptr), image_pointer_size_(sizeof(void*)) { CHECK(intern_table_ != nullptr); - for (size_t i = 0; i < kFindArrayCacheSize; ++i) { - find_array_class_cache_[i] = GcRoot<mirror::Class>(nullptr); + for (auto& root : find_array_class_cache_) { + root = GcRoot<mirror::Class>(nullptr); } } void ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> boot_class_path) { VLOG(startup) << "ClassLinker::Init"; - CHECK(!Runtime::Current()->GetHeap()->HasImageSpace()) << "Runtime has image. We should use it."; + Thread* const self = Thread::Current(); + Runtime* const runtime = Runtime::Current(); + gc::Heap* const heap = runtime->GetHeap(); + + CHECK(!heap->HasImageSpace()) << "Runtime has image. We should use it."; CHECK(!init_done_); + // Use the pointer size from the runtime since we are probably creating the image. + image_pointer_size_ = InstructionSetPointerSize(runtime->GetInstructionSet()); + // java_lang_Class comes first, it's needed for AllocClass - Thread* const self = Thread::Current(); - gc::Heap* const heap = Runtime::Current()->GetHeap(); // The GC can't handle an object with a null class since we can't get the size of this object. heap->IncrementDisableMovingGC(self); StackHandleScope<64> hs(self); // 64 is picked arbitrarily. + auto class_class_size = mirror::Class::ClassClassSize(image_pointer_size_); Handle<mirror::Class> java_lang_Class(hs.NewHandle(down_cast<mirror::Class*>( - heap->AllocNonMovableObject<true>(self, nullptr, - mirror::Class::ClassClassSize(), - VoidFunctor())))); + heap->AllocNonMovableObject<true>(self, nullptr, class_class_size, VoidFunctor())))); CHECK(java_lang_Class.Get() != nullptr); mirror::Class::SetClassClass(java_lang_Class.Get()); java_lang_Class->SetClass(java_lang_Class.Get()); if (kUseBakerOrBrooksReadBarrier) { java_lang_Class->AssertReadBarrierPointer(); } - java_lang_Class->SetClassSize(mirror::Class::ClassClassSize()); + java_lang_Class->SetClassSize(class_class_size); java_lang_Class->SetPrimitiveType(Primitive::kPrimNot); heap->DecrementDisableMovingGC(self); // AllocClass(mirror::Class*) can now be used // Class[] is used for reflection support. + auto class_array_class_size = mirror::ObjectArray<mirror::Class>::ClassSize(image_pointer_size_); Handle<mirror::Class> class_array_class(hs.NewHandle( - AllocClass(self, java_lang_Class.Get(), mirror::ObjectArray<mirror::Class>::ClassSize()))); + AllocClass(self, java_lang_Class.Get(), class_array_class_size))); 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(), mirror::Object::ClassSize()))); + AllocClass(self, java_lang_Class.Get(), mirror::Object::ClassSize(image_pointer_size_)))); CHECK(java_lang_Object.Get() != nullptr); // backfill Object as the super class of Class. java_lang_Class->SetSuperClass(java_lang_Object.Get()); @@ -322,12 +329,14 @@ void ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b // Object[] next to hold class roots. Handle<mirror::Class> object_array_class(hs.NewHandle( - AllocClass(self, java_lang_Class.Get(), mirror::ObjectArray<mirror::Object>::ClassSize()))); + AllocClass(self, java_lang_Class.Get(), + mirror::ObjectArray<mirror::Object>::ClassSize(image_pointer_size_)))); object_array_class->SetComponentType(java_lang_Object.Get()); // 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()))); + AllocClass(self, java_lang_Class.Get(), + mirror::Class::PrimitiveClassSize(image_pointer_size_)))); // The primitive char class won't be initialized by // InitializePrimitiveClass until line 459, but strings (and // internal char arrays) will be allocated before that and the @@ -337,21 +346,20 @@ void ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b // Setup the char[] class to be used for String. Handle<mirror::Class> char_array_class(hs.NewHandle( - AllocClass(self, java_lang_Class.Get(), - mirror::Array::ClassSize()))); + AllocClass(self, java_lang_Class.Get(), mirror::Array::ClassSize(image_pointer_size_)))); 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(), mirror::String::ClassSize()))); + AllocClass(self, java_lang_Class.Get(), mirror::String::ClassSize(image_pointer_size_)))); mirror::String::SetClass(java_lang_String.Get()); mirror::Class::SetStatus(java_lang_String, mirror::Class::kStatusResolved, self); java_lang_String->SetStringClass(); // Setup java.lang.ref.Reference. Handle<mirror::Class> java_lang_ref_Reference(hs.NewHandle( - AllocClass(self, java_lang_Class.Get(), mirror::Reference::ClassSize()))); + AllocClass(self, java_lang_Class.Get(), mirror::Reference::ClassSize(image_pointer_size_)))); mirror::Reference::SetClass(java_lang_ref_Reference.Get()); java_lang_ref_Reference->SetObjectSize(mirror::Reference::InstanceSize()); mirror::Class::SetStatus(java_lang_ref_Reference, mirror::Class::kStatusResolved, self); @@ -384,14 +392,14 @@ void ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b // Create int array type for AllocDexCache (done in AppendToBootClassPath). Handle<mirror::Class> int_array_class(hs.NewHandle( - AllocClass(self, java_lang_Class.Get(), mirror::Array::ClassSize()))); + AllocClass(self, java_lang_Class.Get(), mirror::Array::ClassSize(image_pointer_size_)))); int_array_class->SetComponentType(GetClassRoot(kPrimitiveInt)); mirror::IntArray::SetArrayClass(int_array_class.Get()); SetClassRoot(kIntArrayClass, int_array_class.Get()); // Create long array type for AllocDexCache (done in AppendToBootClassPath). Handle<mirror::Class> long_array_class(hs.NewHandle( - AllocClass(self, java_lang_Class.Get(), mirror::Array::ClassSize()))); + AllocClass(self, java_lang_Class.Get(), mirror::Array::ClassSize(image_pointer_size_)))); long_array_class->SetComponentType(GetClassRoot(kPrimitiveLong)); mirror::LongArray::SetArrayClass(long_array_class.Get()); SetClassRoot(kLongArrayClass, long_array_class.Get()); @@ -400,35 +408,22 @@ void ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b // 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(), mirror::DexCache::ClassSize()))); + AllocClass(self, java_lang_Class.Get(), mirror::DexCache::ClassSize(image_pointer_size_)))); SetClassRoot(kJavaLangDexCache, java_lang_DexCache.Get()); java_lang_DexCache->SetObjectSize(mirror::DexCache::InstanceSize()); mirror::Class::SetStatus(java_lang_DexCache, mirror::Class::kStatusResolved, self); - // Constructor, Method, and AbstractMethod are necessary so - // that FindClass can link members. - - Handle<mirror::Class> java_lang_reflect_ArtMethod(hs.NewHandle( - AllocClass(self, java_lang_Class.Get(), mirror::ArtMethod::ClassSize()))); - CHECK(java_lang_reflect_ArtMethod.Get() != nullptr); - size_t pointer_size = GetInstructionSetPointerSize(Runtime::Current()->GetInstructionSet()); - java_lang_reflect_ArtMethod->SetObjectSize(mirror::ArtMethod::InstanceSize(pointer_size)); - SetClassRoot(kJavaLangReflectArtMethod, java_lang_reflect_ArtMethod.Get()); - mirror::Class::SetStatus(java_lang_reflect_ArtMethod, 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(), - mirror::ObjectArray<mirror::String>::ClassSize()))); + mirror::ObjectArray<mirror::String>::ClassSize(image_pointer_size_)))); 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(), - mirror::ObjectArray<mirror::ArtMethod>::ClassSize()))); - object_array_art_method->SetComponentType(java_lang_reflect_ArtMethod.Get()); - SetClassRoot(kJavaLangReflectArtMethodArrayClass, object_array_art_method.Get()); + // Create runtime resolution and imt conflict methods. + runtime->SetResolutionMethod(runtime->CreateResolutionMethod()); + runtime->SetImtConflictMethod(runtime->CreateImtConflictMethod()); + runtime->SetImtUnimplementedMethod(runtime->CreateImtConflictMethod()); // Setup boot_class_path_ and register class_path now that we can use AllocObjectArray to create // DexCache instances. Needs to be after String, Field, Method arrays since AllocDexCache uses @@ -446,13 +441,6 @@ void ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b InitializePrimitiveClass(char_class.Get(), Primitive::kPrimChar); SetClassRoot(kPrimitiveChar, char_class.Get()); // needs descriptor - // Create runtime resolution and imt conflict methods. Also setup the default imt. - Runtime* runtime = Runtime::Current(); - runtime->SetResolutionMethod(runtime->CreateResolutionMethod()); - runtime->SetImtConflictMethod(runtime->CreateImtConflictMethod()); - runtime->SetImtUnimplementedMethod(runtime->CreateImtConflictMethod()); - runtime->SetDefaultImt(runtime->CreateDefaultImt(this)); - // Set up GenericJNI entrypoint. That is mainly a hack for common_compiler_test.h so that // we do not need friend classes or a publicly exposed setter. quick_generic_jni_trampoline_ = GetQuickGenericJniStub(); @@ -529,13 +517,8 @@ void ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b // dex_cache_ fields and register them in class_table_. CHECK_EQ(java_lang_Class.Get(), FindSystemClass(self, "Ljava/lang/Class;")); - mirror::Class::SetStatus(java_lang_reflect_ArtMethod, mirror::Class::kStatusNotReady, self); - CHECK_EQ(java_lang_reflect_ArtMethod.Get(), - FindSystemClass(self, "Ljava/lang/reflect/ArtMethod;")); CHECK_EQ(object_array_string.Get(), FindSystemClass(self, GetClassRootDescriptor(kJavaLangStringArrayClass))); - CHECK_EQ(object_array_art_method.Get(), - FindSystemClass(self, GetClassRootDescriptor(kJavaLangReflectArtMethodArrayClass))); // End of special init trickery, subsequent classes may be loaded via FindSystemClass. @@ -579,7 +562,8 @@ void ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b mirror::Class::SetStatus(java_lang_ref_Reference, mirror::Class::kStatusNotReady, self); CHECK_EQ(java_lang_ref_Reference.Get(), FindSystemClass(self, "Ljava/lang/ref/Reference;")); CHECK_EQ(java_lang_ref_Reference->GetObjectSize(), mirror::Reference::InstanceSize()); - CHECK_EQ(java_lang_ref_Reference->GetClassSize(), mirror::Reference::ClassSize()); + CHECK_EQ(java_lang_ref_Reference->GetClassSize(), + mirror::Reference::ClassSize(image_pointer_size_)); class_root = FindSystemClass(self, "Ljava/lang/ref/FinalizerReference;"); class_root->SetAccessFlags(class_root->GetAccessFlags() | kAccClassIsReference | kAccClassIsFinalizerReference); @@ -1027,24 +1011,41 @@ const OatFile* ClassLinker::FindOpenedOatFileFromOatLocation(const std::string& return nullptr; } -void ClassLinker::InitFromImageInterpretOnlyCallback(mirror::Object* obj, void* arg) { - ClassLinker* class_linker = reinterpret_cast<ClassLinker*>(arg); - DCHECK(obj != nullptr); - DCHECK(class_linker != nullptr); - if (obj->IsArtMethod()) { - mirror::ArtMethod* method = obj->AsArtMethod(); - if (!method->IsNative()) { - const size_t pointer_size = class_linker->image_pointer_size_; - method->SetEntryPointFromInterpreterPtrSize(artInterpreterToInterpreterBridge, pointer_size); - if (!method->IsRuntimeMethod() && method != Runtime::Current()->GetResolutionMethod()) { - method->SetEntryPointFromQuickCompiledCodePtrSize(GetQuickToInterpreterBridge(), - pointer_size); - } +static void SanityCheckArtMethod(ArtMethod* m, mirror::Class* expected_class, + gc::space::ImageSpace* space) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + if (m->IsRuntimeMethod()) { + CHECK(m->GetDeclaringClass() == nullptr) << PrettyMethod(m); + } else if (m->IsMiranda()) { + CHECK(m->GetDeclaringClass() != nullptr) << PrettyMethod(m); + } else if (expected_class != nullptr) { + CHECK_EQ(m->GetDeclaringClassUnchecked(), expected_class) << PrettyMethod(m); + } + if (space != nullptr) { + auto& header = space->GetImageHeader(); + auto& methods = header.GetMethodsSection(); + auto offset = reinterpret_cast<uint8_t*>(m) - space->Begin(); + CHECK(methods.Contains(offset)) << m << " not in " << methods; + } +} + +static void SanityCheckArtMethodPointerArray( + mirror::PointerArray* arr, mirror::Class* expected_class, size_t pointer_size, + gc::space::ImageSpace* space) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + CHECK(arr != nullptr); + for (int32_t j = 0; j < arr->GetLength(); ++j) { + auto* method = arr->GetElementPtrSize<ArtMethod*>(j, pointer_size); + // expected_class == null means we are a dex cache. + if (expected_class != nullptr) { + CHECK(method != nullptr); + } + if (method != nullptr) { + SanityCheckArtMethod(method, expected_class, space); } } } -void SanityCheckObjectsCallback(mirror::Object* obj, void* arg ATTRIBUTE_UNUSED) +static void SanityCheckObjectsCallback(mirror::Object* obj, void* arg ATTRIBUTE_UNUSED) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { DCHECK(obj != nullptr); CHECK(obj->GetClass() != nullptr) << "Null class " << obj; @@ -1058,6 +1059,36 @@ void SanityCheckObjectsCallback(mirror::Object* obj, void* arg ATTRIBUTE_UNUSED) CHECK_EQ(fields[i][j].GetDeclaringClass(), klass); } } + auto* runtime = Runtime::Current(); + auto* image_space = runtime->GetHeap()->GetImageSpace(); + auto pointer_size = runtime->GetClassLinker()->GetImagePointerSize(); + for (auto& m : klass->GetDirectMethods(pointer_size)) { + SanityCheckArtMethod(&m, klass, image_space); + } + for (auto& m : klass->GetVirtualMethods(pointer_size)) { + SanityCheckArtMethod(&m, klass, image_space); + } + auto* vtable = klass->GetVTable(); + if (vtable != nullptr) { + SanityCheckArtMethodPointerArray(vtable, nullptr, pointer_size, image_space); + } + if (klass->ShouldHaveEmbeddedImtAndVTable()) { + for (size_t i = 0; i < mirror::Class::kImtSize; ++i) { + SanityCheckArtMethod(klass->GetEmbeddedImTableEntry(i, pointer_size), nullptr, image_space); + } + for (int32_t i = 0; i < klass->GetEmbeddedVTableLength(); ++i) { + SanityCheckArtMethod(klass->GetEmbeddedVTableEntry(i, pointer_size), nullptr, image_space); + } + } + auto* iftable = klass->GetIfTable(); + if (iftable != nullptr) { + for (int32_t i = 0; i < klass->GetIfTableCount(); ++i) { + if (iftable->GetMethodArrayCount(i) > 0) { + SanityCheckArtMethodPointerArray(iftable->GetMethodArray(i), nullptr, pointer_size, + image_space); + } + } + } } } @@ -1069,8 +1100,9 @@ void ClassLinker::InitFromImage() { Thread* const self = Thread::Current(); gc::Heap* const heap = runtime->GetHeap(); gc::space::ImageSpace* const space = heap->GetImageSpace(); - dex_cache_image_class_lookup_required_ = true; CHECK(space != nullptr); + image_pointer_size_ = space->GetImageHeader().GetPointerSize(); + dex_cache_image_class_lookup_required_ = true; OatFile& oat_file = GetImageOatFile(space); CHECK_EQ(oat_file.GetOatHeader().GetImageFileLocationOatChecksum(), 0U); CHECK_EQ(oat_file.GetOatHeader().GetImageFileLocationOatDataBegin(), 0U); @@ -1113,34 +1145,28 @@ void ClassLinker::InitFromImage() { UNREACHABLE(); } + if (kSanityCheckObjects) { + SanityCheckArtMethodPointerArray(dex_cache->GetResolvedMethods(), nullptr, + image_pointer_size_, space); + } + CHECK_EQ(dex_file->GetLocationChecksum(), oat_dex_file->GetDexFileLocationChecksum()); AppendToBootClassPath(*dex_file.get(), dex_cache); opened_dex_files_.push_back(std::move(dex_file)); } + CHECK(ValidPointerSize(image_pointer_size_)) << image_pointer_size_; + // Set classes on AbstractMethod early so that IsMethod tests can be performed during the live // bitmap walk. - mirror::ArtMethod::SetClass(GetClassRoot(kJavaLangReflectArtMethod)); - size_t art_method_object_size = mirror::ArtMethod::GetJavaLangReflectArtMethod()->GetObjectSize(); if (!runtime->IsAotCompiler()) { - // Aot compiler supports having an image with a different pointer size than the runtime. This - // happens on the host for compile 32 bit tests since we use a 64 bit libart compiler. We may - // also use 32 bit dex2oat on a system with 64 bit apps. - CHECK_EQ(art_method_object_size, mirror::ArtMethod::InstanceSize(sizeof(void*))) - << sizeof(void*); - } - if (art_method_object_size == mirror::ArtMethod::InstanceSize(4)) { - image_pointer_size_ = 4; - } else { - CHECK_EQ(art_method_object_size, mirror::ArtMethod::InstanceSize(8)); - image_pointer_size_ = 8; + // Only the Aot compiler supports having an image with a different pointer size than the + // runtime. This happens on the host for compile 32 bit tests since we use a 64 bit libart + // compiler. We may also use 32 bit dex2oat on a system with 64 bit apps. + CHECK_EQ(image_pointer_size_, sizeof(void*)); } - // Set entry point to interpreter if in InterpretOnly mode. - if (!runtime->IsAotCompiler() && runtime->GetInstrumentation()->InterpretOnly()) { - heap->VisitObjects(InitFromImageInterpretOnlyCallback, this); - } if (kSanityCheckObjects) { for (int32_t i = 0; i < dex_caches->GetLength(); i++) { auto* dex_cache = dex_caches->Get(i); @@ -1154,6 +1180,27 @@ void ClassLinker::InitFromImage() { heap->VisitObjects(SanityCheckObjectsCallback, nullptr); } + // Set entry point to interpreter if in InterpretOnly mode. + if (!runtime->IsAotCompiler() && runtime->GetInstrumentation()->InterpretOnly()) { + const auto& header = space->GetImageHeader(); + const auto& methods = header.GetMethodsSection(); + const auto art_method_size = ArtMethod::ObjectSize(image_pointer_size_); + for (uintptr_t pos = 0; pos < methods.Size(); pos += art_method_size) { + auto* method = reinterpret_cast<ArtMethod*>(space->Begin() + pos + methods.Offset()); + if (kIsDebugBuild && !method->IsRuntimeMethod()) { + CHECK(method->GetDeclaringClass() != nullptr); + } + if (!method->IsNative()) { + method->SetEntryPointFromInterpreterPtrSize( + artInterpreterToInterpreterBridge, image_pointer_size_); + if (!method->IsRuntimeMethod() && method != runtime->GetResolutionMethod()) { + method->SetEntryPointFromQuickCompiledCodePtrSize(GetQuickToInterpreterBridge(), + image_pointer_size_); + } + } + } + } + // reinit class_roots_ mirror::Class::SetClassClass(class_roots->Get(kJavaLangClass)); class_roots_ = GcRoot<mirror::ObjectArray<mirror::Class>>(class_roots.Get()); @@ -1185,24 +1232,55 @@ void ClassLinker::InitFromImage() { VLOG(startup) << "ClassLinker::InitFromImage exiting"; } +bool ClassLinker::ClassInClassTable(mirror::Class* klass) { + ReaderMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_); + auto it = class_table_.Find(GcRoot<mirror::Class>(klass)); + if (it == class_table_.end()) { + return false; + } + return it->Read() == klass; +} + void ClassLinker::VisitClassRoots(RootVisitor* visitor, VisitRootFlags flags) { WriterMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_); BufferedRootVisitor<kDefaultBufferedRootCount> buffered_visitor( visitor, RootInfo(kRootStickyClass)); if ((flags & kVisitRootFlagAllRoots) != 0) { + // Argument for how root visiting deals with ArtField and ArtMethod roots. + // There is 3 GC cases to handle: + // Non moving concurrent: + // This case is easy to handle since the reference members of ArtMethod and ArtFields are held + // live by the class and class roots. In this case we probably don't even need to call + // VisitNativeRoots. + // + // Moving non-concurrent: + // This case needs to call visit VisitNativeRoots in case the classes or dex cache arrays move. + // To prevent missing roots, this case needs to ensure that there is no + // suspend points between the point which we allocate ArtMethod arrays and place them in a + // class which is in the class table. + // + // Moving concurrent: + // Need to make sure to not copy ArtMethods without doing read barriers since the roots are + // marked concurrently and we don't hold the classlinker_classes_lock_ when we do the copy. for (GcRoot<mirror::Class>& root : class_table_) { buffered_visitor.VisitRoot(root); - root.Read()->VisitFieldRoots(buffered_visitor); + if ((flags & kVisitRootFlagNonMoving) == 0) { + // Don't bother visiting ArtField and ArtMethod if kVisitRootFlagNonMoving is set since + // these roots are all reachable from the class or dex cache. + root.Read()->VisitNativeRoots(buffered_visitor, image_pointer_size_); + } } // PreZygote classes can't move so we won't need to update fields' declaring classes. for (GcRoot<mirror::Class>& root : pre_zygote_class_table_) { buffered_visitor.VisitRoot(root); - root.Read()->VisitFieldRoots(buffered_visitor); + if ((flags & kVisitRootFlagNonMoving) == 0) { + root.Read()->VisitNativeRoots(buffered_visitor, image_pointer_size_); + } } } else if ((flags & kVisitRootFlagNewRoots) != 0) { for (auto& root : new_class_roots_) { mirror::Class* old_ref = root.Read<kWithoutReadBarrier>(); - old_ref->VisitFieldRoots(buffered_visitor); + old_ref->VisitNativeRoots(buffered_visitor, image_pointer_size_); root.VisitRoot(visitor, RootInfo(kRootStickyClass)); mirror::Class* new_ref = root.Read<kWithoutReadBarrier>(); if (UNLIKELY(new_ref != old_ref)) { @@ -1353,7 +1431,6 @@ void ClassLinker::VisitClassesWithoutClassesLock(ClassVisitor* visitor, void* ar } ClassLinker::~ClassLinker() { - mirror::ArtMethod::ResetClass(); mirror::Class::ResetClass(); mirror::Constructor::ResetClass(); mirror::Field::ResetClass(); @@ -1376,48 +1453,47 @@ ClassLinker::~ClassLinker() { STLDeleteElements(&oat_files_); } +mirror::PointerArray* ClassLinker::AllocPointerArray(Thread* self, size_t length) { + return down_cast<mirror::PointerArray*>(image_pointer_size_ == 8u ? + static_cast<mirror::Array*>(mirror::LongArray::Alloc(self, length)) : + static_cast<mirror::Array*>(mirror::IntArray::Alloc(self, length))); +} + mirror::DexCache* ClassLinker::AllocDexCache(Thread* self, const DexFile& dex_file) { - gc::Heap* const heap = Runtime::Current()->GetHeap(); - StackHandleScope<16> hs(self); - Handle<mirror::Class> dex_cache_class(hs.NewHandle(GetClassRoot(kJavaLangDexCache))); - Handle<mirror::DexCache> dex_cache( - hs.NewHandle(down_cast<mirror::DexCache*>( - heap->AllocObject<true>(self, dex_cache_class.Get(), dex_cache_class->GetObjectSize(), - VoidFunctor())))); + StackHandleScope<6> hs(self); + auto dex_cache(hs.NewHandle(down_cast<mirror::DexCache*>( + GetClassRoot(kJavaLangDexCache)->AllocObject(self)))); if (dex_cache.Get() == nullptr) { + self->AssertPendingOOMException(); return nullptr; } - Handle<mirror::String> - location(hs.NewHandle(intern_table_->InternStrong(dex_file.GetLocation().c_str()))); + auto location(hs.NewHandle(intern_table_->InternStrong(dex_file.GetLocation().c_str()))); if (location.Get() == nullptr) { + self->AssertPendingOOMException(); return nullptr; } - Handle<mirror::ObjectArray<mirror::String>> - strings(hs.NewHandle(AllocStringArray(self, dex_file.NumStringIds()))); + auto strings(hs.NewHandle(AllocStringArray(self, dex_file.NumStringIds()))); if (strings.Get() == nullptr) { + self->AssertPendingOOMException(); return nullptr; } - Handle<mirror::ObjectArray<mirror::Class>> - types(hs.NewHandle(AllocClassArray(self, dex_file.NumTypeIds()))); + auto types(hs.NewHandle(AllocClassArray(self, dex_file.NumTypeIds()))); if (types.Get() == nullptr) { + self->AssertPendingOOMException(); return nullptr; } - Handle<mirror::ObjectArray<mirror::ArtMethod>> - methods(hs.NewHandle(AllocArtMethodArray(self, dex_file.NumMethodIds()))); + auto methods(hs.NewHandle(AllocPointerArray(self, dex_file.NumMethodIds()))); if (methods.Get() == nullptr) { + self->AssertPendingOOMException(); return nullptr; } - Handle<mirror::Array> fields; - if (image_pointer_size_ == 8) { - fields = hs.NewHandle<mirror::Array>(mirror::LongArray::Alloc(self, dex_file.NumFieldIds())); - } else { - fields = hs.NewHandle<mirror::Array>(mirror::IntArray::Alloc(self, dex_file.NumFieldIds())); - } + auto fields(hs.NewHandle(AllocPointerArray(self, dex_file.NumFieldIds()))); if (fields.Get() == nullptr) { + self->AssertPendingOOMException(); return nullptr; } dex_cache->Init(&dex_file, location.Get(), strings.Get(), types.Get(), methods.Get(), - fields.Get()); + fields.Get(), image_pointer_size_); return dex_cache.Get(); } @@ -1430,7 +1506,7 @@ mirror::Class* ClassLinker::AllocClass(Thread* self, mirror::Class* java_lang_Cl heap->AllocObject<true>(self, java_lang_Class, class_size, visitor) : heap->AllocNonMovableObject<true>(self, java_lang_Class, class_size, visitor); if (UNLIKELY(k == nullptr)) { - CHECK(self->IsExceptionPending()); // OOME. + self->AssertPendingOOMException(); return nullptr; } return k->AsClass(); @@ -1440,11 +1516,6 @@ mirror::Class* ClassLinker::AllocClass(Thread* self, uint32_t class_size) { return AllocClass(self, GetClassRoot(kJavaLangClass), class_size); } -mirror::ArtMethod* ClassLinker::AllocArtMethod(Thread* self) { - return down_cast<mirror::ArtMethod*>( - GetClassRoot(kJavaLangReflectArtMethod)->AllocNonMovableObject(self)); -} - mirror::ObjectArray<mirror::StackTraceElement>* ClassLinker::AllocStackTraceElementArray( Thread* self, size_t length) { return mirror::ObjectArray<mirror::StackTraceElement>::Alloc( @@ -1749,8 +1820,6 @@ mirror::Class* ClassLinker::DefineClass(Thread* self, const char* descriptor, si klass.Assign(GetClassRoot(kJavaLangRefReference)); } else if (strcmp(descriptor, "Ljava/lang/DexCache;") == 0) { klass.Assign(GetClassRoot(kJavaLangDexCache)); - } else if (strcmp(descriptor, "Ljava/lang/reflect/ArtMethod;") == 0) { - klass.Assign(GetClassRoot(kJavaLangReflectArtMethod)); } } @@ -1896,7 +1965,8 @@ uint32_t ClassLinker::SizeOfClassWithoutEmbeddedTables(const DexFile& dex_file, } } } - return mirror::Class::ComputeClassSize(false, 0, num_8, num_16, num_32, num_64, num_ref); + return mirror::Class::ComputeClassSize(false, 0, num_8, num_16, num_32, num_64, num_ref, + image_pointer_size_); } OatFile::OatClass ClassLinker::FindOatClass(const DexFile& dex_file, uint16_t class_def_idx, @@ -1945,7 +2015,7 @@ static uint32_t GetOatMethodIndexFromMethodIndex(const DexFile& dex_file, uint16 UNREACHABLE(); } -const OatFile::OatMethod ClassLinker::FindOatMethodFor(mirror::ArtMethod* method, bool* found) { +const OatFile::OatMethod ClassLinker::FindOatMethodFor(ArtMethod* method, bool* found) { // Although we overwrite the trampoline of non-static methods, we may get here via the resolution // method for direct methods (or virtual methods made direct). mirror::Class* declaring_class = method->GetDeclaringClass(); @@ -1962,7 +2032,7 @@ const OatFile::OatMethod ClassLinker::FindOatMethodFor(mirror::ArtMethod* method for (size_t i = 0; i < end; i++) { // Check method index instead of identity in case of duplicate method definitions. if (method->GetDexMethodIndex() == - declaring_class->GetVirtualMethod(i)->GetDexMethodIndex()) { + declaring_class->GetVirtualMethod(i, image_pointer_size_)->GetDexMethodIndex()) { found_virtual = true; break; } @@ -1985,7 +2055,7 @@ const OatFile::OatMethod ClassLinker::FindOatMethodFor(mirror::ArtMethod* method } // Special case to get oat code without overwriting a trampoline. -const void* ClassLinker::GetQuickOatCodeFor(mirror::ArtMethod* method) { +const void* ClassLinker::GetQuickOatCodeFor(ArtMethod* method) { CHECK(!method->IsAbstract()) << PrettyMethod(method); if (method->IsProxyMethod()) { return GetQuickProxyInvokeHandler(); @@ -2012,7 +2082,7 @@ const void* ClassLinker::GetQuickOatCodeFor(mirror::ArtMethod* method) { return GetQuickToInterpreterBridge(); } -const void* ClassLinker::GetOatMethodQuickCodeFor(mirror::ArtMethod* method) { +const void* ClassLinker::GetOatMethodQuickCodeFor(ArtMethod* method) { if (method->IsNative() || method->IsAbstract() || method->IsProxyMethod()) { return nullptr; } @@ -2043,7 +2113,7 @@ const void* ClassLinker::GetQuickOatCodeFor(const DexFile& dex_file, uint16_t cl } // Returns true if the method must run with interpreter, false otherwise. -static bool NeedsInterpreter(mirror::ArtMethod* method, const void* quick_code) +static bool NeedsInterpreter(ArtMethod* method, const void* quick_code) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { if (quick_code == nullptr) { // No code: need interpreter. @@ -2088,7 +2158,7 @@ void ClassLinker::FixupStaticTrampolines(mirror::Class* klass) { &has_oat_class); // Link the code of methods skipped by LinkCode. for (size_t method_index = 0; it.HasNextDirectMethod(); ++method_index, it.Next()) { - mirror::ArtMethod* method = klass->GetDirectMethod(method_index); + ArtMethod* method = klass->GetDirectMethod(method_index, image_pointer_size_); if (!method->IsStatic()) { // Only update static methods. continue; @@ -2113,10 +2183,9 @@ void ClassLinker::FixupStaticTrampolines(mirror::Class* klass) { // Ignore virtual methods on the iterator. } -void ClassLinker::LinkCode(Handle<mirror::ArtMethod> method, - const OatFile::OatClass* oat_class, +void ClassLinker::LinkCode(ArtMethod* method, const OatFile::OatClass* oat_class, uint32_t class_def_method_index) { - Runtime* runtime = Runtime::Current(); + Runtime* const runtime = Runtime::Current(); if (runtime->IsAotCompiler()) { // The following code only applies to a non-compiler runtime. return; @@ -2127,12 +2196,11 @@ void ClassLinker::LinkCode(Handle<mirror::ArtMethod> method, // Every kind of method should at least get an invoke stub from the oat_method. // non-abstract methods also get their code pointers. const OatFile::OatMethod oat_method = oat_class->GetOatMethod(class_def_method_index); - oat_method.LinkMethod(method.Get()); + oat_method.LinkMethod(method); } // Install entry point from interpreter. - bool enter_interpreter = NeedsInterpreter(method.Get(), - method->GetEntryPointFromQuickCompiledCode()); + bool enter_interpreter = NeedsInterpreter(method, method->GetEntryPointFromQuickCompiledCode()); if (enter_interpreter && !method->IsNative()) { method->SetEntryPointFromInterpreter(artInterpreterToInterpreterBridge); } else { @@ -2221,93 +2289,83 @@ ArtField* ClassLinker::AllocArtFieldArray(Thread* self, size_t length) { return ptr; } +ArtMethod* ClassLinker::AllocArtMethodArray(Thread* self, size_t length) { + const size_t method_size = ArtMethod::ObjectSize(image_pointer_size_); + uintptr_t ptr = reinterpret_cast<uintptr_t>( + Runtime::Current()->GetLinearAlloc()->Alloc(self, method_size * length)); + CHECK_NE(ptr, 0u); + for (size_t i = 0; i < length; ++i) { + new(reinterpret_cast<void*>(ptr + i * method_size)) ArtMethod; + } + return reinterpret_cast<ArtMethod*>(ptr); +} + void ClassLinker::LoadClassMembers(Thread* self, const DexFile& dex_file, const uint8_t* class_data, Handle<mirror::Class> klass, const OatFile::OatClass* oat_class) { - // Load static fields. - ClassDataItemIterator it(dex_file, class_data); - const size_t num_sfields = it.NumStaticFields(); - ArtField* sfields = num_sfields != 0 ? AllocArtFieldArray(self, num_sfields) : nullptr; - for (size_t i = 0; it.HasNextStaticField(); i++, it.Next()) { - CHECK_LT(i, num_sfields); - LoadField(it, klass, &sfields[i]); - } - klass->SetSFields(sfields); - klass->SetNumStaticFields(num_sfields); - DCHECK_EQ(klass->NumStaticFields(), num_sfields); - // Load instance fields. - const size_t num_ifields = it.NumInstanceFields(); - ArtField* ifields = num_ifields != 0 ? AllocArtFieldArray(self, num_ifields) : nullptr; - for (size_t i = 0; it.HasNextInstanceField(); i++, it.Next()) { - CHECK_LT(i, num_ifields); - LoadField(it, klass, &ifields[i]); - } - klass->SetIFields(ifields); - klass->SetNumInstanceFields(num_ifields); - DCHECK_EQ(klass->NumInstanceFields(), num_ifields); - // Note: We cannot have thread suspension until the field arrays are setup or else - // Class::VisitFieldRoots may miss some fields. - self->AllowThreadSuspension(); - // Load methods. - if (it.NumDirectMethods() != 0) { - // TODO: append direct methods to class object - mirror::ObjectArray<mirror::ArtMethod>* directs = - AllocArtMethodArray(self, it.NumDirectMethods()); - if (UNLIKELY(directs == nullptr)) { - CHECK(self->IsExceptionPending()); // OOME. - return; - } - klass->SetDirectMethods(directs); - } - if (it.NumVirtualMethods() != 0) { - // TODO: append direct methods to class object - mirror::ObjectArray<mirror::ArtMethod>* virtuals = - AllocArtMethodArray(self, it.NumVirtualMethods()); - if (UNLIKELY(virtuals == nullptr)) { - CHECK(self->IsExceptionPending()); // OOME. - return; - } - klass->SetVirtualMethods(virtuals); - } - size_t class_def_method_index = 0; - uint32_t last_dex_method_index = DexFile::kDexNoIndex; - size_t last_class_def_method_index = 0; - for (size_t i = 0; it.HasNextDirectMethod(); i++, it.Next()) { - self->AllowThreadSuspension(); - StackHandleScope<1> hs(self); - Handle<mirror::ArtMethod> method(hs.NewHandle(LoadMethod(self, dex_file, it, klass))); - if (UNLIKELY(method.Get() == nullptr)) { - CHECK(self->IsExceptionPending()); // OOME. - return; + { + // Note: We cannot have thread suspension until the field and method arrays are setup or else + // Class::VisitFieldRoots may miss some fields or methods. + ScopedAssertNoThreadSuspension nts(self, __FUNCTION__); + // Load static fields. + ClassDataItemIterator it(dex_file, class_data); + const size_t num_sfields = it.NumStaticFields(); + ArtField* sfields = num_sfields != 0 ? AllocArtFieldArray(self, num_sfields) : nullptr; + for (size_t i = 0; it.HasNextStaticField(); i++, it.Next()) { + CHECK_LT(i, num_sfields); + LoadField(it, klass, &sfields[i]); + } + klass->SetSFields(sfields); + klass->SetNumStaticFields(num_sfields); + DCHECK_EQ(klass->NumStaticFields(), num_sfields); + // Load instance fields. + const size_t num_ifields = it.NumInstanceFields(); + ArtField* ifields = num_ifields != 0 ? AllocArtFieldArray(self, num_ifields) : nullptr; + for (size_t i = 0; it.HasNextInstanceField(); i++, it.Next()) { + CHECK_LT(i, num_ifields); + LoadField(it, klass, &ifields[i]); + } + klass->SetIFields(ifields); + klass->SetNumInstanceFields(num_ifields); + DCHECK_EQ(klass->NumInstanceFields(), num_ifields); + // Load methods. + if (it.NumDirectMethods() != 0) { + klass->SetDirectMethodsPtr(AllocArtMethodArray(self, it.NumDirectMethods())); + } + klass->SetNumDirectMethods(it.NumDirectMethods()); + if (it.NumVirtualMethods() != 0) { + klass->SetVirtualMethodsPtr(AllocArtMethodArray(self, it.NumVirtualMethods())); + } + klass->SetNumVirtualMethods(it.NumVirtualMethods()); + size_t class_def_method_index = 0; + uint32_t last_dex_method_index = DexFile::kDexNoIndex; + size_t last_class_def_method_index = 0; + for (size_t i = 0; it.HasNextDirectMethod(); i++, it.Next()) { + ArtMethod* method = klass->GetDirectMethodUnchecked(i, image_pointer_size_); + LoadMethod(self, dex_file, it, klass, method); + LinkCode(method, oat_class, class_def_method_index); + uint32_t it_method_index = it.GetMemberIndex(); + if (last_dex_method_index == it_method_index) { + // duplicate case + method->SetMethodIndex(last_class_def_method_index); + } else { + method->SetMethodIndex(class_def_method_index); + last_dex_method_index = it_method_index; + last_class_def_method_index = class_def_method_index; + } + class_def_method_index++; } - klass->SetDirectMethod(i, method.Get()); - LinkCode(method, oat_class, class_def_method_index); - uint32_t it_method_index = it.GetMemberIndex(); - if (last_dex_method_index == it_method_index) { - // duplicate case - method->SetMethodIndex(last_class_def_method_index); - } else { - method->SetMethodIndex(class_def_method_index); - last_dex_method_index = it_method_index; - last_class_def_method_index = class_def_method_index; + for (size_t i = 0; it.HasNextVirtualMethod(); i++, it.Next()) { + ArtMethod* method = klass->GetVirtualMethodUnchecked(i, image_pointer_size_); + LoadMethod(self, dex_file, it, klass, method); + DCHECK_EQ(class_def_method_index, it.NumDirectMethods() + i); + LinkCode(method, oat_class, class_def_method_index); + class_def_method_index++; } - class_def_method_index++; + DCHECK(!it.HasNext()); } - for (size_t i = 0; it.HasNextVirtualMethod(); i++, it.Next()) { - self->AllowThreadSuspension(); - StackHandleScope<1> hs(self); - Handle<mirror::ArtMethod> method(hs.NewHandle(LoadMethod(self, dex_file, it, klass))); - if (UNLIKELY(method.Get() == nullptr)) { - CHECK(self->IsExceptionPending()); // OOME. - return; - } - klass->SetVirtualMethod(i, method.Get()); - DCHECK_EQ(class_def_method_index, it.NumDirectMethods() + i); - LinkCode(method, oat_class, class_def_method_index); - class_def_method_index++; - } - DCHECK(!it.HasNext()); + self->AllowThreadSuspension(); } void ClassLinker::LoadField(const ClassDataItemIterator& it, Handle<mirror::Class> klass, @@ -2318,20 +2376,12 @@ void ClassLinker::LoadField(const ClassDataItemIterator& it, Handle<mirror::Clas dst->SetAccessFlags(it.GetFieldAccessFlags()); } -mirror::ArtMethod* ClassLinker::LoadMethod(Thread* self, const DexFile& dex_file, - const ClassDataItemIterator& it, - Handle<mirror::Class> klass) { +void ClassLinker::LoadMethod(Thread* self, const DexFile& dex_file, const ClassDataItemIterator& it, + Handle<mirror::Class> klass, ArtMethod* dst) { uint32_t dex_method_idx = it.GetMemberIndex(); const DexFile::MethodId& method_id = dex_file.GetMethodId(dex_method_idx); const char* method_name = dex_file.StringDataByIdx(method_id.name_idx_); - mirror::ArtMethod* dst = AllocArtMethod(self); - if (UNLIKELY(dst == nullptr)) { - CHECK(self->IsExceptionPending()); // OOME. - return nullptr; - } - DCHECK(dst->IsArtMethod()) << PrettyDescriptor(dst->GetClass()); - ScopedAssertNoThreadSuspension ants(self, "LoadMethod"); dst->SetDexMethodIndex(dex_method_idx); dst->SetDeclaringClass(klass.Get()); @@ -2377,8 +2427,6 @@ mirror::ArtMethod* ClassLinker::LoadMethod(Thread* self, const DexFile& dex_file } } dst->SetAccessFlags(access_flags); - - return dst; } void ClassLinker::AppendToBootClassPath(Thread* self, const DexFile& dex_file) { @@ -2482,17 +2530,17 @@ mirror::DexCache* ClassLinker::FindDexCache(const DexFile& dex_file) { UNREACHABLE(); } -void ClassLinker::FixupDexCaches(mirror::ArtMethod* resolution_method) { +void ClassLinker::FixupDexCaches(ArtMethod* resolution_method) { ReaderMutexLock mu(Thread::Current(), dex_lock_); - for (size_t i = 0; i != dex_caches_.size(); ++i) { - mirror::DexCache* dex_cache = GetDexCache(i); - dex_cache->Fixup(resolution_method); + for (auto& dex_cache : dex_caches_) { + dex_cache.Read()->Fixup(resolution_method, image_pointer_size_); } } mirror::Class* ClassLinker::CreatePrimitiveClass(Thread* self, Primitive::Type type) { - mirror::Class* klass = AllocClass(self, mirror::Class::PrimitiveClassSize()); + mirror::Class* klass = AllocClass(self, mirror::Class::PrimitiveClassSize(image_pointer_size_)); if (UNLIKELY(klass == nullptr)) { + self->AssertPendingOOMException(); return nullptr; } return InitializePrimitiveClass(klass, type); @@ -2593,9 +2641,6 @@ mirror::Class* ClassLinker::CreateArrayClass(Thread* self, const char* descripto new_class.Assign(GetClassRoot(kObjectArrayClass)); } else if (strcmp(descriptor, GetClassRootDescriptor(kJavaLangStringArrayClass)) == 0) { new_class.Assign(GetClassRoot(kJavaLangStringArrayClass)); - } else if (strcmp(descriptor, - GetClassRootDescriptor(kJavaLangReflectArtMethodArrayClass)) == 0) { - new_class.Assign(GetClassRoot(kJavaLangReflectArtMethodArrayClass)); } else if (strcmp(descriptor, "[C") == 0) { new_class.Assign(GetClassRoot(kCharArrayClass)); } else if (strcmp(descriptor, "[I") == 0) { @@ -2605,8 +2650,9 @@ mirror::Class* ClassLinker::CreateArrayClass(Thread* self, const char* descripto } } if (new_class.Get() == nullptr) { - new_class.Assign(AllocClass(self, mirror::Array::ClassSize())); + new_class.Assign(AllocClass(self, mirror::Array::ClassSize(image_pointer_size_))); if (new_class.Get() == nullptr) { + self->AssertPendingOOMException(); return nullptr; } new_class->SetComponentType(component_type.Get()); @@ -2620,9 +2666,9 @@ mirror::Class* ClassLinker::CreateArrayClass(Thread* self, const char* descripto new_class->SetClassLoader(component_type->GetClassLoader()); mirror::Class::SetStatus(new_class, mirror::Class::kStatusLoaded, self); { - StackHandleScope<mirror::Class::kImtSize> hs2(self, - Runtime::Current()->GetImtUnimplementedMethod()); - new_class->PopulateEmbeddedImtAndVTable(&hs2); + ArtMethod* imt[mirror::Class::kImtSize]; + std::fill_n(imt, arraysize(imt), Runtime::Current()->GetImtUnimplementedMethod()); + new_class->PopulateEmbeddedImtAndVTable(imt, image_pointer_size_); } mirror::Class::SetStatus(new_class, mirror::Class::kStatusInitialized, self); // don't need to set new_class->SetObjectSize(..) @@ -2732,6 +2778,18 @@ mirror::Class* ClassLinker::InsertClass(const char* descriptor, mirror::Class* k return nullptr; } +void ClassLinker::UpdateClassVirtualMethods(mirror::Class* klass, ArtMethod* new_methods, + size_t new_num_methods) { + // classlinker_classes_lock_ is used to guard against races between root marking and changing the + // direct and virtual method pointers. + WriterMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_); + klass->SetNumVirtualMethods(new_num_methods); + klass->SetVirtualMethodsPtr(new_methods); + if (log_new_class_table_roots_) { + new_class_roots_.push_back(GcRoot<mirror::Class>(klass)); + } +} + mirror::Class* ClassLinker::UpdateClass(const char* descriptor, mirror::Class* klass, size_t hash) { WriterMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_); @@ -3073,7 +3131,7 @@ void ClassLinker::VerifyClass(Thread* self, Handle<mirror::Class> klass) { void ClassLinker::EnsurePreverifiedMethods(Handle<mirror::Class> klass) { if (!klass->IsPreverified()) { - klass->SetPreverifiedFlagOnAllMethods(); + klass->SetPreverifiedFlagOnAllMethods(image_pointer_size_); klass->SetPreverified(); } } @@ -3164,15 +3222,15 @@ bool ClassLinker::VerifyClassUsingOatFile(const DexFile& dex_file, mirror::Class void ClassLinker::ResolveClassExceptionHandlerTypes(const DexFile& dex_file, Handle<mirror::Class> klass) { for (size_t i = 0; i < klass->NumDirectMethods(); i++) { - ResolveMethodExceptionHandlerTypes(dex_file, klass->GetDirectMethod(i)); + ResolveMethodExceptionHandlerTypes(dex_file, klass->GetDirectMethod(i, image_pointer_size_)); } for (size_t i = 0; i < klass->NumVirtualMethods(); i++) { - ResolveMethodExceptionHandlerTypes(dex_file, klass->GetVirtualMethod(i)); + ResolveMethodExceptionHandlerTypes(dex_file, klass->GetVirtualMethod(i, image_pointer_size_)); } } void ClassLinker::ResolveMethodExceptionHandlerTypes(const DexFile& dex_file, - mirror::ArtMethod* method) { + ArtMethod* method) { // similar to DexVerifier::ScanTryCatchBlocks and dex2oat's ResolveExceptionsForMethod. const DexFile::CodeItem* code_item = dex_file.GetCodeItem(method->GetCodeItemOffset()); if (code_item == nullptr) { @@ -3201,10 +3259,6 @@ void ClassLinker::ResolveMethodExceptionHandlerTypes(const DexFile& dex_file, } } -static void CheckProxyConstructor(mirror::ArtMethod* constructor); -static void CheckProxyMethod(Handle<mirror::ArtMethod> method, - Handle<mirror::ArtMethod> prototype); - mirror::Class* ClassLinker::CreateProxyClass(ScopedObjectAccessAlreadyRunnable& soa, jstring name, jobjectArray interfaces, jobject loader, jobjectArray methods, jobjectArray throws) { @@ -3255,48 +3309,37 @@ mirror::Class* ClassLinker::CreateProxyClass(ScopedObjectAccessAlreadyRunnable& throws_sfield->SetAccessFlags(kAccStatic | kAccPublic | kAccFinal); // Proxies have 1 direct method, the constructor - { - StackHandleScope<2> hs2(self); - Handle<mirror::ObjectArray<mirror::ArtMethod>> directs = - hs2.NewHandle(AllocArtMethodArray(self, 1)); - if (UNLIKELY(directs.Get() == nullptr)) { - CHECK(self->IsExceptionPending()); // OOME. - return nullptr; - } - klass->SetDirectMethods(directs.Get()); - Handle<mirror::ArtMethod> constructor = - hs2.NewHandle(CreateProxyConstructor(self, klass)); - if (UNLIKELY(constructor.Get() == nullptr)) { - CHECK(self->IsExceptionPending()); // OOME. - return nullptr; - } - klass->SetDirectMethod(0, constructor.Get()); + auto* directs = AllocArtMethodArray(self, 1); + // Currently AllocArtMethodArray cannot return null, but the OOM logic is left there in case we + // want to throw OOM in the future. + if (UNLIKELY(directs == nullptr)) { + self->AssertPendingOOMException(); + return nullptr; } + klass->SetDirectMethodsPtr(directs); + klass->SetNumDirectMethods(1u); + CreateProxyConstructor(klass, klass->GetDirectMethodUnchecked(0, image_pointer_size_)); // Create virtual method using specified prototypes. auto h_methods = hs.NewHandle(soa.Decode<mirror::ObjectArray<mirror::Method>*>(methods)); DCHECK_EQ(h_methods->GetClass(), mirror::Method::ArrayClass()) << PrettyClass(h_methods->GetClass()); const size_t num_virtual_methods = h_methods->GetLength(); - { - StackHandleScope<1> hs2(self); - Handle<mirror::ObjectArray<mirror::ArtMethod>> virtuals = - hs2.NewHandle(AllocArtMethodArray(self, num_virtual_methods)); - if (UNLIKELY(virtuals.Get() == nullptr)) { - CHECK(self->IsExceptionPending()); // OOME. - return nullptr; - } - klass->SetVirtualMethods(virtuals.Get()); + auto* virtuals = AllocArtMethodArray(self, num_virtual_methods); + // Currently AllocArtMethodArray cannot return null, but the OOM logic is left there in case we + // want to throw OOM in the future. + if (UNLIKELY(virtuals == nullptr)) { + self->AssertPendingOOMException(); + return nullptr; } + klass->SetVirtualMethodsPtr(virtuals); + klass->SetNumVirtualMethods(num_virtual_methods); for (size_t i = 0; i < num_virtual_methods; ++i) { - StackHandleScope<2> hs2(self); - Handle<mirror::ArtMethod> prototype(hs2.NewHandle(h_methods->Get(i)->GetArtMethod())); - Handle<mirror::ArtMethod> clone(hs2.NewHandle(CreateProxyMethod(self, klass, prototype))); - if (UNLIKELY(clone.Get() == nullptr)) { - CHECK(self->IsExceptionPending()); // OOME. - return nullptr; - } - klass->SetVirtualMethod(i, clone.Get()); + auto* virtual_method = klass->GetVirtualMethodUnchecked(i, image_pointer_size_); + auto* prototype = h_methods->Get(i)->GetArtMethod(); + CreateProxyMethod(klass, prototype, virtual_method); + DCHECK(virtual_method->GetDeclaringClass() != nullptr); + DCHECK(prototype->GetDeclaringClass() != nullptr); } // The super class is java.lang.reflect.Proxy @@ -3311,7 +3354,7 @@ mirror::Class* ClassLinker::CreateProxyClass(ScopedObjectAccessAlreadyRunnable& ObjectLock<mirror::Class> resolution_lock(self, klass); // Link the fields and virtual methods, creating vtable and iftables. // The new class will replace the old one in the class table. - 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, descriptor.c_str(), klass, h_interfaces, &new_class)) { mirror::Class::SetStatus(klass, mirror::Class::kStatusError, self); @@ -3338,11 +3381,11 @@ mirror::Class* ClassLinker::CreateProxyClass(ScopedObjectAccessAlreadyRunnable& // sanity checks if (kIsDebugBuild) { CHECK(klass->GetIFields() == nullptr); - CheckProxyConstructor(klass->GetDirectMethod(0)); + CheckProxyConstructor(klass->GetDirectMethod(0, image_pointer_size_)); + for (size_t i = 0; i < num_virtual_methods; ++i) { - StackHandleScope<2> hs2(self); - Handle<mirror::ArtMethod> prototype(hs2.NewHandle(h_methods->Get(i)->GetArtMethod())); - Handle<mirror::ArtMethod> virtual_method(hs2.NewHandle(klass->GetVirtualMethod(i))); + auto* virtual_method = klass->GetVirtualMethodUnchecked(i, image_pointer_size_); + auto* prototype = h_methods->Get(i++)->GetArtMethod(); CheckProxyMethod(virtual_method, prototype); } @@ -3371,8 +3414,8 @@ std::string ClassLinker::GetDescriptorForProxy(mirror::Class* proxy_class) { return DotToDescriptor(name->ToModifiedUtf8().c_str()); } -mirror::ArtMethod* ClassLinker::FindMethodForProxy(mirror::Class* proxy_class, - mirror::ArtMethod* proxy_method) { +ArtMethod* ClassLinker::FindMethodForProxy(mirror::Class* proxy_class, + ArtMethod* proxy_method) { DCHECK(proxy_class->IsProxyClass()); DCHECK(proxy_method->IsProxyMethod()); { @@ -3381,8 +3424,8 @@ mirror::ArtMethod* ClassLinker::FindMethodForProxy(mirror::Class* proxy_class, for (const GcRoot<mirror::DexCache>& root : dex_caches_) { auto* dex_cache = root.Read(); if (proxy_method->HasSameDexCacheResolvedTypes(dex_cache->GetResolvedTypes())) { - mirror::ArtMethod* resolved_method = dex_cache->GetResolvedMethod( - proxy_method->GetDexMethodIndex()); + ArtMethod* resolved_method = dex_cache->GetResolvedMethod( + proxy_method->GetDexMethodIndex(), image_pointer_size_); CHECK(resolved_method != nullptr); return resolved_method; } @@ -3393,74 +3436,60 @@ mirror::ArtMethod* ClassLinker::FindMethodForProxy(mirror::Class* proxy_class, UNREACHABLE(); } - -mirror::ArtMethod* ClassLinker::CreateProxyConstructor(Thread* self, - Handle<mirror::Class> klass) { - // Create constructor for Proxy that must initialize h - mirror::ObjectArray<mirror::ArtMethod>* proxy_direct_methods = - GetClassRoot(kJavaLangReflectProxy)->GetDirectMethods(); - CHECK_EQ(proxy_direct_methods->GetLength(), 16); - mirror::ArtMethod* proxy_constructor = proxy_direct_methods->Get(2); +void ClassLinker::CreateProxyConstructor(Handle<mirror::Class> klass, ArtMethod* out) { + // Create constructor for Proxy that must initialize the method. + CHECK_EQ(GetClassRoot(kJavaLangReflectProxy)->NumDirectMethods(), 16u); + ArtMethod* proxy_constructor = GetClassRoot(kJavaLangReflectProxy)->GetDirectMethodUnchecked( + 2, image_pointer_size_); // Ensure constructor is in dex cache so that we can use the dex cache to look up the overridden // constructor method. GetClassRoot(kJavaLangReflectProxy)->GetDexCache()->SetResolvedMethod( - proxy_constructor->GetDexMethodIndex(), proxy_constructor); + proxy_constructor->GetDexMethodIndex(), proxy_constructor, image_pointer_size_); // Clone the existing constructor of Proxy (our constructor would just invoke it so steal its // code_ too) - mirror::ArtMethod* constructor = down_cast<mirror::ArtMethod*>(proxy_constructor->Clone(self)); - if (constructor == nullptr) { - CHECK(self->IsExceptionPending()); // OOME. - return nullptr; - } + DCHECK(out != nullptr); + out->CopyFrom(proxy_constructor, image_pointer_size_); // Make this constructor public and fix the class to be our Proxy version - constructor->SetAccessFlags((constructor->GetAccessFlags() & ~kAccProtected) | kAccPublic); - constructor->SetDeclaringClass(klass.Get()); - return constructor; + out->SetAccessFlags((out->GetAccessFlags() & ~kAccProtected) | kAccPublic); + out->SetDeclaringClass(klass.Get()); } -static void CheckProxyConstructor(mirror::ArtMethod* constructor) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { +void ClassLinker::CheckProxyConstructor(ArtMethod* constructor) const { CHECK(constructor->IsConstructor()); - CHECK_STREQ(constructor->GetName(), "<init>"); - CHECK_STREQ(constructor->GetSignature().ToString().c_str(), - "(Ljava/lang/reflect/InvocationHandler;)V"); + auto* np = constructor->GetInterfaceMethodIfProxy(image_pointer_size_); + CHECK_STREQ(np->GetName(), "<init>"); + CHECK_STREQ(np->GetSignature().ToString().c_str(), "(Ljava/lang/reflect/InvocationHandler;)V"); DCHECK(constructor->IsPublic()); } -mirror::ArtMethod* ClassLinker::CreateProxyMethod(Thread* self, - Handle<mirror::Class> klass, - Handle<mirror::ArtMethod> prototype) { +void ClassLinker::CreateProxyMethod(Handle<mirror::Class> klass, ArtMethod* prototype, + ArtMethod* out) { // Ensure prototype is in dex cache so that we can use the dex cache to look up the overridden // prototype method auto* dex_cache = prototype->GetDeclaringClass()->GetDexCache(); // Avoid dirtying the dex cache unless we need to. - if (dex_cache->GetResolvedMethod(prototype->GetDexMethodIndex()) != prototype.Get()) { - dex_cache->SetResolvedMethod(prototype->GetDexMethodIndex(), prototype.Get()); + if (dex_cache->GetResolvedMethod(prototype->GetDexMethodIndex(), image_pointer_size_) != + prototype) { + dex_cache->SetResolvedMethod( + prototype->GetDexMethodIndex(), prototype, image_pointer_size_); } // We steal everything from the prototype (such as DexCache, invoke stub, etc.) then specialize // as necessary - mirror::ArtMethod* method = down_cast<mirror::ArtMethod*>(prototype->Clone(self)); - if (UNLIKELY(method == nullptr)) { - CHECK(self->IsExceptionPending()); // OOME. - return nullptr; - } + DCHECK(out != nullptr); + out->CopyFrom(prototype, image_pointer_size_); // Set class to be the concrete proxy class and clear the abstract flag, modify exceptions to // the intersection of throw exceptions as defined in Proxy - method->SetDeclaringClass(klass.Get()); - method->SetAccessFlags((method->GetAccessFlags() & ~kAccAbstract) | kAccFinal); + out->SetDeclaringClass(klass.Get()); + out->SetAccessFlags((out->GetAccessFlags() & ~kAccAbstract) | kAccFinal); // At runtime the method looks like a reference and argument saving method, clone the code // related parameters from this method. - method->SetEntryPointFromQuickCompiledCode(GetQuickProxyInvokeHandler()); - method->SetEntryPointFromInterpreter(artInterpreterToCompiledCodeBridge); - - return method; + out->SetEntryPointFromQuickCompiledCode(GetQuickProxyInvokeHandler()); + out->SetEntryPointFromInterpreter(artInterpreterToCompiledCodeBridge); } -static void CheckProxyMethod(Handle<mirror::ArtMethod> method, - Handle<mirror::ArtMethod> prototype) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { +void ClassLinker::CheckProxyMethod(ArtMethod* method, ArtMethod* prototype) const { // Basic sanity CHECK(!prototype->IsFinal()); CHECK(method->IsFinal()); @@ -3468,26 +3497,26 @@ static void CheckProxyMethod(Handle<mirror::ArtMethod> method, // The proxy method doesn't have its own dex cache or dex file and so it steals those of its // interface prototype. The exception to this are Constructors and the Class of the Proxy itself. - CHECK(prototype->HasSameDexCacheResolvedMethods(method.Get())); - CHECK(prototype->HasSameDexCacheResolvedTypes(method.Get())); - CHECK_EQ(prototype->GetDeclaringClass()->GetDexCache(), method->GetDexCache()); + CHECK(prototype->HasSameDexCacheResolvedMethods(method)); + CHECK(prototype->HasSameDexCacheResolvedTypes(method)); + auto* np = method->GetInterfaceMethodIfProxy(image_pointer_size_); + CHECK_EQ(prototype->GetDeclaringClass()->GetDexCache(), np->GetDexCache()); CHECK_EQ(prototype->GetDexMethodIndex(), method->GetDexMethodIndex()); - CHECK_STREQ(method->GetName(), prototype->GetName()); - CHECK_STREQ(method->GetShorty(), prototype->GetShorty()); + CHECK_STREQ(np->GetName(), prototype->GetName()); + CHECK_STREQ(np->GetShorty(), prototype->GetShorty()); // More complex sanity - via dex cache - CHECK_EQ(method->GetInterfaceMethodIfProxy()->GetReturnType(), prototype->GetReturnType()); + CHECK_EQ(np->GetReturnType(), prototype->GetReturnType()); } -static bool CanWeInitializeClass(mirror::Class* klass, bool can_init_statics, - bool can_init_parents) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { +bool ClassLinker::CanWeInitializeClass(mirror::Class* klass, bool can_init_statics, + bool can_init_parents) { if (can_init_statics && can_init_parents) { return true; } if (!can_init_statics) { // Check if there's a class initializer. - mirror::ArtMethod* clinit = klass->FindClassInitializer(); + ArtMethod* clinit = klass->FindClassInitializer(image_pointer_size_); if (clinit != nullptr) { return false; } @@ -3500,17 +3529,14 @@ static bool CanWeInitializeClass(mirror::Class* klass, bool can_init_statics, } } } - if (!klass->IsInterface() && klass->HasSuperClass()) { - mirror::Class* super_class = klass->GetSuperClass(); - if (!can_init_parents && !super_class->IsInitialized()) { - return false; - } else { - if (!CanWeInitializeClass(super_class, can_init_statics, can_init_parents)) { - return false; - } - } + if (klass->IsInterface() || !klass->HasSuperClass()) { + return true; } - return true; + mirror::Class* super_class = klass->GetSuperClass(); + if (!can_init_parents && !super_class->IsInitialized()) { + return false; + } + return CanWeInitializeClass(super_class, can_init_statics, can_init_parents); } bool ClassLinker::InitializeClass(Thread* self, Handle<mirror::Class> klass, @@ -3670,7 +3696,7 @@ bool ClassLinker::InitializeClass(Thread* self, Handle<mirror::Class> klass, } } - mirror::ArtMethod* clinit = klass->FindClassInitializer(); + ArtMethod* clinit = klass->FindClassInitializer(image_pointer_size_); if (clinit != nullptr) { CHECK(can_init_statics); JValue result; @@ -3761,8 +3787,8 @@ bool ClassLinker::WaitForInitializeClass(Handle<mirror::Class> klass, Thread* se static void ThrowSignatureCheckResolveReturnTypeException(Handle<mirror::Class> klass, Handle<mirror::Class> super_klass, - Handle<mirror::ArtMethod> method, - mirror::ArtMethod* m) + ArtMethod* method, + ArtMethod* m) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { DCHECK(Thread::Current()->IsExceptionPending()); DCHECK(!m->IsProxyMethod()); @@ -3776,7 +3802,7 @@ static void ThrowSignatureCheckResolveReturnTypeException(Handle<mirror::Class> "While checking class %s method %s signature against %s %s: " "Failed to resolve return type %s with %s", PrettyDescriptor(klass.Get()).c_str(), - PrettyMethod(method.Get()).c_str(), + PrettyMethod(method).c_str(), super_klass->IsInterface() ? "interface" : "superclass", PrettyDescriptor(super_klass.Get()).c_str(), return_type.c_str(), class_loader.c_str()); @@ -3784,8 +3810,8 @@ static void ThrowSignatureCheckResolveReturnTypeException(Handle<mirror::Class> static void ThrowSignatureCheckResolveArgException(Handle<mirror::Class> klass, Handle<mirror::Class> super_klass, - Handle<mirror::ArtMethod> method, - mirror::ArtMethod* m, + ArtMethod* method, + ArtMethod* m, uint32_t index, uint32_t arg_type_idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { DCHECK(Thread::Current()->IsExceptionPending()); @@ -3797,7 +3823,7 @@ static void ThrowSignatureCheckResolveArgException(Handle<mirror::Class> klass, "While checking class %s method %s signature against %s %s: " "Failed to resolve arg %u type %s with %s", PrettyDescriptor(klass.Get()).c_str(), - PrettyMethod(method.Get()).c_str(), + PrettyMethod(method).c_str(), super_klass->IsInterface() ? "interface" : "superclass", PrettyDescriptor(super_klass.Get()).c_str(), index, arg_type.c_str(), class_loader.c_str()); @@ -3805,13 +3831,13 @@ static void ThrowSignatureCheckResolveArgException(Handle<mirror::Class> klass, static void ThrowSignatureMismatch(Handle<mirror::Class> klass, Handle<mirror::Class> super_klass, - Handle<mirror::ArtMethod> method, + ArtMethod* method, const std::string& error_msg) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { ThrowLinkageError(klass.Get(), "Class %s method %s resolves differently in %s %s: %s", PrettyDescriptor(klass.Get()).c_str(), - PrettyMethod(method.Get()).c_str(), + PrettyMethod(method).c_str(), super_klass->IsInterface() ? "interface" : "superclass", PrettyDescriptor(super_klass.Get()).c_str(), error_msg.c_str()); @@ -3820,19 +3846,19 @@ static void ThrowSignatureMismatch(Handle<mirror::Class> klass, static bool HasSameSignatureWithDifferentClassLoaders(Thread* self, Handle<mirror::Class> klass, Handle<mirror::Class> super_klass, - Handle<mirror::ArtMethod> method1, - Handle<mirror::ArtMethod> method2) + ArtMethod* method1, + ArtMethod* method2) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { { StackHandleScope<1> hs(self); Handle<mirror::Class> return_type(hs.NewHandle(method1->GetReturnType())); if (UNLIKELY(return_type.Get() == nullptr)) { - ThrowSignatureCheckResolveReturnTypeException(klass, super_klass, method1, method1.Get()); + ThrowSignatureCheckResolveReturnTypeException(klass, super_klass, method1, method1); return false; } mirror::Class* other_return_type = method2->GetReturnType(); if (UNLIKELY(other_return_type == nullptr)) { - ThrowSignatureCheckResolveReturnTypeException(klass, super_klass, method1, method2.Get()); + ThrowSignatureCheckResolveReturnTypeException(klass, super_klass, method1, method2); return false; } if (UNLIKELY(other_return_type != return_type.Get())) { @@ -3851,7 +3877,7 @@ static bool HasSameSignatureWithDifferentClassLoaders(Thread* self, if (types2 != nullptr && types2->Size() != 0) { ThrowSignatureMismatch(klass, super_klass, method1, StringPrintf("Type list mismatch with %s", - PrettyMethod(method2.Get(), true).c_str())); + PrettyMethod(method2, true).c_str())); return false; } return true; @@ -3859,7 +3885,7 @@ static bool HasSameSignatureWithDifferentClassLoaders(Thread* self, if (types1->Size() != 0) { ThrowSignatureMismatch(klass, super_klass, method1, StringPrintf("Type list mismatch with %s", - PrettyMethod(method2.Get(), true).c_str())); + PrettyMethod(method2, true).c_str())); return false; } return true; @@ -3868,7 +3894,7 @@ static bool HasSameSignatureWithDifferentClassLoaders(Thread* self, if (UNLIKELY(num_types != types2->Size())) { ThrowSignatureMismatch(klass, super_klass, method1, StringPrintf("Type list mismatch with %s", - PrettyMethod(method2.Get(), true).c_str())); + PrettyMethod(method2, true).c_str())); return false; } for (uint32_t i = 0; i < num_types; ++i) { @@ -3878,7 +3904,7 @@ static bool HasSameSignatureWithDifferentClassLoaders(Thread* self, method1->GetClassFromTypeIndex(param_type_idx, true))); if (UNLIKELY(param_type.Get() == nullptr)) { ThrowSignatureCheckResolveArgException(klass, super_klass, method1, - method1.Get(), i, param_type_idx); + method1, i, param_type_idx); return false; } uint32_t other_param_type_idx = types2->GetTypeItem(i).type_idx_; @@ -3886,7 +3912,7 @@ static bool HasSameSignatureWithDifferentClassLoaders(Thread* self, method2->GetClassFromTypeIndex(other_param_type_idx, true); if (UNLIKELY(other_param_type == nullptr)) { ThrowSignatureCheckResolveArgException(klass, super_klass, method1, - method2.Get(), i, other_param_type_idx); + method2, i, other_param_type_idx); return false; } if (UNLIKELY(param_type.Get() != other_param_type)) { @@ -3910,19 +3936,17 @@ bool ClassLinker::ValidateSuperClassDescriptors(Handle<mirror::Class> klass) { } // Begin with the methods local to the superclass. Thread* self = Thread::Current(); - StackHandleScope<3> hs(self); + StackHandleScope<1> hs(self); MutableHandle<mirror::Class> super_klass(hs.NewHandle<mirror::Class>(nullptr)); - MutableHandle<mirror::ArtMethod> h_m(hs.NewHandle<mirror::ArtMethod>(nullptr)); - MutableHandle<mirror::ArtMethod> super_h_m(hs.NewHandle<mirror::ArtMethod>(nullptr)); if (klass->HasSuperClass() && klass->GetClassLoader() != klass->GetSuperClass()->GetClassLoader()) { super_klass.Assign(klass->GetSuperClass()); for (int i = klass->GetSuperClass()->GetVTableLength() - 1; i >= 0; --i) { - h_m.Assign(klass->GetVTableEntry(i)); - super_h_m.Assign(klass->GetSuperClass()->GetVTableEntry(i)); - if (h_m.Get() != super_h_m.Get()) { + auto* m = klass->GetVTableEntry(i, image_pointer_size_); + auto* super_m = klass->GetSuperClass()->GetVTableEntry(i, image_pointer_size_); + if (m != super_m) { if (UNLIKELY(!HasSameSignatureWithDifferentClassLoaders(self, klass, super_klass, - h_m, super_h_m))) { + m, super_m))) { self->AssertPendingException(); return false; } @@ -3934,11 +3958,12 @@ bool ClassLinker::ValidateSuperClassDescriptors(Handle<mirror::Class> klass) { if (klass->GetClassLoader() != super_klass->GetClassLoader()) { uint32_t num_methods = super_klass->NumVirtualMethods(); for (uint32_t j = 0; j < num_methods; ++j) { - h_m.Assign(klass->GetIfTable()->GetMethodArray(i)->GetWithoutChecks(j)); - super_h_m.Assign(super_klass->GetVirtualMethod(j)); - if (h_m.Get() != super_h_m.Get()) { + auto* m = klass->GetIfTable()->GetMethodArray(i)->GetElementPtrSize<ArtMethod*>( + j, image_pointer_size_); + auto* super_m = super_klass->GetVirtualMethod(j, image_pointer_size_); + if (m != super_m) { if (UNLIKELY(!HasSameSignatureWithDifferentClassLoaders(self, klass, super_klass, - h_m, super_h_m))) { + m, super_m))) { self->AssertPendingException(); return false; } @@ -3967,8 +3992,10 @@ bool ClassLinker::EnsureInitialized(Thread* self, Handle<mirror::Class> c, bool return success; } -void ClassLinker::FixupTemporaryDeclaringClass(mirror::Class* temp_class, mirror::Class* new_class) { +void ClassLinker::FixupTemporaryDeclaringClass(mirror::Class* temp_class, + mirror::Class* new_class) { ArtField* fields = new_class->GetIFields(); + DCHECK_EQ(temp_class->NumInstanceFields(), new_class->NumInstanceFields()); for (size_t i = 0, count = new_class->NumInstanceFields(); i < count; i++) { if (fields[i].GetDeclaringClass() == temp_class) { fields[i].SetDeclaringClass(new_class); @@ -3976,27 +4003,24 @@ void ClassLinker::FixupTemporaryDeclaringClass(mirror::Class* temp_class, mirror } fields = new_class->GetSFields(); + DCHECK_EQ(temp_class->NumStaticFields(), new_class->NumStaticFields()); for (size_t i = 0, count = new_class->NumStaticFields(); i < count; i++) { if (fields[i].GetDeclaringClass() == temp_class) { fields[i].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); - } + DCHECK_EQ(temp_class->NumDirectMethods(), new_class->NumDirectMethods()); + for (auto& method : new_class->GetDirectMethods(image_pointer_size_)) { + if (method.GetDeclaringClass() == temp_class) { + method.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); - } + DCHECK_EQ(temp_class->NumVirtualMethods(), new_class->NumVirtualMethods()); + for (auto& method : new_class->GetVirtualMethods(image_pointer_size_)) { + if (method.GetDeclaringClass() == temp_class) { + method.SetDeclaringClass(new_class); } } } @@ -4009,9 +4033,9 @@ bool ClassLinker::LinkClass(Thread* self, const char* descriptor, Handle<mirror: if (!LinkSuperClass(klass)) { return false; } - StackHandleScope<mirror::Class::kImtSize> imt_handle_scope( - self, Runtime::Current()->GetImtUnimplementedMethod()); - if (!LinkMethods(self, klass, interfaces, &imt_handle_scope)) { + ArtMethod* imt[mirror::Class::kImtSize]; + std::fill_n(imt, arraysize(imt), Runtime::Current()->GetImtUnimplementedMethod()); + if (!LinkMethods(self, klass, interfaces, imt)) { return false; } if (!LinkInstanceFields(self, klass)) { @@ -4030,7 +4054,7 @@ bool ClassLinker::LinkClass(Thread* self, const char* descriptor, Handle<mirror: CHECK_EQ(klass->GetClassSize(), class_size) << PrettyDescriptor(klass.Get()); if (klass->ShouldHaveEmbeddedImtAndVTable()) { - klass->PopulateEmbeddedImtAndVTable(&imt_handle_scope); + klass->PopulateEmbeddedImtAndVTable(imt, image_pointer_size_); } // This will notify waiters on klass that saw the not yet resolved @@ -4041,10 +4065,9 @@ bool ClassLinker::LinkClass(Thread* self, const char* descriptor, Handle<mirror: CHECK(!klass->IsResolved()); // Retire the temporary class and create the correctly sized resolved class. StackHandleScope<1> hs(self); - auto h_new_class = hs.NewHandle<mirror::Class>( - klass->CopyOf(self, class_size, &imt_handle_scope)); + auto h_new_class = hs.NewHandle(klass->CopyOf(self, class_size, imt, image_pointer_size_)); if (UNLIKELY(h_new_class.Get() == nullptr)) { - CHECK(self->IsExceptionPending()); // Expect an OOME. + self->AssertPendingOOMException(); mirror::Class::SetStatus(klass, mirror::Class::kStatusError, self); return false; } @@ -4356,7 +4379,7 @@ bool ClassLinker::LinkSuperClass(Handle<mirror::Class> klass) { // Populate the class vtable and itable. Compute return type indices. bool ClassLinker::LinkMethods(Thread* self, Handle<mirror::Class> klass, Handle<mirror::ObjectArray<mirror::Class>> interfaces, - StackHandleScope<mirror::Class::kImtSize>* out_imt) { + ArtMethod** out_imt) { self->AllowThreadSuspension(); if (klass->IsInterface()) { // No vtable. @@ -4366,7 +4389,7 @@ bool ClassLinker::LinkMethods(Thread* self, Handle<mirror::Class> klass, return false; } for (size_t i = 0; i < count; ++i) { - klass->GetVirtualMethodDuringLinking(i)->SetMethodIndex(i); + klass->GetVirtualMethodDuringLinking(i, image_pointer_size_)->SetMethodIndex(i); } } else if (!LinkVirtualMethods(self, klass)) { // Link virtual methods first. return false; @@ -4379,7 +4402,7 @@ bool ClassLinker::LinkMethods(Thread* self, Handle<mirror::Class> klass, // caches in the implementation below. class MethodNameAndSignatureComparator FINAL : public ValueObject { public: - explicit MethodNameAndSignatureComparator(mirror::ArtMethod* method) + explicit MethodNameAndSignatureComparator(ArtMethod* method) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) : dex_file_(method->GetDexFile()), mid_(&dex_file_->GetMethodId(method->GetDexMethodIndex())), name_(nullptr), name_len_(0) { @@ -4393,7 +4416,7 @@ class MethodNameAndSignatureComparator FINAL : public ValueObject { return name_; } - bool HasSameNameAndSignature(mirror::ArtMethod* other) + bool HasSameNameAndSignature(ArtMethod* other) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { DCHECK(!other->IsProxyMethod()) << PrettyMethod(other); const DexFile* other_dex_file = other->GetDexFile(); @@ -4424,13 +4447,16 @@ class MethodNameAndSignatureComparator FINAL : public ValueObject { class LinkVirtualHashTable { public: - LinkVirtualHashTable(Handle<mirror::Class> klass, size_t hash_size, uint32_t* hash_table) - : klass_(klass), hash_size_(hash_size), hash_table_(hash_table) { + LinkVirtualHashTable(Handle<mirror::Class> klass, size_t hash_size, uint32_t* hash_table, + size_t image_pointer_size) + : klass_(klass), hash_size_(hash_size), hash_table_(hash_table), + image_pointer_size_(image_pointer_size) { std::fill(hash_table_, hash_table_ + hash_size_, invalid_index_); } void Add(uint32_t virtual_method_index) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - mirror::ArtMethod* local_method = klass_->GetVirtualMethodDuringLinking(virtual_method_index); - const char* name = local_method->GetName(); + ArtMethod* local_method = klass_->GetVirtualMethodDuringLinking( + virtual_method_index, image_pointer_size_); + const char* name = local_method->GetInterfaceMethodIfProxy(image_pointer_size_)->GetName(); uint32_t hash = ComputeModifiedUtf8Hash(name); uint32_t index = hash % hash_size_; // Linear probe until we have an empty slot. @@ -4454,9 +4480,10 @@ class LinkVirtualHashTable { break; } if (value != removed_index_) { // This signifies not already overriden. - mirror::ArtMethod* virtual_method = - klass_->GetVirtualMethodDuringLinking(value); - if (comparator->HasSameNameAndSignature(virtual_method->GetInterfaceMethodIfProxy())) { + ArtMethod* virtual_method = + klass_->GetVirtualMethodDuringLinking(value, image_pointer_size_); + if (comparator->HasSameNameAndSignature( + virtual_method->GetInterfaceMethodIfProxy(image_pointer_size_))) { hash_table_[index] = removed_index_; return value; } @@ -4478,6 +4505,7 @@ class LinkVirtualHashTable { Handle<mirror::Class> klass_; const size_t hash_size_; uint32_t* const hash_table_; + const size_t image_pointer_size_; }; const uint32_t LinkVirtualHashTable::invalid_index_ = std::numeric_limits<uint32_t>::max(); @@ -4490,30 +4518,32 @@ bool ClassLinker::LinkVirtualMethods(Thread* self, Handle<mirror::Class> klass) const size_t max_count = num_virtual_methods + super_vtable_length; StackHandleScope<2> hs(self); Handle<mirror::Class> super_class(hs.NewHandle(klass->GetSuperClass())); - MutableHandle<mirror::ObjectArray<mirror::ArtMethod>> vtable; + MutableHandle<mirror::PointerArray> vtable; if (super_class->ShouldHaveEmbeddedImtAndVTable()) { - vtable = hs.NewHandle(AllocArtMethodArray(self, max_count)); + vtable = hs.NewHandle(AllocPointerArray(self, max_count)); if (UNLIKELY(vtable.Get() == nullptr)) { - CHECK(self->IsExceptionPending()); // OOME. + self->AssertPendingOOMException(); return false; } for (size_t i = 0; i < super_vtable_length; i++) { - vtable->SetWithoutChecks<false>(i, super_class->GetEmbeddedVTableEntry(i)); + vtable->SetElementPtrSize( + i, super_class->GetEmbeddedVTableEntry(i, image_pointer_size_), image_pointer_size_); } if (num_virtual_methods == 0) { klass->SetVTable(vtable.Get()); return true; } } else { - mirror::ObjectArray<mirror::ArtMethod>* super_vtable = super_class->GetVTable(); + auto* super_vtable = super_class->GetVTable(); CHECK(super_vtable != nullptr) << PrettyClass(super_class.Get()); if (num_virtual_methods == 0) { klass->SetVTable(super_vtable); return true; } - vtable = hs.NewHandle(super_vtable->CopyOf(self, max_count)); + vtable = hs.NewHandle(down_cast<mirror::PointerArray*>( + super_vtable->CopyOf(self, max_count))); if (UNLIKELY(vtable.Get() == nullptr)) { - CHECK(self->IsExceptionPending()); // OOME. + self->AssertPendingOOMException(); return false; } } @@ -4537,21 +4567,24 @@ bool ClassLinker::LinkVirtualMethods(Thread* self, Handle<mirror::Class> klass) hash_heap_storage.reset(new uint32_t[hash_table_size]); hash_table_ptr = hash_heap_storage.get(); } - LinkVirtualHashTable hash_table(klass, hash_table_size, hash_table_ptr); + LinkVirtualHashTable hash_table(klass, hash_table_size, hash_table_ptr, image_pointer_size_); // Add virtual methods to the hash table. for (size_t i = 0; i < num_virtual_methods; ++i) { + DCHECK(klass->GetVirtualMethodDuringLinking( + i, image_pointer_size_)->GetDeclaringClass() != nullptr); hash_table.Add(i); } // Loop through each super vtable method and see if they are overriden by a method we added to // the hash table. for (size_t j = 0; j < super_vtable_length; ++j) { // Search the hash table to see if we are overidden by any method. - mirror::ArtMethod* super_method = vtable->GetWithoutChecks(j); + ArtMethod* super_method = vtable->GetElementPtrSize<ArtMethod*>(j, image_pointer_size_); MethodNameAndSignatureComparator super_method_name_comparator( - super_method->GetInterfaceMethodIfProxy()); + super_method->GetInterfaceMethodIfProxy(image_pointer_size_)); uint32_t hash_index = hash_table.FindAndRemove(&super_method_name_comparator); if (hash_index != hash_table.GetNotFoundIndex()) { - mirror::ArtMethod* virtual_method = klass->GetVirtualMethodDuringLinking(hash_index); + ArtMethod* virtual_method = klass->GetVirtualMethodDuringLinking( + hash_index, image_pointer_size_); if (klass->CanAccessMember(super_method->GetDeclaringClass(), super_method->GetAccessFlags())) { if (super_method->IsFinal()) { @@ -4560,7 +4593,7 @@ bool ClassLinker::LinkVirtualMethods(Thread* self, Handle<mirror::Class> klass) super_method->GetDeclaringClassDescriptor()); return false; } - vtable->SetWithoutChecks<false>(j, virtual_method); + vtable->SetElementPtrSize(j, virtual_method, image_pointer_size_); virtual_method->SetMethodIndex(j); } else { LOG(WARNING) << "Before Android 4.1, method " << PrettyMethod(virtual_method) @@ -4572,13 +4605,13 @@ bool ClassLinker::LinkVirtualMethods(Thread* self, Handle<mirror::Class> klass) // Add the non overridden methods at the end. size_t actual_count = super_vtable_length; for (size_t i = 0; i < num_virtual_methods; ++i) { - mirror::ArtMethod* local_method = klass->GetVirtualMethodDuringLinking(i); + ArtMethod* local_method = klass->GetVirtualMethodDuringLinking(i, image_pointer_size_); size_t method_idx = local_method->GetMethodIndexDuringLinking(); if (method_idx < super_vtable_length && - local_method == vtable->GetWithoutChecks(method_idx)) { + local_method == vtable->GetElementPtrSize<ArtMethod*>(method_idx, image_pointer_size_)) { continue; } - vtable->SetWithoutChecks<false>(actual_count, local_method); + vtable->SetElementPtrSize(actual_count, local_method, image_pointer_size_); local_method->SetMethodIndex(actual_count); ++actual_count; } @@ -4589,9 +4622,9 @@ bool ClassLinker::LinkVirtualMethods(Thread* self, Handle<mirror::Class> klass) // Shrink vtable if possible CHECK_LE(actual_count, max_count); if (actual_count < max_count) { - vtable.Assign(vtable->CopyOf(self, actual_count)); + vtable.Assign(down_cast<mirror::PointerArray*>(vtable->CopyOf(self, actual_count))); if (UNLIKELY(vtable.Get() == nullptr)) { - CHECK(self->IsExceptionPending()); // OOME. + self->AssertPendingOOMException(); return false; } } @@ -4603,14 +4636,14 @@ bool ClassLinker::LinkVirtualMethods(Thread* self, Handle<mirror::Class> klass) static_cast<int>(num_virtual_methods)); return false; } - mirror::ObjectArray<mirror::ArtMethod>* vtable = AllocArtMethodArray(self, num_virtual_methods); + auto* vtable = AllocPointerArray(self, num_virtual_methods); if (UNLIKELY(vtable == nullptr)) { - CHECK(self->IsExceptionPending()); // OOME. + self->AssertPendingOOMException(); return false; } for (size_t i = 0; i < num_virtual_methods; ++i) { - mirror::ArtMethod* virtual_method = klass->GetVirtualMethodDuringLinking(i); - vtable->SetWithoutChecks<false>(i, virtual_method); + ArtMethod* virtual_method = klass->GetVirtualMethodDuringLinking(i, image_pointer_size_); + vtable->SetElementPtrSize(i, virtual_method, image_pointer_size_); virtual_method->SetMethodIndex(i & 0xFFFF); } klass->SetVTable(vtable); @@ -4620,7 +4653,7 @@ bool ClassLinker::LinkVirtualMethods(Thread* self, Handle<mirror::Class> klass) bool ClassLinker::LinkInterfaceMethods(Thread* self, Handle<mirror::Class> klass, Handle<mirror::ObjectArray<mirror::Class>> interfaces, - StackHandleScope<mirror::Class::kImtSize>* out_imt) { + ArtMethod** out_imt) { StackHandleScope<3> hs(self); Runtime* const runtime = Runtime::Current(); const bool has_superclass = klass->HasSuperClass(); @@ -4628,6 +4661,7 @@ bool ClassLinker::LinkInterfaceMethods(Thread* self, Handle<mirror::Class> klass const bool have_interfaces = interfaces.Get() != nullptr; const size_t num_interfaces = have_interfaces ? interfaces->GetLength() : klass->NumDirectInterfaces(); + const size_t method_size = ArtMethod::ObjectSize(image_pointer_size_); if (num_interfaces == 0) { if (super_ifcount == 0) { // Class implements no interfaces. @@ -4666,7 +4700,7 @@ bool ClassLinker::LinkInterfaceMethods(Thread* self, Handle<mirror::Class> klass } MutableHandle<mirror::IfTable> iftable(hs.NewHandle(AllocIfTable(self, ifcount))); if (UNLIKELY(iftable.Get() == nullptr)) { - CHECK(self->IsExceptionPending()); // OOME. + self->AssertPendingOOMException(); return false; } if (super_ifcount != 0) { @@ -4715,9 +4749,10 @@ bool ClassLinker::LinkInterfaceMethods(Thread* self, Handle<mirror::Class> klass // Shrink iftable in case duplicates were found if (idx < ifcount) { DCHECK_NE(num_interfaces, 0U); - iftable.Assign(down_cast<mirror::IfTable*>(iftable->CopyOf(self, idx * mirror::IfTable::kMax))); + iftable.Assign(down_cast<mirror::IfTable*>( + iftable->CopyOf(self, idx * mirror::IfTable::kMax))); if (UNLIKELY(iftable.Get() == nullptr)) { - CHECK(self->IsExceptionPending()); // OOME. + self->AssertPendingOOMException(); return false; } ifcount = idx; @@ -4729,15 +4764,18 @@ bool ClassLinker::LinkInterfaceMethods(Thread* self, Handle<mirror::Class> klass if (klass->IsInterface()) { return true; } - size_t miranda_list_size = 0; - size_t max_miranda_methods = 0; // The max size of miranda_list. - for (size_t i = 0; i < ifcount; ++i) { - max_miranda_methods += iftable->GetInterface(i)->NumVirtualMethods(); - } - MutableHandle<mirror::ObjectArray<mirror::ArtMethod>> - miranda_list(hs.NewHandle(AllocArtMethodArray(self, max_miranda_methods))); - MutableHandle<mirror::ObjectArray<mirror::ArtMethod>> vtable( - hs.NewHandle(klass->GetVTableDuringLinking())); + // These are allocated on the heap to begin, we then transfer to linear alloc when we re-create + // the virtual methods array. + // Need to use low 4GB arenas for compiler or else the pointers wont fit in 32 bit method array + // during cross compilation. + // Use the linear alloc pool since this one is in the low 4gb for the compiler. + ArenaStack stack(runtime->GetLinearAlloc()->GetArenaPool()); + ScopedArenaAllocator allocator(&stack); + ScopedArenaVector<ArtMethod*> miranda_methods(allocator.Adapter()); + + MutableHandle<mirror::PointerArray> vtable(hs.NewHandle(klass->GetVTableDuringLinking())); + ArtMethod* const unimplemented_method = runtime->GetImtUnimplementedMethod(); + ArtMethod* const conflict_method = runtime->GetImtConflictMethod(); // Copy the IMT from the super class if possible. bool extend_super_iftable = false; if (has_superclass) { @@ -4745,12 +4783,11 @@ bool ClassLinker::LinkInterfaceMethods(Thread* self, Handle<mirror::Class> klass extend_super_iftable = true; if (super_class->ShouldHaveEmbeddedImtAndVTable()) { for (size_t i = 0; i < mirror::Class::kImtSize; ++i) { - out_imt->SetReference(i, super_class->GetEmbeddedImTableEntry(i)); + out_imt[i] = super_class->GetEmbeddedImTableEntry(i, image_pointer_size_); } } else { // No imt in the super class, need to reconstruct from the iftable. mirror::IfTable* if_table = super_class->GetIfTable(); - mirror::ArtMethod* conflict_method = runtime->GetImtConflictMethod(); const size_t length = super_class->GetIfTableCount(); for (size_t i = 0; i < length; ++i) { mirror::Class* interface = iftable->GetInterface(i); @@ -4760,63 +4797,84 @@ bool ClassLinker::LinkInterfaceMethods(Thread* self, Handle<mirror::Class> klass if (method_array_count == 0) { continue; } - mirror::ObjectArray<mirror::ArtMethod>* method_array = if_table->GetMethodArray(i); + auto* method_array = if_table->GetMethodArray(i); for (size_t j = 0; j < num_virtuals; ++j) { - mirror::ArtMethod* method = method_array->GetWithoutChecks(j); + auto method = method_array->GetElementPtrSize<ArtMethod*>(j, image_pointer_size_); + DCHECK(method != nullptr) << PrettyClass(super_class); if (method->IsMiranda()) { continue; } - mirror::ArtMethod* interface_method = interface->GetVirtualMethod(j); + ArtMethod* interface_method = interface->GetVirtualMethod(j, image_pointer_size_); uint32_t imt_index = interface_method->GetDexMethodIndex() % mirror::Class::kImtSize; - mirror::ArtMethod* imt_ref = out_imt->GetReference(imt_index)->AsArtMethod(); - if (imt_ref == runtime->GetImtUnimplementedMethod()) { - out_imt->SetReference(imt_index, method); + auto*& imt_ref = out_imt[imt_index]; + if (imt_ref == unimplemented_method) { + imt_ref = method; } else if (imt_ref != conflict_method) { - out_imt->SetReference(imt_index, conflict_method); + imt_ref = conflict_method; } } } } } + // Allocate method arrays before since we don't want miss visiting miranda method roots due to + // thread suspension. for (size_t i = 0; i < ifcount; ++i) { - self->AllowThreadSuspension(); size_t num_methods = iftable->GetInterface(i)->NumVirtualMethods(); if (num_methods > 0) { - StackHandleScope<2> hs2(self); const bool is_super = i < super_ifcount; const bool super_interface = is_super && extend_super_iftable; - Handle<mirror::ObjectArray<mirror::ArtMethod>> method_array; - Handle<mirror::ObjectArray<mirror::ArtMethod>> input_array; + mirror::PointerArray* method_array; if (super_interface) { mirror::IfTable* if_table = klass->GetSuperClass()->GetIfTable(); DCHECK(if_table != nullptr); DCHECK(if_table->GetMethodArray(i) != nullptr); // If we are working on a super interface, try extending the existing method array. - method_array = hs2.NewHandle(if_table->GetMethodArray(i)->Clone(self)-> - AsObjectArray<mirror::ArtMethod>()); + method_array = down_cast<mirror::PointerArray*>(if_table->GetMethodArray(i)->Clone(self)); + } else { + method_array = AllocPointerArray(self, num_methods); + } + if (UNLIKELY(method_array == nullptr)) { + self->AssertPendingOOMException(); + return false; + } + iftable->SetMethodArray(i, method_array); + } + } + + auto* old_cause = self->StartAssertNoThreadSuspension( + "Copying ArtMethods for LinkInterfaceMethods"); + for (size_t i = 0; i < ifcount; ++i) { + size_t num_methods = iftable->GetInterface(i)->NumVirtualMethods(); + if (num_methods > 0) { + StackHandleScope<2> hs2(self); + const bool is_super = i < super_ifcount; + const bool super_interface = is_super && extend_super_iftable; + auto method_array(hs2.NewHandle(iftable->GetMethodArray(i))); + + ArtMethod* input_virtual_methods = nullptr; + Handle<mirror::PointerArray> input_vtable_array = NullHandle<mirror::PointerArray>(); + int32_t input_array_length = 0; + if (super_interface) { // We are overwriting a super class interface, try to only virtual methods instead of the // whole vtable. - input_array = hs2.NewHandle(klass->GetVirtualMethods()); + input_virtual_methods = klass->GetVirtualMethodsPtr(); + input_array_length = klass->NumVirtualMethods(); } else { - method_array = hs2.NewHandle(AllocArtMethodArray(self, num_methods)); - // A new interface, we need the whole vtable incase a new interface method is implemented + // A new interface, we need the whole vtable in case a new interface method is implemented // in the whole superclass. - input_array = vtable; - } - if (UNLIKELY(method_array.Get() == nullptr)) { - CHECK(self->IsExceptionPending()); // OOME. - return false; + input_vtable_array = vtable; + input_array_length = input_vtable_array->GetLength(); } - iftable->SetMethodArray(i, method_array.Get()); - if (input_array.Get() == nullptr) { + if (input_array_length == 0) { // If the added virtual methods is empty, do nothing. DCHECK(super_interface); continue; } for (size_t j = 0; j < num_methods; ++j) { - mirror::ArtMethod* interface_method = iftable->GetInterface(i)->GetVirtualMethod(j); + auto* interface_method = iftable->GetInterface(i)->GetVirtualMethod( + j, image_pointer_size_); MethodNameAndSignatureComparator interface_name_comparator( - interface_method->GetInterfaceMethodIfProxy()); + interface_method->GetInterfaceMethodIfProxy(image_pointer_size_)); int32_t k; // For each method listed in the interface's method list, find the // matching method in our class's method list. We want to favor the @@ -4826,108 +4884,161 @@ bool ClassLinker::LinkInterfaceMethods(Thread* self, Handle<mirror::Class> klass // it -- otherwise it would use the same vtable slot. In .dex files // those don't end up in the virtual method table, so it shouldn't // matter which direction we go. We walk it backward anyway.) - for (k = input_array->GetLength() - 1; k >= 0; --k) { - mirror::ArtMethod* vtable_method = input_array->GetWithoutChecks(k); - mirror::ArtMethod* vtable_method_for_name_comparison = - vtable_method->GetInterfaceMethodIfProxy(); + for (k = input_array_length - 1; k >= 0; --k) { + ArtMethod* vtable_method = input_virtual_methods != nullptr ? + reinterpret_cast<ArtMethod*>( + reinterpret_cast<uintptr_t>(input_virtual_methods) + method_size * k) : + input_vtable_array->GetElementPtrSize<ArtMethod*>(k, image_pointer_size_); + ArtMethod* vtable_method_for_name_comparison = + vtable_method->GetInterfaceMethodIfProxy(image_pointer_size_); if (interface_name_comparator.HasSameNameAndSignature( vtable_method_for_name_comparison)) { if (!vtable_method->IsAbstract() && !vtable_method->IsPublic()) { - ThrowIllegalAccessError( - klass.Get(), + ThrowIllegalAccessError(klass.Get(), "Method '%s' implementing interface method '%s' is not public", - PrettyMethod(vtable_method).c_str(), - PrettyMethod(interface_method).c_str()); + PrettyMethod(vtable_method).c_str(), PrettyMethod(interface_method).c_str()); return false; } - method_array->SetWithoutChecks<false>(j, vtable_method); + method_array->SetElementPtrSize(j, vtable_method, image_pointer_size_); // Place method in imt if entry is empty, place conflict otherwise. uint32_t imt_index = interface_method->GetDexMethodIndex() % mirror::Class::kImtSize; - mirror::ArtMethod* imt_ref = out_imt->GetReference(imt_index)->AsArtMethod(); - mirror::ArtMethod* conflict_method = runtime->GetImtConflictMethod(); - if (imt_ref == runtime->GetImtUnimplementedMethod()) { - out_imt->SetReference(imt_index, vtable_method); - } else if (imt_ref != conflict_method) { + auto** imt_ref = &out_imt[imt_index]; + if (*imt_ref == unimplemented_method) { + *imt_ref = vtable_method; + } else if (*imt_ref != conflict_method) { // If we are not a conflict and we have the same signature and name as the imt entry, // it must be that we overwrote a superclass vtable entry. - MethodNameAndSignatureComparator imt_ref_name_comparator( - imt_ref->GetInterfaceMethodIfProxy()); - if (imt_ref_name_comparator.HasSameNameAndSignature( - vtable_method_for_name_comparison)) { - out_imt->SetReference(imt_index, vtable_method); - } else { - out_imt->SetReference(imt_index, conflict_method); - } + MethodNameAndSignatureComparator imt_comparator( + (*imt_ref)->GetInterfaceMethodIfProxy(image_pointer_size_)); + *imt_ref = imt_comparator.HasSameNameAndSignature(vtable_method_for_name_comparison) ? + vtable_method : conflict_method; } break; } } if (k < 0 && !super_interface) { - mirror::ArtMethod* miranda_method = nullptr; - for (size_t l = 0; l < miranda_list_size; ++l) { - mirror::ArtMethod* mir_method = miranda_list->Get(l); + ArtMethod* miranda_method = nullptr; + for (auto& mir_method : miranda_methods) { if (interface_name_comparator.HasSameNameAndSignature(mir_method)) { miranda_method = mir_method; break; } } if (miranda_method == nullptr) { + size_t size = ArtMethod::ObjectSize(image_pointer_size_); + miranda_method = reinterpret_cast<ArtMethod*>(allocator.Alloc(size)); + CHECK(miranda_method != nullptr); // Point the interface table at a phantom slot. - miranda_method = interface_method->Clone(self)->AsArtMethod(); - if (UNLIKELY(miranda_method == nullptr)) { - CHECK(self->IsExceptionPending()); // OOME. - return false; - } - DCHECK_LT(miranda_list_size, max_miranda_methods); - miranda_list->Set<false>(miranda_list_size++, miranda_method); + new(miranda_method) ArtMethod(*interface_method, image_pointer_size_); + miranda_methods.push_back(miranda_method); } - method_array->SetWithoutChecks<false>(j, miranda_method); + method_array->SetElementPtrSize(j, miranda_method, image_pointer_size_); } } } } - if (miranda_list_size > 0) { - int old_method_count = klass->NumVirtualMethods(); - int new_method_count = old_method_count + miranda_list_size; - mirror::ObjectArray<mirror::ArtMethod>* virtuals; - if (old_method_count == 0) { - virtuals = AllocArtMethodArray(self, new_method_count); - } else { - virtuals = klass->GetVirtualMethods()->CopyOf(self, new_method_count); - } + if (!miranda_methods.empty()) { + const size_t old_method_count = klass->NumVirtualMethods(); + const size_t new_method_count = old_method_count + miranda_methods.size(); + // Attempt to realloc to save RAM if possible. + ArtMethod* old_virtuals = klass->GetVirtualMethodsPtr(); + // The Realloced virtual methods aren't visiblef from the class roots, so there is no issue + // where GCs could attempt to mark stale pointers due to memcpy. And since we overwrite the + // realloced memory with out->CopyFrom, we are guaranteed to have objects in the to space since + // CopyFrom has internal read barriers. + auto* virtuals = reinterpret_cast<ArtMethod*>(runtime->GetLinearAlloc()->Realloc( + self, old_virtuals, old_method_count * method_size, new_method_count * method_size)); if (UNLIKELY(virtuals == nullptr)) { - CHECK(self->IsExceptionPending()); // OOME. + self->AssertPendingOOMException(); return false; } - klass->SetVirtualMethods(virtuals); + ScopedArenaUnorderedMap<ArtMethod*, ArtMethod*> move_table(allocator.Adapter()); + if (virtuals != old_virtuals) { + // Maps from heap allocated miranda method to linear alloc miranda method. + StrideIterator<ArtMethod> out(reinterpret_cast<uintptr_t>(virtuals), method_size); + // Copy over the old methods + miranda methods. + for (auto& m : klass->GetVirtualMethods(image_pointer_size_)) { + move_table.emplace(&m, &*out); + // The CopyFrom is only necessary to not miss read barriers since Realloc won't do read + // barriers when it copies. + out->CopyFrom(&m, image_pointer_size_); + ++out; + } + } + UpdateClassVirtualMethods(klass.Get(), virtuals, new_method_count); + // Done copying methods, they are all reachable from the class now, so we can end the no thread + // suspension assert. + self->EndAssertNoThreadSuspension(old_cause); - int old_vtable_count = vtable->GetLength(); - int new_vtable_count = old_vtable_count + miranda_list_size; - vtable.Assign(vtable->CopyOf(self, new_vtable_count)); + size_t old_vtable_count = vtable->GetLength(); + const size_t new_vtable_count = old_vtable_count + miranda_methods.size(); + vtable.Assign(down_cast<mirror::PointerArray*>(vtable->CopyOf(self, new_vtable_count))); if (UNLIKELY(vtable.Get() == nullptr)) { - CHECK(self->IsExceptionPending()); // OOME. + self->AssertPendingOOMException(); return false; } - for (size_t i = 0; i < miranda_list_size; ++i) { - mirror::ArtMethod* method = miranda_list->Get(i); + StrideIterator<ArtMethod> out( + reinterpret_cast<uintptr_t>(virtuals) + old_method_count * method_size, method_size); + for (auto* mir_method : miranda_methods) { + ArtMethod* out_method = &*out; + out->CopyFrom(mir_method, image_pointer_size_); // Leave the declaring class alone as type indices are relative to it - method->SetAccessFlags(method->GetAccessFlags() | kAccMiranda); - method->SetMethodIndex(0xFFFF & (old_vtable_count + i)); - klass->SetVirtualMethod(old_method_count + i, method); - vtable->SetWithoutChecks<false>(old_vtable_count + i, method); + out_method->SetAccessFlags(out_method->GetAccessFlags() | kAccMiranda); + out_method->SetMethodIndex(0xFFFF & old_vtable_count); + vtable->SetElementPtrSize(old_vtable_count, out_method, image_pointer_size_); + move_table.emplace(mir_method, out_method); + ++out; + ++old_vtable_count; + } + + // Update old vtable methods. + for (size_t i = 0; i < old_vtable_count - miranda_methods.size(); ++i) { + auto* m = vtable->GetElementPtrSize<ArtMethod*>(i, image_pointer_size_); + DCHECK(m != nullptr) << PrettyClass(klass.Get()); + auto it = move_table.find(m); + if (it != move_table.end()) { + auto* new_m = it->second; + DCHECK(new_m != nullptr) << PrettyClass(klass.Get()); + vtable->SetElementPtrSize(i, new_m, image_pointer_size_); + } } - // TODO: do not assign to the vtable field until it is fully constructed. klass->SetVTable(vtable.Get()); + CHECK_EQ(old_vtable_count, new_vtable_count); + // Go fix up all the stale miranda pointers. + for (size_t i = 0; i < ifcount; ++i) { + for (size_t j = 0, count = iftable->GetMethodArrayCount(i); j < count; ++j) { + auto* method_array = iftable->GetMethodArray(i); + auto* m = method_array->GetElementPtrSize<ArtMethod*>(j, image_pointer_size_); + DCHECK(m != nullptr) << PrettyClass(klass.Get()); + auto it = move_table.find(m); + if (it != move_table.end()) { + auto* new_m = it->second; + DCHECK(new_m != nullptr) << PrettyClass(klass.Get()); + method_array->SetElementPtrSize(j, new_m, image_pointer_size_); + } + } + } + // Check that there are no stale methods are in the dex cache array. + if (kIsDebugBuild) { + auto* resolved_methods = klass->GetDexCache()->GetResolvedMethods(); + for (size_t i = 0, count = resolved_methods->GetLength(); i < count; ++i) { + auto* m = resolved_methods->GetElementPtrSize<ArtMethod*>(i, image_pointer_size_); + CHECK(move_table.find(m) == move_table.end()) << PrettyMethod(m); + } + } + // Put some random garbage in old virtuals to help find stale pointers. + if (virtuals != old_virtuals) { + memset(old_virtuals, 0xFEu, ArtMethod::ObjectSize(image_pointer_size_) * old_method_count); + } + } else { + self->EndAssertNoThreadSuspension(old_cause); } - if (kIsDebugBuild) { - mirror::ObjectArray<mirror::ArtMethod>* check_vtable = klass->GetVTableDuringLinking(); + auto* check_vtable = klass->GetVTableDuringLinking(); for (int i = 0; i < check_vtable->GetLength(); ++i) { - CHECK(check_vtable->GetWithoutChecks(i) != nullptr); + CHECK(check_vtable->GetElementPtrSize<ArtMethod*>(i, image_pointer_size_) != nullptr); } } - - self->AllowThreadSuspension(); return true; } @@ -4984,7 +5095,7 @@ bool ClassLinker::LinkFields(Thread* self, Handle<mirror::Class> klass, bool is_ // Initialize field_offset MemberOffset field_offset(0); if (is_static) { - field_offset = klass->GetFirstReferenceStaticFieldOffsetDuringLinking(); + field_offset = klass->GetFirstReferenceStaticFieldOffsetDuringLinking(image_pointer_size_); } else { mirror::Class* super_class = klass->GetSuperClass(); if (super_class != nullptr) { @@ -5059,19 +5170,14 @@ bool ClassLinker::LinkFields(Thread* self, Handle<mirror::Class> klass, bool is_ } else { klass->SetNumReferenceInstanceFields(num_reference_fields); if (!klass->IsVariableSize()) { - if (klass->DescriptorEquals("Ljava/lang/reflect/ArtMethod;")) { - size_t pointer_size = GetInstructionSetPointerSize(Runtime::Current()->GetInstructionSet()); - klass->SetObjectSize(mirror::ArtMethod::InstanceSize(pointer_size)); - } else { - std::string temp; - DCHECK_GE(size, sizeof(mirror::Object)) << klass->GetDescriptor(&temp); - size_t previous_size = klass->GetObjectSize(); - if (previous_size != 0) { - // Make sure that we didn't originally have an incorrect size. - CHECK_EQ(previous_size, size) << klass->GetDescriptor(&temp); - } - klass->SetObjectSize(size); + std::string temp; + DCHECK_GE(size, sizeof(mirror::Object)) << klass->GetDescriptor(&temp); + size_t previous_size = klass->GetObjectSize(); + if (previous_size != 0) { + // Make sure that we didn't originally have an incorrect size. + CHECK_EQ(previous_size, size) << klass->GetDescriptor(&temp); } + klass->SetObjectSize(size); } } @@ -5079,7 +5185,7 @@ bool ClassLinker::LinkFields(Thread* self, Handle<mirror::Class> klass, bool is_ // Make sure that the fields array is ordered by name but all reference // offsets are at the beginning as far as alignment allows. MemberOffset start_ref_offset = is_static - ? klass->GetFirstReferenceStaticFieldOffsetDuringLinking() + ? klass->GetFirstReferenceStaticFieldOffsetDuringLinking(image_pointer_size_) : klass->GetFirstReferenceInstanceFieldOffset(); MemberOffset end_ref_offset(start_ref_offset.Uint32Value() + num_reference_fields * @@ -5203,19 +5309,19 @@ mirror::Class* ClassLinker::ResolveType(const DexFile& dex_file, uint16_t type_i } } DCHECK((resolved == nullptr) || resolved->IsResolved() || resolved->IsErroneous()) - << PrettyDescriptor(resolved) << " " << resolved->GetStatus(); + << PrettyDescriptor(resolved) << " " << resolved->GetStatus(); return resolved; } -mirror::ArtMethod* ClassLinker::ResolveMethod(const DexFile& dex_file, uint32_t method_idx, - Handle<mirror::DexCache> dex_cache, - Handle<mirror::ClassLoader> class_loader, - Handle<mirror::ArtMethod> referrer, - InvokeType type) { +ArtMethod* ClassLinker::ResolveMethod(const DexFile& dex_file, uint32_t method_idx, + Handle<mirror::DexCache> dex_cache, + Handle<mirror::ClassLoader> class_loader, + ArtMethod* referrer, InvokeType type) { DCHECK(dex_cache.Get() != nullptr); // Check for hit in the dex cache. - mirror::ArtMethod* resolved = dex_cache->GetResolvedMethod(method_idx); + ArtMethod* resolved = dex_cache->GetResolvedMethod(method_idx, image_pointer_size_); if (resolved != nullptr && !resolved->IsRuntimeMethod()) { + DCHECK(resolved->GetDeclaringClassUnchecked() != nullptr) << resolved->GetDexMethodIndex(); return resolved; } // Fail, get the declaring class. @@ -5230,15 +5336,16 @@ mirror::ArtMethod* ClassLinker::ResolveMethod(const DexFile& dex_file, uint32_t switch (type) { case kDirect: // Fall-through. case kStatic: - resolved = klass->FindDirectMethod(dex_cache.Get(), method_idx); + resolved = klass->FindDirectMethod(dex_cache.Get(), method_idx, image_pointer_size_); + DCHECK(resolved == nullptr || resolved->GetDeclaringClassUnchecked() != nullptr); break; case kInterface: - resolved = klass->FindInterfaceMethod(dex_cache.Get(), method_idx); + resolved = klass->FindInterfaceMethod(dex_cache.Get(), method_idx, image_pointer_size_); DCHECK(resolved == nullptr || resolved->GetDeclaringClass()->IsInterface()); break; case kSuper: // Fall-through. case kVirtual: - resolved = klass->FindVirtualMethod(dex_cache.Get(), method_idx); + resolved = klass->FindVirtualMethod(dex_cache.Get(), method_idx, image_pointer_size_); break; default: LOG(FATAL) << "Unreachable - invocation type: " << type; @@ -5251,27 +5358,28 @@ mirror::ArtMethod* ClassLinker::ResolveMethod(const DexFile& dex_file, uint32_t switch (type) { case kDirect: // Fall-through. case kStatic: - resolved = klass->FindDirectMethod(name, signature); + resolved = klass->FindDirectMethod(name, signature, image_pointer_size_); + DCHECK(resolved == nullptr || resolved->GetDeclaringClassUnchecked() != nullptr); break; case kInterface: - resolved = klass->FindInterfaceMethod(name, signature); + resolved = klass->FindInterfaceMethod(name, signature, image_pointer_size_); DCHECK(resolved == nullptr || resolved->GetDeclaringClass()->IsInterface()); break; case kSuper: // Fall-through. case kVirtual: - resolved = klass->FindVirtualMethod(name, signature); + resolved = klass->FindVirtualMethod(name, signature, image_pointer_size_); break; } } // If we found a method, check for incompatible class changes. if (LIKELY(resolved != nullptr && !resolved->CheckIncompatibleClassChange(type))) { // Be a good citizen and update the dex cache to speed subsequent calls. - dex_cache->SetResolvedMethod(method_idx, resolved); + dex_cache->SetResolvedMethod(method_idx, resolved, image_pointer_size_); return resolved; } else { // If we had a method, it's an incompatible-class-change error. if (resolved != nullptr) { - ThrowIncompatibleClassChangeError(type, resolved->GetInvokeType(), resolved, referrer.Get()); + ThrowIncompatibleClassChangeError(type, resolved->GetInvokeType(), resolved, referrer); } else { // We failed to find the method which means either an access error, an incompatible class // change, or no such method. First try to find the method among direct and virtual methods. @@ -5280,28 +5388,27 @@ mirror::ArtMethod* ClassLinker::ResolveMethod(const DexFile& dex_file, uint32_t switch (type) { case kDirect: case kStatic: - resolved = klass->FindVirtualMethod(name, signature); + resolved = klass->FindVirtualMethod(name, signature, image_pointer_size_); // Note: kDirect and kStatic are also mutually exclusive, but in that case we would // have had a resolved method before, which triggers the "true" branch above. break; case kInterface: case kVirtual: case kSuper: - resolved = klass->FindDirectMethod(name, signature); + resolved = klass->FindDirectMethod(name, signature, image_pointer_size_); break; } // If we found something, check that it can be accessed by the referrer. bool exception_generated = false; - if (resolved != nullptr && referrer.Get() != nullptr) { + if (resolved != nullptr && referrer != nullptr) { mirror::Class* methods_class = resolved->GetDeclaringClass(); mirror::Class* referring_class = referrer->GetDeclaringClass(); if (!referring_class->CanAccess(methods_class)) { - ThrowIllegalAccessErrorClassForMethodDispatch(referring_class, methods_class, - resolved, type); + ThrowIllegalAccessErrorClassForMethodDispatch(referring_class, methods_class, resolved, + type); exception_generated = true; - } else if (!referring_class->CanAccessMember(methods_class, - resolved->GetAccessFlags())) { + } else if (!referring_class->CanAccessMember(methods_class, resolved->GetAccessFlags())) { ThrowIllegalAccessErrorMethod(referring_class, resolved); exception_generated = true; } @@ -5314,11 +5421,11 @@ mirror::ArtMethod* ClassLinker::ResolveMethod(const DexFile& dex_file, uint32_t case kDirect: case kStatic: if (resolved != nullptr) { - ThrowIncompatibleClassChangeError(type, kVirtual, resolved, referrer.Get()); + ThrowIncompatibleClassChangeError(type, kVirtual, resolved, referrer); } else { - resolved = klass->FindInterfaceMethod(name, signature); + resolved = klass->FindInterfaceMethod(name, signature, image_pointer_size_); if (resolved != nullptr) { - ThrowIncompatibleClassChangeError(type, kInterface, resolved, referrer.Get()); + ThrowIncompatibleClassChangeError(type, kInterface, resolved, referrer); } else { ThrowNoSuchMethodError(type, klass, name, signature); } @@ -5326,11 +5433,11 @@ mirror::ArtMethod* ClassLinker::ResolveMethod(const DexFile& dex_file, uint32_t break; case kInterface: if (resolved != nullptr) { - ThrowIncompatibleClassChangeError(type, kDirect, resolved, referrer.Get()); + ThrowIncompatibleClassChangeError(type, kDirect, resolved, referrer); } else { - resolved = klass->FindVirtualMethod(name, signature); + resolved = klass->FindVirtualMethod(name, signature, image_pointer_size_); if (resolved != nullptr) { - ThrowIncompatibleClassChangeError(type, kVirtual, resolved, referrer.Get()); + ThrowIncompatibleClassChangeError(type, kVirtual, resolved, referrer); } else { ThrowNoSuchMethodError(type, klass, name, signature); } @@ -5338,18 +5445,18 @@ mirror::ArtMethod* ClassLinker::ResolveMethod(const DexFile& dex_file, uint32_t break; case kSuper: if (resolved != nullptr) { - ThrowIncompatibleClassChangeError(type, kDirect, resolved, referrer.Get()); + ThrowIncompatibleClassChangeError(type, kDirect, resolved, referrer); } else { ThrowNoSuchMethodError(type, klass, name, signature); } break; case kVirtual: if (resolved != nullptr) { - ThrowIncompatibleClassChangeError(type, kDirect, resolved, referrer.Get()); + ThrowIncompatibleClassChangeError(type, kDirect, resolved, referrer); } else { - resolved = klass->FindInterfaceMethod(name, signature); + resolved = klass->FindInterfaceMethod(name, signature, image_pointer_size_); if (resolved != nullptr) { - ThrowIncompatibleClassChangeError(type, kInterface, resolved, referrer.Get()); + ThrowIncompatibleClassChangeError(type, kInterface, resolved, referrer); } else { ThrowNoSuchMethodError(type, klass, name, signature); } @@ -5434,7 +5541,7 @@ ArtField* ClassLinker::ResolveFieldJLS(const DexFile& dex_file, uint32_t field_i return resolved; } -const char* ClassLinker::MethodShorty(uint32_t method_idx, mirror::ArtMethod* referrer, +const char* ClassLinker::MethodShorty(uint32_t method_idx, ArtMethod* referrer, uint32_t* length) { mirror::Class* declaring_class = referrer->GetDeclaringClass(); mirror::DexCache* dex_cache = declaring_class->GetDexCache(); @@ -5489,14 +5596,14 @@ const void* ClassLinker::GetRuntimeQuickGenericJniStub() const { return GetQuickGenericJniStub(); } -void ClassLinker::SetEntryPointsToCompiledCode(mirror::ArtMethod* method, +void ClassLinker::SetEntryPointsToCompiledCode(ArtMethod* method, const void* method_code) const { OatFile::OatMethod oat_method = CreateOatMethod(method_code); oat_method.LinkMethod(method); method->SetEntryPointFromInterpreter(artInterpreterToCompiledCodeBridge); } -void ClassLinker::SetEntryPointsToInterpreter(mirror::ArtMethod* method) const { +void ClassLinker::SetEntryPointsToInterpreter(ArtMethod* method) const { if (!method->IsNative()) { method->SetEntryPointFromInterpreter(artInterpreterToInterpreterBridge); method->SetEntryPointFromQuickCompiledCode(GetQuickToInterpreterBridge()); @@ -5557,13 +5664,11 @@ const char* ClassLinker::GetClassRootDescriptor(ClassRoot class_root) { "Ljava/lang/String;", "Ljava/lang/DexCache;", "Ljava/lang/ref/Reference;", - "Ljava/lang/reflect/ArtMethod;", "Ljava/lang/reflect/Constructor;", "Ljava/lang/reflect/Field;", "Ljava/lang/reflect/Method;", "Ljava/lang/reflect/Proxy;", "[Ljava/lang/String;", - "[Ljava/lang/reflect/ArtMethod;", "[Ljava/lang/reflect/Constructor;", "[Ljava/lang/reflect/Field;", "[Ljava/lang/reflect/Method;", @@ -5635,7 +5740,7 @@ std::size_t ClassLinker::ClassDescriptorHashEquals::operator()(const char* descr return ComputeModifiedUtf8Hash(descriptor); } -bool ClassLinker::MayBeCalledWithDirectCodePointer(mirror::ArtMethod* m) { +bool ClassLinker::MayBeCalledWithDirectCodePointer(ArtMethod* m) { if (Runtime::Current()->UseJit()) { // JIT can have direct code pointers from any method to any other method. return true; @@ -5757,4 +5862,12 @@ jobject ClassLinker::CreatePathClassLoader(Thread* self, std::vector<const DexFi return soa.Env()->NewGlobalRef(local_ref.get()); } +ArtMethod* ClassLinker::CreateRuntimeMethod() { + ArtMethod* method = AllocArtMethodArray(Thread::Current(), 1); + CHECK(method != nullptr); + method->SetDexMethodIndex(DexFile::kDexNoIndex); + CHECK(method->IsRuntimeMethod()); + return method; +} + } // namespace art |