From 9539150b85142c18e9e8c2264b5b6100942667c3 Mon Sep 17 00:00:00 2001 From: Alex Light Date: Thu, 3 Dec 2015 17:38:56 -0800 Subject: [PATCH] Combine direct_methods_ and virtual_methods_ fields of mirror::Class Manual cherry-pick of 6286a97 to master This makes several parts of the overall runtime simpler and reduces the size of a class object by 32-bits. Bug: 24618811 Change-Id: I36129b52189e26898ea56fa2b7b45652e06af236 --- compiler/common_compiler_test.cc | 10 +- compiler/compiled_method.h | 2 +- compiler/driver/compiled_method_storage.h | 2 +- compiler/driver/compiler_driver.cc | 5 +- compiler/driver/compiler_driver_test.cc | 5 +- compiler/image_writer.cc | 42 +++--- compiler/image_writer.h | 2 +- compiler/oat_test.cc | 12 +- runtime/asm_support.h | 4 +- runtime/base/array_slice.h | 148 +++++++++++++++++++ runtime/{ => base}/length_prefixed_array.h | 6 +- runtime/class_linker.cc | 209 ++++++++++++++++----------- runtime/class_linker.h | 4 +- runtime/class_linker_test.cc | 24 ++-- runtime/entrypoints/entrypoint_utils.cc | 6 +- runtime/jni_internal.cc | 15 +- runtime/mirror/class-inl.h | 221 +++++++++++++++++++++-------- runtime/mirror/class.cc | 17 +-- runtime/mirror/class.h | 117 ++++++++++++--- runtime/native/java_lang_Class.cc | 26 +--- runtime/native/java_lang_reflect_Method.cc | 2 +- runtime/native_bridge_art_interface.cc | 19 +-- runtime/proxy_test.cc | 2 +- 23 files changed, 609 insertions(+), 291 deletions(-) create mode 100644 runtime/base/array_slice.h rename runtime/{ => base}/length_prefixed_array.h (96%) diff --git a/compiler/common_compiler_test.cc b/compiler/common_compiler_test.cc index 638b897ee..c7c190793 100644 --- a/compiler/common_compiler_test.cc +++ b/compiler/common_compiler_test.cc @@ -142,10 +142,7 @@ void CommonCompilerTest::MakeExecutable(mirror::ClassLoader* class_loader, const mirror::Class* klass = class_linker_->FindClass(self, class_descriptor.c_str(), loader); CHECK(klass != nullptr) << "Class not found " << class_name; size_t pointer_size = class_linker_->GetImagePointerSize(); - for (auto& m : klass->GetDirectMethods(pointer_size)) { - MakeExecutable(&m); - } - for (auto& m : klass->GetVirtualMethods(pointer_size)) { + for (auto& m : klass->GetMethods(pointer_size)) { MakeExecutable(&m); } } @@ -259,10 +256,7 @@ void CommonCompilerTest::CompileClass(mirror::ClassLoader* class_loader, const c mirror::Class* klass = class_linker_->FindClass(self, class_descriptor.c_str(), loader); CHECK(klass != nullptr) << "Class not found " << class_name; auto pointer_size = class_linker_->GetImagePointerSize(); - for (auto& m : klass->GetDirectMethods(pointer_size)) { - CompileMethod(&m); - } - for (auto& m : klass->GetVirtualMethods(pointer_size)) { + for (auto& m : klass->GetMethods(pointer_size)) { CompileMethod(&m); } } diff --git a/compiler/compiled_method.h b/compiler/compiled_method.h index 15a4ba0f6..7a9361348 100644 --- a/compiler/compiled_method.h +++ b/compiler/compiled_method.h @@ -23,7 +23,7 @@ #include "arch/instruction_set.h" #include "base/bit_utils.h" -#include "length_prefixed_array.h" +#include "base/length_prefixed_array.h" #include "method_reference.h" #include "utils/array_ref.h" diff --git a/compiler/driver/compiled_method_storage.h b/compiler/driver/compiled_method_storage.h index ef10b6768..d6961a087 100644 --- a/compiler/driver/compiled_method_storage.h +++ b/compiler/driver/compiled_method_storage.h @@ -20,8 +20,8 @@ #include #include +#include "base/length_prefixed_array.h" #include "base/macros.h" -#include "length_prefixed_array.h" #include "utils/array_ref.h" #include "utils/dedupe_set.h" #include "utils/swap_space.h" diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index ba8f1d0df..56839f85f 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -790,10 +790,7 @@ class ResolveCatchBlockExceptionsClassVisitor : public ClassVisitor { virtual bool Visit(mirror::Class* c) OVERRIDE SHARED_REQUIRES(Locks::mutator_lock_) { const auto pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize(); - for (auto& m : c->GetVirtualMethods(pointer_size)) { - ResolveExceptionsForMethod(&m, pointer_size); - } - for (auto& m : c->GetDirectMethods(pointer_size)) { + for (auto& m : c->GetMethods(pointer_size)) { ResolveExceptionsForMethod(&m, pointer_size); } return true; diff --git a/compiler/driver/compiler_driver_test.cc b/compiler/driver/compiler_driver_test.cc index 2e43c2c71..462c511a8 100644 --- a/compiler/driver/compiler_driver_test.cc +++ b/compiler/driver/compiler_driver_test.cc @@ -86,10 +86,7 @@ class CompilerDriverTest : public CommonCompilerTest { mirror::Class* c = class_linker->FindClass(soa.Self(), descriptor, loader); CHECK(c != nullptr); const auto pointer_size = class_linker->GetImagePointerSize(); - for (auto& m : c->GetDirectMethods(pointer_size)) { - MakeExecutable(&m); - } - for (auto& m : c->GetVirtualMethods(pointer_size)) { + for (auto& m : c->GetMethods(pointer_size)) { MakeExecutable(&m); } } diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc index fce08ea5f..b9ec47d3f 100644 --- a/compiler/image_writer.cc +++ b/compiler/image_writer.cc @@ -1030,44 +1030,42 @@ void ImageWriter::WalkFieldsInOrder(mirror::Object* obj) { } } // Visit and assign offsets for methods. - LengthPrefixedArray* method_arrays[] = { - as_klass->GetDirectMethodsPtr(), as_klass->GetVirtualMethodsPtr(), - }; - for (LengthPrefixedArray* array : method_arrays) { - if (array == nullptr) { - continue; - } + size_t num_methods = as_klass->NumMethods(); + if (num_methods != 0) { bool any_dirty = false; - size_t count = 0; - const size_t method_alignment = ArtMethod::Alignment(target_ptr_size_); - const size_t method_size = ArtMethod::Size(target_ptr_size_); - auto iteration_range = - MakeIterationRangeFromLengthPrefixedArray(array, method_size, method_alignment); - for (auto& m : iteration_range) { - any_dirty = any_dirty || WillMethodBeDirty(&m); - ++count; + for (auto& m : as_klass->GetMethods(target_ptr_size_)) { + if (WillMethodBeDirty(&m)) { + any_dirty = true; + break; + } } NativeObjectRelocationType type = any_dirty ? kNativeObjectRelocationTypeArtMethodDirty : kNativeObjectRelocationTypeArtMethodClean; Bin bin_type = BinTypeForNativeRelocationType(type); // Forward the entire array at once, but header first. + const size_t method_alignment = ArtMethod::Alignment(target_ptr_size_); + const size_t method_size = ArtMethod::Size(target_ptr_size_); const size_t header_size = LengthPrefixedArray::ComputeSize(0, method_size, method_alignment); + LengthPrefixedArray* array = as_klass->GetMethodsPtr(); auto it = native_object_relocations_.find(array); - CHECK(it == native_object_relocations_.end()) << "Method array " << array - << " already forwarded"; + CHECK(it == native_object_relocations_.end()) + << "Method array " << array << " already forwarded"; size_t& offset = bin_slot_sizes_[bin_type]; DCHECK(!IsInBootImage(array)); - native_object_relocations_.emplace(array, NativeObjectRelocation { offset, - any_dirty ? kNativeObjectRelocationTypeArtMethodArrayDirty : - kNativeObjectRelocationTypeArtMethodArrayClean }); + native_object_relocations_.emplace( + array, NativeObjectRelocation { + offset, + any_dirty ? kNativeObjectRelocationTypeArtMethodArrayDirty + : kNativeObjectRelocationTypeArtMethodArrayClean + }); offset += header_size; - for (auto& m : iteration_range) { + for (auto& m : as_klass->GetMethods(target_ptr_size_)) { AssignMethodOffset(&m, type); } - (any_dirty ? dirty_methods_ : clean_methods_) += count; + (any_dirty ? dirty_methods_ : clean_methods_) += num_methods; } } else if (h_obj->IsObjectArray()) { // Walk elements of an object array. diff --git a/compiler/image_writer.h b/compiler/image_writer.h index 8e930f037..f1b2965a1 100644 --- a/compiler/image_writer.h +++ b/compiler/image_writer.h @@ -27,11 +27,11 @@ #include #include "base/bit_utils.h" +#include "base/length_prefixed_array.h" #include "base/macros.h" #include "driver/compiler_driver.h" #include "gc/space/space.h" #include "image.h" -#include "length_prefixed_array.h" #include "lock_word.h" #include "mem_map.h" #include "oat_file.h" diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc index c414e3120..d6aafcbee 100644 --- a/compiler/oat_test.cc +++ b/compiler/oat_test.cc @@ -238,12 +238,12 @@ TEST_F(OatTest, WriteRead) { ++method_index; } size_t visited_virtuals = 0; - for (auto& m : klass->GetVirtualMethods(pointer_size)) { - if (!m.IsMiranda()) { - CheckMethod(&m, oat_class.GetOatMethod(method_index), dex_file); - ++method_index; - ++visited_virtuals; - } + // TODO We should also check copied methods in this test. + for (auto& m : klass->GetDeclaredVirtualMethods(pointer_size)) { + EXPECT_FALSE(m.IsMiranda()); + CheckMethod(&m, oat_class.GetOatMethod(method_index), dex_file); + ++method_index; + ++visited_virtuals; } EXPECT_EQ(visited_virtuals, num_virtual_methods); } diff --git a/runtime/asm_support.h b/runtime/asm_support.h index 5ec89738d..cb01a64c4 100644 --- a/runtime/asm_support.h +++ b/runtime/asm_support.h @@ -166,10 +166,10 @@ ADD_TEST_EQ(MIRROR_CLASS_COMPONENT_TYPE_OFFSET, #define MIRROR_CLASS_ACCESS_FLAGS_OFFSET (36 + MIRROR_OBJECT_HEADER_SIZE) ADD_TEST_EQ(MIRROR_CLASS_ACCESS_FLAGS_OFFSET, art::mirror::Class::AccessFlagsOffset().Int32Value()) -#define MIRROR_CLASS_OBJECT_SIZE_OFFSET (108 + MIRROR_OBJECT_HEADER_SIZE) +#define MIRROR_CLASS_OBJECT_SIZE_OFFSET (100 + MIRROR_OBJECT_HEADER_SIZE) ADD_TEST_EQ(MIRROR_CLASS_OBJECT_SIZE_OFFSET, art::mirror::Class::ObjectSizeOffset().Int32Value()) -#define MIRROR_CLASS_STATUS_OFFSET (120 + MIRROR_OBJECT_HEADER_SIZE) +#define MIRROR_CLASS_STATUS_OFFSET (112 + MIRROR_OBJECT_HEADER_SIZE) ADD_TEST_EQ(MIRROR_CLASS_STATUS_OFFSET, art::mirror::Class::StatusOffset().Int32Value()) diff --git a/runtime/base/array_slice.h b/runtime/base/array_slice.h new file mode 100644 index 000000000..19ad302c9 --- /dev/null +++ b/runtime/base/array_slice.h @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_RUNTIME_BASE_ARRAY_SLICE_H_ +#define ART_RUNTIME_BASE_ARRAY_SLICE_H_ + +#include "length_prefixed_array.h" +#include "stride_iterator.h" +#include "base/bit_utils.h" +#include "base/casts.h" +#include "base/iteration_range.h" + +namespace art { + +// An ArraySlice is an abstraction over an array or a part of an array of a particular type. It does +// bounds checking and can be made from several common array-like structures in Art. +template +class ArraySlice { + public: + // Create an empty array slice. + ArraySlice() : array_(nullptr), size_(0), element_size_(0) {} + + // Create an array slice of the first 'length' elements of the array, with each element being + // element_size bytes long. + ArraySlice(T* array, + size_t length, + size_t element_size = sizeof(T)) + : array_(array), + size_(dchecked_integral_cast(length)), + element_size_(element_size) { + DCHECK(array_ != nullptr || length == 0); + } + + // Create an array slice of the elements between start_offset and end_offset of the array with + // each element being element_size bytes long. Both start_offset and end_offset are in + // element_size units. + ArraySlice(T* array, + uint32_t start_offset, + uint32_t end_offset, + size_t element_size = sizeof(T)) + : array_(nullptr), + size_(end_offset - start_offset), + element_size_(element_size) { + DCHECK(array_ != nullptr || size_ == 0); + DCHECK_LE(start_offset, end_offset); + if (size_ != 0) { + uintptr_t offset = start_offset * element_size_; + array_ = *reinterpret_cast(reinterpret_cast(array) + offset); + } + } + + // Create an array slice of the elements between start_offset and end_offset of the array with + // each element being element_size bytes long and having the given alignment. Both start_offset + // and end_offset are in element_size units. + ArraySlice(LengthPrefixedArray* array, + uint32_t start_offset, + uint32_t end_offset, + size_t element_size = sizeof(T), + size_t alignment = alignof(T)) + : array_(nullptr), + size_(end_offset - start_offset), + element_size_(element_size) { + DCHECK(array != nullptr || size_ == 0); + if (size_ != 0) { + DCHECK_LE(start_offset, end_offset); + DCHECK_LE(start_offset, array->size()); + DCHECK_LE(end_offset, array->size()); + array_ = &array->At(start_offset, element_size_, alignment); + } + } + + T& At(size_t index) { + DCHECK_LT(index, size_); + return AtUnchecked(index); + } + + const T& At(size_t index) const { + DCHECK_LT(index, size_); + return AtUnchecked(index); + } + + T& operator[](size_t index) { + return At(index); + } + + const T& operator[](size_t index) const { + return At(index); + } + + StrideIterator begin() { + return StrideIterator(&AtUnchecked(0), element_size_); + } + + StrideIterator begin() const { + return StrideIterator(&AtUnchecked(0), element_size_); + } + + StrideIterator end() { + return StrideIterator(&AtUnchecked(size_), element_size_); + } + + StrideIterator end() const { + return StrideIterator(&AtUnchecked(size_), element_size_); + } + + IterationRange> AsRange() { + return size() != 0 ? MakeIterationRange(begin(), end()) + : MakeEmptyIterationRange(StrideIterator(nullptr, 0)); + } + + size_t size() const { + return size_; + } + + size_t ElementSize() const { + return element_size_; + } + + private: + T& AtUnchecked(size_t index) { + return *reinterpret_cast(reinterpret_cast(array_) + index * element_size_); + } + + const T& AtUnchecked(size_t index) const { + return *reinterpret_cast(reinterpret_cast(array_) + index * element_size_); + } + + T* array_; + size_t size_; + size_t element_size_; +}; + +} // namespace art + +#endif // ART_RUNTIME_BASE_ARRAY_SLICE_H_ diff --git a/runtime/length_prefixed_array.h b/runtime/base/length_prefixed_array.h similarity index 96% rename from runtime/length_prefixed_array.h rename to runtime/base/length_prefixed_array.h index e01b6ccd2..d6328717e 100644 --- a/runtime/length_prefixed_array.h +++ b/runtime/base/length_prefixed_array.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_LENGTH_PREFIXED_ARRAY_H_ -#define ART_RUNTIME_LENGTH_PREFIXED_ARRAY_H_ +#ifndef ART_RUNTIME_BASE_LENGTH_PREFIXED_ARRAY_H_ +#define ART_RUNTIME_BASE_LENGTH_PREFIXED_ARRAY_H_ #include // for offsetof() @@ -110,4 +110,4 @@ IterationRange> MakeIterationRangeFromLengthPrefixedArray( } // namespace art -#endif // ART_RUNTIME_LENGTH_PREFIXED_ARRAY_H_ +#endif // ART_RUNTIME_BASE_LENGTH_PREFIXED_ARRAY_H_ diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index d82883826..b988c276f 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -807,10 +807,7 @@ static void SanityCheckObjectsCallback(mirror::Object* obj, void* arg ATTRIBUTE_ auto* runtime = Runtime::Current(); auto* image_space = runtime->GetHeap()->GetBootImageSpace(); 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)) { + for (auto& m : klass->GetMethods(pointer_size)) { SanityCheckArtMethod(&m, klass, image_space); } auto* vtable = klass->GetVTable(); @@ -2245,11 +2242,14 @@ void ClassLinker::LoadClassMembers(Thread* self, klass->SetIFieldsPtr(ifields); DCHECK_EQ(klass->NumInstanceFields(), num_ifields); // Load methods. - klass->SetDirectMethodsPtr(AllocArtMethodArray(self, allocator, it.NumDirectMethods())); - klass->SetVirtualMethodsPtr(AllocArtMethodArray(self, allocator, it.NumVirtualMethods())); + klass->SetMethodsPtr( + AllocArtMethodArray(self, allocator, it.NumDirectMethods() + it.NumVirtualMethods()), + it.NumDirectMethods(), + 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; + // TODO These should really use the iterators. 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); @@ -2728,9 +2728,12 @@ mirror::Class* ClassLinker::InsertClass(const char* descriptor, mirror::Class* k return nullptr; } -void ClassLinker::UpdateClassVirtualMethods(mirror::Class* klass, - LengthPrefixedArray* new_methods) { - klass->SetVirtualMethodsPtr(new_methods); +// TODO This should really be in mirror::Class. +void ClassLinker::UpdateClassMethods(mirror::Class* klass, + LengthPrefixedArray* new_methods) { + klass->SetMethodsPtrUnchecked(new_methods, + klass->NumDirectMethods(), + klass->NumDeclaredVirtualMethods()); // Need to mark the card so that the remembered sets and mod union tables get updated. Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(klass); } @@ -3302,29 +3305,30 @@ mirror::Class* ClassLinker::CreateProxyClass(ScopedObjectAccessAlreadyRunnable& throws_sfield.SetAccessFlags(kAccStatic | kAccPublic | kAccFinal); // Proxies have 1 direct method, the constructor - LengthPrefixedArray* directs = AllocArtMethodArray(self, allocator, 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); - CreateProxyConstructor(klass, klass->GetDirectMethodUnchecked(0, image_pointer_size_)); + const size_t num_direct_methods = 1; - // Create virtual method using specified prototypes. + // They have as many virtual methods as the array auto h_methods = hs.NewHandle(soa.Decode*>(methods)); DCHECK_EQ(h_methods->GetClass(), mirror::Method::ArrayClass()) << PrettyClass(h_methods->GetClass()); const size_t num_virtual_methods = h_methods->GetLength(); - auto* virtuals = AllocArtMethodArray(self, allocator, num_virtual_methods); + + // Create the methods array. + LengthPrefixedArray* proxy_class_methods = AllocArtMethodArray( + self, allocator, num_direct_methods + 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)) { + if (UNLIKELY(proxy_class_methods == nullptr)) { self->AssertPendingOOMException(); return nullptr; } - klass->SetVirtualMethodsPtr(virtuals); + klass->SetMethodsPtr(proxy_class_methods, num_direct_methods, num_virtual_methods); + + // Create the single direct method. + CreateProxyConstructor(klass, klass->GetDirectMethodUnchecked(0, image_pointer_size_)); + + // Create virtual method using specified prototypes. + // TODO These should really use the iterators. for (size_t i = 0; i < num_virtual_methods; ++i) { auto* virtual_method = klass->GetVirtualMethodUnchecked(i, image_pointer_size_); auto* prototype = h_methods->Get(i)->GetArtMethod(); @@ -4102,14 +4106,8 @@ void ClassLinker::FixupTemporaryDeclaringClass(mirror::Class* temp_class, } DCHECK_EQ(temp_class->NumDirectMethods(), 0u); - for (auto& method : new_class->GetDirectMethods(image_pointer_size_)) { - if (method.GetDeclaringClass() == temp_class) { - method.SetDeclaringClass(new_class); - } - } - DCHECK_EQ(temp_class->NumVirtualMethods(), 0u); - for (auto& method : new_class->GetVirtualMethods(image_pointer_size_)) { + for (auto& method : new_class->GetMethods(image_pointer_size_)) { if (method.GetDeclaringClass() == temp_class) { method.SetDeclaringClass(new_class); } @@ -4193,8 +4191,7 @@ bool ClassLinker::LinkClass(Thread* self, // ArtMethod array pointers. If this occurs, it causes bugs in remembered sets since the GC // may not see any references to the target space and clean the card for a class if another // class had the same array pointer. - klass->SetDirectMethodsPtrUnchecked(nullptr); - klass->SetVirtualMethodsPtr(nullptr); + klass->SetMethodsPtrUnchecked(nullptr, 0, 0); klass->SetSFieldsPtrUnchecked(nullptr); klass->SetIFieldsPtrUnchecked(nullptr); if (UNLIKELY(h_new_class.Get() == nullptr)) { @@ -4959,12 +4956,10 @@ static bool ContainsOverridingMethodOf(Thread* self, for (size_t k = ifstart + 1; k < iftable_count; k++) { // Skip ifstart since our current interface obviously cannot override itself. current_iface.Assign(iftable->GetInterface(k)); - size_t num_instance_methods = current_iface->NumVirtualMethods(); - // Iterate through every method on this interface. The order does not matter so we go forwards. - for (size_t m = 0; m < num_instance_methods; m++) { - ArtMethod* current_method = current_iface->GetVirtualMethodUnchecked(m, image_pointer_size); + // Iterate through every method on this interface. The order does not matter. + for (ArtMethod& current_method : current_iface->GetDeclaredVirtualMethods(image_pointer_size)) { if (UNLIKELY(target.HasSameNameAndSignature( - current_method->GetInterfaceMethodIfProxy(image_pointer_size)))) { + current_method.GetInterfaceMethodIfProxy(image_pointer_size)))) { // Check if the i'th interface is a subtype of this one. if (iface->IsAssignableFrom(current_iface.Get())) { return true; @@ -5017,10 +5012,9 @@ ClassLinker::DefaultMethodSearchResult ClassLinker::FindDefaultMethodImplementat DCHECK_LT(k, iftable->Count()); iface.Assign(iftable->GetInterface(k)); - size_t num_instance_methods = iface->NumVirtualMethods(); - // Iterate through every method on this interface. The order does not matter so we go forwards. - for (size_t m = 0; m < num_instance_methods; m++) { - ArtMethod* current_method = iface->GetVirtualMethodUnchecked(m, image_pointer_size_); + // Iterate through every declared method on this interface. The order does not matter. + for (auto& method_iter : iface->GetDeclaredVirtualMethods(image_pointer_size_)) { + ArtMethod* current_method = &method_iter; // Skip abstract methods and methods with different names. if (current_method->IsAbstract() || !target_name_comparator.HasSameNameAndSignature( @@ -5327,6 +5321,27 @@ static ArtMethod* FindSameNameAndSignature(MethodNameAndSignatureComparator& cmp return nullptr; } +static void SanityCheckVTable(Handle klass, uint32_t pointer_size) + SHARED_REQUIRES(Locks::mutator_lock_) { + mirror::PointerArray* check_vtable = klass->GetVTableDuringLinking(); + mirror::Class* superclass = (klass->HasSuperClass()) ? klass->GetSuperClass() : nullptr; + int32_t super_vtable_length = (superclass != nullptr) ? superclass->GetVTableLength() : 0; + for (int32_t i = 0; i < check_vtable->GetLength(); ++i) { + ArtMethod* m = check_vtable->GetElementPtrSize(i, pointer_size); + CHECK(m != nullptr); + + ArraySlice virtuals = klass->GetVirtualMethodsSliceUnchecked(pointer_size); + auto is_same_method = [m] (const ArtMethod& meth) { + return &meth == m; + }; + CHECK((super_vtable_length > i && superclass->GetVTableEntry(i, pointer_size) == m) || + std::find_if(virtuals.begin(), virtuals.end(), is_same_method) != virtuals.end()) + << "While linking class '" << PrettyClass(klass.Get()) << "' unable to find owning class " + << "of '" << PrettyMethod(m) << "' (vtable index: " << i << ")."; + } +} + +// TODO Combine virtuals and directs. bool ClassLinker::LinkInterfaceMethods( Thread* self, Handle klass, @@ -5449,25 +5464,27 @@ bool ClassLinker::LinkInterfaceMethods( const bool super_interface = is_super && extend_super_iftable; auto method_array(hs2.NewHandle(iftable->GetMethodArray(i))); - LengthPrefixedArray* input_virtual_methods = nullptr; + ArraySlice input_virtual_methods; Handle input_vtable_array = NullHandle(); int32_t input_array_length = 0; + // TODO Cleanup Needed: In the presence of default methods this optimization is rather dirty // and confusing. Default methods should always look through all the superclasses // because they are the last choice of an implementation. We get around this by looking // at the super-classes iftable methods (copied into method_array previously) when we are // looking for the implementation of a super-interface method but that is rather dirty. if (super_interface) { - // We are overwriting a super class interface, try to only virtual methods instead of the + // If we are overwriting a super class interface, try to only virtual methods instead of the // whole vtable. - input_virtual_methods = klass->GetVirtualMethodsPtr(); - input_array_length = klass->NumVirtualMethods(); + input_virtual_methods = klass->GetDeclaredMethodsSlice(image_pointer_size_); + input_array_length = input_virtual_methods.size(); } else { - // A new interface, we need the whole vtable in case a new interface method is implemented - // in the whole superclass. + // For a new interface, however, we need the whole vtable in case a new + // interface method is implemented in the whole superclass. input_vtable_array = vtable; input_array_length = input_vtable_array->GetLength(); } + // For each method in interface for (size_t j = 0; j < num_methods; ++j) { auto* interface_method = iftable->GetInterface(i)->GetVirtualMethod(j, image_pointer_size_); @@ -5488,8 +5505,8 @@ bool ClassLinker::LinkInterfaceMethods( bool found_impl = false; ArtMethod* vtable_impl = nullptr; for (int32_t k = input_array_length - 1; k >= 0; --k) { - ArtMethod* vtable_method = input_virtual_methods != nullptr ? - &input_virtual_methods->At(k, method_size, method_alignment) : + ArtMethod* vtable_method = input_vtable_array.Get() == nullptr ? + &input_virtual_methods[k] : input_vtable_array->GetElementPtrSize(k, image_pointer_size_); ArtMethod* vtable_method_for_name_comparison = vtable_method->GetInterfaceMethodIfProxy(image_pointer_size_); @@ -5650,38 +5667,39 @@ bool ClassLinker::LinkInterfaceMethods( VLOG(class_linker) << PrettyClass(klass.Get()) << ": miranda_methods=" << miranda_methods.size() << " default_methods=" << default_methods.size() << " default_conflict_methods=" << default_conflict_methods.size(); - const size_t old_method_count = klass->NumVirtualMethods(); + const size_t old_method_count = klass->NumMethods(); const size_t new_method_count = old_method_count + miranda_methods.size() + default_methods.size() + default_conflict_methods.size(); // Attempt to realloc to save RAM if possible. - LengthPrefixedArray* old_virtuals = klass->GetVirtualMethodsPtr(); - // The Realloced virtual methods aren't visiblef from the class roots, so there is no issue + LengthPrefixedArray* old_methods = klass->GetMethodsPtr(); + // The Realloced virtual methods aren't visible 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. - const size_t old_size = old_virtuals != nullptr - ? LengthPrefixedArray::ComputeSize(old_method_count, - method_size, - method_alignment) - : 0u; + // + // TODO We should maybe move some of this into mirror::Class or at least into another method. + const size_t old_size = LengthPrefixedArray::ComputeSize(old_method_count, + method_size, + method_alignment); const size_t new_size = LengthPrefixedArray::ComputeSize(new_method_count, method_size, method_alignment); - auto* virtuals = reinterpret_cast*>( - runtime->GetLinearAlloc()->Realloc(self, old_virtuals, old_size, new_size)); - if (UNLIKELY(virtuals == nullptr)) { + const size_t old_methods_ptr_size = (old_methods != nullptr) ? old_size : 0; + auto* methods = reinterpret_cast*>( + runtime->GetLinearAlloc()->Realloc(self, old_methods, old_methods_ptr_size, new_size)); + if (UNLIKELY(methods == nullptr)) { self->AssertPendingOOMException(); self->EndAssertNoThreadSuspension(old_cause); return false; } ScopedArenaUnorderedMap move_table(allocator.Adapter()); - if (virtuals != old_virtuals) { + if (methods != old_methods) { // Maps from heap allocated miranda method to linear alloc miranda method. - StrideIterator out = virtuals->begin(method_size, method_alignment); - // Copy over the old methods + miranda methods. - for (auto& m : klass->GetVirtualMethods(image_pointer_size_)) { + StrideIterator out = methods->begin(method_size, method_alignment); + // Copy over the old methods. + for (auto& m : klass->GetMethods(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. @@ -5689,8 +5707,7 @@ bool ClassLinker::LinkInterfaceMethods( ++out; } } - StrideIterator out(virtuals->begin(method_size, method_alignment) - + old_method_count); + StrideIterator out(methods->begin(method_size, method_alignment) + old_method_count); // Copy over miranda methods before copying vtable since CopyOf may cause thread suspension and // we want the roots of the miranda methods to get visited. for (ArtMethod* mir_method : miranda_methods) { @@ -5702,9 +5719,8 @@ bool ClassLinker::LinkInterfaceMethods( move_table.emplace(mir_method, &new_method); ++out; } - // We need to copy the default methods into our own virtual method table since the runtime - // requires that every method on a class's vtable be in that respective class's virtual method - // table. + // We need to copy the default methods into our own method table since the runtime requires that + // every method on a class's vtable be in that respective class's virtual method table. // NOTE This means that two classes might have the same implementation of a method from the same // interface but will have different ArtMethod*s for them. This also means we cannot compare a // default method found on a class with one found on the declaring interface directly and must @@ -5738,8 +5754,8 @@ bool ClassLinker::LinkInterfaceMethods( move_table.emplace(conf_method, &new_method); ++out; } - virtuals->SetSize(new_method_count); - UpdateClassVirtualMethods(klass.Get(), virtuals); + methods->SetSize(new_method_count); + UpdateClassMethods(klass.Get(), methods); // Done copying methods, they are all roots in the class now, so we can end the no thread // suspension assert. self->EndAssertNoThreadSuspension(old_cause); @@ -5755,7 +5771,7 @@ bool ClassLinker::LinkInterfaceMethods( self->AssertPendingOOMException(); return false; } - out = virtuals->begin(method_size, method_alignment) + old_method_count; + out = methods->begin(method_size, method_alignment) + old_method_count; size_t vtable_pos = old_vtable_count; for (size_t i = old_method_count; i < new_method_count; ++i) { // Leave the declaring class alone as type indices are relative to it @@ -5809,8 +5825,16 @@ bool ClassLinker::LinkInterfaceMethods( } } + if (kIsDebugBuild) { + for (size_t i = 0; i < new_vtable_count; ++i) { + CHECK(move_table.find(vtable->GetElementPtrSize(i, image_pointer_size_)) == + move_table.end()); + } + } + klass->SetVTable(vtable.Get()); - // Go fix up all the stale miranda pointers. + // Go fix up all the stale (old miranda or default method) pointers. + // First do it on the iftable. 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); @@ -5824,7 +5848,7 @@ bool ClassLinker::LinkInterfaceMethods( } } } - // Fix up IMT in case it has any miranda methods in it. + // Fix up IMT next for (size_t i = 0; i < mirror::Class::kImtSize; ++i) { auto it = move_table.find(out_imt[i]); if (it != move_table.end()) { @@ -5836,25 +5860,26 @@ bool ClassLinker::LinkInterfaceMethods( auto* resolved_methods = klass->GetDexCache()->GetResolvedMethods(); for (size_t i = 0, count = klass->GetDexCache()->NumResolvedMethods(); i < count; ++i) { auto* m = mirror::DexCache::GetElementPtrSize(resolved_methods, i, image_pointer_size_); - // We don't remove default methods from the move table since we need them to update the - // vtable. Therefore just skip them for this check. - if (!m->IsDefault()) { - CHECK(move_table.find(m) == move_table.end()) << PrettyMethod(m); - } + CHECK(move_table.find(m) == move_table.end() || + // The original versions of copied methods will still be present so allow those too. + // Note that if the first check passes this might fail to GetDeclaringClass(). + std::find_if(m->GetDeclaringClass()->GetMethods(image_pointer_size_).begin(), + m->GetDeclaringClass()->GetMethods(image_pointer_size_).end(), + [m] (ArtMethod& meth) { + return &meth == m; + }) != m->GetDeclaringClass()->GetMethods(image_pointer_size_).end()) + << "Obsolete methods " << PrettyMethod(m) << " is in dex cache!"; } } - // Put some random garbage in old virtuals to help find stale pointers. - if (virtuals != old_virtuals) { - memset(old_virtuals, 0xFEu, old_size); + // Put some random garbage in old methods to help find stale pointers. + if (methods != old_methods && old_methods != nullptr) { + memset(old_methods, 0xFEu, old_size); } } else { self->EndAssertNoThreadSuspension(old_cause); } if (kIsDebugBuild) { - auto* check_vtable = klass->GetVTableDuringLinking(); - for (int i = 0; i < check_vtable->GetLength(); ++i) { - CHECK(check_vtable->GetElementPtrSize(i, image_pointer_size_) != nullptr); - } + SanityCheckVTable(klass, image_pointer_size_); } return true; } @@ -5929,6 +5954,20 @@ bool ClassLinker::LinkFields(Thread* self, // we want a relatively stable order so that adding new fields // minimizes disruption of C++ version such as Class and Method. + // + // The overall sort order order is: + // 1) All object reference fields, sorted alphabetically. + // 2) All java long (64-bit) integer fields, sorted alphabetically. + // 3) All java double (64-bit) floating point fields, sorted alphabetically. + // 4) All java int (32-bit) integer fields, sorted alphabetically. + // 5) All java float (32-bit) floating point fields, sorted alphabetically. + // 6) All java char (16-bit) integer fields, sorted alphabetically. + // 7) All java short (16-bit) integer fields, sorted alphabetically. + // 8) All java boolean (8-bit) integer fields, sorted alphabetically. + // 9) All java byte (8-bit) integer fields, sorted alphabetically. + // + // Once the fields are sorted in this order we will attempt to fill any gaps that might be present + // in the memory layout of the structure. See ShuffleForward for how this is done. std::deque grouped_and_sorted_fields; const char* old_no_suspend_cause = self->StartAssertNoThreadSuspension( "Naked ArtField references in deque"); diff --git a/runtime/class_linker.h b/runtime/class_linker.h index 0d3bc1e2c..f16fe92d8 100644 --- a/runtime/class_linker.h +++ b/runtime/class_linker.h @@ -983,8 +983,8 @@ class ClassLinker { bool CanWeInitializeClass(mirror::Class* klass, bool can_init_statics, bool can_init_parents) SHARED_REQUIRES(Locks::mutator_lock_); - void UpdateClassVirtualMethods(mirror::Class* klass, - LengthPrefixedArray* new_methods) + void UpdateClassMethods(mirror::Class* klass, + LengthPrefixedArray* new_methods) SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!Locks::classlinker_classes_lock_); diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc index ea2a39c2c..1a38ecb61 100644 --- a/runtime/class_linker_test.cc +++ b/runtime/class_linker_test.cc @@ -254,10 +254,20 @@ class ClassLinkerTest : public CommonRuntimeTest { EXPECT_EQ(klass.Get(), method.GetDeclaringClass()); } - for (ArtMethod& method : klass->GetVirtualMethods(sizeof(void*))) { + for (ArtMethod& method : klass->GetDeclaredVirtualMethods(sizeof(void*))) { AssertMethod(&method); EXPECT_FALSE(method.IsDirect()); - EXPECT_TRUE(method.GetDeclaringClass()->IsAssignableFrom(klass.Get())); + EXPECT_EQ(klass.Get(), method.GetDeclaringClass()); + } + + for (ArtMethod& method : klass->GetCopiedMethods(sizeof(void*))) { + AssertMethod(&method); + EXPECT_FALSE(method.IsDirect()); + EXPECT_TRUE(method.IsMiranda() || method.IsDefault() || method.IsDefaultConflicting()); + EXPECT_TRUE(method.GetDeclaringClass()->IsInterface()) + << "declaring class: " << PrettyClass(method.GetDeclaringClass()); + EXPECT_TRUE(method.GetDeclaringClass()->IsAssignableFrom(klass.Get())) + << "declaring class: " << PrettyClass(method.GetDeclaringClass()); } for (size_t i = 0; i < klass->NumInstanceFields(); i++) { @@ -497,13 +507,14 @@ struct ClassOffsets : public CheckOffsets { addOffset(OFFSETOF_MEMBER(mirror::Class, class_size_), "classSize"); addOffset(OFFSETOF_MEMBER(mirror::Class, clinit_thread_id_), "clinitThreadId"); addOffset(OFFSETOF_MEMBER(mirror::Class, component_type_), "componentType"); + addOffset(OFFSETOF_MEMBER(mirror::Class, copied_methods_offset_), "copiedMethodsOffset"); addOffset(OFFSETOF_MEMBER(mirror::Class, dex_cache_), "dexCache"); addOffset(OFFSETOF_MEMBER(mirror::Class, dex_cache_strings_), "dexCacheStrings"); addOffset(OFFSETOF_MEMBER(mirror::Class, dex_class_def_idx_), "dexClassDefIndex"); addOffset(OFFSETOF_MEMBER(mirror::Class, dex_type_idx_), "dexTypeIndex"); - addOffset(OFFSETOF_MEMBER(mirror::Class, direct_methods_), "directMethods"); addOffset(OFFSETOF_MEMBER(mirror::Class, ifields_), "iFields"); addOffset(OFFSETOF_MEMBER(mirror::Class, iftable_), "ifTable"); + addOffset(OFFSETOF_MEMBER(mirror::Class, methods_), "methods"); addOffset(OFFSETOF_MEMBER(mirror::Class, name_), "name"); addOffset(OFFSETOF_MEMBER(mirror::Class, num_reference_instance_fields_), "numReferenceInstanceFields"); @@ -517,7 +528,7 @@ struct ClassOffsets : public CheckOffsets { addOffset(OFFSETOF_MEMBER(mirror::Class, status_), "status"); addOffset(OFFSETOF_MEMBER(mirror::Class, super_class_), "superClass"); addOffset(OFFSETOF_MEMBER(mirror::Class, verify_error_), "verifyError"); - addOffset(OFFSETOF_MEMBER(mirror::Class, virtual_methods_), "virtualMethods"); + addOffset(OFFSETOF_MEMBER(mirror::Class, virtual_methods_offset_), "virtualMethodsOffset"); addOffset(OFFSETOF_MEMBER(mirror::Class, vtable_), "vtable"); }; }; @@ -1123,10 +1134,7 @@ static void CheckPreverified(mirror::Class* c, bool preverified) SHARED_REQUIRES(Locks::mutator_lock_) { EXPECT_EQ((c->GetAccessFlags() & kAccPreverified) != 0U, preverified) << "Class " << PrettyClass(c) << " not as expected"; - for (auto& m : c->GetDirectMethods(sizeof(void*))) { - CheckMethod(&m, preverified); - } - for (auto& m : c->GetVirtualMethods(sizeof(void*))) { + for (auto& m : c->GetMethods(sizeof(void*))) { CheckMethod(&m, preverified); } } diff --git a/runtime/entrypoints/entrypoint_utils.cc b/runtime/entrypoints/entrypoint_utils.cc index 87e29ae3c..915d9ab5e 100644 --- a/runtime/entrypoints/entrypoint_utils.cc +++ b/runtime/entrypoints/entrypoint_utils.cc @@ -306,11 +306,13 @@ JValue InvokeProxyInvocationHandler(ScopedObjectAccessAlreadyRunnable& soa, cons mirror::Method* interface_method = soa.Decode(interface_method_jobj); ArtMethod* proxy_method = rcvr->GetClass()->FindVirtualMethodForInterface( interface_method->GetArtMethod(), sizeof(void*)); - auto* virtual_methods = proxy_class->GetVirtualMethodsPtr(); + auto virtual_methods = proxy_class->GetVirtualMethodsSlice(sizeof(void*)); size_t num_virtuals = proxy_class->NumVirtualMethods(); size_t method_size = ArtMethod::Size(sizeof(void*)); + // Rely on the fact that the methods are contiguous to determine the index of the method in + // the slice. int throws_index = (reinterpret_cast(proxy_method) - - reinterpret_cast(virtual_methods)) / method_size; + reinterpret_cast(&virtual_methods.At(0))) / method_size; CHECK_LT(throws_index, static_cast(num_virtuals)); mirror::ObjectArray* declared_exceptions = proxy_class->GetThrows()->Get(throws_index); diff --git a/runtime/jni_internal.cc b/runtime/jni_internal.cc index 5e3fa199e..cb67ee3b3 100644 --- a/runtime/jni_internal.cc +++ b/runtime/jni_internal.cc @@ -316,12 +316,7 @@ template static ArtMethod* FindMethod(mirror::Class* c, const StringPiece& name, const StringPiece& sig) SHARED_REQUIRES(Locks::mutator_lock_) { auto pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize(); - for (auto& method : c->GetDirectMethods(pointer_size)) { - if (kNative == method.IsNative() && name == method.GetName() && method.GetSignature() == sig) { - return &method; - } - } - for (auto& method : c->GetVirtualMethods(pointer_size)) { + for (auto& method : c->GetMethods(pointer_size)) { if (kNative == method.IsNative() && name == method.GetName() && method.GetSignature() == sig) { return &method; } @@ -2220,13 +2215,7 @@ class JNI { size_t unregistered_count = 0; auto pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize(); - for (auto& m : c->GetDirectMethods(pointer_size)) { - if (m.IsNative()) { - m.UnregisterNative(); - unregistered_count++; - } - } - for (auto& m : c->GetVirtualMethods(pointer_size)) { + for (auto& m : c->GetMethods(pointer_size)) { if (m.IsNative()) { m.UnregisterNative(); unregistered_count++; diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h index 9e416dc88..ef4fe15cc 100644 --- a/runtime/mirror/class-inl.h +++ b/runtime/mirror/class-inl.h @@ -22,13 +22,14 @@ #include "art_field-inl.h" #include "art_method.h" #include "art_method-inl.h" +#include "base/array_slice.h" +#include "base/length_prefixed_array.h" #include "class_loader.h" #include "common_throws.h" #include "dex_cache.h" #include "dex_file.h" #include "gc/heap-inl.h" #include "iftable.h" -#include "length_prefixed_array.h" #include "object_array-inl.h" #include "read_barrier-inl.h" #include "reference-inl.h" @@ -62,61 +63,148 @@ inline DexCache* Class::GetDexCache() { return GetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, dex_cache_)); } -inline LengthPrefixedArray* Class::GetDirectMethodsPtr() { +inline uint32_t Class::GetCopiedMethodsStartOffset() { + return GetFieldShort(OFFSET_OF_OBJECT_MEMBER(Class, copied_methods_offset_)); +} + +inline uint32_t Class::GetDirectMethodsStartOffset() { + return 0; +} + +inline uint32_t Class::GetVirtualMethodsStartOffset() { + return GetFieldShort(OFFSET_OF_OBJECT_MEMBER(Class, virtual_methods_offset_)); +} + +template +inline ArraySlice Class::GetDirectMethodsSlice(size_t pointer_size) { DCHECK(IsLoaded() || IsErroneous()); - return GetDirectMethodsPtrUnchecked(); + DCHECK(ValidPointerSize(pointer_size)) << pointer_size; + return GetDirectMethodsSliceUnchecked(pointer_size); } -inline LengthPrefixedArray* Class::GetDirectMethodsPtrUnchecked() { - return reinterpret_cast*>( - GetField64(OFFSET_OF_OBJECT_MEMBER(Class, direct_methods_))); +inline ArraySlice Class::GetDirectMethodsSliceUnchecked(size_t pointer_size) { + return ArraySlice(GetMethodsPtr(), + GetDirectMethodsStartOffset(), + GetVirtualMethodsStartOffset(), + ArtMethod::Size(pointer_size), + ArtMethod::Alignment(pointer_size)); } -inline LengthPrefixedArray* Class::GetVirtualMethodsPtrUnchecked() { +template +inline ArraySlice Class::GetDeclaredMethodsSlice(size_t pointer_size) { + DCHECK(IsLoaded() || IsErroneous()); + DCHECK(ValidPointerSize(pointer_size)) << pointer_size; + return GetDeclaredMethodsSliceUnchecked(pointer_size); +} + +inline ArraySlice Class::GetDeclaredMethodsSliceUnchecked(size_t pointer_size) { + return ArraySlice(GetMethodsPtr(), + GetDirectMethodsStartOffset(), + GetCopiedMethodsStartOffset(), + ArtMethod::Size(pointer_size), + ArtMethod::Alignment(pointer_size)); +} +template +inline ArraySlice Class::GetDeclaredVirtualMethodsSlice(size_t pointer_size) { + DCHECK(IsLoaded() || IsErroneous()); + DCHECK(ValidPointerSize(pointer_size)) << pointer_size; + return GetDeclaredVirtualMethodsSliceUnchecked(pointer_size); +} + +inline ArraySlice Class::GetDeclaredVirtualMethodsSliceUnchecked(size_t pointer_size) { + return ArraySlice(GetMethodsPtr(), + GetVirtualMethodsStartOffset(), + GetCopiedMethodsStartOffset(), + ArtMethod::Size(pointer_size), + ArtMethod::Alignment(pointer_size)); +} + +template +inline ArraySlice Class::GetVirtualMethodsSlice(size_t pointer_size) { + DCHECK(IsLoaded() || IsErroneous()); + DCHECK(ValidPointerSize(pointer_size)) << pointer_size; + return GetVirtualMethodsSliceUnchecked(pointer_size); +} + +inline ArraySlice Class::GetVirtualMethodsSliceUnchecked(size_t pointer_size) { + LengthPrefixedArray* methods = GetMethodsPtr(); + return ArraySlice(methods, + GetVirtualMethodsStartOffset(), + NumMethods(), + ArtMethod::Size(pointer_size), + ArtMethod::Alignment(pointer_size)); +} + +template +inline ArraySlice Class::GetCopiedMethodsSlice(size_t pointer_size) { + DCHECK(IsLoaded() || IsErroneous()); + DCHECK(ValidPointerSize(pointer_size)) << pointer_size; + return GetCopiedMethodsSliceUnchecked(pointer_size); +} + +inline ArraySlice Class::GetCopiedMethodsSliceUnchecked(size_t pointer_size) { + LengthPrefixedArray* methods = GetMethodsPtr(); + return ArraySlice(methods, + GetCopiedMethodsStartOffset(), + NumMethods(), + ArtMethod::Size(pointer_size), + ArtMethod::Alignment(pointer_size)); +} + +inline LengthPrefixedArray* Class::GetMethodsPtr() { return reinterpret_cast*>( - GetField64(OFFSET_OF_OBJECT_MEMBER(Class, virtual_methods_))); + GetField64(OFFSET_OF_OBJECT_MEMBER(Class, methods_))); } -inline void Class::SetDirectMethodsPtr(LengthPrefixedArray* new_direct_methods) { - DCHECK(GetDirectMethodsPtrUnchecked() == nullptr); - SetDirectMethodsPtrUnchecked(new_direct_methods); +template +inline ArraySlice Class::GetMethodsSlice(size_t pointer_size) { + DCHECK(IsLoaded() || IsErroneous()); + LengthPrefixedArray* methods = GetMethodsPtr(); + return ArraySlice(methods, + 0, + NumMethods(), + ArtMethod::Size(pointer_size), + ArtMethod::Alignment(pointer_size)); } -inline void Class::SetDirectMethodsPtrUnchecked( - LengthPrefixedArray* new_direct_methods) { - SetField64(OFFSET_OF_OBJECT_MEMBER(Class, direct_methods_), - reinterpret_cast(new_direct_methods)); + +inline uint32_t Class::NumMethods() { + LengthPrefixedArray* methods = GetMethodsPtr(); + return (methods == nullptr) ? 0 : methods->size(); } inline ArtMethod* Class::GetDirectMethodUnchecked(size_t i, size_t pointer_size) { CheckPointerSize(pointer_size); - auto* methods = GetDirectMethodsPtrUnchecked(); - DCHECK(methods != nullptr); - return &methods->At(i, - ArtMethod::Size(pointer_size), - ArtMethod::Alignment(pointer_size)); + return &GetDirectMethodsSliceUnchecked(pointer_size).At(i); } inline ArtMethod* Class::GetDirectMethod(size_t i, size_t pointer_size) { CheckPointerSize(pointer_size); - auto* methods = GetDirectMethodsPtr(); - DCHECK(methods != nullptr); - return &methods->At(i, - ArtMethod::Size(pointer_size), - ArtMethod::Alignment(pointer_size)); + return &GetDirectMethodsSlice(pointer_size).At(i); } -template -inline LengthPrefixedArray* Class::GetVirtualMethodsPtr() { - DCHECK(IsLoaded() || IsErroneous()); - return GetVirtualMethodsPtrUnchecked(); +inline void Class::SetMethodsPtr(LengthPrefixedArray* new_methods, + uint32_t num_direct, + uint32_t num_virtual) { + DCHECK(GetMethodsPtr() == nullptr); + SetMethodsPtrUnchecked(new_methods, num_direct, num_virtual); +} + + +inline void Class::SetMethodsPtrUnchecked(LengthPrefixedArray* new_methods, + uint32_t num_direct, + uint32_t num_virtual) { + DCHECK_LE(num_direct + num_virtual, (new_methods == nullptr) ? 0 : new_methods->size()); + SetMethodsPtrInternal(new_methods); + SetFieldShort(OFFSET_OF_OBJECT_MEMBER(Class, copied_methods_offset_), + dchecked_integral_cast(num_direct + num_virtual)); + SetFieldShort(OFFSET_OF_OBJECT_MEMBER(Class, virtual_methods_offset_), + dchecked_integral_cast(num_direct)); } -inline void Class::SetVirtualMethodsPtr(LengthPrefixedArray* new_virtual_methods) { - // TODO: we reassign virtual methods to grow the table for miranda - // methods.. they should really just be assigned once. - SetField64(OFFSET_OF_OBJECT_MEMBER(Class, virtual_methods_), - reinterpret_cast(new_virtual_methods)); +inline void Class::SetMethodsPtrInternal(LengthPrefixedArray* new_methods) { + SetField64(OFFSET_OF_OBJECT_MEMBER(Class, methods_), + reinterpret_cast(new_methods)); } template @@ -135,11 +223,7 @@ inline ArtMethod* Class::GetVirtualMethodDuringLinking(size_t i, size_t pointer_ inline ArtMethod* Class::GetVirtualMethodUnchecked(size_t i, size_t pointer_size) { CheckPointerSize(pointer_size); - LengthPrefixedArray* methods = GetVirtualMethodsPtrUnchecked(); - DCHECK(methods != nullptr); - return &methods->At(i, - ArtMethod::Size(pointer_size), - ArtMethod::Alignment(pointer_size)); + return &GetVirtualMethodsSliceUnchecked(pointer_size).At(i); } inline PointerArray* Class::GetVTable() { @@ -833,24 +917,42 @@ void mirror::Class::VisitNativeRoots(Visitor& visitor, size_t pointer_size) { CHECK_EQ(field.GetDeclaringClass(), this) << GetStatus(); } } - for (ArtMethod& method : GetDirectMethods(pointer_size)) { - method.VisitRoots(visitor, pointer_size); - } - for (ArtMethod& method : GetVirtualMethods(pointer_size)) { + for (ArtMethod& method : GetMethods(pointer_size)) { method.VisitRoots(visitor, pointer_size); } } inline IterationRange> Class::GetDirectMethods(size_t pointer_size) { CheckPointerSize(pointer_size); - return MakeIterationRangeFromLengthPrefixedArray(GetDirectMethodsPtrUnchecked(), - ArtMethod::Size(pointer_size), - ArtMethod::Alignment(pointer_size)); + return GetDirectMethodsSliceUnchecked(pointer_size).AsRange(); +} + +inline IterationRange> Class::GetDeclaredMethods( + size_t pointer_size) { + CheckPointerSize(pointer_size); + return GetDeclaredMethodsSliceUnchecked(pointer_size).AsRange(); +} + +inline IterationRange> Class::GetDeclaredVirtualMethods( + size_t pointer_size) { + CheckPointerSize(pointer_size); + return GetDeclaredVirtualMethodsSliceUnchecked(pointer_size).AsRange(); } inline IterationRange> Class::GetVirtualMethods(size_t pointer_size) { CheckPointerSize(pointer_size); - return MakeIterationRangeFromLengthPrefixedArray(GetVirtualMethodsPtrUnchecked(), + return GetVirtualMethodsSliceUnchecked(pointer_size).AsRange(); +} + +inline IterationRange> Class::GetCopiedMethods(size_t pointer_size) { + CheckPointerSize(pointer_size); + return GetCopiedMethodsSliceUnchecked(pointer_size).AsRange(); +} + + +inline IterationRange> Class::GetMethods(size_t pointer_size) { + CheckPointerSize(pointer_size); + return MakeIterationRangeFromLengthPrefixedArray(GetMethodsPtr(), ArtMethod::Size(pointer_size), ArtMethod::Alignment(pointer_size)); } @@ -918,13 +1020,15 @@ inline bool Class::IsAssignableFrom(Class* src) { } inline uint32_t Class::NumDirectMethods() { - LengthPrefixedArray* arr = GetDirectMethodsPtrUnchecked(); - return arr != nullptr ? arr->size() : 0u; + return GetVirtualMethodsStartOffset(); +} + +inline uint32_t Class::NumDeclaredVirtualMethods() { + return GetCopiedMethodsStartOffset() - GetVirtualMethodsStartOffset(); } inline uint32_t Class::NumVirtualMethods() { - LengthPrefixedArray* arr = GetVirtualMethodsPtrUnchecked(); - return arr != nullptr ? arr->size() : 0u; + return NumMethods() - GetVirtualMethodsStartOffset(); } inline uint32_t Class::NumInstanceFields() { @@ -952,16 +1056,11 @@ inline void Class::FixupNativePointers(mirror::Class* dest, if (ifields != new_ifields) { dest->SetIFieldsPtrUnchecked(new_ifields); } - // Update direct and virtual method arrays. - LengthPrefixedArray* direct_methods = GetDirectMethodsPtr(); - LengthPrefixedArray* new_direct_methods = visitor(direct_methods); - if (direct_methods != new_direct_methods) { - dest->SetDirectMethodsPtrUnchecked(new_direct_methods); - } - LengthPrefixedArray* virtual_methods = GetVirtualMethodsPtr(); - LengthPrefixedArray* new_virtual_methods = visitor(virtual_methods); - if (virtual_methods != new_virtual_methods) { - dest->SetVirtualMethodsPtr(new_virtual_methods); + // Update method array. + LengthPrefixedArray* methods = GetMethodsPtr(); + LengthPrefixedArray* new_methods = visitor(methods); + if (methods != new_methods) { + dest->SetMethodsPtrInternal(new_methods); } // Update dex cache strings. GcRoot* strings = GetDexCacheStrings(); diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc index 05a9039ae..66060f222 100644 --- a/runtime/mirror/class.cc +++ b/runtime/mirror/class.cc @@ -457,6 +457,10 @@ ArtMethod* Class::FindDirectMethod( return nullptr; } +// TODO These should maybe be changed to be named FindOwnedVirtualMethod or something similar +// because they do not only find 'declared' methods and will return copied methods. This behavior is +// desired and correct but the naming can lead to confusion because in the java language declared +// excludes interface methods which might be found by this. ArtMethod* Class::FindDeclaredVirtualMethod(const StringPiece& name, const StringPiece& signature, size_t pointer_size) { for (auto& method : GetVirtualMethods(pointer_size)) { @@ -482,10 +486,8 @@ ArtMethod* Class::FindDeclaredVirtualMethod(const StringPiece& name, const Signa ArtMethod* Class::FindDeclaredVirtualMethod(const DexCache* dex_cache, uint32_t dex_method_idx, size_t pointer_size) { if (GetDexCache() == dex_cache) { - for (auto& method : GetVirtualMethods(pointer_size)) { - // A miranda method may have a different DexCache and is always created by linking, - // never *declared* in the class. - if (method.GetDexMethodIndex() == dex_method_idx && !method.IsMiranda()) { + for (auto& method : GetDeclaredVirtualMethods(pointer_size)) { + if (method.GetDexMethodIndex() == dex_method_idx) { return &method; } } @@ -725,12 +727,7 @@ ArtField* Class::FindField(Thread* self, Handle klass, const StringPiece& void Class::SetPreverifiedFlagOnAllMethods(size_t pointer_size) { DCHECK(IsVerified()); - for (auto& m : GetDirectMethods(pointer_size)) { - if (!m.IsNative() && m.IsInvokable()) { - m.SetPreverified(); - } - } - for (auto& m : GetVirtualMethods(pointer_size)) { + for (auto& m : GetMethods(pointer_size)) { if (!m.IsNative() && m.IsInvokable()) { m.SetPreverified(); } diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h index 98e144004..489c269ac 100644 --- a/runtime/mirror/class.h +++ b/runtime/mirror/class.h @@ -44,6 +44,7 @@ class ArtMethod; struct ClassOffsets; template class Handle; template class LengthPrefixedArray; +template class ArraySlice; class Signature; class StringPiece; template class PACKED(4) StackHandleScope; @@ -702,12 +703,24 @@ class MANAGED Class FINAL : public Object { ALWAYS_INLINE IterationRange> GetDirectMethods(size_t pointer_size) SHARED_REQUIRES(Locks::mutator_lock_); - LengthPrefixedArray* GetDirectMethodsPtr() SHARED_REQUIRES(Locks::mutator_lock_); + ALWAYS_INLINE LengthPrefixedArray* GetMethodsPtr() + SHARED_REQUIRES(Locks::mutator_lock_); + + ALWAYS_INLINE IterationRange> GetMethods(size_t pointer_size) + SHARED_REQUIRES(Locks::mutator_lock_); - void SetDirectMethodsPtr(LengthPrefixedArray* new_direct_methods) + void SetMethodsPtr(LengthPrefixedArray* new_methods, + uint32_t num_direct, + uint32_t num_virtual) SHARED_REQUIRES(Locks::mutator_lock_); // Used by image writer. - void SetDirectMethodsPtrUnchecked(LengthPrefixedArray* new_direct_methods) + void SetMethodsPtrUnchecked(LengthPrefixedArray* new_methods, + uint32_t num_direct, + uint32_t num_virtual) + SHARED_REQUIRES(Locks::mutator_lock_); + + template + ALWAYS_INLINE ArraySlice GetDirectMethodsSlice(size_t pointer_size) SHARED_REQUIRES(Locks::mutator_lock_); ALWAYS_INLINE ArtMethod* GetDirectMethod(size_t i, size_t pointer_size) @@ -723,18 +736,50 @@ class MANAGED Class FINAL : public Object { ALWAYS_INLINE uint32_t NumDirectMethods() SHARED_REQUIRES(Locks::mutator_lock_); template - ALWAYS_INLINE LengthPrefixedArray* GetVirtualMethodsPtr() + ALWAYS_INLINE ArraySlice GetMethodsSlice(size_t pointer_size) SHARED_REQUIRES(Locks::mutator_lock_); - ALWAYS_INLINE IterationRange> GetVirtualMethods(size_t pointer_size) + template + ALWAYS_INLINE ArraySlice GetDeclaredMethodsSlice(size_t pointer_size) + SHARED_REQUIRES(Locks::mutator_lock_); + + ALWAYS_INLINE IterationRange> GetDeclaredMethods( + size_t pointer_size) + SHARED_REQUIRES(Locks::mutator_lock_); + + template + ALWAYS_INLINE ArraySlice GetDeclaredVirtualMethodsSlice(size_t pointer_size) + SHARED_REQUIRES(Locks::mutator_lock_); + + ALWAYS_INLINE IterationRange> GetDeclaredVirtualMethods( + size_t pointer_size) + SHARED_REQUIRES(Locks::mutator_lock_); + + template + ALWAYS_INLINE ArraySlice GetCopiedMethodsSlice(size_t pointer_size) SHARED_REQUIRES(Locks::mutator_lock_); - void SetVirtualMethodsPtr(LengthPrefixedArray* new_virtual_methods) + ALWAYS_INLINE IterationRange> GetCopiedMethods(size_t pointer_size) + SHARED_REQUIRES(Locks::mutator_lock_); + + template + ALWAYS_INLINE ArraySlice GetVirtualMethodsSlice(size_t pointer_size) + SHARED_REQUIRES(Locks::mutator_lock_); + + ALWAYS_INLINE IterationRange> GetVirtualMethods(size_t pointer_size) SHARED_REQUIRES(Locks::mutator_lock_); - // Returns the number of non-inherited virtual methods. + // Returns the number of non-inherited virtual methods (sum of declared and copied methods). ALWAYS_INLINE uint32_t NumVirtualMethods() SHARED_REQUIRES(Locks::mutator_lock_); + // Returns the number of copied virtual methods. + ALWAYS_INLINE uint32_t NumCopiedVirtualMethods() SHARED_REQUIRES(Locks::mutator_lock_); + + // Returns the number of declared virtual methods. + ALWAYS_INLINE uint32_t NumDeclaredVirtualMethods() SHARED_REQUIRES(Locks::mutator_lock_); + + ALWAYS_INLINE uint32_t NumMethods() SHARED_REQUIRES(Locks::mutator_lock_); + template ArtMethod* GetVirtualMethod(size_t i, size_t pointer_size) SHARED_REQUIRES(Locks::mutator_lock_); @@ -1155,10 +1200,19 @@ class MANAGED Class FINAL : public Object { return pointer_size; } - ALWAYS_INLINE LengthPrefixedArray* GetDirectMethodsPtrUnchecked() + ALWAYS_INLINE ArraySlice GetDirectMethodsSliceUnchecked(size_t pointer_size) + SHARED_REQUIRES(Locks::mutator_lock_); + + ALWAYS_INLINE ArraySlice GetVirtualMethodsSliceUnchecked(size_t pointer_size) + SHARED_REQUIRES(Locks::mutator_lock_); + + ALWAYS_INLINE ArraySlice GetDeclaredMethodsSliceUnchecked(size_t pointer_size) + SHARED_REQUIRES(Locks::mutator_lock_); + + ALWAYS_INLINE ArraySlice GetDeclaredVirtualMethodsSliceUnchecked(size_t pointer_size) SHARED_REQUIRES(Locks::mutator_lock_); - ALWAYS_INLINE LengthPrefixedArray* GetVirtualMethodsPtrUnchecked() + ALWAYS_INLINE ArraySlice GetCopiedMethodsSliceUnchecked(size_t pointer_size) SHARED_REQUIRES(Locks::mutator_lock_); // Fix up all of the native pointers in the class by running them through the visitor. Only sets @@ -1169,6 +1223,9 @@ class MANAGED Class FINAL : public Object { SHARED_REQUIRES(Locks::mutator_lock_); private: + ALWAYS_INLINE void SetMethodsPtrInternal(LengthPrefixedArray* new_methods) + SHARED_REQUIRES(Locks::mutator_lock_); + void SetVerifyError(Object* klass) SHARED_REQUIRES(Locks::mutator_lock_); template @@ -1194,6 +1251,15 @@ class MANAGED Class FINAL : public Object { IterationRange> GetIFieldsUnchecked() SHARED_REQUIRES(Locks::mutator_lock_); + // The index in the methods_ array where the first declared virtual method is. + ALWAYS_INLINE uint32_t GetVirtualMethodsStartOffset() SHARED_REQUIRES(Locks::mutator_lock_); + + // The index in the methods_ array where the first direct method is. + ALWAYS_INLINE uint32_t GetDirectMethodsStartOffset() SHARED_REQUIRES(Locks::mutator_lock_); + + // The index in the methods_ array where the first copied method is. + ALWAYS_INLINE uint32_t GetCopiedMethodsStartOffset() SHARED_REQUIRES(Locks::mutator_lock_); + bool ProxyDescriptorEquals(const char* match) SHARED_REQUIRES(Locks::mutator_lock_); // Check that the pointer size matches the one in the class linker. @@ -1206,6 +1272,9 @@ class MANAGED Class FINAL : public Object { void VisitReferences(mirror::Class* klass, const Visitor& visitor) SHARED_REQUIRES(Locks::mutator_lock_); + // 'Class' Object Fields + // Order governed by java field ordering. See art::ClassLinker::LinkFields. + HeapReference annotation_type_; // Defining class loader, or null for the "bootstrap" system loader. @@ -1259,9 +1328,6 @@ class MANAGED Class FINAL : public Object { // Short cuts to dex_cache_ member for fast compiled code access. uint64_t dex_cache_strings_; - // static, private, and methods. Pointer to an ArtMethod length-prefixed array. - uint64_t direct_methods_; - // instance fields // // These describe the layout of the contents of an Object. @@ -1273,13 +1339,24 @@ class MANAGED Class FINAL : public Object { // ArtFields. uint64_t ifields_; + // Pointer to an ArtMethod length-prefixed array. All the methods where this class is the place + // where they are logically defined. This includes all private, static, final and virtual methods + // as well as inherited default methods and miranda methods. + // + // The slice methods_ [0, virtual_methods_offset_) are the direct (static, private, init) methods + // declared by this class. + // + // The slice methods_ [virtual_methods_offset_, copied_methods_offset_) are the virtual methods + // declared by this class. + // + // The slice methods_ [copied_methods_offset_, |methods_|) are the methods that are copied from + // interfaces such as miranda or default methods. These are copied for resolution purposes as this + // class is where they are (logically) declared as far as the virtual dispatch is concerned. + uint64_t methods_; + // Static fields length-prefixed array. uint64_t sfields_; - // Virtual methods defined in this class; invoked through vtable. Pointer to an ArtMethod - // length-prefixed array. - uint64_t virtual_methods_; - // Class flags to help speed up visiting object references. uint32_t class_flags_; @@ -1319,6 +1396,14 @@ class MANAGED Class FINAL : public Object { // State of class initialization. Status status_; + // The offset of the first virtual method that is copied from an interface. This includes miranda, + // default, and default-conflict methods. Having a hard limit of ((2 << 16) - 1) for methods + // defined on a single class is well established in Java so we will use only uint16_t's here. + uint16_t copied_methods_offset_; + + // The offset of the first declared virtual methods in the methods_ array. + uint16_t virtual_methods_offset_; + // TODO: ? // initiating class loader list // NOTE: for classes with low serialNumber, these are unused, and the diff --git a/runtime/native/java_lang_Class.cc b/runtime/native/java_lang_Class.cc index 5e423920c..14d284e00 100644 --- a/runtime/native/java_lang_Class.cc +++ b/runtime/native/java_lang_Class.cc @@ -439,16 +439,9 @@ static jobjectArray Class_getDeclaredMethodsUnchecked(JNIEnv* env, jobject javaT StackHandleScope<2> hs(soa.Self()); Handle klass = hs.NewHandle(DecodeClass(soa, javaThis)); size_t num_methods = 0; - for (auto& m : klass->GetVirtualMethods(sizeof(void*))) { + for (auto& m : klass->GetDeclaredMethods(sizeof(void*))) { auto modifiers = m.GetAccessFlags(); - if ((publicOnly == JNI_FALSE || (modifiers & kAccPublic) != 0) && - (modifiers & kAccMiranda) == 0) { - ++num_methods; - } - } - for (auto& m : klass->GetDirectMethods(sizeof(void*))) { - auto modifiers = m.GetAccessFlags(); - // Add non-constructor direct/static methods. + // Add non-constructor declared methods. if ((publicOnly == JNI_FALSE || (modifiers & kAccPublic) != 0) && (modifiers & kAccConstructor) == 0) { ++num_methods; @@ -457,21 +450,8 @@ static jobjectArray Class_getDeclaredMethodsUnchecked(JNIEnv* env, jobject javaT auto ret = hs.NewHandle(mirror::ObjectArray::Alloc( soa.Self(), mirror::Method::ArrayClass(), num_methods)); num_methods = 0; - for (auto& m : klass->GetVirtualMethods(sizeof(void*))) { - auto modifiers = m.GetAccessFlags(); - if ((publicOnly == JNI_FALSE || (modifiers & kAccPublic) != 0) && - (modifiers & kAccMiranda) == 0) { - auto* method = mirror::Method::CreateFromArtMethod(soa.Self(), &m); - if (method == nullptr) { - soa.Self()->AssertPendingException(); - return nullptr; - } - ret->SetWithoutChecks(num_methods++, method); - } - } - for (auto& m : klass->GetDirectMethods(sizeof(void*))) { + for (auto& m : klass->GetDeclaredMethods(sizeof(void*))) { auto modifiers = m.GetAccessFlags(); - // Add non-constructor direct/static methods. if ((publicOnly == JNI_FALSE || (modifiers & kAccPublic) != 0) && (modifiers & kAccConstructor) == 0) { auto* method = mirror::Method::CreateFromArtMethod(soa.Self(), &m); diff --git a/runtime/native/java_lang_reflect_Method.cc b/runtime/native/java_lang_reflect_Method.cc index caacba6ec..d7cf62e99 100644 --- a/runtime/native/java_lang_reflect_Method.cc +++ b/runtime/native/java_lang_reflect_Method.cc @@ -71,7 +71,7 @@ static jobjectArray Method_getExceptionTypes(JNIEnv* env, jobject javaMethod) { mirror::Class* klass = method->GetDeclaringClass(); int throws_index = -1; size_t i = 0; - for (const auto& m : klass->GetVirtualMethods(sizeof(void*))) { + for (const auto& m : klass->GetDeclaredVirtualMethods(sizeof(void*))) { if (&m == method) { throws_index = i; break; diff --git a/runtime/native_bridge_art_interface.cc b/runtime/native_bridge_art_interface.cc index 46cc5aaff..61a1085c0 100644 --- a/runtime/native_bridge_art_interface.cc +++ b/runtime/native_bridge_art_interface.cc @@ -45,10 +45,7 @@ static uint32_t GetNativeMethodCount(JNIEnv* env, jclass clazz) { mirror::Class* c = soa.Decode(clazz); uint32_t native_method_count = 0; - for (auto& m : c->GetDirectMethods(sizeof(void*))) { - native_method_count += m.IsNative() ? 1u : 0u; - } - for (auto& m : c->GetVirtualMethods(sizeof(void*))) { + for (auto& m : c->GetMethods(sizeof(void*))) { native_method_count += m.IsNative() ? 1u : 0u; } return native_method_count; @@ -63,19 +60,7 @@ static uint32_t GetNativeMethods(JNIEnv* env, jclass clazz, JNINativeMethod* met mirror::Class* c = soa.Decode(clazz); uint32_t count = 0; - for (auto& m : c->GetDirectMethods(sizeof(void*))) { - if (m.IsNative()) { - if (count < method_count) { - methods[count].name = m.GetName(); - methods[count].signature = m.GetShorty(); - methods[count].fnPtr = m.GetEntryPointFromJni(); - count++; - } else { - LOG(WARNING) << "Output native method array too small. Skipping " << PrettyMethod(&m); - } - } - } - for (auto& m : c->GetVirtualMethods(sizeof(void*))) { + for (auto& m : c->GetMethods(sizeof(void*))) { if (m.IsNative()) { if (count < method_count) { methods[count].name = m.GetName(); diff --git a/runtime/proxy_test.cc b/runtime/proxy_test.cc index 57472adb6..4d9ca6d44 100644 --- a/runtime/proxy_test.cc +++ b/runtime/proxy_test.cc @@ -79,7 +79,7 @@ class ProxyTest : public CommonCompilerTest { mirror::Method::CreateFromArtMethod(soa.Self(), method))); // Now adds all interfaces virtual methods. for (mirror::Class* interface : interfaces) { - for (auto& m : interface->GetVirtualMethods(sizeof(void*))) { + for (auto& m : interface->GetDeclaredVirtualMethods(sizeof(void*))) { soa.Env()->SetObjectArrayElement( proxyClassMethods, array_index++, soa.AddLocalReference( mirror::Method::CreateFromArtMethod(soa.Self(), &m))); -- 2.11.0