diff options
| -rw-r--r-- | compiler/optimizing/instruction_builder.cc | 74 | ||||
| -rw-r--r-- | runtime/base/arena_allocator.cc | 20 | ||||
| -rw-r--r-- | runtime/base/arena_allocator.h | 2 | ||||
| -rw-r--r-- | runtime/base/arena_allocator_test.cc | 22 | ||||
| -rw-r--r-- | runtime/class_linker-inl.h | 17 | ||||
| -rw-r--r-- | runtime/class_linker.h | 6 | ||||
| -rw-r--r-- | runtime/entrypoints/quick/quick_trampoline_entrypoints.cc | 7 | ||||
| -rw-r--r-- | runtime/jit/offline_profiling_info.cc | 3 |
8 files changed, 87 insertions, 64 deletions
diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc index 00cd2f659d..a834216d0c 100644 --- a/compiler/optimizing/instruction_builder.cc +++ b/compiler/optimizing/instruction_builder.cc @@ -673,6 +673,16 @@ ArtMethod* HInstructionBuilder::ResolveMethod(uint16_t method_idx, InvokeType in Handle<mirror::ClassLoader> class_loader(hs.NewHandle( soa.Decode<mirror::ClassLoader*>(dex_compilation_unit_->GetClassLoader()))); Handle<mirror::Class> compiling_class(hs.NewHandle(GetCompilingClass())); + // We fetch the referenced class eagerly (that is, the class pointed by in the MethodId + // at method_idx), as `CanAccessResolvedMethod` expects it be be in the dex cache. + Handle<mirror::Class> methods_class(hs.NewHandle(class_linker->ResolveReferencedClassOfMethod( + method_idx, dex_compilation_unit_->GetDexCache(), class_loader))); + + if (UNLIKELY(methods_class.Get() == nullptr)) { + // Clean up any exception left by type resolution. + soa.Self()->ClearException(); + return nullptr; + } ArtMethod* resolved_method = class_linker->ResolveMethod<ClassLinker::kForceICCECheck>( *dex_compilation_unit_->GetDexFile(), @@ -711,47 +721,33 @@ ArtMethod* HInstructionBuilder::ResolveMethod(uint16_t method_idx, InvokeType in DCHECK(Runtime::Current()->IsAotCompiler()); return nullptr; } - ArtMethod* current_method = graph_->GetArtMethod(); - DCHECK(current_method != nullptr); - Handle<mirror::Class> methods_class(hs.NewHandle( - dex_compilation_unit_->GetClassLinker()->ResolveReferencedClassOfMethod(Thread::Current(), - method_idx, - current_method))); - if (methods_class.Get() == nullptr) { - // Invoking a super method requires knowing the actual super class. If we did not resolve - // the compiling method's declaring class (which only happens for ahead of time - // compilation), bail out. - DCHECK(Runtime::Current()->IsAotCompiler()); - return nullptr; + ArtMethod* actual_method; + if (methods_class->IsInterface()) { + actual_method = methods_class->FindVirtualMethodForInterfaceSuper( + resolved_method, class_linker->GetImagePointerSize()); } else { - ArtMethod* actual_method; - if (methods_class->IsInterface()) { - actual_method = methods_class->FindVirtualMethodForInterfaceSuper( - resolved_method, class_linker->GetImagePointerSize()); - } else { - uint16_t vtable_index = resolved_method->GetMethodIndex(); - actual_method = compiling_class->GetSuperClass()->GetVTableEntry( - vtable_index, class_linker->GetImagePointerSize()); - } - if (actual_method != resolved_method && - !IsSameDexFile(*actual_method->GetDexFile(), *dex_compilation_unit_->GetDexFile())) { - // The back-end code generator relies on this check in order to ensure that it will not - // attempt to read the dex_cache with a dex_method_index that is not from the correct - // dex_file. If we didn't do this check then the dex_method_index will not be updated in the - // builder, which means that the code-generator (and compiler driver during sharpening and - // inliner, maybe) might invoke an incorrect method. - // TODO: The actual method could still be referenced in the current dex file, so we - // could try locating it. - // TODO: Remove the dex_file restriction. - return nullptr; - } - if (!actual_method->IsInvokable()) { - // Fail if the actual method cannot be invoked. Otherwise, the runtime resolution stub - // could resolve the callee to the wrong method. - return nullptr; - } - resolved_method = actual_method; + uint16_t vtable_index = resolved_method->GetMethodIndex(); + actual_method = compiling_class->GetSuperClass()->GetVTableEntry( + vtable_index, class_linker->GetImagePointerSize()); + } + if (actual_method != resolved_method && + !IsSameDexFile(*actual_method->GetDexFile(), *dex_compilation_unit_->GetDexFile())) { + // The back-end code generator relies on this check in order to ensure that it will not + // attempt to read the dex_cache with a dex_method_index that is not from the correct + // dex_file. If we didn't do this check then the dex_method_index will not be updated in the + // builder, which means that the code-generator (and compiler driver during sharpening and + // inliner, maybe) might invoke an incorrect method. + // TODO: The actual method could still be referenced in the current dex file, so we + // could try locating it. + // TODO: Remove the dex_file restriction. + return nullptr; + } + if (!actual_method->IsInvokable()) { + // Fail if the actual method cannot be invoked. Otherwise, the runtime resolution stub + // could resolve the callee to the wrong method. + return nullptr; } + resolved_method = actual_method; } // Check for incompatible class changes. The class linker has a fast path for diff --git a/runtime/base/arena_allocator.cc b/runtime/base/arena_allocator.cc index 5b6801f5c3..b84e29f7ce 100644 --- a/runtime/base/arena_allocator.cc +++ b/runtime/base/arena_allocator.cc @@ -321,24 +321,26 @@ void* ArenaAllocator::AllocWithMemoryTool(size_t bytes, ArenaAllocKind kind) { // and padding between allocations marked as inaccessible. size_t rounded_bytes = RoundUp(bytes + kMemoryToolRedZoneBytes, 8); ArenaAllocatorStats::RecordAlloc(rounded_bytes, kind); + uint8_t* ret; if (UNLIKELY(rounded_bytes > static_cast<size_t>(end_ - ptr_))) { - void* ret = AllocFromNewArena(rounded_bytes); + ret = AllocFromNewArena(rounded_bytes); + uint8_t* noaccess_begin = ret + bytes; + uint8_t* noaccess_end; if (ret == arena_head_->Begin()) { DCHECK(ptr_ - rounded_bytes == ret); - uint8_t* noaccess_begin = ptr_ - rounded_bytes + bytes; - MEMORY_TOOL_MAKE_NOACCESS(noaccess_begin, end_ - noaccess_begin); + noaccess_end = end_; } else { // We're still using the old arena but `ret` comes from a new one just after it. DCHECK(arena_head_->next_ != nullptr); DCHECK(ret == arena_head_->next_->Begin()); DCHECK_EQ(rounded_bytes, arena_head_->next_->GetBytesAllocated()); - uint8_t* noaccess_begin = arena_head_->next_->Begin() + bytes; - MEMORY_TOOL_MAKE_NOACCESS(noaccess_begin, arena_head_->next_->End() - noaccess_begin); + noaccess_end = arena_head_->next_->End(); } - return ret; + MEMORY_TOOL_MAKE_NOACCESS(noaccess_begin, noaccess_end - noaccess_begin); + } else { + ret = ptr_; + ptr_ += rounded_bytes; } - uint8_t* ret = ptr_; - ptr_ += rounded_bytes; MEMORY_TOOL_MAKE_DEFINED(ret, bytes); // Check that the memory is already zeroed out. DCHECK(std::all_of(ret, ret + bytes, [](uint8_t val) { return val == 0u; })); @@ -351,7 +353,7 @@ ArenaAllocator::~ArenaAllocator() { pool_->FreeArenaChain(arena_head_); } -void* ArenaAllocator::AllocFromNewArena(size_t bytes) { +uint8_t* ArenaAllocator::AllocFromNewArena(size_t bytes) { Arena* new_arena = pool_->AllocArena(std::max(Arena::kDefaultSize, bytes)); DCHECK(new_arena != nullptr); DCHECK_LE(bytes, new_arena->Size()); diff --git a/runtime/base/arena_allocator.h b/runtime/base/arena_allocator.h index 4b745f088b..6c1a8984cd 100644 --- a/runtime/base/arena_allocator.h +++ b/runtime/base/arena_allocator.h @@ -364,7 +364,7 @@ class ArenaAllocator private: void* AllocWithMemoryTool(size_t bytes, ArenaAllocKind kind); - void* AllocFromNewArena(size_t bytes); + uint8_t* AllocFromNewArena(size_t bytes); static constexpr size_t kAlignment = 8; diff --git a/runtime/base/arena_allocator_test.cc b/runtime/base/arena_allocator_test.cc index c07c0ed030..9de3cc4312 100644 --- a/runtime/base/arena_allocator_test.cc +++ b/runtime/base/arena_allocator_test.cc @@ -41,6 +41,28 @@ TEST_F(ArenaAllocatorTest, Test) { EXPECT_EQ(2U, bv.GetStorageSize()); } +TEST_F(ArenaAllocatorTest, MakeDefined) { + // Regression test to make sure we mark the allocated area defined. + ArenaPool pool; + static constexpr size_t kSmallArraySize = 10; + static constexpr size_t kLargeArraySize = 50; + uint32_t* small_array; + { + // Allocate a small array from an arena and release it. + ArenaAllocator arena(&pool); + small_array = arena.AllocArray<uint32_t>(kSmallArraySize); + ASSERT_EQ(0u, small_array[kSmallArraySize - 1u]); + } + { + // Reuse the previous arena and allocate more than previous allocation including red zone. + ArenaAllocator arena(&pool); + uint32_t* large_array = arena.AllocArray<uint32_t>(kLargeArraySize); + ASSERT_EQ(0u, large_array[kLargeArraySize - 1u]); + // Verify that the allocation was made on the same arena. + ASSERT_EQ(small_array, large_array); + } +} + TEST_F(ArenaAllocatorTest, LargeAllocations) { { ArenaPool pool; diff --git a/runtime/class_linker-inl.h b/runtime/class_linker-inl.h index 7e8a4a4fcd..f3e260be56 100644 --- a/runtime/class_linker-inl.h +++ b/runtime/class_linker-inl.h @@ -116,9 +116,10 @@ inline ArtMethod* ClassLinker::GetResolvedMethod(uint32_t method_idx, ArtMethod* return resolved_method; } -inline mirror::Class* ClassLinker::ResolveReferencedClassOfMethod(Thread* self, - uint32_t method_idx, - ArtMethod* referrer) { +inline mirror::Class* ClassLinker::ResolveReferencedClassOfMethod( + uint32_t method_idx, + Handle<mirror::DexCache> dex_cache, + Handle<mirror::ClassLoader> class_loader) { // NB: We cannot simply use `GetResolvedMethod(method_idx, ...)->GetDeclaringClass()`. This is // because if we did so than an invoke-super could be incorrectly dispatched in cases where // GetMethodId(method_idx).class_idx_ refers to a non-interface, non-direct-superclass @@ -127,15 +128,11 @@ inline mirror::Class* ClassLinker::ResolveReferencedClassOfMethod(Thread* self, // interface (either miranda, default or conflict) we would incorrectly assume that is what we // want to invoke on, instead of the 'concrete' implementation that the direct superclass // contains. - mirror::Class* declaring_class = referrer->GetDeclaringClass(); - StackHandleScope<2> hs(self); - Handle<mirror::DexCache> h_dex_cache(hs.NewHandle(declaring_class->GetDexCache())); - const DexFile* dex_file = h_dex_cache->GetDexFile(); + const DexFile* dex_file = dex_cache->GetDexFile(); const DexFile::MethodId& method = dex_file->GetMethodId(method_idx); - mirror::Class* resolved_type = h_dex_cache->GetResolvedType(method.class_idx_); + mirror::Class* resolved_type = dex_cache->GetResolvedType(method.class_idx_); if (UNLIKELY(resolved_type == nullptr)) { - Handle<mirror::ClassLoader> class_loader(hs.NewHandle(declaring_class->GetClassLoader())); - resolved_type = ResolveType(*dex_file, method.class_idx_, h_dex_cache, class_loader); + resolved_type = ResolveType(*dex_file, method.class_idx_, dex_cache, class_loader); } return resolved_type; } diff --git a/runtime/class_linker.h b/runtime/class_linker.h index 5de502b540..97a10367fe 100644 --- a/runtime/class_linker.h +++ b/runtime/class_linker.h @@ -310,9 +310,9 @@ class ClassLinker { // This returns the class referred to by GetMethodId(method_idx).class_idx_. This might be // different then the declaring class of the resolved method due to copied // miranda/default/conflict methods. - mirror::Class* ResolveReferencedClassOfMethod(Thread* self, - uint32_t method_idx, - ArtMethod* referrer) + mirror::Class* ResolveReferencedClassOfMethod(uint32_t method_idx, + Handle<mirror::DexCache> dex_cache, + Handle<mirror::ClassLoader> class_loader) SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!dex_lock_, !Roles::uninterruptible_); template <ResolveMode kResolveMode> diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc index f3e8dbadbe..da6af724ac 100644 --- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc @@ -1038,9 +1038,14 @@ extern "C" const void* artQuickResolutionTrampoline( } else { DCHECK_EQ(invoke_type, kSuper); CHECK(caller != nullptr) << invoke_type; + StackHandleScope<2> hs(self); + Handle<mirror::DexCache> dex_cache( + hs.NewHandle(caller->GetDeclaringClass()->GetDexCache())); + Handle<mirror::ClassLoader> class_loader( + hs.NewHandle(caller->GetDeclaringClass()->GetClassLoader())); // TODO Maybe put this into a mirror::Class function. mirror::Class* ref_class = linker->ResolveReferencedClassOfMethod( - self, called_method.dex_method_index, caller); + called_method.dex_method_index, dex_cache, class_loader); if (ref_class->IsInterface()) { called = ref_class->FindVirtualMethodForInterfaceSuper(called, sizeof(void*)); } else { diff --git a/runtime/jit/offline_profiling_info.cc b/runtime/jit/offline_profiling_info.cc index a79bcf05ae..a3078bc1ba 100644 --- a/runtime/jit/offline_profiling_info.cc +++ b/runtime/jit/offline_profiling_info.cc @@ -406,7 +406,8 @@ ProfileCompilationInfo::ProfileLoadSatus ProfileCompilationInfo::ReadProfileLine line_header->checksum = header_buffer.ReadUintAndAdvance<uint32_t>(); if (dex_location_size == 0 || dex_location_size > kMaxDexFileKeyLength) { - *error = "DexFileKey has an invalid size: " + std::to_string(dex_location_size); + *error = "DexFileKey has an invalid size: " + + std::to_string(static_cast<uint32_t>(dex_location_size)); return kProfileLoadBadData; } |