diff options
23 files changed, 292 insertions, 610 deletions
diff --git a/compiler/common_compiler_test.cc b/compiler/common_compiler_test.cc index c7c190793c..638b897eea 100644 --- a/compiler/common_compiler_test.cc +++ b/compiler/common_compiler_test.cc @@ -142,7 +142,10 @@ 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->GetMethods(pointer_size)) { + for (auto& m : klass->GetDirectMethods(pointer_size)) { + MakeExecutable(&m); + } + for (auto& m : klass->GetVirtualMethods(pointer_size)) { MakeExecutable(&m); } } @@ -256,7 +259,10 @@ 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->GetMethods(pointer_size)) { + for (auto& m : klass->GetDirectMethods(pointer_size)) { + CompileMethod(&m); + } + for (auto& m : klass->GetVirtualMethods(pointer_size)) { CompileMethod(&m); } } diff --git a/compiler/compiled_method.h b/compiler/compiled_method.h index 7a93613481..15a4ba0f6f 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 "base/length_prefixed_array.h" +#include "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 d6961a0876..ef10b6768b 100644 --- a/compiler/driver/compiled_method_storage.h +++ b/compiler/driver/compiled_method_storage.h @@ -20,8 +20,8 @@ #include <iosfwd> #include <memory> -#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 56839f85f9..ba8f1d0df1 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -790,7 +790,10 @@ 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->GetMethods(pointer_size)) { + for (auto& m : c->GetVirtualMethods(pointer_size)) { + ResolveExceptionsForMethod(&m, pointer_size); + } + for (auto& m : c->GetDirectMethods(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 86f8b823cc..f8de9fa4a1 100644 --- a/compiler/driver/compiler_driver_test.cc +++ b/compiler/driver/compiler_driver_test.cc @@ -86,7 +86,10 @@ 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->GetMethods(pointer_size)) { + for (auto& m : c->GetDirectMethods(pointer_size)) { + MakeExecutable(&m); + } + for (auto& m : c->GetVirtualMethods(pointer_size)) { MakeExecutable(&m); } } diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc index b9ec47d3fe..fce08ea5f0 100644 --- a/compiler/image_writer.cc +++ b/compiler/image_writer.cc @@ -1030,42 +1030,44 @@ void ImageWriter::WalkFieldsInOrder(mirror::Object* obj) { } } // Visit and assign offsets for methods. - size_t num_methods = as_klass->NumMethods(); - if (num_methods != 0) { + LengthPrefixedArray<ArtMethod>* method_arrays[] = { + as_klass->GetDirectMethodsPtr(), as_klass->GetVirtualMethodsPtr(), + }; + for (LengthPrefixedArray<ArtMethod>* array : method_arrays) { + if (array == nullptr) { + continue; + } bool any_dirty = false; - for (auto& m : as_klass->GetMethods(target_ptr_size_)) { - if (WillMethodBeDirty(&m)) { - any_dirty = true; - break; - } + 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; } 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<ArtMethod>::ComputeSize(0, method_size, method_alignment); - LengthPrefixedArray<ArtMethod>* 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 : as_klass->GetMethods(target_ptr_size_)) { + for (auto& m : iteration_range) { AssignMethodOffset(&m, type); } - (any_dirty ? dirty_methods_ : clean_methods_) += num_methods; + (any_dirty ? dirty_methods_ : clean_methods_) += count; } } else if (h_obj->IsObjectArray()) { // Walk elements of an object array. diff --git a/compiler/image_writer.h b/compiler/image_writer.h index f1b2965a12..8e930f0373 100644 --- a/compiler/image_writer.h +++ b/compiler/image_writer.h @@ -27,11 +27,11 @@ #include <ostream> #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 451aa682d6..eea52045cc 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; - // 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; + for (auto& m : klass->GetVirtualMethods(pointer_size)) { + if (!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 2bc6c79d57..c86614c0fd 100644 --- a/runtime/asm_support.h +++ b/runtime/asm_support.h @@ -163,13 +163,13 @@ ADD_TEST_EQ(size_t(MIRROR_OBJECT_HEADER_SIZE), sizeof(art::mirror::Object)) #define MIRROR_CLASS_COMPONENT_TYPE_OFFSET (4 + MIRROR_OBJECT_HEADER_SIZE) ADD_TEST_EQ(MIRROR_CLASS_COMPONENT_TYPE_OFFSET, art::mirror::Class::ComponentTypeOffset().Int32Value()) -#define MIRROR_CLASS_ACCESS_FLAGS_OFFSET (64 + MIRROR_OBJECT_HEADER_SIZE) +#define MIRROR_CLASS_ACCESS_FLAGS_OFFSET (72 + MIRROR_OBJECT_HEADER_SIZE) ADD_TEST_EQ(MIRROR_CLASS_ACCESS_FLAGS_OFFSET, art::mirror::Class::AccessFlagsOffset().Int32Value()) -#define MIRROR_CLASS_OBJECT_SIZE_OFFSET (96 + MIRROR_OBJECT_HEADER_SIZE) +#define MIRROR_CLASS_OBJECT_SIZE_OFFSET (104 + MIRROR_OBJECT_HEADER_SIZE) ADD_TEST_EQ(MIRROR_CLASS_OBJECT_SIZE_OFFSET, art::mirror::Class::ObjectSizeOffset().Int32Value()) -#define MIRROR_CLASS_STATUS_OFFSET (108 + MIRROR_OBJECT_HEADER_SIZE) +#define MIRROR_CLASS_STATUS_OFFSET (116 + 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 deleted file mode 100644 index 19ad302c9d..0000000000 --- a/runtime/base/array_slice.h +++ /dev/null @@ -1,148 +0,0 @@ -/* - * 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<typename T> -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<uint32_t>(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<T*>(reinterpret_cast<uintptr_t>(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<T>* 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<T> begin() { - return StrideIterator<T>(&AtUnchecked(0), element_size_); - } - - StrideIterator<const T> begin() const { - return StrideIterator<const T>(&AtUnchecked(0), element_size_); - } - - StrideIterator<T> end() { - return StrideIterator<T>(&AtUnchecked(size_), element_size_); - } - - StrideIterator<const T> end() const { - return StrideIterator<const T>(&AtUnchecked(size_), element_size_); - } - - IterationRange<StrideIterator<T>> AsRange() { - return size() != 0 ? MakeIterationRange(begin(), end()) - : MakeEmptyIterationRange(StrideIterator<T>(nullptr, 0)); - } - - size_t size() const { - return size_; - } - - size_t ElementSize() const { - return element_size_; - } - - private: - T& AtUnchecked(size_t index) { - return *reinterpret_cast<T*>(reinterpret_cast<uintptr_t>(array_) + index * element_size_); - } - - const T& AtUnchecked(size_t index) const { - return *reinterpret_cast<T*>(reinterpret_cast<uintptr_t>(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/class_linker.cc b/runtime/class_linker.cc index a82c1dce0a..f5085ed417 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -807,7 +807,10 @@ 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->GetMethods(pointer_size)) { + 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(); @@ -2242,14 +2245,11 @@ void ClassLinker::LoadClassMembers(Thread* self, klass->SetIFieldsPtr(ifields); DCHECK_EQ(klass->NumInstanceFields(), num_ifields); // Load methods. - klass->SetMethodsPtr( - AllocArtMethodArray(self, allocator, it.NumDirectMethods() + it.NumVirtualMethods()), - it.NumDirectMethods(), - it.NumVirtualMethods()); + klass->SetDirectMethodsPtr(AllocArtMethodArray(self, allocator, it.NumDirectMethods())); + klass->SetVirtualMethodsPtr(AllocArtMethodArray(self, allocator, 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,12 +2728,9 @@ mirror::Class* ClassLinker::InsertClass(const char* descriptor, mirror::Class* k return nullptr; } -// TODO This should really be in mirror::Class. -void ClassLinker::UpdateClassMethods(mirror::Class* klass, - LengthPrefixedArray<ArtMethod>* new_methods) { - klass->SetMethodsPtrUnchecked(new_methods, - klass->NumDirectMethods(), - klass->NumDeclaredVirtualMethods()); +void ClassLinker::UpdateClassVirtualMethods(mirror::Class* klass, + LengthPrefixedArray<ArtMethod>* new_methods) { + klass->SetVirtualMethodsPtr(new_methods); // Need to mark the card so that the remembered sets and mod union tables get updated. Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(klass); } @@ -3305,30 +3302,29 @@ mirror::Class* ClassLinker::CreateProxyClass(ScopedObjectAccessAlreadyRunnable& throws_sfield.SetAccessFlags(kAccStatic | kAccPublic | kAccFinal); // Proxies have 1 direct method, the constructor - const size_t num_direct_methods = 1; + LengthPrefixedArray<ArtMethod>* 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_)); - // They have as many virtual methods as the array + // 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(); - - // Create the methods array. - LengthPrefixedArray<ArtMethod>* proxy_class_methods = AllocArtMethodArray( - self, allocator, num_direct_methods + num_virtual_methods); + auto* virtuals = AllocArtMethodArray(self, allocator, 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(proxy_class_methods == nullptr)) { + if (UNLIKELY(virtuals == nullptr)) { self->AssertPendingOOMException(); return nullptr; } - 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. + klass->SetVirtualMethodsPtr(virtuals); 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(); @@ -4106,8 +4102,14 @@ 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->GetMethods(image_pointer_size_)) { + for (auto& method : new_class->GetVirtualMethods(image_pointer_size_)) { if (method.GetDeclaringClass() == temp_class) { method.SetDeclaringClass(new_class); } @@ -4191,7 +4193,8 @@ 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->SetMethodsPtrUnchecked(nullptr, 0, 0); + klass->SetDirectMethodsPtrUnchecked(nullptr); + klass->SetVirtualMethodsPtr(nullptr); klass->SetSFieldsPtrUnchecked(nullptr); klass->SetIFieldsPtrUnchecked(nullptr); if (UNLIKELY(h_new_class.Get() == nullptr)) { @@ -4956,10 +4959,12 @@ 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)); - // Iterate through every method on this interface. The order does not matter. - for (ArtMethod& current_method : current_iface->GetDeclaredVirtualMethods(image_pointer_size)) { + 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); 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; @@ -5012,9 +5017,10 @@ ClassLinker::DefaultMethodSearchResult ClassLinker::FindDefaultMethodImplementat DCHECK_LT(k, iftable->Count()); iface.Assign(iftable->GetInterface(k)); - // 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; + 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_); // Skip abstract methods and methods with different names. if (current_method->IsAbstract() || !target_name_comparator.HasSameNameAndSignature( @@ -5321,27 +5327,6 @@ static ArtMethod* FindSameNameAndSignature(MethodNameAndSignatureComparator& cmp return nullptr; } -static void SanityCheckVTable(Handle<mirror::Class> 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<ArtMethod*>(i, pointer_size); - CHECK(m != nullptr); - - ArraySlice<ArtMethod> 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<mirror::Class> klass, @@ -5464,27 +5449,25 @@ bool ClassLinker::LinkInterfaceMethods( const bool super_interface = is_super && extend_super_iftable; auto method_array(hs2.NewHandle(iftable->GetMethodArray(i))); - ArraySlice<ArtMethod> input_virtual_methods; + LengthPrefixedArray<ArtMethod>* input_virtual_methods = nullptr; Handle<mirror::PointerArray> input_vtable_array = NullHandle<mirror::PointerArray>(); 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) { - // If we are overwriting a super class interface, try to only virtual methods instead of the + // We are overwriting a super class interface, try to only virtual methods instead of the // whole vtable. - input_virtual_methods = klass->GetDeclaredMethodsSlice(image_pointer_size_); - input_array_length = input_virtual_methods.size(); + input_virtual_methods = klass->GetVirtualMethodsPtr(); + input_array_length = klass->NumVirtualMethods(); } else { - // For a new interface, however, we need the whole vtable in case a new - // interface method is implemented in the whole superclass. + // A new interface, 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_); @@ -5505,8 +5488,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_vtable_array.Get() == nullptr ? - &input_virtual_methods[k] : + ArtMethod* vtable_method = input_virtual_methods != nullptr ? + &input_virtual_methods->At(k, method_size, method_alignment) : input_vtable_array->GetElementPtrSize<ArtMethod*>(k, image_pointer_size_); ArtMethod* vtable_method_for_name_comparison = vtable_method->GetInterfaceMethodIfProxy(image_pointer_size_); @@ -5667,39 +5650,38 @@ 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->NumMethods(); + const size_t old_method_count = klass->NumVirtualMethods(); 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<ArtMethod>* old_methods = klass->GetMethodsPtr(); - // The Realloced virtual methods aren't visible from the class roots, so there is no issue + LengthPrefixedArray<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. - // - // TODO We should maybe move some of this into mirror::Class or at least into another method. - const size_t old_size = LengthPrefixedArray<ArtMethod>::ComputeSize(old_method_count, - method_size, - method_alignment); + const size_t old_size = old_virtuals != nullptr + ? LengthPrefixedArray<ArtMethod>::ComputeSize(old_method_count, + method_size, + method_alignment) + : 0u; const size_t new_size = LengthPrefixedArray<ArtMethod>::ComputeSize(new_method_count, method_size, method_alignment); - const size_t old_methods_ptr_size = (old_methods != nullptr) ? old_size : 0; - auto* methods = reinterpret_cast<LengthPrefixedArray<ArtMethod>*>( - runtime->GetLinearAlloc()->Realloc(self, old_methods, old_methods_ptr_size, new_size)); - if (UNLIKELY(methods == nullptr)) { + auto* virtuals = reinterpret_cast<LengthPrefixedArray<ArtMethod>*>( + runtime->GetLinearAlloc()->Realloc(self, old_virtuals, old_size, new_size)); + if (UNLIKELY(virtuals == nullptr)) { self->AssertPendingOOMException(); self->EndAssertNoThreadSuspension(old_cause); return false; } ScopedArenaUnorderedMap<ArtMethod*, ArtMethod*> move_table(allocator.Adapter()); - if (methods != old_methods) { + if (virtuals != old_virtuals) { // Maps from heap allocated miranda method to linear alloc miranda method. - StrideIterator<ArtMethod> out = methods->begin(method_size, method_alignment); - // Copy over the old methods. - for (auto& m : klass->GetMethods(image_pointer_size_)) { + StrideIterator<ArtMethod> out = virtuals->begin(method_size, method_alignment); + // 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. @@ -5707,7 +5689,8 @@ bool ClassLinker::LinkInterfaceMethods( ++out; } } - StrideIterator<ArtMethod> out(methods->begin(method_size, method_alignment) + old_method_count); + StrideIterator<ArtMethod> out(virtuals->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) { @@ -5719,8 +5702,9 @@ bool ClassLinker::LinkInterfaceMethods( move_table.emplace(mir_method, &new_method); ++out; } - // 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. + // 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. // 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 @@ -5754,8 +5738,8 @@ bool ClassLinker::LinkInterfaceMethods( move_table.emplace(conf_method, &new_method); ++out; } - methods->SetSize(new_method_count); - UpdateClassMethods(klass.Get(), methods); + virtuals->SetSize(new_method_count); + UpdateClassVirtualMethods(klass.Get(), virtuals); // Done copying methods, they are all roots in the class now, so we can end the no thread // suspension assert. self->EndAssertNoThreadSuspension(old_cause); @@ -5771,7 +5755,7 @@ bool ClassLinker::LinkInterfaceMethods( self->AssertPendingOOMException(); return false; } - out = methods->begin(method_size, method_alignment) + old_method_count; + out = virtuals->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 @@ -5825,16 +5809,8 @@ bool ClassLinker::LinkInterfaceMethods( } } - if (kIsDebugBuild) { - for (size_t i = 0; i < new_vtable_count; ++i) { - CHECK(move_table.find(vtable->GetElementPtrSize<ArtMethod*>(i, image_pointer_size_)) == - move_table.end()); - } - } - klass->SetVTable(vtable.Get()); - // Go fix up all the stale (old miranda or default method) pointers. - // First do it on the iftable. + // 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); @@ -5848,7 +5824,7 @@ bool ClassLinker::LinkInterfaceMethods( } } } - // Fix up IMT next + // Fix up IMT in case it has any miranda methods in it. for (size_t i = 0; i < mirror::Class::kImtSize; ++i) { auto it = move_table.find(out_imt[i]); if (it != move_table.end()) { @@ -5860,26 +5836,25 @@ 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_); - 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!"; + // 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); + } } } - // 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); + // Put some random garbage in old virtuals to help find stale pointers. + if (virtuals != old_virtuals) { + memset(old_virtuals, 0xFEu, old_size); } } else { self->EndAssertNoThreadSuspension(old_cause); } if (kIsDebugBuild) { - SanityCheckVTable(klass, image_pointer_size_); + auto* check_vtable = klass->GetVTableDuringLinking(); + for (int i = 0; i < check_vtable->GetLength(); ++i) { + CHECK(check_vtable->GetElementPtrSize<ArtMethod*>(i, image_pointer_size_) != nullptr); + } } return true; } @@ -5954,20 +5929,6 @@ 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<ArtField*> 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 f16fe92d80..0d3bc1e2c3 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 UpdateClassMethods(mirror::Class* klass, - LengthPrefixedArray<ArtMethod>* new_methods) + void UpdateClassVirtualMethods(mirror::Class* klass, + LengthPrefixedArray<ArtMethod>* 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 387ac0aee2..2c086c59f0 100644 --- a/runtime/class_linker_test.cc +++ b/runtime/class_linker_test.cc @@ -254,20 +254,10 @@ class ClassLinkerTest : public CommonRuntimeTest { EXPECT_EQ(klass.Get(), method.GetDeclaringClass()); } - for (ArtMethod& method : klass->GetDeclaredVirtualMethods(sizeof(void*))) { + for (ArtMethod& method : klass->GetVirtualMethods(sizeof(void*))) { AssertMethod(&method); EXPECT_FALSE(method.IsDirect()); - 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()); + EXPECT_TRUE(method.GetDeclaringClass()->IsAssignableFrom(klass.Get())); } for (size_t i = 0; i < klass->NumInstanceFields(); i++) { @@ -506,14 +496,13 @@ struct ClassOffsets : public CheckOffsets<mirror::Class> { 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"); @@ -527,7 +516,7 @@ struct ClassOffsets : public CheckOffsets<mirror::Class> { 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_offset_), "virtualMethodsOffset"); + addOffset(OFFSETOF_MEMBER(mirror::Class, virtual_methods_), "virtualMethods"); addOffset(OFFSETOF_MEMBER(mirror::Class, vtable_), "vtable"); }; }; @@ -1133,7 +1122,10 @@ 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->GetMethods(sizeof(void*))) { + for (auto& m : c->GetDirectMethods(sizeof(void*))) { + CheckMethod(&m, preverified); + } + for (auto& m : c->GetVirtualMethods(sizeof(void*))) { CheckMethod(&m, preverified); } } diff --git a/runtime/entrypoints/entrypoint_utils.cc b/runtime/entrypoints/entrypoint_utils.cc index 915d9ab5e7..87e29ae3c3 100644 --- a/runtime/entrypoints/entrypoint_utils.cc +++ b/runtime/entrypoints/entrypoint_utils.cc @@ -306,13 +306,11 @@ JValue InvokeProxyInvocationHandler(ScopedObjectAccessAlreadyRunnable& soa, cons mirror::Method* interface_method = soa.Decode<mirror::Method*>(interface_method_jobj); ArtMethod* proxy_method = rcvr->GetClass()->FindVirtualMethodForInterface( interface_method->GetArtMethod(), sizeof(void*)); - auto virtual_methods = proxy_class->GetVirtualMethodsSlice(sizeof(void*)); + auto* virtual_methods = proxy_class->GetVirtualMethodsPtr(); 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<uintptr_t>(proxy_method) - - reinterpret_cast<uintptr_t>(&virtual_methods.At(0))) / method_size; + reinterpret_cast<uintptr_t>(virtual_methods)) / method_size; CHECK_LT(throws_index, static_cast<int>(num_virtuals)); mirror::ObjectArray<mirror::Class>* declared_exceptions = proxy_class->GetThrows()->Get(throws_index); diff --git a/runtime/jni_internal.cc b/runtime/jni_internal.cc index cb67ee3b39..5e3fa199e5 100644 --- a/runtime/jni_internal.cc +++ b/runtime/jni_internal.cc @@ -316,7 +316,12 @@ template <bool kNative> 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->GetMethods(pointer_size)) { + 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)) { if (kNative == method.IsNative() && name == method.GetName() && method.GetSignature() == sig) { return &method; } @@ -2215,7 +2220,13 @@ class JNI { size_t unregistered_count = 0; auto pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize(); - for (auto& m : c->GetMethods(pointer_size)) { + for (auto& m : c->GetDirectMethods(pointer_size)) { + if (m.IsNative()) { + m.UnregisterNative(); + unregistered_count++; + } + } + for (auto& m : c->GetVirtualMethods(pointer_size)) { if (m.IsNative()) { m.UnregisterNative(); unregistered_count++; diff --git a/runtime/base/length_prefixed_array.h b/runtime/length_prefixed_array.h index d6328717e6..e01b6ccd26 100644 --- a/runtime/base/length_prefixed_array.h +++ b/runtime/length_prefixed_array.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_BASE_LENGTH_PREFIXED_ARRAY_H_ -#define ART_RUNTIME_BASE_LENGTH_PREFIXED_ARRAY_H_ +#ifndef ART_RUNTIME_LENGTH_PREFIXED_ARRAY_H_ +#define ART_RUNTIME_LENGTH_PREFIXED_ARRAY_H_ #include <stddef.h> // for offsetof() @@ -110,4 +110,4 @@ IterationRange<StrideIterator<T>> MakeIterationRangeFromLengthPrefixedArray( } // namespace art -#endif // ART_RUNTIME_BASE_LENGTH_PREFIXED_ARRAY_H_ +#endif // ART_RUNTIME_LENGTH_PREFIXED_ARRAY_H_ diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h index ef4fe15cc1..9e416dc888 100644 --- a/runtime/mirror/class-inl.h +++ b/runtime/mirror/class-inl.h @@ -22,14 +22,13 @@ #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" @@ -63,148 +62,61 @@ inline DexCache* Class::GetDexCache() { return GetFieldObject<DexCache, kVerifyFlags>(OFFSET_OF_OBJECT_MEMBER(Class, dex_cache_)); } -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<VerifyObjectFlags kVerifyFlags> -inline ArraySlice<ArtMethod> Class::GetDirectMethodsSlice(size_t pointer_size) { +inline LengthPrefixedArray<ArtMethod>* Class::GetDirectMethodsPtr() { DCHECK(IsLoaded() || IsErroneous()); - DCHECK(ValidPointerSize(pointer_size)) << pointer_size; - return GetDirectMethodsSliceUnchecked(pointer_size); + return GetDirectMethodsPtrUnchecked(); } -inline ArraySlice<ArtMethod> Class::GetDirectMethodsSliceUnchecked(size_t pointer_size) { - return ArraySlice<ArtMethod>(GetMethodsPtr(), - GetDirectMethodsStartOffset(), - GetVirtualMethodsStartOffset(), - ArtMethod::Size(pointer_size), - ArtMethod::Alignment(pointer_size)); -} - -template<VerifyObjectFlags kVerifyFlags> -inline ArraySlice<ArtMethod> Class::GetDeclaredMethodsSlice(size_t pointer_size) { - DCHECK(IsLoaded() || IsErroneous()); - DCHECK(ValidPointerSize(pointer_size)) << pointer_size; - return GetDeclaredMethodsSliceUnchecked(pointer_size); -} - -inline ArraySlice<ArtMethod> Class::GetDeclaredMethodsSliceUnchecked(size_t pointer_size) { - return ArraySlice<ArtMethod>(GetMethodsPtr(), - GetDirectMethodsStartOffset(), - GetCopiedMethodsStartOffset(), - ArtMethod::Size(pointer_size), - ArtMethod::Alignment(pointer_size)); -} -template<VerifyObjectFlags kVerifyFlags> -inline ArraySlice<ArtMethod> Class::GetDeclaredVirtualMethodsSlice(size_t pointer_size) { - DCHECK(IsLoaded() || IsErroneous()); - DCHECK(ValidPointerSize(pointer_size)) << pointer_size; - return GetDeclaredVirtualMethodsSliceUnchecked(pointer_size); -} - -inline ArraySlice<ArtMethod> Class::GetDeclaredVirtualMethodsSliceUnchecked(size_t pointer_size) { - return ArraySlice<ArtMethod>(GetMethodsPtr(), - GetVirtualMethodsStartOffset(), - GetCopiedMethodsStartOffset(), - ArtMethod::Size(pointer_size), - ArtMethod::Alignment(pointer_size)); -} - -template<VerifyObjectFlags kVerifyFlags> -inline ArraySlice<ArtMethod> Class::GetVirtualMethodsSlice(size_t pointer_size) { - DCHECK(IsLoaded() || IsErroneous()); - DCHECK(ValidPointerSize(pointer_size)) << pointer_size; - return GetVirtualMethodsSliceUnchecked(pointer_size); -} - -inline ArraySlice<ArtMethod> Class::GetVirtualMethodsSliceUnchecked(size_t pointer_size) { - LengthPrefixedArray<ArtMethod>* methods = GetMethodsPtr(); - return ArraySlice<ArtMethod>(methods, - GetVirtualMethodsStartOffset(), - NumMethods(), - ArtMethod::Size(pointer_size), - ArtMethod::Alignment(pointer_size)); -} - -template<VerifyObjectFlags kVerifyFlags> -inline ArraySlice<ArtMethod> Class::GetCopiedMethodsSlice(size_t pointer_size) { - DCHECK(IsLoaded() || IsErroneous()); - DCHECK(ValidPointerSize(pointer_size)) << pointer_size; - return GetCopiedMethodsSliceUnchecked(pointer_size); -} - -inline ArraySlice<ArtMethod> Class::GetCopiedMethodsSliceUnchecked(size_t pointer_size) { - LengthPrefixedArray<ArtMethod>* methods = GetMethodsPtr(); - return ArraySlice<ArtMethod>(methods, - GetCopiedMethodsStartOffset(), - NumMethods(), - ArtMethod::Size(pointer_size), - ArtMethod::Alignment(pointer_size)); +inline LengthPrefixedArray<ArtMethod>* Class::GetDirectMethodsPtrUnchecked() { + return reinterpret_cast<LengthPrefixedArray<ArtMethod>*>( + GetField64(OFFSET_OF_OBJECT_MEMBER(Class, direct_methods_))); } -inline LengthPrefixedArray<ArtMethod>* Class::GetMethodsPtr() { +inline LengthPrefixedArray<ArtMethod>* Class::GetVirtualMethodsPtrUnchecked() { return reinterpret_cast<LengthPrefixedArray<ArtMethod>*>( - GetField64(OFFSET_OF_OBJECT_MEMBER(Class, methods_))); + GetField64(OFFSET_OF_OBJECT_MEMBER(Class, virtual_methods_))); } -template<VerifyObjectFlags kVerifyFlags> -inline ArraySlice<ArtMethod> Class::GetMethodsSlice(size_t pointer_size) { - DCHECK(IsLoaded() || IsErroneous()); - LengthPrefixedArray<ArtMethod>* methods = GetMethodsPtr(); - return ArraySlice<ArtMethod>(methods, - 0, - NumMethods(), - ArtMethod::Size(pointer_size), - ArtMethod::Alignment(pointer_size)); +inline void Class::SetDirectMethodsPtr(LengthPrefixedArray<ArtMethod>* new_direct_methods) { + DCHECK(GetDirectMethodsPtrUnchecked() == nullptr); + SetDirectMethodsPtrUnchecked(new_direct_methods); } - -inline uint32_t Class::NumMethods() { - LengthPrefixedArray<ArtMethod>* methods = GetMethodsPtr(); - return (methods == nullptr) ? 0 : methods->size(); +inline void Class::SetDirectMethodsPtrUnchecked( + LengthPrefixedArray<ArtMethod>* new_direct_methods) { + SetField64<false>(OFFSET_OF_OBJECT_MEMBER(Class, direct_methods_), + reinterpret_cast<uint64_t>(new_direct_methods)); } inline ArtMethod* Class::GetDirectMethodUnchecked(size_t i, size_t pointer_size) { CheckPointerSize(pointer_size); - return &GetDirectMethodsSliceUnchecked(pointer_size).At(i); + auto* methods = GetDirectMethodsPtrUnchecked(); + DCHECK(methods != nullptr); + return &methods->At(i, + ArtMethod::Size(pointer_size), + ArtMethod::Alignment(pointer_size)); } inline ArtMethod* Class::GetDirectMethod(size_t i, size_t pointer_size) { CheckPointerSize(pointer_size); - return &GetDirectMethodsSlice(pointer_size).At(i); -} - -inline void Class::SetMethodsPtr(LengthPrefixedArray<ArtMethod>* new_methods, - uint32_t num_direct, - uint32_t num_virtual) { - DCHECK(GetMethodsPtr() == nullptr); - SetMethodsPtrUnchecked(new_methods, num_direct, num_virtual); + auto* methods = GetDirectMethodsPtr(); + DCHECK(methods != nullptr); + return &methods->At(i, + ArtMethod::Size(pointer_size), + ArtMethod::Alignment(pointer_size)); } - -inline void Class::SetMethodsPtrUnchecked(LengthPrefixedArray<ArtMethod>* 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<false>(OFFSET_OF_OBJECT_MEMBER(Class, copied_methods_offset_), - dchecked_integral_cast<uint16_t>(num_direct + num_virtual)); - SetFieldShort<false>(OFFSET_OF_OBJECT_MEMBER(Class, virtual_methods_offset_), - dchecked_integral_cast<uint16_t>(num_direct)); +template<VerifyObjectFlags kVerifyFlags> +inline LengthPrefixedArray<ArtMethod>* Class::GetVirtualMethodsPtr() { + DCHECK(IsLoaded<kVerifyFlags>() || IsErroneous<kVerifyFlags>()); + return GetVirtualMethodsPtrUnchecked(); } -inline void Class::SetMethodsPtrInternal(LengthPrefixedArray<ArtMethod>* new_methods) { - SetField64<false>(OFFSET_OF_OBJECT_MEMBER(Class, methods_), - reinterpret_cast<uint64_t>(new_methods)); +inline void Class::SetVirtualMethodsPtr(LengthPrefixedArray<ArtMethod>* new_virtual_methods) { + // TODO: we reassign virtual methods to grow the table for miranda + // methods.. they should really just be assigned once. + SetField64<false>(OFFSET_OF_OBJECT_MEMBER(Class, virtual_methods_), + reinterpret_cast<uint64_t>(new_virtual_methods)); } template<VerifyObjectFlags kVerifyFlags> @@ -223,7 +135,11 @@ inline ArtMethod* Class::GetVirtualMethodDuringLinking(size_t i, size_t pointer_ inline ArtMethod* Class::GetVirtualMethodUnchecked(size_t i, size_t pointer_size) { CheckPointerSize(pointer_size); - return &GetVirtualMethodsSliceUnchecked(pointer_size).At(i); + LengthPrefixedArray<ArtMethod>* methods = GetVirtualMethodsPtrUnchecked(); + DCHECK(methods != nullptr); + return &methods->At(i, + ArtMethod::Size(pointer_size), + ArtMethod::Alignment(pointer_size)); } inline PointerArray* Class::GetVTable() { @@ -917,42 +833,24 @@ void mirror::Class::VisitNativeRoots(Visitor& visitor, size_t pointer_size) { CHECK_EQ(field.GetDeclaringClass(), this) << GetStatus(); } } - for (ArtMethod& method : GetMethods(pointer_size)) { + for (ArtMethod& method : GetDirectMethods(pointer_size)) { + method.VisitRoots(visitor, pointer_size); + } + for (ArtMethod& method : GetVirtualMethods(pointer_size)) { method.VisitRoots(visitor, pointer_size); } } inline IterationRange<StrideIterator<ArtMethod>> Class::GetDirectMethods(size_t pointer_size) { CheckPointerSize(pointer_size); - return GetDirectMethodsSliceUnchecked(pointer_size).AsRange(); -} - -inline IterationRange<StrideIterator<ArtMethod>> Class::GetDeclaredMethods( - size_t pointer_size) { - CheckPointerSize(pointer_size); - return GetDeclaredMethodsSliceUnchecked(pointer_size).AsRange(); -} - -inline IterationRange<StrideIterator<ArtMethod>> Class::GetDeclaredVirtualMethods( - size_t pointer_size) { - CheckPointerSize(pointer_size); - return GetDeclaredVirtualMethodsSliceUnchecked(pointer_size).AsRange(); + return MakeIterationRangeFromLengthPrefixedArray(GetDirectMethodsPtrUnchecked(), + ArtMethod::Size(pointer_size), + ArtMethod::Alignment(pointer_size)); } inline IterationRange<StrideIterator<ArtMethod>> Class::GetVirtualMethods(size_t pointer_size) { CheckPointerSize(pointer_size); - return GetVirtualMethodsSliceUnchecked(pointer_size).AsRange(); -} - -inline IterationRange<StrideIterator<ArtMethod>> Class::GetCopiedMethods(size_t pointer_size) { - CheckPointerSize(pointer_size); - return GetCopiedMethodsSliceUnchecked(pointer_size).AsRange(); -} - - -inline IterationRange<StrideIterator<ArtMethod>> Class::GetMethods(size_t pointer_size) { - CheckPointerSize(pointer_size); - return MakeIterationRangeFromLengthPrefixedArray(GetMethodsPtr(), + return MakeIterationRangeFromLengthPrefixedArray(GetVirtualMethodsPtrUnchecked(), ArtMethod::Size(pointer_size), ArtMethod::Alignment(pointer_size)); } @@ -1020,15 +918,13 @@ inline bool Class::IsAssignableFrom(Class* src) { } inline uint32_t Class::NumDirectMethods() { - return GetVirtualMethodsStartOffset(); -} - -inline uint32_t Class::NumDeclaredVirtualMethods() { - return GetCopiedMethodsStartOffset() - GetVirtualMethodsStartOffset(); + LengthPrefixedArray<ArtMethod>* arr = GetDirectMethodsPtrUnchecked(); + return arr != nullptr ? arr->size() : 0u; } inline uint32_t Class::NumVirtualMethods() { - return NumMethods() - GetVirtualMethodsStartOffset(); + LengthPrefixedArray<ArtMethod>* arr = GetVirtualMethodsPtrUnchecked(); + return arr != nullptr ? arr->size() : 0u; } inline uint32_t Class::NumInstanceFields() { @@ -1056,11 +952,16 @@ inline void Class::FixupNativePointers(mirror::Class* dest, if (ifields != new_ifields) { dest->SetIFieldsPtrUnchecked(new_ifields); } - // Update method array. - LengthPrefixedArray<ArtMethod>* methods = GetMethodsPtr(); - LengthPrefixedArray<ArtMethod>* new_methods = visitor(methods); - if (methods != new_methods) { - dest->SetMethodsPtrInternal(new_methods); + // Update direct and virtual method arrays. + LengthPrefixedArray<ArtMethod>* direct_methods = GetDirectMethodsPtr(); + LengthPrefixedArray<ArtMethod>* new_direct_methods = visitor(direct_methods); + if (direct_methods != new_direct_methods) { + dest->SetDirectMethodsPtrUnchecked(new_direct_methods); + } + LengthPrefixedArray<ArtMethod>* virtual_methods = GetVirtualMethodsPtr(); + LengthPrefixedArray<ArtMethod>* new_virtual_methods = visitor(virtual_methods); + if (virtual_methods != new_virtual_methods) { + dest->SetVirtualMethodsPtr(new_virtual_methods); } // Update dex cache strings. GcRoot<mirror::String>* strings = GetDexCacheStrings(); diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc index 66060f2221..05a9039ae9 100644 --- a/runtime/mirror/class.cc +++ b/runtime/mirror/class.cc @@ -457,10 +457,6 @@ 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)) { @@ -486,8 +482,10 @@ 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 : GetDeclaredVirtualMethods(pointer_size)) { - if (method.GetDexMethodIndex() == dex_method_idx) { + 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()) { return &method; } } @@ -727,7 +725,12 @@ ArtField* Class::FindField(Thread* self, Handle<Class> klass, const StringPiece& void Class::SetPreverifiedFlagOnAllMethods(size_t pointer_size) { DCHECK(IsVerified()); - for (auto& m : GetMethods(pointer_size)) { + for (auto& m : GetDirectMethods(pointer_size)) { + if (!m.IsNative() && m.IsInvokable()) { + m.SetPreverified(); + } + } + for (auto& m : GetVirtualMethods(pointer_size)) { if (!m.IsNative() && m.IsInvokable()) { m.SetPreverified(); } diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h index ce879ba2ee..0ab5b97d72 100644 --- a/runtime/mirror/class.h +++ b/runtime/mirror/class.h @@ -44,7 +44,6 @@ class ArtMethod; struct ClassOffsets; template<class T> class Handle; template<typename T> class LengthPrefixedArray; -template<typename T> class ArraySlice; class Signature; class StringPiece; template<size_t kNumReferences> class PACKED(4) StackHandleScope; @@ -703,24 +702,12 @@ class MANAGED Class FINAL : public Object { ALWAYS_INLINE IterationRange<StrideIterator<ArtMethod>> GetDirectMethods(size_t pointer_size) SHARED_REQUIRES(Locks::mutator_lock_); - ALWAYS_INLINE LengthPrefixedArray<ArtMethod>* GetMethodsPtr() - SHARED_REQUIRES(Locks::mutator_lock_); - - ALWAYS_INLINE IterationRange<StrideIterator<ArtMethod>> GetMethods(size_t pointer_size) - SHARED_REQUIRES(Locks::mutator_lock_); + LengthPrefixedArray<ArtMethod>* GetDirectMethodsPtr() SHARED_REQUIRES(Locks::mutator_lock_); - void SetMethodsPtr(LengthPrefixedArray<ArtMethod>* new_methods, - uint32_t num_direct, - uint32_t num_virtual) + void SetDirectMethodsPtr(LengthPrefixedArray<ArtMethod>* new_direct_methods) SHARED_REQUIRES(Locks::mutator_lock_); // Used by image writer. - void SetMethodsPtrUnchecked(LengthPrefixedArray<ArtMethod>* new_methods, - uint32_t num_direct, - uint32_t num_virtual) - SHARED_REQUIRES(Locks::mutator_lock_); - - template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> - ALWAYS_INLINE ArraySlice<ArtMethod> GetDirectMethodsSlice(size_t pointer_size) + void SetDirectMethodsPtrUnchecked(LengthPrefixedArray<ArtMethod>* new_direct_methods) SHARED_REQUIRES(Locks::mutator_lock_); ALWAYS_INLINE ArtMethod* GetDirectMethod(size_t i, size_t pointer_size) @@ -736,50 +723,18 @@ class MANAGED Class FINAL : public Object { ALWAYS_INLINE uint32_t NumDirectMethods() SHARED_REQUIRES(Locks::mutator_lock_); template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> - ALWAYS_INLINE ArraySlice<ArtMethod> GetMethodsSlice(size_t pointer_size) - SHARED_REQUIRES(Locks::mutator_lock_); - - template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> - ALWAYS_INLINE ArraySlice<ArtMethod> GetDeclaredMethodsSlice(size_t pointer_size) - SHARED_REQUIRES(Locks::mutator_lock_); - - ALWAYS_INLINE IterationRange<StrideIterator<ArtMethod>> GetDeclaredMethods( - size_t pointer_size) - SHARED_REQUIRES(Locks::mutator_lock_); - - template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> - ALWAYS_INLINE ArraySlice<ArtMethod> GetDeclaredVirtualMethodsSlice(size_t pointer_size) - SHARED_REQUIRES(Locks::mutator_lock_); - - ALWAYS_INLINE IterationRange<StrideIterator<ArtMethod>> GetDeclaredVirtualMethods( - size_t pointer_size) - SHARED_REQUIRES(Locks::mutator_lock_); - - template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> - ALWAYS_INLINE ArraySlice<ArtMethod> GetCopiedMethodsSlice(size_t pointer_size) - SHARED_REQUIRES(Locks::mutator_lock_); - - ALWAYS_INLINE IterationRange<StrideIterator<ArtMethod>> GetCopiedMethods(size_t pointer_size) + ALWAYS_INLINE LengthPrefixedArray<ArtMethod>* GetVirtualMethodsPtr() SHARED_REQUIRES(Locks::mutator_lock_); - template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> - ALWAYS_INLINE ArraySlice<ArtMethod> GetVirtualMethodsSlice(size_t pointer_size) + ALWAYS_INLINE IterationRange<StrideIterator<ArtMethod>> GetVirtualMethods(size_t pointer_size) SHARED_REQUIRES(Locks::mutator_lock_); - ALWAYS_INLINE IterationRange<StrideIterator<ArtMethod>> GetVirtualMethods(size_t pointer_size) + void SetVirtualMethodsPtr(LengthPrefixedArray<ArtMethod>* new_virtual_methods) SHARED_REQUIRES(Locks::mutator_lock_); - // Returns the number of non-inherited virtual methods (sum of declared and copied methods). + // Returns the number of non-inherited virtual 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<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> ArtMethod* GetVirtualMethod(size_t i, size_t pointer_size) SHARED_REQUIRES(Locks::mutator_lock_); @@ -1200,19 +1155,10 @@ class MANAGED Class FINAL : public Object { return pointer_size; } - ALWAYS_INLINE ArraySlice<ArtMethod> GetDirectMethodsSliceUnchecked(size_t pointer_size) - SHARED_REQUIRES(Locks::mutator_lock_); - - ALWAYS_INLINE ArraySlice<ArtMethod> GetVirtualMethodsSliceUnchecked(size_t pointer_size) - SHARED_REQUIRES(Locks::mutator_lock_); - - ALWAYS_INLINE ArraySlice<ArtMethod> GetDeclaredMethodsSliceUnchecked(size_t pointer_size) - SHARED_REQUIRES(Locks::mutator_lock_); - - ALWAYS_INLINE ArraySlice<ArtMethod> GetDeclaredVirtualMethodsSliceUnchecked(size_t pointer_size) + ALWAYS_INLINE LengthPrefixedArray<ArtMethod>* GetDirectMethodsPtrUnchecked() SHARED_REQUIRES(Locks::mutator_lock_); - ALWAYS_INLINE ArraySlice<ArtMethod> GetCopiedMethodsSliceUnchecked(size_t pointer_size) + ALWAYS_INLINE LengthPrefixedArray<ArtMethod>* GetVirtualMethodsPtrUnchecked() SHARED_REQUIRES(Locks::mutator_lock_); // Fix up all of the native pointers in the class by running them through the visitor. Only sets @@ -1223,9 +1169,6 @@ class MANAGED Class FINAL : public Object { SHARED_REQUIRES(Locks::mutator_lock_); private: - ALWAYS_INLINE void SetMethodsPtrInternal(LengthPrefixedArray<ArtMethod>* new_methods) - SHARED_REQUIRES(Locks::mutator_lock_); - void SetVerifyError(Object* klass) SHARED_REQUIRES(Locks::mutator_lock_); template <bool throw_on_failure, bool use_referrers_cache> @@ -1251,15 +1194,6 @@ class MANAGED Class FINAL : public Object { IterationRange<StrideIterator<ArtField>> 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. @@ -1272,9 +1206,6 @@ 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. - // Defining class loader, or null for the "bootstrap" system loader. HeapReference<ClassLoader> class_loader_; @@ -1323,6 +1254,9 @@ 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 <init> methods. Pointer to an ArtMethod length-prefixed array. + uint64_t direct_methods_; + // instance fields // // These describe the layout of the contents of an Object. @@ -1334,24 +1268,13 @@ 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_; + // Access flags; low 16 bits are defined by VM spec. uint32_t access_flags_; @@ -1394,14 +1317,6 @@ 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 14d284e003..5e423920c0 100644 --- a/runtime/native/java_lang_Class.cc +++ b/runtime/native/java_lang_Class.cc @@ -439,9 +439,16 @@ static jobjectArray Class_getDeclaredMethodsUnchecked(JNIEnv* env, jobject javaT StackHandleScope<2> hs(soa.Self()); Handle<mirror::Class> klass = hs.NewHandle(DecodeClass(soa, javaThis)); size_t num_methods = 0; - for (auto& m : klass->GetDeclaredMethods(sizeof(void*))) { + for (auto& m : klass->GetVirtualMethods(sizeof(void*))) { auto modifiers = m.GetAccessFlags(); - // Add non-constructor declared methods. + 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. if ((publicOnly == JNI_FALSE || (modifiers & kAccPublic) != 0) && (modifiers & kAccConstructor) == 0) { ++num_methods; @@ -450,8 +457,21 @@ static jobjectArray Class_getDeclaredMethodsUnchecked(JNIEnv* env, jobject javaT auto ret = hs.NewHandle(mirror::ObjectArray<mirror::Method>::Alloc( soa.Self(), mirror::Method::ArrayClass(), num_methods)); num_methods = 0; - for (auto& m : klass->GetDeclaredMethods(sizeof(void*))) { + 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<false>(num_methods++, method); + } + } + for (auto& m : klass->GetDirectMethods(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 d7cf62e994..caacba6ec3 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->GetDeclaredVirtualMethods(sizeof(void*))) { + for (const auto& m : klass->GetVirtualMethods(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 61a1085c0e..46cc5aaff8 100644 --- a/runtime/native_bridge_art_interface.cc +++ b/runtime/native_bridge_art_interface.cc @@ -45,7 +45,10 @@ static uint32_t GetNativeMethodCount(JNIEnv* env, jclass clazz) { mirror::Class* c = soa.Decode<mirror::Class*>(clazz); uint32_t native_method_count = 0; - for (auto& m : c->GetMethods(sizeof(void*))) { + for (auto& m : c->GetDirectMethods(sizeof(void*))) { + native_method_count += m.IsNative() ? 1u : 0u; + } + for (auto& m : c->GetVirtualMethods(sizeof(void*))) { native_method_count += m.IsNative() ? 1u : 0u; } return native_method_count; @@ -60,7 +63,19 @@ static uint32_t GetNativeMethods(JNIEnv* env, jclass clazz, JNINativeMethod* met mirror::Class* c = soa.Decode<mirror::Class*>(clazz); uint32_t count = 0; - for (auto& m : c->GetMethods(sizeof(void*))) { + 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*))) { 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 4d9ca6d440..57472adb64 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->GetDeclaredVirtualMethods(sizeof(void*))) { + for (auto& m : interface->GetVirtualMethods(sizeof(void*))) { soa.Env()->SetObjectArrayElement( proxyClassMethods, array_index++, soa.AddLocalReference<jobject>( mirror::Method::CreateFromArtMethod(soa.Self(), &m))); |