diff options
| author | 2015-04-22 13:56:20 -0700 | |
|---|---|---|
| committer | 2015-06-02 09:21:27 -0700 | |
| commit | 3d21bdf8894e780d349c481e5c9e29fe1556051c (patch) | |
| tree | 61a5231f36c0dabd73457fec81df103462a05aff /runtime/class_linker.cc | |
| parent | 71f0a8a123fa27bdc857a98afebbaf0ed09dac15 (diff) | |
Move mirror::ArtMethod to native
Optimizing + quick tests are passing, devices boot.
TODO: Test and fix bugs in mips64.
Saves 16 bytes per most ArtMethod, 7.5MB reduction in system PSS.
Some of the savings are from removal of virtual methods and direct
methods object arrays.
Bug: 19264997
(cherry picked from commit e401d146407d61eeb99f8d6176b2ac13c4df1e33)
Change-Id: I622469a0cfa0e7082a2119f3d6a9491eb61e3f3d
Fix some ArtMethod related bugs
Added root visiting for runtime methods, not currently required
since the GcRoots in these methods are null.
Added missing GetInterfaceMethodIfProxy in GetMethodLine, fixes
--trace run-tests 005, 044.
Fixed optimizing compiler bug where we used a normal stack location
instead of double on ARM64, this fixes the debuggable tests.
TODO: Fix JDWP tests.
Bug: 19264997
Change-Id: I7c55f69c61d1b45351fd0dc7185ffe5efad82bd3
ART: Fix casts for 64-bit pointers on 32-bit compiler.
Bug: 19264997
Change-Id: Ief45cdd4bae5a43fc8bfdfa7cf744e2c57529457
Fix JDWP tests after ArtMethod change
Fixes Throwable::GetStackDepth for exception event detection after
internal stack trace representation change.
Adds missing ArtMethod::GetInterfaceMethodIfProxy call in case of
proxy method.
Bug: 19264997
Change-Id: I363e293796848c3ec491c963813f62d868da44d2
Fix accidental IMT and root marking regression
Was always using the conflict trampoline. Also included fix for
regression in GC time caused by extra roots. Most of the regression
was IMT.
Fixed bug in DumpGcPerformanceInfo where we would get SIGABRT due to
detached thread.
EvaluateAndApplyChanges:
From ~2500 -> ~1980
GC time: 8.2s -> 7.2s due to 1s less of MarkConcurrentRoots
Bug: 19264997
Change-Id: I4333e80a8268c2ed1284f87f25b9f113d4f2c7e0
Fix bogus image test assert
Previously we were comparing the size of the non moving space to
size of the image file.
Now we properly compare the size of the image space against the size
of the image file.
Bug: 19264997
Change-Id: I7359f1f73ae3df60c5147245935a24431c04808a
[MIPS64] Fix art_quick_invoke_stub argument offsets.
ArtMethod reference's size got bigger, so we need to move other args
and leave enough space for ArtMethod* and 'this' pointer.
This fixes mips64 boot.
Bug: 19264997
Change-Id: I47198d5f39a4caab30b3b77479d5eedaad5006ab
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 a028942c7a..fb2debd63f 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 |