diff options
102 files changed, 1375 insertions, 1671 deletions
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk index f67da3ff4c..8309bd854f 100644 --- a/build/Android.gtest.mk +++ b/build/Android.gtest.mk @@ -195,7 +195,6 @@ RUNTIME_GTEST_COMMON_SRC_FILES := \ runtime/entrypoints/math_entrypoints_test.cc \ runtime/entrypoints/quick/quick_trampoline_entrypoints_test.cc \ runtime/entrypoints_order_test.cc \ - runtime/exception_test.cc \ runtime/gc/accounting/card_table_test.cc \ runtime/gc/accounting/mod_union_table_test.cc \ runtime/gc/accounting/space_bitmap_test.cc \ @@ -251,6 +250,7 @@ COMPILER_GTEST_COMMON_SRC_FILES := \ compiler/driver/compiled_method_storage_test.cc \ compiler/driver/compiler_driver_test.cc \ compiler/elf_writer_test.cc \ + compiler/exception_test.cc \ compiler/image_test.cc \ compiler/jni/jni_compiler_test.cc \ compiler/linker/multi_oat_relative_patcher_test.cc \ diff --git a/compiler/common_compiler_test.cc b/compiler/common_compiler_test.cc index 6483ef63b1..f75a252df2 100644 --- a/compiler/common_compiler_test.cc +++ b/compiler/common_compiler_test.cc @@ -59,36 +59,20 @@ void CommonCompilerTest::MakeExecutable(ArtMethod* method) { ArrayRef<const uint8_t> vmap_table = compiled_method->GetVmapTable(); uint32_t vmap_table_offset = vmap_table.empty() ? 0u : sizeof(OatQuickMethodHeader) + vmap_table.size(); - ArrayRef<const uint8_t> mapping_table = compiled_method->GetMappingTable(); - bool mapping_table_used = !mapping_table.empty(); - size_t mapping_table_size = mapping_table.size(); - uint32_t mapping_table_offset = !mapping_table_used ? 0u - : sizeof(OatQuickMethodHeader) + vmap_table.size() + mapping_table_size; - ArrayRef<const uint8_t> gc_map = compiled_method->GetGcMap(); - bool gc_map_used = !gc_map.empty(); - size_t gc_map_size = gc_map.size(); - uint32_t gc_map_offset = !gc_map_used ? 0u - : sizeof(OatQuickMethodHeader) + vmap_table.size() + mapping_table_size + gc_map_size; - OatQuickMethodHeader method_header(mapping_table_offset, vmap_table_offset, gc_map_offset, + OatQuickMethodHeader method_header(vmap_table_offset, compiled_method->GetFrameSizeInBytes(), compiled_method->GetCoreSpillMask(), - compiled_method->GetFpSpillMask(), code_size); + compiled_method->GetFpSpillMask(), + code_size); header_code_and_maps_chunks_.push_back(std::vector<uint8_t>()); std::vector<uint8_t>* chunk = &header_code_and_maps_chunks_.back(); const size_t max_padding = GetInstructionSetAlignment(compiled_method->GetInstructionSet()); - const size_t size = - gc_map_size + mapping_table_size + vmap_table.size() + sizeof(method_header) + code_size; + const size_t size = vmap_table.size() + sizeof(method_header) + code_size; chunk->reserve(size + max_padding); chunk->resize(sizeof(method_header)); memcpy(&(*chunk)[0], &method_header, sizeof(method_header)); chunk->insert(chunk->begin(), vmap_table.begin(), vmap_table.end()); - if (mapping_table_used) { - chunk->insert(chunk->begin(), mapping_table.begin(), mapping_table.end()); - } - if (gc_map_used) { - chunk->insert(chunk->begin(), gc_map.begin(), gc_map.end()); - } chunk->insert(chunk->end(), code.begin(), code.end()); CHECK_EQ(chunk->size(), size); const void* unaligned_code_ptr = chunk->data() + (size - code_size); @@ -301,7 +285,7 @@ void CommonCompilerTest::ReserveImageSpace() { MemMap::Init(); image_reservation_.reset(MemMap::MapAnonymous("image reservation", reinterpret_cast<uint8_t*>(ART_BASE_ADDRESS), - (size_t)100 * 1024 * 1024, // 100MB + (size_t)120 * 1024 * 1024, // 120MB PROT_NONE, false /* no need for 4gb flag with fixed mmap*/, false /* not reusing existing reservation */, diff --git a/compiler/common_compiler_test.h b/compiler/common_compiler_test.h index 7c2c844e6f..2d139eb841 100644 --- a/compiler/common_compiler_test.h +++ b/compiler/common_compiler_test.h @@ -115,13 +115,6 @@ class CommonCompilerTest : public CommonRuntimeTest { std::list<std::vector<uint8_t>> header_code_and_maps_chunks_; }; -// TODO: When heap reference poisoning works with all compilers in use, get rid of this. -#define TEST_DISABLED_FOR_HEAP_REFERENCE_POISONING_WITH_QUICK() \ - if (kPoisonHeapReferences && GetCompilerKind() == Compiler::kQuick) { \ - printf("WARNING: TEST DISABLED FOR HEAP REFERENCE POISONING WITH QUICK\n"); \ - return; \ - } - // TODO: When read barrier works with all tests, get rid of this. #define TEST_DISABLED_FOR_READ_BARRIER() \ if (kUseReadBarrier) { \ @@ -129,13 +122,6 @@ class CommonCompilerTest : public CommonRuntimeTest { return; \ } -// TODO: When read barrier works with all compilers in use, get rid of this. -#define TEST_DISABLED_FOR_READ_BARRIER_WITH_QUICK() \ - if (kUseReadBarrier && GetCompilerKind() == Compiler::kQuick) { \ - printf("WARNING: TEST DISABLED FOR READ BARRIER WITH QUICK\n"); \ - return; \ - } - // TODO: When read barrier works with all Optimizing back ends, get rid of this. #define TEST_DISABLED_FOR_READ_BARRIER_WITH_OPTIMIZING_FOR_UNSUPPORTED_INSTRUCTION_SETS() \ if (kUseReadBarrier && GetCompilerKind() == Compiler::kOptimizing) { \ @@ -155,13 +141,6 @@ class CommonCompilerTest : public CommonRuntimeTest { } \ } -// TODO: When non-PIC works with all compilers in use, get rid of this. -#define TEST_DISABLED_FOR_NON_PIC_COMPILING_WITH_OPTIMIZING() \ - if (GetCompilerKind() == Compiler::kOptimizing) { \ - printf("WARNING: TEST DISABLED FOR NON-PIC COMPILING WITH OPTIMIZING\n"); \ - return; \ - } - } // namespace art #endif // ART_COMPILER_COMMON_COMPILER_TEST_H_ diff --git a/compiler/compiled_method.cc b/compiler/compiled_method.cc index 9551d2298b..f06d90c81c 100644 --- a/compiler/compiled_method.cc +++ b/compiler/compiled_method.cc @@ -106,9 +106,7 @@ CompiledMethod::CompiledMethod(CompilerDriver* driver, const uint32_t core_spill_mask, const uint32_t fp_spill_mask, const ArrayRef<const SrcMapElem>& src_mapping_table, - const ArrayRef<const uint8_t>& mapping_table, const ArrayRef<const uint8_t>& vmap_table, - const ArrayRef<const uint8_t>& native_gc_map, const ArrayRef<const uint8_t>& cfi_info, const ArrayRef<const LinkerPatch>& patches) : CompiledCode(driver, instruction_set, quick_code), @@ -116,9 +114,7 @@ CompiledMethod::CompiledMethod(CompilerDriver* driver, fp_spill_mask_(fp_spill_mask), src_mapping_table_( driver->GetCompiledMethodStorage()->DeduplicateSrcMappingTable(src_mapping_table)), - mapping_table_(driver->GetCompiledMethodStorage()->DeduplicateMappingTable(mapping_table)), vmap_table_(driver->GetCompiledMethodStorage()->DeduplicateVMapTable(vmap_table)), - gc_map_(driver->GetCompiledMethodStorage()->DeduplicateGCMap(native_gc_map)), cfi_info_(driver->GetCompiledMethodStorage()->DeduplicateCFIInfo(cfi_info)), patches_(driver->GetCompiledMethodStorage()->DeduplicateLinkerPatches(patches)) { } @@ -131,15 +127,20 @@ CompiledMethod* CompiledMethod::SwapAllocCompiledMethod( const uint32_t core_spill_mask, const uint32_t fp_spill_mask, const ArrayRef<const SrcMapElem>& src_mapping_table, - const ArrayRef<const uint8_t>& mapping_table, const ArrayRef<const uint8_t>& vmap_table, - const ArrayRef<const uint8_t>& native_gc_map, const ArrayRef<const uint8_t>& cfi_info, const ArrayRef<const LinkerPatch>& patches) { SwapAllocator<CompiledMethod> alloc(driver->GetCompiledMethodStorage()->GetSwapSpaceAllocator()); CompiledMethod* ret = alloc.allocate(1); - alloc.construct(ret, driver, instruction_set, quick_code, frame_size_in_bytes, core_spill_mask, - fp_spill_mask, src_mapping_table, mapping_table, vmap_table, native_gc_map, + alloc.construct(ret, + driver, + instruction_set, + quick_code, + frame_size_in_bytes, + core_spill_mask, + fp_spill_mask, + src_mapping_table, + vmap_table, cfi_info, patches); return ret; } @@ -154,9 +155,7 @@ CompiledMethod::~CompiledMethod() { CompiledMethodStorage* storage = GetCompilerDriver()->GetCompiledMethodStorage(); storage->ReleaseLinkerPatches(patches_); storage->ReleaseCFIInfo(cfi_info_); - storage->ReleaseGCMap(gc_map_); storage->ReleaseVMapTable(vmap_table_); - storage->ReleaseMappingTable(mapping_table_); storage->ReleaseSrcMappingTable(src_mapping_table_); } diff --git a/compiler/compiled_method.h b/compiler/compiled_method.h index 70161eb221..9479ff38be 100644 --- a/compiler/compiled_method.h +++ b/compiler/compiled_method.h @@ -377,9 +377,7 @@ class CompiledMethod FINAL : public CompiledCode { const uint32_t core_spill_mask, const uint32_t fp_spill_mask, const ArrayRef<const SrcMapElem>& src_mapping_table, - const ArrayRef<const uint8_t>& mapping_table, const ArrayRef<const uint8_t>& vmap_table, - const ArrayRef<const uint8_t>& native_gc_map, const ArrayRef<const uint8_t>& cfi_info, const ArrayRef<const LinkerPatch>& patches); @@ -393,9 +391,7 @@ class CompiledMethod FINAL : public CompiledCode { const uint32_t core_spill_mask, const uint32_t fp_spill_mask, const ArrayRef<const SrcMapElem>& src_mapping_table, - const ArrayRef<const uint8_t>& mapping_table, const ArrayRef<const uint8_t>& vmap_table, - const ArrayRef<const uint8_t>& native_gc_map, const ArrayRef<const uint8_t>& cfi_info, const ArrayRef<const LinkerPatch>& patches); @@ -417,18 +413,10 @@ class CompiledMethod FINAL : public CompiledCode { return GetArray(src_mapping_table_); } - ArrayRef<const uint8_t> GetMappingTable() const { - return GetArray(mapping_table_); - } - ArrayRef<const uint8_t> GetVmapTable() const { return GetArray(vmap_table_); } - ArrayRef<const uint8_t> GetGcMap() const { - return GetArray(gc_map_); - } - ArrayRef<const uint8_t> GetCFIInfo() const { return GetArray(cfi_info_); } @@ -446,14 +434,8 @@ class CompiledMethod FINAL : public CompiledCode { const uint32_t fp_spill_mask_; // For quick code, a set of pairs (PC, DEX) mapping from native PC offset to DEX offset. const LengthPrefixedArray<SrcMapElem>* const src_mapping_table_; - // For quick code, a uleb128 encoded map from native PC offset to dex PC aswell as dex PC to - // native PC offset. Size prefixed. - const LengthPrefixedArray<uint8_t>* const mapping_table_; // For quick code, a uleb128 encoded map from GPR/FPR register to dex register. Size prefixed. const LengthPrefixedArray<uint8_t>* const vmap_table_; - // For quick code, a map keyed by native PC indices to bitmaps describing what dalvik registers - // are live. - const LengthPrefixedArray<uint8_t>* const gc_map_; // For quick code, a FDE entry for the debug_frame section. const LengthPrefixedArray<uint8_t>* const cfi_info_; // For quick code, linker patches needed by the method. diff --git a/compiler/dex/dex_to_dex_compiler.cc b/compiler/dex/dex_to_dex_compiler.cc index efddeba6a9..3ce786e008 100644 --- a/compiler/dex/dex_to_dex_compiler.cc +++ b/compiler/dex/dex_to_dex_compiler.cc @@ -363,9 +363,7 @@ CompiledMethod* ArtCompileDEX( 0, 0, ArrayRef<const SrcMapElem>(), // src_mapping_table - ArrayRef<const uint8_t>(), // mapping_table ArrayRef<const uint8_t>(builder.GetData()), // vmap_table - ArrayRef<const uint8_t>(), // gc_map ArrayRef<const uint8_t>(), // cfi data ArrayRef<const LinkerPatch>()); } diff --git a/compiler/driver/compiled_method_storage.cc b/compiler/driver/compiled_method_storage.cc index 510613ecf4..a0a8f81c1f 100644 --- a/compiler/driver/compiled_method_storage.cc +++ b/compiler/driver/compiled_method_storage.cc @@ -174,11 +174,8 @@ CompiledMethodStorage::CompiledMethodStorage(int swap_fd) dedupe_code_("dedupe code", LengthPrefixedArrayAlloc<uint8_t>(swap_space_.get())), dedupe_src_mapping_table_("dedupe source mapping table", LengthPrefixedArrayAlloc<SrcMapElem>(swap_space_.get())), - dedupe_mapping_table_("dedupe mapping table", - LengthPrefixedArrayAlloc<uint8_t>(swap_space_.get())), dedupe_vmap_table_("dedupe vmap table", LengthPrefixedArrayAlloc<uint8_t>(swap_space_.get())), - dedupe_gc_map_("dedupe gc map", LengthPrefixedArrayAlloc<uint8_t>(swap_space_.get())), dedupe_cfi_info_("dedupe cfi info", LengthPrefixedArrayAlloc<uint8_t>(swap_space_.get())), dedupe_linker_patches_("dedupe cfi info", LengthPrefixedArrayAlloc<LinkerPatch>(swap_space_.get())) { @@ -196,9 +193,7 @@ void CompiledMethodStorage::DumpMemoryUsage(std::ostream& os, bool extended) con if (extended) { Thread* self = Thread::Current(); os << "\nCode dedupe: " << dedupe_code_.DumpStats(self); - os << "\nMapping table dedupe: " << dedupe_mapping_table_.DumpStats(self); os << "\nVmap table dedupe: " << dedupe_vmap_table_.DumpStats(self); - os << "\nGC map dedupe: " << dedupe_gc_map_.DumpStats(self); os << "\nCFI info dedupe: " << dedupe_cfi_info_.DumpStats(self); } } @@ -221,15 +216,6 @@ void CompiledMethodStorage::ReleaseSrcMappingTable(const LengthPrefixedArray<Src ReleaseArrayIfNotDeduplicated(src_map); } -const LengthPrefixedArray<uint8_t>* CompiledMethodStorage::DeduplicateMappingTable( - const ArrayRef<const uint8_t>& table) { - return AllocateOrDeduplicateArray(table, &dedupe_mapping_table_); -} - -void CompiledMethodStorage::ReleaseMappingTable(const LengthPrefixedArray<uint8_t>* table) { - ReleaseArrayIfNotDeduplicated(table); -} - const LengthPrefixedArray<uint8_t>* CompiledMethodStorage::DeduplicateVMapTable( const ArrayRef<const uint8_t>& table) { return AllocateOrDeduplicateArray(table, &dedupe_vmap_table_); @@ -239,15 +225,6 @@ void CompiledMethodStorage::ReleaseVMapTable(const LengthPrefixedArray<uint8_t>* ReleaseArrayIfNotDeduplicated(table); } -const LengthPrefixedArray<uint8_t>* CompiledMethodStorage::DeduplicateGCMap( - const ArrayRef<const uint8_t>& gc_map) { - return AllocateOrDeduplicateArray(gc_map, &dedupe_gc_map_); -} - -void CompiledMethodStorage::ReleaseGCMap(const LengthPrefixedArray<uint8_t>* gc_map) { - ReleaseArrayIfNotDeduplicated(gc_map); -} - const LengthPrefixedArray<uint8_t>* CompiledMethodStorage::DeduplicateCFIInfo( const ArrayRef<const uint8_t>& cfi_info) { return AllocateOrDeduplicateArray(cfi_info, &dedupe_cfi_info_); diff --git a/compiler/driver/compiled_method_storage.h b/compiler/driver/compiled_method_storage.h index d6961a0876..8674abf815 100644 --- a/compiler/driver/compiled_method_storage.h +++ b/compiler/driver/compiled_method_storage.h @@ -56,15 +56,9 @@ class CompiledMethodStorage { const ArrayRef<const SrcMapElem>& src_map); void ReleaseSrcMappingTable(const LengthPrefixedArray<SrcMapElem>* src_map); - const LengthPrefixedArray<uint8_t>* DeduplicateMappingTable(const ArrayRef<const uint8_t>& table); - void ReleaseMappingTable(const LengthPrefixedArray<uint8_t>* table); - const LengthPrefixedArray<uint8_t>* DeduplicateVMapTable(const ArrayRef<const uint8_t>& table); void ReleaseVMapTable(const LengthPrefixedArray<uint8_t>* table); - const LengthPrefixedArray<uint8_t>* DeduplicateGCMap(const ArrayRef<const uint8_t>& gc_map); - void ReleaseGCMap(const LengthPrefixedArray<uint8_t>* gc_map); - const LengthPrefixedArray<uint8_t>* DeduplicateCFIInfo(const ArrayRef<const uint8_t>& cfi_info); void ReleaseCFIInfo(const LengthPrefixedArray<uint8_t>* cfi_info); @@ -103,9 +97,7 @@ class CompiledMethodStorage { ArrayDedupeSet<uint8_t> dedupe_code_; ArrayDedupeSet<SrcMapElem> dedupe_src_mapping_table_; - ArrayDedupeSet<uint8_t> dedupe_mapping_table_; ArrayDedupeSet<uint8_t> dedupe_vmap_table_; - ArrayDedupeSet<uint8_t> dedupe_gc_map_; ArrayDedupeSet<uint8_t> dedupe_cfi_info_; ArrayDedupeSet<LinkerPatch> dedupe_linker_patches_; diff --git a/compiler/driver/compiled_method_storage_test.cc b/compiler/driver/compiled_method_storage_test.cc index 0695cb56b3..9e0c22c68c 100644 --- a/compiler/driver/compiled_method_storage_test.cc +++ b/compiler/driver/compiled_method_storage_test.cc @@ -61,24 +61,12 @@ TEST(CompiledMethodStorage, Deduplicate) { ArrayRef<const SrcMapElem>(raw_src_map1), ArrayRef<const SrcMapElem>(raw_src_map2), }; - const uint8_t raw_mapping_table1[] = { 5, 6, 7 }; - const uint8_t raw_mapping_table2[] = { 7, 6, 5, 4 }; - ArrayRef<const uint8_t> mapping_table[] = { - ArrayRef<const uint8_t>(raw_mapping_table1), - ArrayRef<const uint8_t>(raw_mapping_table2), - }; const uint8_t raw_vmap_table1[] = { 2, 4, 6 }; const uint8_t raw_vmap_table2[] = { 7, 5, 3, 1 }; ArrayRef<const uint8_t> vmap_table[] = { ArrayRef<const uint8_t>(raw_vmap_table1), ArrayRef<const uint8_t>(raw_vmap_table2), }; - const uint8_t raw_gc_map1[] = { 9, 8, 7 }; - const uint8_t raw_gc_map2[] = { 6, 7, 8, 9 }; - ArrayRef<const uint8_t> gc_map[] = { - ArrayRef<const uint8_t>(raw_gc_map1), - ArrayRef<const uint8_t>(raw_gc_map2), - }; const uint8_t raw_cfi_info1[] = { 1, 3, 5 }; const uint8_t raw_cfi_info2[] = { 8, 6, 4, 2 }; ArrayRef<const uint8_t> cfi_info[] = { @@ -102,49 +90,37 @@ TEST(CompiledMethodStorage, Deduplicate) { compiled_methods.reserve(1u << 7); for (auto&& c : code) { for (auto&& s : src_map) { - for (auto&& m : mapping_table) { - for (auto&& v : vmap_table) { - for (auto&& g : gc_map) { - for (auto&& f : cfi_info) { - for (auto&& p : patches) { - compiled_methods.push_back(CompiledMethod::SwapAllocCompiledMethod( - &driver, kNone, c, 0u, 0u, 0u, s, m, v, g, f, p)); - } - } + for (auto&& v : vmap_table) { + for (auto&& f : cfi_info) { + for (auto&& p : patches) { + compiled_methods.push_back(CompiledMethod::SwapAllocCompiledMethod( + &driver, kNone, c, 0u, 0u, 0u, s, v, f, p)); } } } } } - constexpr size_t code_bit = 1u << 6; - constexpr size_t src_map_bit = 1u << 5; - constexpr size_t mapping_table_bit = 1u << 4; - constexpr size_t vmap_table_bit = 1u << 3; - constexpr size_t gc_map_bit = 1u << 2; + constexpr size_t code_bit = 1u << 4; + constexpr size_t src_map_bit = 1u << 3; + constexpr size_t vmap_table_bit = 1u << 2; constexpr size_t cfi_info_bit = 1u << 1; constexpr size_t patches_bit = 1u << 0; - CHECK_EQ(compiled_methods.size(), 1u << 7); + CHECK_EQ(compiled_methods.size(), 1u << 5); for (size_t i = 0; i != compiled_methods.size(); ++i) { for (size_t j = 0; j != compiled_methods.size(); ++j) { CompiledMethod* lhs = compiled_methods[i]; CompiledMethod* rhs = compiled_methods[j]; bool same_code = ((i ^ j) & code_bit) == 0u; bool same_src_map = ((i ^ j) & src_map_bit) == 0u; - bool same_mapping_table = ((i ^ j) & mapping_table_bit) == 0u; bool same_vmap_table = ((i ^ j) & vmap_table_bit) == 0u; - bool same_gc_map = ((i ^ j) & gc_map_bit) == 0u; bool same_cfi_info = ((i ^ j) & cfi_info_bit) == 0u; bool same_patches = ((i ^ j) & patches_bit) == 0u; ASSERT_EQ(same_code, lhs->GetQuickCode().data() == rhs->GetQuickCode().data()) << i << " " << j; ASSERT_EQ(same_src_map, lhs->GetSrcMappingTable().data() == rhs->GetSrcMappingTable().data()) << i << " " << j; - ASSERT_EQ(same_mapping_table, lhs->GetMappingTable().data() == rhs->GetMappingTable().data()) - << i << " " << j; ASSERT_EQ(same_vmap_table, lhs->GetVmapTable().data() == rhs->GetVmapTable().data()) << i << " " << j; - ASSERT_EQ(same_gc_map, lhs->GetGcMap().data() == rhs->GetGcMap().data()) - << i << " " << j; ASSERT_EQ(same_cfi_info, lhs->GetCFIInfo().data() == rhs->GetCFIInfo().data()) << i << " " << j; ASSERT_EQ(same_patches, lhs->GetPatches().data() == rhs->GetPatches().data()) diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index d29d528c27..52940687de 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -357,7 +357,7 @@ CompilerDriver::CompilerDriver( compiler_kind_(compiler_kind), instruction_set_(instruction_set), instruction_set_features_(instruction_set_features), - freezing_constructor_lock_("freezing constructor lock"), + requires_constructor_barrier_lock_("constructor barrier lock"), compiled_classes_lock_("compiled classes lock"), compiled_methods_lock_("compiled method lock"), compiled_methods_(MethodTable::key_compare()), @@ -2006,6 +2006,28 @@ static void CheckAndClearResolveException(Thread* self) self->ClearException(); } +bool CompilerDriver::RequiresConstructorBarrier(const DexFile& dex_file, + uint16_t class_def_idx) const { + const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_idx); + const uint8_t* class_data = dex_file.GetClassData(class_def); + if (class_data == nullptr) { + // Empty class such as a marker interface. + return false; + } + ClassDataItemIterator it(dex_file, class_data); + while (it.HasNextStaticField()) { + it.Next(); + } + // We require a constructor barrier if there are final instance fields. + while (it.HasNextInstanceField()) { + if (it.MemberIsFinal()) { + return true; + } + it.Next(); + } + return false; +} + class ResolveClassFieldsAndMethodsVisitor : public CompilationVisitor { public: explicit ResolveClassFieldsAndMethodsVisitor(const ParallelCompilationManager* manager) @@ -2110,9 +2132,10 @@ class ResolveClassFieldsAndMethodsVisitor : public CompilationVisitor { DCHECK(!it.HasNext()); } } - if (requires_constructor_barrier) { - manager_->GetCompiler()->AddRequiresConstructorBarrier(self, &dex_file, class_def_index); - } + manager_->GetCompiler()->SetRequiresConstructorBarrier(self, + &dex_file, + class_def_index, + requires_constructor_barrier); } private: @@ -2486,6 +2509,20 @@ void CompilerDriver::InitializeClasses(jobject jni_class_loader, context.ForAll(0, dex_file.NumClassDefs(), &visitor, init_thread_count); } +class InitializeArrayClassVisitor : public ClassVisitor { + public: + virtual bool operator()(mirror::Class* klass) OVERRIDE SHARED_REQUIRES(Locks::mutator_lock_) { + if (klass->IsArrayClass()) { + StackHandleScope<1> hs(Thread::Current()); + Runtime::Current()->GetClassLinker()->EnsureInitialized(hs.Self(), + hs.NewHandle(klass), + true, + true); + } + return true; + } +}; + void CompilerDriver::InitializeClasses(jobject class_loader, const std::vector<const DexFile*>& dex_files, TimingLogger* timings) { @@ -2494,6 +2531,14 @@ void CompilerDriver::InitializeClasses(jobject class_loader, CHECK(dex_file != nullptr); InitializeClasses(class_loader, *dex_file, dex_files, timings); } + { + // Make sure that we call EnsureIntiailized on all the array classes to call + // SetVerificationAttempted so that the access flags are set. If we do not do this they get + // changed at runtime resulting in more dirty image pages. + ScopedObjectAccess soa(Thread::Current()); + InitializeArrayClassVisitor visitor; + Runtime::Current()->GetClassLinker()->VisitClasses(&visitor); + } if (IsBootImage()) { // Prune garbage objects created during aborted transactions. Runtime::Current()->GetHeap()->CollectGarbage(true); @@ -2747,16 +2792,29 @@ size_t CompilerDriver::GetNonRelativeLinkerPatchCount() const { return non_relative_linker_patch_count_; } -void CompilerDriver::AddRequiresConstructorBarrier(Thread* self, const DexFile* dex_file, - uint16_t class_def_index) { - WriterMutexLock mu(self, freezing_constructor_lock_); - freezing_constructor_classes_.insert(ClassReference(dex_file, class_def_index)); +void CompilerDriver::SetRequiresConstructorBarrier(Thread* self, + const DexFile* dex_file, + uint16_t class_def_index, + bool requires) { + WriterMutexLock mu(self, requires_constructor_barrier_lock_); + requires_constructor_barrier_.emplace(ClassReference(dex_file, class_def_index), requires); } -bool CompilerDriver::RequiresConstructorBarrier(Thread* self, const DexFile* dex_file, - uint16_t class_def_index) const { - ReaderMutexLock mu(self, freezing_constructor_lock_); - return freezing_constructor_classes_.count(ClassReference(dex_file, class_def_index)) != 0; +bool CompilerDriver::RequiresConstructorBarrier(Thread* self, + const DexFile* dex_file, + uint16_t class_def_index) { + ClassReference class_ref(dex_file, class_def_index); + { + ReaderMutexLock mu(self, requires_constructor_barrier_lock_); + auto it = requires_constructor_barrier_.find(class_ref); + if (it != requires_constructor_barrier_.end()) { + return it->second; + } + } + WriterMutexLock mu(self, requires_constructor_barrier_lock_); + const bool requires = RequiresConstructorBarrier(*dex_file, class_def_index); + requires_constructor_barrier_.emplace(class_ref, requires); + return requires; } std::string CompilerDriver::GetMemoryUsageString(bool extended) const { diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h index 64a06a2f83..905f84dd45 100644 --- a/compiler/driver/compiler_driver.h +++ b/compiler/driver/compiler_driver.h @@ -183,12 +183,15 @@ class CompilerDriver { // Remove and delete a compiled method. void RemoveCompiledMethod(const MethodReference& method_ref) REQUIRES(!compiled_methods_lock_); - void AddRequiresConstructorBarrier(Thread* self, const DexFile* dex_file, - uint16_t class_def_index) - REQUIRES(!freezing_constructor_lock_); - bool RequiresConstructorBarrier(Thread* self, const DexFile* dex_file, - uint16_t class_def_index) const - REQUIRES(!freezing_constructor_lock_); + void SetRequiresConstructorBarrier(Thread* self, + const DexFile* dex_file, + uint16_t class_def_index, + bool requires) + REQUIRES(!requires_constructor_barrier_lock_); + bool RequiresConstructorBarrier(Thread* self, + const DexFile* dex_file, + uint16_t class_def_index) + REQUIRES(!requires_constructor_barrier_lock_); // Callbacks from compiler to see what runtime checks must be generated. @@ -619,6 +622,8 @@ class CompilerDriver { void FreeThreadPools(); void CheckThreadPools(); + bool RequiresConstructorBarrier(const DexFile& dex_file, uint16_t class_def_idx) const; + const CompilerOptions* const compiler_options_; VerificationResults* const verification_results_; DexFileToMethodInlinerMap* const method_inliner_map_; @@ -629,9 +634,11 @@ class CompilerDriver { const InstructionSet instruction_set_; const InstructionSetFeatures* const instruction_set_features_; - // All class references that require - mutable ReaderWriterMutex freezing_constructor_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER; - std::set<ClassReference> freezing_constructor_classes_ GUARDED_BY(freezing_constructor_lock_); + // All class references that require constructor barriers. If the class reference is not in the + // set then the result has not yet been computed. + mutable ReaderWriterMutex requires_constructor_barrier_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER; + std::map<ClassReference, bool> requires_constructor_barrier_ + GUARDED_BY(requires_constructor_barrier_lock_); typedef SafeMap<const ClassReference, CompiledClass*> ClassTable; // All class references that this compiler has compiled. diff --git a/compiler/driver/compiler_driver_test.cc b/compiler/driver/compiler_driver_test.cc index 00375641f3..b9a5a781da 100644 --- a/compiler/driver/compiler_driver_test.cc +++ b/compiler/driver/compiler_driver_test.cc @@ -143,21 +143,11 @@ TEST_F(CompilerDriverTest, DISABLED_LARGE_CompileDexLibCore) { // TODO: check that all Method::GetCode() values are non-null } -TEST_F(CompilerDriverTest, DISABLED_AbstractMethodErrorStub) { - TEST_DISABLED_FOR_HEAP_REFERENCE_POISONING_WITH_QUICK(); - TEST_DISABLED_FOR_READ_BARRIER_WITH_QUICK(); +TEST_F(CompilerDriverTest, AbstractMethodErrorStub) { TEST_DISABLED_FOR_READ_BARRIER_WITH_OPTIMIZING_FOR_UNSUPPORTED_INSTRUCTION_SETS(); jobject class_loader; { ScopedObjectAccess soa(Thread::Current()); - CompileVirtualMethod(ScopedNullHandle<mirror::ClassLoader>(), - "java.lang.Class", - "isFinalizable", - "()Z"); - CompileDirectMethod(ScopedNullHandle<mirror::ClassLoader>(), - "java.lang.Object", - "<init>", - "()V"); class_loader = LoadDex("AbstractMethod"); } ASSERT_TRUE(class_loader != nullptr); @@ -197,8 +187,6 @@ class CompilerDriverMethodsTest : public CompilerDriverTest { }; TEST_F(CompilerDriverMethodsTest, Selection) { - TEST_DISABLED_FOR_HEAP_REFERENCE_POISONING_WITH_QUICK(); - TEST_DISABLED_FOR_READ_BARRIER_WITH_QUICK(); TEST_DISABLED_FOR_READ_BARRIER_WITH_OPTIMIZING_FOR_UNSUPPORTED_INSTRUCTION_SETS(); Thread* self = Thread::Current(); jobject class_loader; @@ -303,8 +291,6 @@ class CompilerDriverProfileTest : public CompilerDriverTest { }; TEST_F(CompilerDriverProfileTest, ProfileGuidedCompilation) { - TEST_DISABLED_FOR_HEAP_REFERENCE_POISONING_WITH_QUICK(); - TEST_DISABLED_FOR_READ_BARRIER_WITH_QUICK(); TEST_DISABLED_FOR_READ_BARRIER_WITH_OPTIMIZING_FOR_UNSUPPORTED_INSTRUCTION_SETS(); Thread* self = Thread::Current(); jobject class_loader; diff --git a/runtime/exception_test.cc b/compiler/exception_test.cc index 18ccd082ec..38ac052830 100644 --- a/runtime/exception_test.cc +++ b/compiler/exception_test.cc @@ -16,6 +16,7 @@ #include <memory> +#include "base/arena_allocator.h" #include "class_linker.h" #include "common_runtime_test.h" #include "dex_file.h" @@ -27,11 +28,11 @@ #include "mirror/object-inl.h" #include "mirror/stack_trace_element.h" #include "oat_quick_method_header.h" +#include "optimizing/stack_map_stream.h" #include "runtime.h" #include "scoped_thread_state_change.h" #include "handle_scope-inl.h" #include "thread.h" -#include "vmap_table.h" namespace art { @@ -57,40 +58,27 @@ class ExceptionTest : public CommonRuntimeTest { fake_code_.push_back(0x70 | i); } - fake_mapping_data_.PushBackUnsigned(4); // first element is count - fake_mapping_data_.PushBackUnsigned(4); // total (non-length) elements - fake_mapping_data_.PushBackUnsigned(2); // count of pc to dex elements - // --- pc to dex table - fake_mapping_data_.PushBackUnsigned(3 - 0); // offset 3 - fake_mapping_data_.PushBackSigned(3 - 0); // maps to dex offset 3 - // --- dex to pc table - fake_mapping_data_.PushBackUnsigned(3 - 0); // offset 3 - fake_mapping_data_.PushBackSigned(3 - 0); // maps to dex offset 3 - - fake_vmap_table_data_.PushBackUnsigned(0 + VmapTable::kEntryAdjustment); - - fake_gc_map_.push_back(0); // 0 bytes to encode references and native pc offsets. - fake_gc_map_.push_back(0); - fake_gc_map_.push_back(0); // 0 entries. - fake_gc_map_.push_back(0); - - const std::vector<uint8_t>& fake_vmap_table_data = fake_vmap_table_data_.GetData(); - const std::vector<uint8_t>& fake_mapping_data = fake_mapping_data_.GetData(); - uint32_t vmap_table_offset = sizeof(OatQuickMethodHeader) + fake_vmap_table_data.size(); - uint32_t mapping_table_offset = vmap_table_offset + fake_mapping_data.size(); - uint32_t gc_map_offset = mapping_table_offset + fake_gc_map_.size(); - OatQuickMethodHeader method_header(mapping_table_offset, vmap_table_offset, gc_map_offset, - 4 * sizeof(void*), 0u, 0u, code_size); - fake_header_code_and_maps_.resize(sizeof(method_header)); - memcpy(&fake_header_code_and_maps_[0], &method_header, sizeof(method_header)); - fake_header_code_and_maps_.insert(fake_header_code_and_maps_.begin(), - fake_vmap_table_data.begin(), fake_vmap_table_data.end()); - fake_header_code_and_maps_.insert(fake_header_code_and_maps_.begin(), - fake_mapping_data.begin(), fake_mapping_data.end()); - fake_header_code_and_maps_.insert(fake_header_code_and_maps_.begin(), - fake_gc_map_.begin(), fake_gc_map_.end()); - fake_header_code_and_maps_.insert(fake_header_code_and_maps_.end(), - fake_code_.begin(), fake_code_.end()); + ArenaPool pool; + ArenaAllocator allocator(&pool); + StackMapStream stack_maps(&allocator); + stack_maps.BeginStackMapEntry(/* dex_pc */ 3u, + /* native_pc_offset */ 3u, + /* register_mask */ 0u, + /* sp_mask */ nullptr, + /* num_dex_registers */ 0u, + /* inlining_depth */ 0u); + stack_maps.EndStackMapEntry(); + size_t stack_maps_size = stack_maps.PrepareForFillIn(); + size_t stack_maps_offset = stack_maps_size + sizeof(OatQuickMethodHeader); + + fake_header_code_and_maps_.resize(stack_maps_offset + fake_code_.size()); + MemoryRegion stack_maps_region(&fake_header_code_and_maps_[0], stack_maps_size); + stack_maps.FillIn(stack_maps_region); + OatQuickMethodHeader method_header(stack_maps_offset, 4 * sizeof(void*), 0u, 0u, code_size); + memcpy(&fake_header_code_and_maps_[stack_maps_size], &method_header, sizeof(method_header)); + std::copy(fake_code_.begin(), + fake_code_.end(), + fake_header_code_and_maps_.begin() + stack_maps_offset); // Align the code. const size_t alignment = GetInstructionSetAlignment(kRuntimeISA); @@ -109,7 +97,7 @@ class ExceptionTest : public CommonRuntimeTest { if (kRuntimeISA == kArm) { // Check that the Thumb2 adjustment will be a NOP, see EntryPointToCodePointer(). - CHECK_ALIGNED(mapping_table_offset, 2); + CHECK_ALIGNED(stack_maps_offset, 2); } method_f_ = my_klass_->FindVirtualMethod("f", "()I", sizeof(void*)); @@ -124,9 +112,6 @@ class ExceptionTest : public CommonRuntimeTest { const DexFile* dex_; std::vector<uint8_t> fake_code_; - Leb128EncodingVector<> fake_mapping_data_; - Leb128EncodingVector<> fake_vmap_table_data_; - std::vector<uint8_t> fake_gc_map_; std::vector<uint8_t> fake_header_code_and_maps_; ArtMethod* method_f_; diff --git a/compiler/gc_map_builder.h b/compiler/gc_map_builder.h deleted file mode 100644 index 2ef7f1a659..0000000000 --- a/compiler/gc_map_builder.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (C) 2014 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_COMPILER_GC_MAP_BUILDER_H_ -#define ART_COMPILER_GC_MAP_BUILDER_H_ - -#include <vector> - -#include "base/bit_utils.h" -#include "gc_map.h" - -namespace art { - -class GcMapBuilder { - public: - template <typename Vector> - GcMapBuilder(Vector* table, size_t entries, uint32_t max_native_offset, - size_t references_width) - : entries_(entries), references_width_(entries != 0u ? references_width : 0u), - native_offset_width_(entries != 0 && max_native_offset != 0 - ? sizeof(max_native_offset) - CLZ(max_native_offset) / 8u - : 0u), - in_use_(entries) { - static_assert(std::is_same<typename Vector::value_type, uint8_t>::value, "Invalid value type"); - - // Resize table and set up header. - table->resize((EntryWidth() * entries) + sizeof(uint32_t)); - table_ = table->data(); - CHECK_LT(native_offset_width_, 1U << 3); - (*table)[0] = native_offset_width_ & 7; - CHECK_LT(references_width_, 1U << 13); - (*table)[0] |= (references_width_ << 3) & 0xFF; - (*table)[1] = (references_width_ >> 5) & 0xFF; - CHECK_LT(entries, 1U << 16); - (*table)[2] = entries & 0xFF; - (*table)[3] = (entries >> 8) & 0xFF; - } - - void AddEntry(uint32_t native_offset, const uint8_t* references) { - size_t table_index = TableIndex(native_offset); - while (in_use_[table_index]) { - table_index = (table_index + 1) % entries_; - } - in_use_[table_index] = true; - SetCodeOffset(table_index, native_offset); - DCHECK_EQ(native_offset, GetCodeOffset(table_index)); - SetReferences(table_index, references); - } - - private: - size_t TableIndex(uint32_t native_offset) { - return NativePcOffsetToReferenceMap::Hash(native_offset) % entries_; - } - - uint32_t GetCodeOffset(size_t table_index) { - uint32_t native_offset = 0; - size_t table_offset = (table_index * EntryWidth()) + sizeof(uint32_t); - for (size_t i = 0; i < native_offset_width_; i++) { - native_offset |= table_[table_offset + i] << (i * 8); - } - return native_offset; - } - - void SetCodeOffset(size_t table_index, uint32_t native_offset) { - size_t table_offset = (table_index * EntryWidth()) + sizeof(uint32_t); - for (size_t i = 0; i < native_offset_width_; i++) { - table_[table_offset + i] = (native_offset >> (i * 8)) & 0xFF; - } - } - - void SetReferences(size_t table_index, const uint8_t* references) { - size_t table_offset = (table_index * EntryWidth()) + sizeof(uint32_t); - memcpy(&table_[table_offset + native_offset_width_], references, references_width_); - } - - size_t EntryWidth() const { - return native_offset_width_ + references_width_; - } - - // Number of entries in the table. - const size_t entries_; - // Number of bytes used to encode the reference bitmap. - const size_t references_width_; - // Number of bytes used to encode a native offset. - const size_t native_offset_width_; - // Entries that are in use. - std::vector<bool> in_use_; - // The table we're building. - uint8_t* table_; -}; - -} // namespace art - -#endif // ART_COMPILER_GC_MAP_BUILDER_H_ diff --git a/compiler/image_test.cc b/compiler/image_test.cc index 7779e44519..91579e9daf 100644 --- a/compiler/image_test.cc +++ b/compiler/image_test.cc @@ -288,17 +288,14 @@ void ImageTest::TestWriteRead(ImageHeader::StorageMode storage_mode) { } TEST_F(ImageTest, WriteReadUncompressed) { - TEST_DISABLED_FOR_READ_BARRIER(); // b/27578460 TestWriteRead(ImageHeader::kStorageModeUncompressed); } TEST_F(ImageTest, WriteReadLZ4) { - TEST_DISABLED_FOR_READ_BARRIER(); // b/27578460 TestWriteRead(ImageHeader::kStorageModeLZ4); } TEST_F(ImageTest, WriteReadLZ4HC) { - TEST_DISABLED_FOR_READ_BARRIER(); // b/27578460 TestWriteRead(ImageHeader::kStorageModeLZ4HC); } diff --git a/compiler/jni/quick/jni_compiler.cc b/compiler/jni/quick/jni_compiler.cc index e92046057c..b8cda24c78 100644 --- a/compiler/jni/quick/jni_compiler.cc +++ b/compiler/jni/quick/jni_compiler.cc @@ -488,9 +488,7 @@ CompiledMethod* ArtJniCompileMethodInternal(CompilerDriver* driver, main_jni_conv->CoreSpillMask(), main_jni_conv->FpSpillMask(), ArrayRef<const SrcMapElem>(), - ArrayRef<const uint8_t>(), // mapping_table. ArrayRef<const uint8_t>(), // vmap_table. - ArrayRef<const uint8_t>(), // native_gc_map. ArrayRef<const uint8_t>(*jni_asm->cfi().data()), ArrayRef<const LinkerPatch>()); } diff --git a/compiler/linker/relative_patcher_test.h b/compiler/linker/relative_patcher_test.h index bf61ea0570..c07de79984 100644 --- a/compiler/linker/relative_patcher_test.h +++ b/compiler/linker/relative_patcher_test.h @@ -85,9 +85,15 @@ class RelativePatcherTest : public testing::Test { const ArrayRef<const LinkerPatch>& patches) { compiled_method_refs_.push_back(method_ref); compiled_methods_.emplace_back(new CompiledMethod( - &driver_, instruction_set_, code, - 0u, 0u, 0u, ArrayRef<const SrcMapElem>(), ArrayRef<const uint8_t>(), - ArrayRef<const uint8_t>(), ArrayRef<const uint8_t>(), ArrayRef<const uint8_t>(), + &driver_, + instruction_set_, + code, + /* frame_size_in_bytes */ 0u, + /* core_spill_mask */ 0u, + /* fp_spill_mask */ 0u, + /* src_mapping_table */ ArrayRef<const SrcMapElem>(), + /* vmap_table */ ArrayRef<const uint8_t>(), + /* cfi_info */ ArrayRef<const uint8_t>(), patches)); } diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc index eaf0e179a5..73b16d5b46 100644 --- a/compiler/oat_test.cc +++ b/compiler/oat_test.cc @@ -442,7 +442,7 @@ TEST_F(OatTest, OatHeaderSizeCheck) { // it is time to update OatHeader::kOatVersion EXPECT_EQ(72U, sizeof(OatHeader)); EXPECT_EQ(4U, sizeof(OatMethodOffsets)); - EXPECT_EQ(28U, sizeof(OatQuickMethodHeader)); + EXPECT_EQ(20U, sizeof(OatQuickMethodHeader)); EXPECT_EQ(132 * GetInstructionSetPointerSize(kRuntimeISA), sizeof(QuickEntryPoints)); } diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc index 3a67b1ec2a..25c671ecad 100644 --- a/compiler/oat_writer.cc +++ b/compiler/oat_writer.cc @@ -275,9 +275,7 @@ OatWriter::OatWriter(bool compiling_boot_image, TimingLogger* timings) size_code_alignment_(0), size_relative_call_thunks_(0), size_misc_thunks_(0), - size_mapping_table_(0), size_vmap_table_(0), - size_gc_map_(0), size_oat_dex_file_location_size_(0), size_oat_dex_file_location_data_(0), size_oat_dex_file_location_checksum_(0), @@ -498,72 +496,6 @@ void OatWriter::PrepareLayout(const CompilerDriver* compiler, OatWriter::~OatWriter() { } -struct OatWriter::GcMapDataAccess { - static ArrayRef<const uint8_t> GetData(const CompiledMethod* compiled_method) ALWAYS_INLINE { - return compiled_method->GetGcMap(); - } - - static uint32_t GetOffset(OatClass* oat_class, size_t method_offsets_index) ALWAYS_INLINE { - uint32_t offset = oat_class->method_headers_[method_offsets_index].gc_map_offset_; - return offset == 0u ? 0u : - (oat_class->method_offsets_[method_offsets_index].code_offset_ & ~1) - offset; - } - - static void SetOffset(OatClass* oat_class, size_t method_offsets_index, uint32_t offset) - ALWAYS_INLINE { - oat_class->method_headers_[method_offsets_index].gc_map_offset_ = - (oat_class->method_offsets_[method_offsets_index].code_offset_ & ~1) - offset; - } - - static const char* Name() { - return "GC map"; - } -}; - -struct OatWriter::MappingTableDataAccess { - static ArrayRef<const uint8_t> GetData(const CompiledMethod* compiled_method) ALWAYS_INLINE { - return compiled_method->GetMappingTable(); - } - - static uint32_t GetOffset(OatClass* oat_class, size_t method_offsets_index) ALWAYS_INLINE { - uint32_t offset = oat_class->method_headers_[method_offsets_index].mapping_table_offset_; - return offset == 0u ? 0u : - (oat_class->method_offsets_[method_offsets_index].code_offset_ & ~1) - offset; - } - - static void SetOffset(OatClass* oat_class, size_t method_offsets_index, uint32_t offset) - ALWAYS_INLINE { - oat_class->method_headers_[method_offsets_index].mapping_table_offset_ = - (oat_class->method_offsets_[method_offsets_index].code_offset_ & ~1) - offset; - } - - static const char* Name() { - return "mapping table"; - } -}; - -struct OatWriter::VmapTableDataAccess { - static ArrayRef<const uint8_t> GetData(const CompiledMethod* compiled_method) ALWAYS_INLINE { - return compiled_method->GetVmapTable(); - } - - static uint32_t GetOffset(OatClass* oat_class, size_t method_offsets_index) ALWAYS_INLINE { - uint32_t offset = oat_class->method_headers_[method_offsets_index].vmap_table_offset_; - return offset == 0u ? 0u : - (oat_class->method_offsets_[method_offsets_index].code_offset_ & ~1) - offset; - } - - static void SetOffset(OatClass* oat_class, size_t method_offsets_index, uint32_t offset) - ALWAYS_INLINE { - oat_class->method_headers_[method_offsets_index].vmap_table_offset_ = - (oat_class->method_offsets_[method_offsets_index].code_offset_ & ~1) - offset; - } - - static const char* Name() { - return "vmap table"; - } -}; - class OatWriter::DexMethodVisitor { public: DexMethodVisitor(OatWriter* writer, size_t offset) @@ -726,26 +658,24 @@ class OatWriter::InitCodeMethodVisitor : public OatDexMethodVisitor { uint32_t thumb_offset = compiled_method->CodeDelta(); // Deduplicate code arrays if we are not producing debuggable code. - bool deduped = false; + bool deduped = true; MethodReference method_ref(dex_file_, it.GetMemberIndex()); if (debuggable_) { quick_code_offset = writer_->relative_patcher_->GetOffset(method_ref); if (quick_code_offset != 0u) { // Duplicate methods, we want the same code for both of them so that the oat writer puts // the same code in both ArtMethods so that we do not get different oat code at runtime. - deduped = true; } else { quick_code_offset = NewQuickCodeOffset(compiled_method, it, thumb_offset); + deduped = false; } } else { - auto lb = dedupe_map_.lower_bound(compiled_method); - if (lb != dedupe_map_.end() && !dedupe_map_.key_comp()(compiled_method, lb->first)) { - quick_code_offset = lb->second; - deduped = true; - } else { - quick_code_offset = NewQuickCodeOffset(compiled_method, it, thumb_offset); - dedupe_map_.PutBefore(lb, compiled_method, quick_code_offset); - } + quick_code_offset = dedupe_map_.GetOrCreate( + compiled_method, + [this, &deduped, compiled_method, &it, thumb_offset]() { + deduped = false; + return NewQuickCodeOffset(compiled_method, it, thumb_offset); + }); } if (code_size != 0) { @@ -763,33 +693,25 @@ class OatWriter::InitCodeMethodVisitor : public OatDexMethodVisitor { // Update quick method header. DCHECK_LT(method_offsets_index_, oat_class->method_headers_.size()); OatQuickMethodHeader* method_header = &oat_class->method_headers_[method_offsets_index_]; - uint32_t mapping_table_offset = method_header->mapping_table_offset_; uint32_t vmap_table_offset = method_header->vmap_table_offset_; // If we don't have quick code, then we must have a vmap, as that is how the dex2dex // compiler records its transformations. DCHECK(!quick_code.empty() || vmap_table_offset != 0); - uint32_t gc_map_offset = method_header->gc_map_offset_; // The code offset was 0 when the mapping/vmap table offset was set, so it's set // to 0-offset and we need to adjust it by code_offset. uint32_t code_offset = quick_code_offset - thumb_offset; - if (mapping_table_offset != 0u && code_offset != 0u) { - mapping_table_offset += code_offset; - DCHECK_LT(mapping_table_offset, code_offset) << "Overflow in oat offsets"; - } if (vmap_table_offset != 0u && code_offset != 0u) { vmap_table_offset += code_offset; DCHECK_LT(vmap_table_offset, code_offset) << "Overflow in oat offsets"; } - if (gc_map_offset != 0u && code_offset != 0u) { - gc_map_offset += code_offset; - DCHECK_LT(gc_map_offset, code_offset) << "Overflow in oat offsets"; - } uint32_t frame_size_in_bytes = compiled_method->GetFrameSizeInBytes(); uint32_t core_spill_mask = compiled_method->GetCoreSpillMask(); uint32_t fp_spill_mask = compiled_method->GetFpSpillMask(); - *method_header = OatQuickMethodHeader(mapping_table_offset, vmap_table_offset, - gc_map_offset, frame_size_in_bytes, core_spill_mask, - fp_spill_mask, code_size); + *method_header = OatQuickMethodHeader(vmap_table_offset, + frame_size_in_bytes, + core_spill_mask, + fp_spill_mask, + code_size); if (!deduped) { // Update offsets. (Checksum is updated when writing.) @@ -831,30 +753,6 @@ class OatWriter::InitCodeMethodVisitor : public OatDexMethodVisitor { writer_->method_info_.push_back(info); } - if (kIsDebugBuild) { - // We expect GC maps except when the class hasn't been verified or the method is native. - const CompilerDriver* compiler_driver = writer_->compiler_driver_; - ClassReference class_ref(dex_file_, class_def_index_); - CompiledClass* compiled_class = compiler_driver->GetCompiledClass(class_ref); - mirror::Class::Status status; - if (compiled_class != nullptr) { - status = compiled_class->GetStatus(); - } else if (compiler_driver->GetVerificationResults()->IsClassRejected(class_ref)) { - status = mirror::Class::kStatusError; - } else { - status = mirror::Class::kStatusNotReady; - } - ArrayRef<const uint8_t> gc_map = compiled_method->GetGcMap(); - if (!gc_map.empty()) { - size_t gc_map_size = gc_map.size() * sizeof(gc_map[0]); - bool is_native = it.MemberIsNative(); - CHECK(gc_map_size != 0 || is_native || status < mirror::Class::kStatusVerified) - << gc_map_size << " " << (is_native ? "true" : "false") << " " - << (status < mirror::Class::kStatusVerified) << " " << status << " " - << PrettyMethod(it.GetMemberIndex(), *dex_file_); - } - } - DCHECK_LT(method_offsets_index_, oat_class->method_offsets_.size()); OatMethodOffsets* offsets = &oat_class->method_offsets_[method_offsets_index_]; offsets->code_offset_ = quick_code_offset; @@ -872,15 +770,9 @@ class OatWriter::InitCodeMethodVisitor : public OatDexMethodVisitor { return lhs->GetQuickCode().data() < rhs->GetQuickCode().data(); } // If the code is the same, all other fields are likely to be the same as well. - if (UNLIKELY(lhs->GetMappingTable().data() != rhs->GetMappingTable().data())) { - return lhs->GetMappingTable().data() < rhs->GetMappingTable().data(); - } if (UNLIKELY(lhs->GetVmapTable().data() != rhs->GetVmapTable().data())) { return lhs->GetVmapTable().data() < rhs->GetVmapTable().data(); } - if (UNLIKELY(lhs->GetGcMap().data() != rhs->GetGcMap().data())) { - return lhs->GetGcMap().data() < rhs->GetGcMap().data(); - } if (UNLIKELY(lhs->GetPatches().data() != rhs->GetPatches().data())) { return lhs->GetPatches().data() < rhs->GetPatches().data(); } @@ -907,7 +799,6 @@ class OatWriter::InitCodeMethodVisitor : public OatDexMethodVisitor { const bool debuggable_; }; -template <typename DataAccess> class OatWriter::InitMapMethodVisitor : public OatDexMethodVisitor { public: InitMapMethodVisitor(OatWriter* writer, size_t offset) @@ -921,19 +812,21 @@ class OatWriter::InitMapMethodVisitor : public OatDexMethodVisitor { if (compiled_method != nullptr) { DCHECK_LT(method_offsets_index_, oat_class->method_offsets_.size()); - DCHECK_EQ(DataAccess::GetOffset(oat_class, method_offsets_index_), 0u); + DCHECK_EQ(oat_class->method_headers_[method_offsets_index_].vmap_table_offset_, 0u); - ArrayRef<const uint8_t> map = DataAccess::GetData(compiled_method); + ArrayRef<const uint8_t> map = compiled_method->GetVmapTable(); uint32_t map_size = map.size() * sizeof(map[0]); if (map_size != 0u) { - auto lb = dedupe_map_.lower_bound(map.data()); - if (lb != dedupe_map_.end() && !dedupe_map_.key_comp()(map.data(), lb->first)) { - DataAccess::SetOffset(oat_class, method_offsets_index_, lb->second); - } else { - DataAccess::SetOffset(oat_class, method_offsets_index_, offset_); - dedupe_map_.PutBefore(lb, map.data(), offset_); - offset_ += map_size; - } + size_t offset = dedupe_map_.GetOrCreate( + map.data(), + [this, map_size]() { + uint32_t new_offset = offset_; + offset_ += map_size; + return new_offset; + }); + // Code offset is not initialized yet, so set the map offset to 0u-offset. + DCHECK_EQ(oat_class->method_offsets_[method_offsets_index_].code_offset_, 0u); + oat_class->method_headers_[method_offsets_index_].vmap_table_offset_ = 0u - offset; } ++method_offsets_index_; } @@ -1342,10 +1235,11 @@ class OatWriter::WriteCodeMethodVisitor : public OatDexMethodVisitor { } }; -template <typename DataAccess> class OatWriter::WriteMapMethodVisitor : public OatDexMethodVisitor { public: - WriteMapMethodVisitor(OatWriter* writer, OutputStream* out, const size_t file_offset, + WriteMapMethodVisitor(OatWriter* writer, + OutputStream* out, + const size_t file_offset, size_t relative_offset) : OatDexMethodVisitor(writer, relative_offset), out_(out), @@ -1360,22 +1254,31 @@ class OatWriter::WriteMapMethodVisitor : public OatDexMethodVisitor { size_t file_offset = file_offset_; OutputStream* out = out_; - uint32_t map_offset = DataAccess::GetOffset(oat_class, method_offsets_index_); + uint32_t map_offset = oat_class->method_headers_[method_offsets_index_].vmap_table_offset_; + uint32_t code_offset = oat_class->method_offsets_[method_offsets_index_].code_offset_; ++method_offsets_index_; - // Write deduplicated map. - ArrayRef<const uint8_t> map = DataAccess::GetData(compiled_method); - size_t map_size = map.size() * sizeof(map[0]); - DCHECK((map_size == 0u && map_offset == 0u) || - (map_size != 0u && map_offset != 0u && map_offset <= offset_)) - << map_size << " " << map_offset << " " << offset_ << " " - << PrettyMethod(it.GetMemberIndex(), *dex_file_) << " for " << DataAccess::Name(); - if (map_size != 0u && map_offset == offset_) { - if (UNLIKELY(!writer_->WriteData(out, map.data(), map_size))) { - ReportWriteFailure(it); - return false; + DCHECK((compiled_method->GetVmapTable().size() == 0u && map_offset == 0u) || + (compiled_method->GetVmapTable().size() != 0u && map_offset != 0u)) + << compiled_method->GetVmapTable().size() << " " << map_offset << " " + << PrettyMethod(it.GetMemberIndex(), *dex_file_); + + if (map_offset != 0u) { + // Transform map_offset to actual oat data offset. + map_offset = (code_offset - compiled_method->CodeDelta()) - map_offset; + DCHECK_NE(map_offset, 0u); + DCHECK_LE(map_offset, offset_) << PrettyMethod(it.GetMemberIndex(), *dex_file_); + + ArrayRef<const uint8_t> map = compiled_method->GetVmapTable(); + size_t map_size = map.size() * sizeof(map[0]); + if (map_offset == offset_) { + // Write deduplicated map (code info for Optimizing or transformation info for dex2dex). + if (UNLIKELY(!writer_->WriteData(out, map.data(), map_size))) { + ReportWriteFailure(it); + return false; + } + offset_ += map_size; } - offset_ += map_size; } DCHECK_OFFSET_(); } @@ -1388,7 +1291,7 @@ class OatWriter::WriteMapMethodVisitor : public OatDexMethodVisitor { size_t const file_offset_; void ReportWriteFailure(const ClassDataItemIterator& it) { - PLOG(ERROR) << "Failed to write " << DataAccess::Name() << " for " + PLOG(ERROR) << "Failed to write map for " << PrettyMethod(it.GetMemberIndex(), *dex_file_) << " to " << out_->GetLocation(); } }; @@ -1481,19 +1384,10 @@ size_t OatWriter::InitOatClasses(size_t offset) { } size_t OatWriter::InitOatMaps(size_t offset) { - #define VISIT(VisitorType) \ - do { \ - VisitorType visitor(this, offset); \ - bool success = VisitDexMethods(&visitor); \ - DCHECK(success); \ - offset = visitor.GetOffset(); \ - } while (false) - - VISIT(InitMapMethodVisitor<GcMapDataAccess>); - VISIT(InitMapMethodVisitor<MappingTableDataAccess>); - VISIT(InitMapMethodVisitor<VmapTableDataAccess>); - - #undef VISIT + InitMapMethodVisitor visitor(this, offset); + bool success = VisitDexMethods(&visitor); + DCHECK(success); + offset = visitor.GetOffset(); return offset; } @@ -1647,9 +1541,7 @@ bool OatWriter::WriteCode(OutputStream* out) { DO_STAT(size_code_alignment_); DO_STAT(size_relative_call_thunks_); DO_STAT(size_misc_thunks_); - DO_STAT(size_mapping_table_); DO_STAT(size_vmap_table_); - DO_STAT(size_gc_map_); DO_STAT(size_oat_dex_file_location_size_); DO_STAT(size_oat_dex_file_location_data_); DO_STAT(size_oat_dex_file_location_checksum_); @@ -1764,29 +1656,14 @@ bool OatWriter::WriteClasses(OutputStream* out) { } size_t OatWriter::WriteMaps(OutputStream* out, const size_t file_offset, size_t relative_offset) { - #define VISIT(VisitorType) \ - do { \ - VisitorType visitor(this, out, file_offset, relative_offset); \ - if (UNLIKELY(!VisitDexMethods(&visitor))) { \ - return 0; \ - } \ - relative_offset = visitor.GetOffset(); \ - } while (false) - - size_t gc_maps_offset = relative_offset; - VISIT(WriteMapMethodVisitor<GcMapDataAccess>); - size_gc_map_ = relative_offset - gc_maps_offset; - - size_t mapping_tables_offset = relative_offset; - VISIT(WriteMapMethodVisitor<MappingTableDataAccess>); - size_mapping_table_ = relative_offset - mapping_tables_offset; - size_t vmap_tables_offset = relative_offset; - VISIT(WriteMapMethodVisitor<VmapTableDataAccess>); + WriteMapMethodVisitor visitor(this, out, file_offset, relative_offset); + if (UNLIKELY(!VisitDexMethods(&visitor))) { + return 0; + } + relative_offset = visitor.GetOffset(); size_vmap_table_ = relative_offset - vmap_tables_offset; - #undef VISIT - return relative_offset; } diff --git a/compiler/oat_writer.h b/compiler/oat_writer.h index 5e7a4a37d1..3862798329 100644 --- a/compiler/oat_writer.h +++ b/compiler/oat_writer.h @@ -219,13 +219,6 @@ class OatWriter { class OatClass; class OatDexFile; - // The DataAccess classes are helper classes that provide access to members related to - // a given map, i.e. GC map, mapping table or vmap table. By abstracting these away - // we can share a lot of code for processing the maps with template classes below. - struct GcMapDataAccess; - struct MappingTableDataAccess; - struct VmapTableDataAccess; - // The function VisitDexMethods() below iterates through all the methods in all // the compiled dex files in order of their definitions. The method visitor // classes provide individual bits of processing for each of the passes we need to @@ -235,11 +228,9 @@ class OatWriter { class OatDexMethodVisitor; class InitOatClassesMethodVisitor; class InitCodeMethodVisitor; - template <typename DataAccess> class InitMapMethodVisitor; class InitImageMethodVisitor; class WriteCodeMethodVisitor; - template <typename DataAccess> class WriteMapMethodVisitor; // Visit all the methods in all the compiled dex files in their definition order @@ -354,9 +345,7 @@ class OatWriter { uint32_t size_code_alignment_; uint32_t size_relative_call_thunks_; uint32_t size_misc_thunks_; - uint32_t size_mapping_table_; uint32_t size_vmap_table_; - uint32_t size_gc_map_; uint32_t size_oat_dex_file_location_size_; uint32_t size_oat_dex_file_location_data_; uint32_t size_oat_dex_file_location_checksum_; diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc index 65e5c3ad48..953c0ae418 100644 --- a/compiler/optimizing/code_generator.cc +++ b/compiler/optimizing/code_generator.cc @@ -44,18 +44,15 @@ #include "compiled_method.h" #include "dex/verified_method.h" #include "driver/compiler_driver.h" -#include "gc_map_builder.h" #include "graph_visualizer.h" #include "intrinsics.h" #include "leb128.h" -#include "mapping_table.h" #include "mirror/array-inl.h" #include "mirror/object_array-inl.h" #include "mirror/object_reference.h" #include "parallel_move_resolver.h" #include "ssa_liveness_analysis.h" #include "utils/assembler.h" -#include "vmap_table.h" namespace art { diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc index a0c14123f3..3049128a87 100644 --- a/compiler/optimizing/code_generator_arm.cc +++ b/compiler/optimizing/code_generator_arm.cc @@ -6373,8 +6373,9 @@ void CodeGeneratorARM::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, reg, method_reg, ArtMethod::DexCacheResolvedMethodsOffset(kArmPointerSize).Int32Value()); - // temp = temp[index_in_cache] - uint32_t index_in_cache = invoke->GetTargetMethod().dex_method_index; + // temp = temp[index_in_cache]; + // Note: Don't use invoke->GetTargetMethod() as it may point to a different dex file. + uint32_t index_in_cache = invoke->GetDexMethodIndex(); __ LoadFromOffset(kLoadWord, reg, reg, CodeGenerator::GetCachePointerOffset(index_in_cache)); break; } diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc index 7699ddd761..c978aaa81d 100644 --- a/compiler/optimizing/code_generator_arm64.cc +++ b/compiler/optimizing/code_generator_arm64.cc @@ -3680,7 +3680,8 @@ void CodeGeneratorARM64::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invok MemOperand(method_reg.X(), ArtMethod::DexCacheResolvedMethodsOffset(kArm64WordSize).Int32Value())); // temp = temp[index_in_cache]; - uint32_t index_in_cache = invoke->GetTargetMethod().dex_method_index; + // Note: Don't use invoke->GetTargetMethod() as it may point to a different dex file. + uint32_t index_in_cache = invoke->GetDexMethodIndex(); __ Ldr(reg.X(), MemOperand(reg.X(), GetCachePointerOffset(index_in_cache))); break; } diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc index 2df37cd429..185397ccdf 100644 --- a/compiler/optimizing/code_generator_mips.cc +++ b/compiler/optimizing/code_generator_mips.cc @@ -3871,8 +3871,9 @@ void CodeGeneratorMIPS::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke reg, method_reg, ArtMethod::DexCacheResolvedMethodsOffset(kMipsPointerSize).Int32Value()); - // temp = temp[index_in_cache] - uint32_t index_in_cache = invoke->GetTargetMethod().dex_method_index; + // temp = temp[index_in_cache]; + // Note: Don't use invoke->GetTargetMethod() as it may point to a different dex file. + uint32_t index_in_cache = invoke->GetDexMethodIndex(); __ LoadFromOffset(kLoadWord, reg, reg, diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc index cc1f372898..246f5b7a65 100644 --- a/compiler/optimizing/code_generator_mips64.cc +++ b/compiler/optimizing/code_generator_mips64.cc @@ -3085,8 +3085,9 @@ void CodeGeneratorMIPS64::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invo reg, method_reg, ArtMethod::DexCacheResolvedMethodsOffset(kMips64PointerSize).Int32Value()); - // temp = temp[index_in_cache] - uint32_t index_in_cache = invoke->GetTargetMethod().dex_method_index; + // temp = temp[index_in_cache]; + // Note: Don't use invoke->GetTargetMethod() as it may point to a different dex file. + uint32_t index_in_cache = invoke->GetDexMethodIndex(); __ LoadFromOffset(kLoadDoubleword, reg, reg, diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc index 94d2f0c0a5..304cf08b51 100644 --- a/compiler/optimizing/code_generator_x86.cc +++ b/compiler/optimizing/code_generator_x86.cc @@ -4366,8 +4366,9 @@ void CodeGeneratorX86::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, // /* ArtMethod*[] */ temp = temp.ptr_sized_fields_->dex_cache_resolved_methods_; __ movl(reg, Address(method_reg, ArtMethod::DexCacheResolvedMethodsOffset(kX86PointerSize).Int32Value())); - // temp = temp[index_in_cache] - uint32_t index_in_cache = invoke->GetTargetMethod().dex_method_index; + // temp = temp[index_in_cache]; + // Note: Don't use invoke->GetTargetMethod() as it may point to a different dex file. + uint32_t index_in_cache = invoke->GetDexMethodIndex(); __ movl(reg, Address(reg, CodeGenerator::GetCachePointerOffset(index_in_cache))); break; } diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc index da126e4b57..056b69baac 100644 --- a/compiler/optimizing/code_generator_x86_64.cc +++ b/compiler/optimizing/code_generator_x86_64.cc @@ -808,8 +808,9 @@ void CodeGeneratorX86_64::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invo __ movq(reg, Address(CpuRegister(method_reg), ArtMethod::DexCacheResolvedMethodsOffset(kX86_64PointerSize).SizeValue())); - // temp = temp[index_in_cache] - uint32_t index_in_cache = invoke->GetTargetMethod().dex_method_index; + // temp = temp[index_in_cache]; + // Note: Don't use invoke->GetTargetMethod() as it may point to a different dex file. + uint32_t index_in_cache = invoke->GetDexMethodIndex(); __ movq(reg, Address(reg, CodeGenerator::GetCachePointerOffset(index_in_cache))); break; } diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc index 33803c1093..77e0cbc600 100644 --- a/compiler/optimizing/inliner.cc +++ b/compiler/optimizing/inliner.cc @@ -1117,41 +1117,10 @@ bool HInliner::TryBuildAndInlineHelper(HInvoke* invoke_instruction, } } - // Run simple optimizations on the graph. - HDeadCodeElimination dce(callee_graph, stats_); - HConstantFolding fold(callee_graph); - HSharpening sharpening(callee_graph, codegen_, dex_compilation_unit, compiler_driver_); - InstructionSimplifier simplify(callee_graph, stats_); - IntrinsicsRecognizer intrinsics(callee_graph, compiler_driver_, stats_); - - HOptimization* optimizations[] = { - &intrinsics, - &sharpening, - &simplify, - &fold, - &dce, - }; - - for (size_t i = 0; i < arraysize(optimizations); ++i) { - HOptimization* optimization = optimizations[i]; - optimization->Run(); - } - size_t number_of_instructions_budget = kMaximumNumberOfHInstructions; - if (depth_ + 1 < compiler_driver_->GetCompilerOptions().GetInlineDepthLimit()) { - HInliner inliner(callee_graph, - outermost_graph_, - codegen_, - outer_compilation_unit_, - dex_compilation_unit, - compiler_driver_, - handles_, - stats_, - total_number_of_dex_registers_ + code_item->registers_size_, - depth_ + 1); - inliner.Run(); - number_of_instructions_budget += inliner.number_of_inlined_instructions_; - } + size_t number_of_inlined_instructions = + RunOptimizations(callee_graph, code_item, dex_compilation_unit); + number_of_instructions_budget += number_of_inlined_instructions; // TODO: We should abort only if all predecessors throw. However, // HGraph::InlineInto currently does not handle an exit block with @@ -1197,7 +1166,7 @@ bool HInliner::TryBuildAndInlineHelper(HInvoke* invoke_instruction, for (HInstructionIterator instr_it(block->GetInstructions()); !instr_it.Done(); instr_it.Advance()) { - if (number_of_instructions++ == number_of_instructions_budget) { + if (number_of_instructions++ == number_of_instructions_budget) { VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file) << " is not inlined because its caller has reached" << " its instruction budget limit."; @@ -1278,6 +1247,47 @@ bool HInliner::TryBuildAndInlineHelper(HInvoke* invoke_instruction, return true; } +size_t HInliner::RunOptimizations(HGraph* callee_graph, + const DexFile::CodeItem* code_item, + const DexCompilationUnit& dex_compilation_unit) { + HDeadCodeElimination dce(callee_graph, stats_); + HConstantFolding fold(callee_graph); + HSharpening sharpening(callee_graph, codegen_, dex_compilation_unit, compiler_driver_); + InstructionSimplifier simplify(callee_graph, stats_); + IntrinsicsRecognizer intrinsics(callee_graph, compiler_driver_, stats_); + + HOptimization* optimizations[] = { + &intrinsics, + &sharpening, + &simplify, + &fold, + &dce, + }; + + for (size_t i = 0; i < arraysize(optimizations); ++i) { + HOptimization* optimization = optimizations[i]; + optimization->Run(); + } + + size_t number_of_inlined_instructions = 0u; + if (depth_ + 1 < compiler_driver_->GetCompilerOptions().GetInlineDepthLimit()) { + HInliner inliner(callee_graph, + outermost_graph_, + codegen_, + outer_compilation_unit_, + dex_compilation_unit, + compiler_driver_, + handles_, + stats_, + total_number_of_dex_registers_ + code_item->registers_size_, + depth_ + 1); + inliner.Run(); + number_of_inlined_instructions += inliner.number_of_inlined_instructions_; + } + + return number_of_inlined_instructions; +} + void HInliner::FixUpReturnReferenceType(HInvoke* invoke_instruction, ArtMethod* resolved_method, HInstruction* return_replacement, diff --git a/compiler/optimizing/inliner.h b/compiler/optimizing/inliner.h index cdb2167082..7cf1424b6d 100644 --- a/compiler/optimizing/inliner.h +++ b/compiler/optimizing/inliner.h @@ -76,6 +76,12 @@ class HInliner : public HOptimization { bool same_dex_file, HInstruction** return_replacement); + // Run simple optimizations on `callee_graph`. + // Returns the number of inlined instructions. + size_t RunOptimizations(HGraph* callee_graph, + const DexFile::CodeItem* code_item, + const DexCompilationUnit& dex_compilation_unit); + // Try to recognize known simple patterns and replace invoke call with appropriate instructions. bool TryPatternSubstitution(HInvoke* invoke_instruction, ArtMethod* resolved_method, diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc index c5f2342027..06b39680b2 100644 --- a/compiler/optimizing/instruction_builder.cc +++ b/compiler/optimizing/instruction_builder.cc @@ -567,10 +567,10 @@ void HInstructionBuilder::Binop_22b(const Instruction& instruction, bool reverse UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction()); } -static bool RequiresConstructorBarrier(const DexCompilationUnit* cu, const CompilerDriver& driver) { +static bool RequiresConstructorBarrier(const DexCompilationUnit* cu, CompilerDriver* driver) { Thread* self = Thread::Current(); return cu->IsConstructor() - && driver.RequiresConstructorBarrier(self, cu->GetDexFile(), cu->GetClassDefIndex()); + && driver->RequiresConstructorBarrier(self, cu->GetDexFile(), cu->GetClassDefIndex()); } // Returns true if `block` has only one successor which starts at the next @@ -616,7 +616,7 @@ void HInstructionBuilder::BuildReturn(const Instruction& instruction, if (graph_->ShouldGenerateConstructorBarrier()) { // The compilation unit is null during testing. if (dex_compilation_unit_ != nullptr) { - DCHECK(RequiresConstructorBarrier(dex_compilation_unit_, *compiler_driver_)) + DCHECK(RequiresConstructorBarrier(dex_compilation_unit_, compiler_driver_)) << "Inconsistent use of ShouldGenerateConstructorBarrier. Should not generate a barrier."; } AppendInstruction(new (arena_) HMemoryBarrier(kStoreStore, dex_pc)); @@ -1687,9 +1687,29 @@ bool HInstructionBuilder::CanDecodeQuickenedInfo() const { uint16_t HInstructionBuilder::LookupQuickenedInfo(uint32_t dex_pc) { DCHECK(interpreter_metadata_ != nullptr); - uint32_t dex_pc_in_map = DecodeUnsignedLeb128(&interpreter_metadata_); - DCHECK_EQ(dex_pc, dex_pc_in_map); - return DecodeUnsignedLeb128(&interpreter_metadata_); + + // First check if the info has already been decoded from `interpreter_metadata_`. + auto it = skipped_interpreter_metadata_.find(dex_pc); + if (it != skipped_interpreter_metadata_.end()) { + // Remove the entry from the map and return the parsed info. + uint16_t value_in_map = it->second; + skipped_interpreter_metadata_.erase(it); + return value_in_map; + } + + // Otherwise start parsing `interpreter_metadata_` until the slot for `dex_pc` + // is found. Store skipped values in the `skipped_interpreter_metadata_` map. + while (true) { + uint32_t dex_pc_in_map = DecodeUnsignedLeb128(&interpreter_metadata_); + uint16_t value_in_map = DecodeUnsignedLeb128(&interpreter_metadata_); + DCHECK_LE(dex_pc_in_map, dex_pc); + + if (dex_pc_in_map == dex_pc) { + return value_in_map; + } else { + skipped_interpreter_metadata_.Put(dex_pc_in_map, value_in_map); + } + } } bool HInstructionBuilder::ProcessDexInstruction(const Instruction& instruction, uint32_t dex_pc) { diff --git a/compiler/optimizing/instruction_builder.h b/compiler/optimizing/instruction_builder.h index 612594f8a8..f480b70062 100644 --- a/compiler/optimizing/instruction_builder.h +++ b/compiler/optimizing/instruction_builder.h @@ -59,6 +59,8 @@ class HInstructionBuilder : public ValueObject { dex_compilation_unit_(dex_compilation_unit), outer_compilation_unit_(outer_compilation_unit), interpreter_metadata_(interpreter_metadata), + skipped_interpreter_metadata_(std::less<uint32_t>(), + arena_->Adapter(kArenaAllocGraphBuilder)), compilation_stats_(compiler_stats), dex_cache_(dex_cache), loop_headers_(graph->GetArena()->Adapter(kArenaAllocGraphBuilder)) { @@ -287,7 +289,15 @@ class HInstructionBuilder : public ValueObject { // methods. const DexCompilationUnit* const outer_compilation_unit_; + // Original values kept after instruction quickening. This is a data buffer + // of Leb128-encoded (dex_pc, value) pairs sorted by dex_pc. const uint8_t* interpreter_metadata_; + + // InstructionBuilder does not parse instructions in dex_pc order. Quickening + // info for out-of-order dex_pcs is stored in a map until the positions + // are eventually visited. + ArenaSafeMap<uint32_t, uint16_t> skipped_interpreter_metadata_; + OptimizingCompilerStats* compilation_stats_; Handle<mirror::DexCache> dex_cache_; diff --git a/compiler/optimizing/intrinsics_arm64.cc b/compiler/optimizing/intrinsics_arm64.cc index a589ef07e2..927e2ecfbb 100644 --- a/compiler/optimizing/intrinsics_arm64.cc +++ b/compiler/optimizing/intrinsics_arm64.cc @@ -1708,7 +1708,7 @@ void IntrinsicCodeGeneratorARM64::VisitStringGetCharsNoCheck(HInvoke* invoke) { // Mirrors ARRAYCOPY_SHORT_CHAR_ARRAY_THRESHOLD in libcore, so we can choose to use the native // implementation there for longer copy lengths. -static constexpr int32_t kSystemArrayCopyThreshold = 32; +static constexpr int32_t kSystemArrayCopyCharThreshold = 32; static void SetSystemArrayCopyLocationRequires(LocationSummary* locations, uint32_t at, @@ -1739,7 +1739,7 @@ void IntrinsicLocationsBuilderARM64::VisitSystemArrayCopyChar(HInvoke* invoke) { HIntConstant* length = invoke->InputAt(4)->AsIntConstant(); if (length != nullptr) { int32_t len = length->GetValue(); - if (len < 0 || len > kSystemArrayCopyThreshold) { + if (len < 0 || len > kSystemArrayCopyCharThreshold) { // Just call as normal. return; } @@ -1882,7 +1882,7 @@ void IntrinsicCodeGeneratorARM64::VisitSystemArrayCopyChar(HInvoke* invoke) { // If the length is negative, bail out. __ Tbnz(WRegisterFrom(length), kWRegSize - 1, slow_path->GetEntryLabel()); // If the length > 32 then (currently) prefer libcore's native implementation. - __ Cmp(WRegisterFrom(length), kSystemArrayCopyThreshold); + __ Cmp(WRegisterFrom(length), kSystemArrayCopyCharThreshold); __ B(slow_path->GetEntryLabel(), gt); } else { // We have already checked in the LocationsBuilder for the constant case. @@ -1943,7 +1943,271 @@ void IntrinsicCodeGeneratorARM64::VisitSystemArrayCopyChar(HInvoke* invoke) { __ Bind(slow_path->GetExitLabel()); } -UNIMPLEMENTED_INTRINSIC(ARM64, SystemArrayCopy) +// We can choose to use the native implementation there for longer copy lengths. +static constexpr int32_t kSystemArrayCopyThreshold = 128; + +// CodeGenerator::CreateSystemArrayCopyLocationSummary use three temporary registers. +// We want to use two temporary registers in order to reduce the register pressure in arm64. +// So we don't use the CodeGenerator::CreateSystemArrayCopyLocationSummary. +void IntrinsicLocationsBuilderARM64::VisitSystemArrayCopy(HInvoke* invoke) { + // Check to see if we have known failures that will cause us to have to bail out + // to the runtime, and just generate the runtime call directly. + HIntConstant* src_pos = invoke->InputAt(1)->AsIntConstant(); + HIntConstant* dest_pos = invoke->InputAt(3)->AsIntConstant(); + + // The positions must be non-negative. + if ((src_pos != nullptr && src_pos->GetValue() < 0) || + (dest_pos != nullptr && dest_pos->GetValue() < 0)) { + // We will have to fail anyways. + return; + } + + // The length must be >= 0. + HIntConstant* length = invoke->InputAt(4)->AsIntConstant(); + if (length != nullptr) { + int32_t len = length->GetValue(); + if (len < 0 || len >= kSystemArrayCopyThreshold) { + // Just call as normal. + return; + } + } + + SystemArrayCopyOptimizations optimizations(invoke); + + if (optimizations.GetDestinationIsSource()) { + if (src_pos != nullptr && dest_pos != nullptr && src_pos->GetValue() < dest_pos->GetValue()) { + // We only support backward copying if source and destination are the same. + return; + } + } + + if (optimizations.GetDestinationIsPrimitiveArray() || optimizations.GetSourceIsPrimitiveArray()) { + // We currently don't intrinsify primitive copying. + return; + } + + ArenaAllocator* allocator = invoke->GetBlock()->GetGraph()->GetArena(); + LocationSummary* locations = new (allocator) LocationSummary(invoke, + LocationSummary::kCallOnSlowPath, + kIntrinsified); + // arraycopy(Object src, int src_pos, Object dest, int dest_pos, int length). + locations->SetInAt(0, Location::RequiresRegister()); + SetSystemArrayCopyLocationRequires(locations, 1, invoke->InputAt(1)); + locations->SetInAt(2, Location::RequiresRegister()); + SetSystemArrayCopyLocationRequires(locations, 3, invoke->InputAt(3)); + SetSystemArrayCopyLocationRequires(locations, 4, invoke->InputAt(4)); + + locations->AddTemp(Location::RequiresRegister()); + locations->AddTemp(Location::RequiresRegister()); +} + +void IntrinsicCodeGeneratorARM64::VisitSystemArrayCopy(HInvoke* invoke) { + vixl::MacroAssembler* masm = GetVIXLAssembler(); + LocationSummary* locations = invoke->GetLocations(); + + uint32_t class_offset = mirror::Object::ClassOffset().Int32Value(); + uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value(); + uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value(); + uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value(); + + Register src = XRegisterFrom(locations->InAt(0)); + Location src_pos = locations->InAt(1); + Register dest = XRegisterFrom(locations->InAt(2)); + Location dest_pos = locations->InAt(3); + Location length = locations->InAt(4); + Register temp1 = WRegisterFrom(locations->GetTemp(0)); + Register temp2 = WRegisterFrom(locations->GetTemp(1)); + + SlowPathCodeARM64* slow_path = new (GetAllocator()) IntrinsicSlowPathARM64(invoke); + codegen_->AddSlowPath(slow_path); + + vixl::Label conditions_on_positions_validated; + SystemArrayCopyOptimizations optimizations(invoke); + + if (!optimizations.GetDestinationIsSource() && + (!src_pos.IsConstant() || !dest_pos.IsConstant())) { + __ Cmp(src, dest); + } + // If source and destination are the same, we go to slow path if we need to do + // forward copying. + if (src_pos.IsConstant()) { + int32_t src_pos_constant = src_pos.GetConstant()->AsIntConstant()->GetValue(); + if (dest_pos.IsConstant()) { + // Checked when building locations. + DCHECK(!optimizations.GetDestinationIsSource() + || (src_pos_constant >= dest_pos.GetConstant()->AsIntConstant()->GetValue())); + } else { + if (!optimizations.GetDestinationIsSource()) { + __ B(&conditions_on_positions_validated, ne); + } + __ Cmp(WRegisterFrom(dest_pos), src_pos_constant); + __ B(slow_path->GetEntryLabel(), gt); + } + } else { + if (!optimizations.GetDestinationIsSource()) { + __ B(&conditions_on_positions_validated, ne); + } + __ Cmp(RegisterFrom(src_pos, invoke->InputAt(1)->GetType()), + OperandFrom(dest_pos, invoke->InputAt(3)->GetType())); + __ B(slow_path->GetEntryLabel(), lt); + } + + __ Bind(&conditions_on_positions_validated); + + if (!optimizations.GetSourceIsNotNull()) { + // Bail out if the source is null. + __ Cbz(src, slow_path->GetEntryLabel()); + } + + if (!optimizations.GetDestinationIsNotNull() && !optimizations.GetDestinationIsSource()) { + // Bail out if the destination is null. + __ Cbz(dest, slow_path->GetEntryLabel()); + } + + // We have already checked in the LocationsBuilder for the constant case. + if (!length.IsConstant() && + !optimizations.GetCountIsSourceLength() && + !optimizations.GetCountIsDestinationLength()) { + // If the length is negative, bail out. + __ Tbnz(WRegisterFrom(length), kWRegSize - 1, slow_path->GetEntryLabel()); + // If the length >= 128 then (currently) prefer native implementation. + __ Cmp(WRegisterFrom(length), kSystemArrayCopyThreshold); + __ B(slow_path->GetEntryLabel(), ge); + } + // Validity checks: source. + CheckSystemArrayCopyPosition(masm, + src_pos, + src, + length, + slow_path, + temp1, + temp2, + optimizations.GetCountIsSourceLength()); + + // Validity checks: dest. + CheckSystemArrayCopyPosition(masm, + dest_pos, + dest, + length, + slow_path, + temp1, + temp2, + optimizations.GetCountIsDestinationLength()); + { + // We use a block to end the scratch scope before the write barrier, thus + // freeing the temporary registers so they can be used in `MarkGCCard`. + UseScratchRegisterScope temps(masm); + Register temp3 = temps.AcquireW(); + if (!optimizations.GetDoesNotNeedTypeCheck()) { + // Check whether all elements of the source array are assignable to the component + // type of the destination array. We do two checks: the classes are the same, + // or the destination is Object[]. If none of these checks succeed, we go to the + // slow path. + __ Ldr(temp1, MemOperand(dest, class_offset)); + __ Ldr(temp2, MemOperand(src, class_offset)); + bool did_unpoison = false; + if (!optimizations.GetDestinationIsNonPrimitiveArray() || + !optimizations.GetSourceIsNonPrimitiveArray()) { + // One or two of the references need to be unpoisoned. Unpoison them + // both to make the identity check valid. + codegen_->GetAssembler()->MaybeUnpoisonHeapReference(temp1); + codegen_->GetAssembler()->MaybeUnpoisonHeapReference(temp2); + did_unpoison = true; + } + + if (!optimizations.GetDestinationIsNonPrimitiveArray()) { + // Bail out if the destination is not a non primitive array. + // /* HeapReference<Class> */ temp3 = temp1->component_type_ + __ Ldr(temp3, HeapOperand(temp1, component_offset)); + __ Cbz(temp3, slow_path->GetEntryLabel()); + codegen_->GetAssembler()->MaybeUnpoisonHeapReference(temp3); + __ Ldrh(temp3, HeapOperand(temp3, primitive_offset)); + static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot"); + __ Cbnz(temp3, slow_path->GetEntryLabel()); + } + + if (!optimizations.GetSourceIsNonPrimitiveArray()) { + // Bail out if the source is not a non primitive array. + // /* HeapReference<Class> */ temp3 = temp2->component_type_ + __ Ldr(temp3, HeapOperand(temp2, component_offset)); + __ Cbz(temp3, slow_path->GetEntryLabel()); + codegen_->GetAssembler()->MaybeUnpoisonHeapReference(temp3); + __ Ldrh(temp3, HeapOperand(temp3, primitive_offset)); + static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot"); + __ Cbnz(temp3, slow_path->GetEntryLabel()); + } + + __ Cmp(temp1, temp2); + + if (optimizations.GetDestinationIsTypedObjectArray()) { + vixl::Label do_copy; + __ B(&do_copy, eq); + if (!did_unpoison) { + codegen_->GetAssembler()->MaybeUnpoisonHeapReference(temp1); + } + // /* HeapReference<Class> */ temp1 = temp1->component_type_ + __ Ldr(temp1, HeapOperand(temp1, component_offset)); + codegen_->GetAssembler()->MaybeUnpoisonHeapReference(temp1); + // /* HeapReference<Class> */ temp1 = temp1->super_class_ + __ Ldr(temp1, HeapOperand(temp1, super_offset)); + // No need to unpoison the result, we're comparing against null. + __ Cbnz(temp1, slow_path->GetEntryLabel()); + __ Bind(&do_copy); + } else { + __ B(slow_path->GetEntryLabel(), ne); + } + } else if (!optimizations.GetSourceIsNonPrimitiveArray()) { + DCHECK(optimizations.GetDestinationIsNonPrimitiveArray()); + // Bail out if the source is not a non primitive array. + // /* HeapReference<Class> */ temp1 = src->klass_ + __ Ldr(temp1, HeapOperand(src.W(), class_offset)); + codegen_->GetAssembler()->MaybeUnpoisonHeapReference(temp1); + // /* HeapReference<Class> */ temp3 = temp1->component_type_ + __ Ldr(temp3, HeapOperand(temp1, component_offset)); + __ Cbz(temp3, slow_path->GetEntryLabel()); + codegen_->GetAssembler()->MaybeUnpoisonHeapReference(temp3); + __ Ldrh(temp3, HeapOperand(temp3, primitive_offset)); + static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot"); + __ Cbnz(temp3, slow_path->GetEntryLabel()); + } + + Register src_curr_addr = temp1.X(); + Register dst_curr_addr = temp2.X(); + Register src_stop_addr = temp3.X(); + + GenSystemArrayCopyAddresses(masm, + Primitive::kPrimNot, + src, + src_pos, + dest, + dest_pos, + length, + src_curr_addr, + dst_curr_addr, + src_stop_addr); + + // Iterate over the arrays and do a raw copy of the objects. We don't need to + // poison/unpoison, nor do any read barrier as the next uses of the destination + // array will do it. + vixl::Label loop, done; + const int32_t element_size = Primitive::ComponentSize(Primitive::kPrimNot); + __ Bind(&loop); + __ Cmp(src_curr_addr, src_stop_addr); + __ B(&done, eq); + { + Register tmp = temps.AcquireW(); + __ Ldr(tmp, MemOperand(src_curr_addr, element_size, vixl::PostIndex)); + __ Str(tmp, MemOperand(dst_curr_addr, element_size, vixl::PostIndex)); + } + __ B(&loop); + __ Bind(&done); + } + // We only need one card marking on the destination array. + codegen_->MarkGCCard(dest.W(), Register(), /* value_can_be_null */ false); + + __ Bind(slow_path->GetExitLabel()); +} + UNIMPLEMENTED_INTRINSIC(ARM64, ReferenceGetReferent) UNIMPLEMENTED_INTRINSIC(ARM64, FloatIsInfinite) UNIMPLEMENTED_INTRINSIC(ARM64, DoubleIsInfinite) diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc index 3d6bf62d0b..cad94c7ad7 100644 --- a/compiler/optimizing/optimizing_compiler.cc +++ b/compiler/optimizing/optimizing_compiler.cc @@ -597,9 +597,7 @@ CompiledMethod* OptimizingCompiler::Emit(ArenaAllocator* arena, codegen->GetCoreSpillMask(), codegen->GetFpuSpillMask(), ArrayRef<const SrcMapElem>(), - ArrayRef<const uint8_t>(), // mapping_table. ArrayRef<const uint8_t>(stack_map), - ArrayRef<const uint8_t>(), // native_gc_map. ArrayRef<const uint8_t>(*codegen->GetAssembler()->cfi().data()), ArrayRef<const LinkerPatch>(linker_patches)); @@ -916,9 +914,7 @@ bool OptimizingCompiler::JitCompile(Thread* self, const void* code = code_cache->CommitCode( self, method, - nullptr, stack_map_data, - nullptr, codegen->HasEmptyFrame() ? 0 : codegen->GetFrameSize(), codegen->GetCoreSpillMask(), codegen->GetFpuSpillMask(), diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc index 0889098fa6..370583e3ba 100644 --- a/dex2oat/dex2oat.cc +++ b/dex2oat/dex2oat.cc @@ -68,6 +68,7 @@ #include "mirror/class_loader.h" #include "mirror/object-inl.h" #include "mirror/object_array-inl.h" +#include "oat_file_assistant.h" #include "oat_writer.h" #include "os.h" #include "runtime.h" @@ -1325,7 +1326,7 @@ class Dex2Oat FINAL { TimingLogger::ScopedTiming t3("Loading image checksum", timings_); std::vector<gc::space::ImageSpace*> image_spaces = Runtime::Current()->GetHeap()->GetBootImageSpaces(); - image_file_location_oat_checksum_ = image_spaces[0]->GetImageHeader().GetOatChecksum(); + image_file_location_oat_checksum_ = OatFileAssistant::CalculateCombinedImageChecksum(); image_file_location_oat_data_begin_ = reinterpret_cast<uintptr_t>(image_spaces[0]->GetImageHeader().GetOatDataBegin()); image_patch_delta_ = image_spaces[0]->GetImageHeader().GetPatchDelta(); diff --git a/disassembler/disassembler_arm.cc b/disassembler/disassembler_arm.cc index 0e709eb419..77efb6be29 100644 --- a/disassembler/disassembler_arm.cc +++ b/disassembler/disassembler_arm.cc @@ -776,7 +776,7 @@ size_t DisassemblerArm::DumpThumb32(std::ostream& os, const uint8_t* instr_ptr) if (imm5 == 0) { args << "rrx"; } else { - args << "ror"; + args << "ror #" << imm5; } break; } diff --git a/imgdiag/imgdiag.cc b/imgdiag/imgdiag.cc index da7f43c9da..c2a812ee09 100644 --- a/imgdiag/imgdiag.cc +++ b/imgdiag/imgdiag.cc @@ -36,7 +36,6 @@ #include "image.h" #include "scoped_thread_state_change.h" #include "os.h" -#include "gc_map.h" #include "cmdline.h" #include "backtrace/BacktraceMap.h" diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc index 9a3bb02906..b673eff9ad 100644 --- a/oatdump/oatdump.cc +++ b/oatdump/oatdump.cc @@ -38,7 +38,6 @@ #include "dex_instruction.h" #include "disassembler.h" #include "elf_builder.h" -#include "gc_map.h" #include "gc/space/image_space.h" #include "gc/space/large_object_space.h" #include "gc/space/space-inl.h" @@ -46,7 +45,6 @@ #include "indenter.h" #include "linker/buffered_output_stream.h" #include "linker/file_output_stream.h" -#include "mapping_table.h" #include "mirror/array-inl.h" #include "mirror/class-inl.h" #include "mirror/dex_cache-inl.h" @@ -62,7 +60,6 @@ #include "ScopedLocalRef.h" #include "thread_list.h" #include "verifier/method_verifier.h" -#include "vmap_table.h" #include "well_known_classes.h" #include <sys/stat.h> @@ -282,9 +279,7 @@ class OatSymbolizer FINAL { class OatDumperOptions { public: - OatDumperOptions(bool dump_raw_mapping_table, - bool dump_raw_gc_map, - bool dump_vmap, + OatDumperOptions(bool dump_vmap, bool dump_code_info_stack_maps, bool disassemble_code, bool absolute_addresses, @@ -297,9 +292,7 @@ class OatDumperOptions { const char* app_image, const char* app_oat, uint32_t addr2instr) - : dump_raw_mapping_table_(dump_raw_mapping_table), - dump_raw_gc_map_(dump_raw_gc_map), - dump_vmap_(dump_vmap), + : dump_vmap_(dump_vmap), dump_code_info_stack_maps_(dump_code_info_stack_maps), disassemble_code_(disassemble_code), absolute_addresses_(absolute_addresses), @@ -314,8 +307,6 @@ class OatDumperOptions { addr2instr_(addr2instr), class_loader_(nullptr) {} - const bool dump_raw_mapping_table_; - const bool dump_raw_gc_map_; const bool dump_vmap_; const bool dump_code_info_stack_maps_; const bool disassemble_code_; @@ -572,9 +563,7 @@ class OatDumper { code_offset &= ~0x1; } offsets_.insert(code_offset); - offsets_.insert(oat_method.GetMappingTableOffset()); offsets_.insert(oat_method.GetVmapTableOffset()); - offsets_.insert(oat_method.GetGcMapOffset()); } bool DumpOatDexFile(std::ostream& os, const OatFile::OatDexFile& oat_dex_file) { @@ -843,22 +832,6 @@ class OatDumper { success = false; } vios->Stream() << "\n"; - - vios->Stream() << "gc_map: "; - if (options_.absolute_addresses_) { - vios->Stream() << StringPrintf("%p ", oat_method.GetGcMap()); - } - uint32_t gc_map_offset = oat_method.GetGcMapOffset(); - vios->Stream() << StringPrintf("(offset=0x%08x)\n", gc_map_offset); - if (gc_map_offset > oat_file_.Size()) { - vios->Stream() << StringPrintf("WARNING: " - "gc map table offset 0x%08x is past end of file 0x%08zx.\n", - gc_map_offset, oat_file_.Size()); - success = false; - } else if (options_.dump_raw_gc_map_) { - ScopedIndentation indent3(vios); - DumpGcMap(vios->Stream(), oat_method, code_item); - } } { vios->Stream() << "OatQuickMethodHeader "; @@ -879,24 +852,6 @@ class OatDumper { } ScopedIndentation indent2(vios); - vios->Stream() << "mapping_table: "; - if (options_.absolute_addresses_) { - vios->Stream() << StringPrintf("%p ", oat_method.GetMappingTable()); - } - uint32_t mapping_table_offset = oat_method.GetMappingTableOffset(); - vios->Stream() << StringPrintf("(offset=0x%08x)\n", oat_method.GetMappingTableOffset()); - if (mapping_table_offset > oat_file_.Size()) { - vios->Stream() << StringPrintf("WARNING: " - "mapping table offset 0x%08x is past end of file 0x%08zx. " - "mapping table offset was loaded from offset 0x%08x.\n", - mapping_table_offset, oat_file_.Size(), - oat_method.GetMappingTableOffsetOffset()); - success = false; - } else if (options_.dump_raw_mapping_table_) { - ScopedIndentation indent3(vios); - DumpMappingTable(vios, oat_method); - } - vios->Stream() << "vmap_table: "; if (options_.absolute_addresses_) { vios->Stream() << StringPrintf("%p ", oat_method.GetVmapTable()); @@ -973,7 +928,7 @@ class OatDumper { success = false; if (options_.disassemble_code_) { if (code_size_offset + kPrologueBytes <= oat_file_.Size()) { - DumpCode(vios, verifier.get(), oat_method, code_item, true, kPrologueBytes); + DumpCode(vios, oat_method, code_item, true, kPrologueBytes); } } } else if (code_size > kMaxCodeSize) { @@ -986,11 +941,11 @@ class OatDumper { success = false; if (options_.disassemble_code_) { if (code_size_offset + kPrologueBytes <= oat_file_.Size()) { - DumpCode(vios, verifier.get(), oat_method, code_item, true, kPrologueBytes); + DumpCode(vios, oat_method, code_item, true, kPrologueBytes); } } } else if (options_.disassemble_code_) { - DumpCode(vios, verifier.get(), oat_method, code_item, !success, 0); + DumpCode(vios, oat_method, code_item, !success, 0); } } } @@ -1040,12 +995,7 @@ class OatDumper { ScopedIndentation indent(vios); vios->Stream() << "quickened data\n"; } else { - // Otherwise, display the vmap table. - const uint8_t* raw_table = oat_method.GetVmapTable(); - if (raw_table != nullptr) { - VmapTable vmap_table(raw_table); - DumpVmapTable(vios->Stream(), oat_method, vmap_table); - } + // Otherwise, there is nothing to display. } } @@ -1060,32 +1010,6 @@ class OatDumper { options_.dump_code_info_stack_maps_); } - // Display a vmap table. - void DumpVmapTable(std::ostream& os, - const OatFile::OatMethod& oat_method, - const VmapTable& vmap_table) { - bool first = true; - bool processing_fp = false; - uint32_t spill_mask = oat_method.GetCoreSpillMask(); - for (size_t i = 0; i < vmap_table.Size(); i++) { - uint16_t dex_reg = vmap_table[i]; - uint32_t cpu_reg = vmap_table.ComputeRegister(spill_mask, i, - processing_fp ? kFloatVReg : kIntVReg); - os << (first ? "v" : ", v") << dex_reg; - if (!processing_fp) { - os << "/r" << cpu_reg; - } else { - os << "/fr" << cpu_reg; - } - first = false; - if (!processing_fp && dex_reg == 0xFFFF) { - processing_fp = true; - spill_mask = oat_method.GetFpSpillMask(); - } - } - os << "\n"; - } - void DumpVregLocations(std::ostream& os, const OatFile::OatMethod& oat_method, const DexFile::CodeItem* code_item) { if (code_item != nullptr) { @@ -1128,203 +1052,18 @@ class OatDumper { } } - void DescribeVReg(std::ostream& os, const OatFile::OatMethod& oat_method, - const DexFile::CodeItem* code_item, size_t reg, VRegKind kind) { - const uint8_t* raw_table = oat_method.GetVmapTable(); - if (raw_table != nullptr) { - const VmapTable vmap_table(raw_table); - uint32_t vmap_offset; - if (vmap_table.IsInContext(reg, kind, &vmap_offset)) { - bool is_float = (kind == kFloatVReg) || (kind == kDoubleLoVReg) || (kind == kDoubleHiVReg); - uint32_t spill_mask = is_float ? oat_method.GetFpSpillMask() - : oat_method.GetCoreSpillMask(); - os << (is_float ? "fr" : "r") << vmap_table.ComputeRegister(spill_mask, vmap_offset, kind); - } else { - uint32_t offset = StackVisitor::GetVRegOffsetFromQuickCode( - code_item, - oat_method.GetCoreSpillMask(), - oat_method.GetFpSpillMask(), - oat_method.GetFrameSizeInBytes(), - reg, - GetInstructionSet()); - os << "[sp + #" << offset << "]"; - } - } - } - - void DumpGcMapRegisters(std::ostream& os, const OatFile::OatMethod& oat_method, - const DexFile::CodeItem* code_item, - size_t num_regs, const uint8_t* reg_bitmap) { - bool first = true; - for (size_t reg = 0; reg < num_regs; reg++) { - if (((reg_bitmap[reg / 8] >> (reg % 8)) & 0x01) != 0) { - if (first) { - os << " v" << reg << " ("; - DescribeVReg(os, oat_method, code_item, reg, kReferenceVReg); - os << ")"; - first = false; - } else { - os << ", v" << reg << " ("; - DescribeVReg(os, oat_method, code_item, reg, kReferenceVReg); - os << ")"; - } - } - } - if (first) { - os << "No registers in GC map\n"; - } else { - os << "\n"; - } - } - void DumpGcMap(std::ostream& os, const OatFile::OatMethod& oat_method, - const DexFile::CodeItem* code_item) { - const uint8_t* gc_map_raw = oat_method.GetGcMap(); - if (gc_map_raw == nullptr) { - return; // No GC map. - } - const void* quick_code = oat_method.GetQuickCode(); - NativePcOffsetToReferenceMap map(gc_map_raw); - for (size_t entry = 0; entry < map.NumEntries(); entry++) { - const uint8_t* native_pc = reinterpret_cast<const uint8_t*>(quick_code) + - map.GetNativePcOffset(entry); - os << StringPrintf("%p", native_pc); - DumpGcMapRegisters(os, oat_method, code_item, map.RegWidth() * 8, map.GetBitMap(entry)); - } - } - - void DumpMappingTable(VariableIndentationOutputStream* vios, - const OatFile::OatMethod& oat_method) { - const void* quick_code = oat_method.GetQuickCode(); - if (quick_code == nullptr) { + void DumpInformationAtOffset(VariableIndentationOutputStream* vios, + const OatFile::OatMethod& oat_method, + const DexFile::CodeItem* code_item, + size_t offset, + bool suspend_point_mapping) { + if (!IsMethodGeneratedByOptimizingCompiler(oat_method, code_item)) { + // Native method. return; } - MappingTable table(oat_method.GetMappingTable()); - if (table.TotalSize() != 0) { - if (table.PcToDexSize() != 0) { - typedef MappingTable::PcToDexIterator It; - vios->Stream() << "suspend point mappings {\n"; - for (It cur = table.PcToDexBegin(), end = table.PcToDexEnd(); cur != end; ++cur) { - ScopedIndentation indent1(vios); - vios->Stream() << StringPrintf("0x%04x -> 0x%04x\n", cur.NativePcOffset(), cur.DexPc()); - } - vios->Stream() << "}\n"; - } - if (table.DexToPcSize() != 0) { - typedef MappingTable::DexToPcIterator It; - vios->Stream() << "catch entry mappings {\n"; - for (It cur = table.DexToPcBegin(), end = table.DexToPcEnd(); cur != end; ++cur) { - ScopedIndentation indent1(vios); - vios->Stream() << StringPrintf("0x%04x -> 0x%04x\n", cur.NativePcOffset(), cur.DexPc()); - } - vios->Stream() << "}\n"; - } - } - } - - uint32_t DumpInformationAtOffset(VariableIndentationOutputStream* vios, - const OatFile::OatMethod& oat_method, - const DexFile::CodeItem* code_item, - size_t offset, - bool suspend_point_mapping) { - if (IsMethodGeneratedByOptimizingCompiler(oat_method, code_item)) { - if (suspend_point_mapping) { - ScopedIndentation indent1(vios); - DumpDexRegisterMapAtOffset(vios, oat_method, code_item, offset); - } - // The return value is not used in the case of a method compiled - // with the optimizing compiler. - return DexFile::kDexNoIndex; - } else { - return DumpMappingAtOffset(vios->Stream(), oat_method, offset, suspend_point_mapping); - } - } - - uint32_t DumpMappingAtOffset(std::ostream& os, const OatFile::OatMethod& oat_method, - size_t offset, bool suspend_point_mapping) { - MappingTable table(oat_method.GetMappingTable()); - if (suspend_point_mapping && table.PcToDexSize() > 0) { - typedef MappingTable::PcToDexIterator It; - for (It cur = table.PcToDexBegin(), end = table.PcToDexEnd(); cur != end; ++cur) { - if (offset == cur.NativePcOffset()) { - os << StringPrintf("suspend point dex PC: 0x%04x\n", cur.DexPc()); - return cur.DexPc(); - } - } - } else if (!suspend_point_mapping && table.DexToPcSize() > 0) { - typedef MappingTable::DexToPcIterator It; - for (It cur = table.DexToPcBegin(), end = table.DexToPcEnd(); cur != end; ++cur) { - if (offset == cur.NativePcOffset()) { - os << StringPrintf("catch entry dex PC: 0x%04x\n", cur.DexPc()); - return cur.DexPc(); - } - } - } - return DexFile::kDexNoIndex; - } - - void DumpGcMapAtNativePcOffset(std::ostream& os, const OatFile::OatMethod& oat_method, - const DexFile::CodeItem* code_item, size_t native_pc_offset) { - const uint8_t* gc_map_raw = oat_method.GetGcMap(); - if (gc_map_raw != nullptr) { - NativePcOffsetToReferenceMap map(gc_map_raw); - if (map.HasEntry(native_pc_offset)) { - size_t num_regs = map.RegWidth() * 8; - const uint8_t* reg_bitmap = map.FindBitMap(native_pc_offset); - bool first = true; - for (size_t reg = 0; reg < num_regs; reg++) { - if (((reg_bitmap[reg / 8] >> (reg % 8)) & 0x01) != 0) { - if (first) { - os << "GC map objects: v" << reg << " ("; - DescribeVReg(os, oat_method, code_item, reg, kReferenceVReg); - os << ")"; - first = false; - } else { - os << ", v" << reg << " ("; - DescribeVReg(os, oat_method, code_item, reg, kReferenceVReg); - os << ")"; - } - } - } - if (!first) { - os << "\n"; - } - } - } - } - - void DumpVRegsAtDexPc(std::ostream& os, verifier::MethodVerifier* verifier, - const OatFile::OatMethod& oat_method, - const DexFile::CodeItem* code_item, uint32_t dex_pc) { - DCHECK(verifier != nullptr); - std::vector<int32_t> kinds = verifier->DescribeVRegs(dex_pc); - bool first = true; - for (size_t reg = 0; reg < code_item->registers_size_; reg++) { - VRegKind kind = static_cast<VRegKind>(kinds.at(reg * 2)); - if (kind != kUndefined) { - if (first) { - os << "VRegs: v"; - first = false; - } else { - os << ", v"; - } - os << reg << " ("; - switch (kind) { - case kImpreciseConstant: - os << "Imprecise Constant: " << kinds.at((reg * 2) + 1) << ", "; - DescribeVReg(os, oat_method, code_item, reg, kind); - break; - case kConstant: - os << "Constant: " << kinds.at((reg * 2) + 1); - break; - default: - DescribeVReg(os, oat_method, code_item, reg, kind); - break; - } - os << ")"; - } - } - if (!first) { - os << "\n"; + if (suspend_point_mapping) { + ScopedIndentation indent1(vios); + DumpDexRegisterMapAtOffset(vios, oat_method, code_item, offset); } } @@ -1349,7 +1088,7 @@ class OatDumper { // null, then this method has been compiled with the optimizing // compiler. return oat_method.GetQuickCode() != nullptr && - oat_method.GetGcMap() == nullptr && + oat_method.GetVmapTable() != nullptr && code_item != nullptr; } @@ -1409,7 +1148,6 @@ class OatDumper { } void DumpCode(VariableIndentationOutputStream* vios, - verifier::MethodVerifier* verifier, const OatFile::OatMethod& oat_method, const DexFile::CodeItem* code_item, bool bad_input, size_t code_size) { const void* quick_code = oat_method.GetQuickCode(); @@ -1429,14 +1167,7 @@ class OatDumper { } offset += disassembler_->Dump(vios->Stream(), quick_native_pc + offset); if (!bad_input) { - uint32_t dex_pc = - DumpInformationAtOffset(vios, oat_method, code_item, offset, true); - if (dex_pc != DexFile::kDexNoIndex) { - DumpGcMapAtNativePcOffset(vios->Stream(), oat_method, code_item, offset); - if (verifier != nullptr) { - DumpVRegsAtDexPc(vios->Stream(), verifier, oat_method, code_item, dex_pc); - } - } + DumpInformationAtOffset(vios, oat_method, code_item, offset, true); } } } @@ -1986,10 +1717,6 @@ class ImageDumper { OatQuickMethodHeader* method_header = reinterpret_cast<OatQuickMethodHeader*>( reinterpret_cast<uintptr_t>(quick_oat_code_begin) - sizeof(OatQuickMethodHeader)); if (method->IsNative()) { - if (!Runtime::Current()->GetClassLinker()->IsQuickGenericJniStub(quick_oat_code_begin)) { - DCHECK(method_header->GetNativeGcMap() == nullptr) << PrettyMethod(method); - DCHECK(method_header->GetMappingTable() == nullptr) << PrettyMethod(method); - } bool first_occurrence; uint32_t quick_oat_code_size = GetQuickOatCodeSize(method); ComputeOatSize(quick_oat_code_begin, &first_occurrence); @@ -2013,17 +1740,6 @@ class ImageDumper { stats_.dex_instruction_bytes += dex_instruction_bytes; bool first_occurrence; - size_t gc_map_bytes = ComputeOatSize(method_header->GetNativeGcMap(), &first_occurrence); - if (first_occurrence) { - stats_.gc_map_bytes += gc_map_bytes; - } - - size_t pc_mapping_table_bytes = ComputeOatSize( - method_header->GetMappingTable(), &first_occurrence); - if (first_occurrence) { - stats_.pc_mapping_table_bytes += pc_mapping_table_bytes; - } - size_t vmap_table_bytes = 0u; if (!method_header->IsOptimized()) { // Method compiled with the optimizing compiler have no vmap table. @@ -2052,11 +1768,12 @@ class ImageDumper { uint32_t method_access_flags = method->GetAccessFlags(); indent_os << StringPrintf("OAT CODE: %p-%p\n", quick_oat_code_begin, quick_oat_code_end); - indent_os << StringPrintf("SIZE: Dex Instructions=%zd GC=%zd Mapping=%zd AccessFlags=0x%x\n", - dex_instruction_bytes, gc_map_bytes, pc_mapping_table_bytes, + indent_os << StringPrintf("SIZE: Dex Instructions=%zd StackMaps=%zd AccessFlags=0x%x\n", + dex_instruction_bytes, + vmap_table_bytes, method_access_flags); - size_t total_size = dex_instruction_bytes + gc_map_bytes + pc_mapping_table_bytes + + size_t total_size = dex_instruction_bytes + vmap_table_bytes + quick_oat_code_size + ArtMethod::Size(image_header_.GetPointerSize()); double expansion = @@ -2101,8 +1818,6 @@ class ImageDumper { size_t large_initializer_code_bytes; size_t large_method_code_bytes; - size_t gc_map_bytes; - size_t pc_mapping_table_bytes; size_t vmap_table_bytes; size_t dex_instruction_bytes; @@ -2131,8 +1846,6 @@ class ImageDumper { class_initializer_code_bytes(0), large_initializer_code_bytes(0), large_method_code_bytes(0), - gc_map_bytes(0), - pc_mapping_table_bytes(0), vmap_table_bytes(0), dex_instruction_bytes(0) {} @@ -2351,11 +2064,7 @@ class ImageDumper { PercentOfOatBytes(oat_dex_file_size.second)); } - os << "\n" << StringPrintf("gc_map_bytes = %7zd (%2.0f%% of oat file bytes)\n" - "pc_mapping_table_bytes = %7zd (%2.0f%% of oat file bytes)\n" - "vmap_table_bytes = %7zd (%2.0f%% of oat file bytes)\n\n", - gc_map_bytes, PercentOfOatBytes(gc_map_bytes), - pc_mapping_table_bytes, PercentOfOatBytes(pc_mapping_table_bytes), + os << "\n" << StringPrintf("vmap_table_bytes = %7zd (%2.0f%% of oat file bytes)\n\n", vmap_table_bytes, PercentOfOatBytes(vmap_table_bytes)) << std::flush; @@ -2590,10 +2299,6 @@ struct OatdumpArgs : public CmdlineArgs { oat_filename_ = option.substr(strlen("--oat-file=")).data(); } else if (option.starts_with("--image=")) { image_location_ = option.substr(strlen("--image=")).data(); - } else if (option =="--dump:raw_mapping_table") { - dump_raw_mapping_table_ = true; - } else if (option == "--dump:raw_gc_map") { - dump_raw_gc_map_ = true; } else if (option == "--no-dump:vmap") { dump_vmap_ = false; } else if (option =="--dump:code_info_stack_maps") { @@ -2683,12 +2388,6 @@ struct OatdumpArgs : public CmdlineArgs { usage += Base::GetUsage(); usage += // Optional. - " --dump:raw_mapping_table enables dumping of the mapping table.\n" - " Example: --dump:raw_mapping_table\n" - "\n" - " --dump:raw_gc_map enables dumping of the GC map.\n" - " Example: --dump:raw_gc_map\n" - "\n" " --no-dump:vmap may be used to disable vmap dumping.\n" " Example: --no-dump:vmap\n" "\n" @@ -2739,8 +2438,6 @@ struct OatdumpArgs : public CmdlineArgs { const char* method_filter_ = ""; const char* image_location_ = nullptr; std::string elf_filename_prefix_; - bool dump_raw_mapping_table_ = false; - bool dump_raw_gc_map_ = false; bool dump_vmap_ = true; bool dump_code_info_stack_maps_ = false; bool disassemble_code_ = true; @@ -2763,8 +2460,6 @@ struct OatdumpMain : public CmdlineMain<OatdumpArgs> { bool absolute_addresses = (args_->oat_filename_ == nullptr); oat_dumper_options_.reset(new OatDumperOptions( - args_->dump_raw_mapping_table_, - args_->dump_raw_gc_map_, args_->dump_vmap_, args_->dump_code_info_stack_maps_, args_->disassemble_code_, diff --git a/oatdump/oatdump_test.cc b/oatdump/oatdump_test.cc index bf062ed292..c7ced8adf2 100644 --- a/oatdump/oatdump_test.cc +++ b/oatdump/oatdump_test.cc @@ -97,16 +97,6 @@ TEST_F(OatDumpTest, TestOatImage) { ASSERT_TRUE(Exec(kModeOat, {}, &error_msg)) << error_msg; } -TEST_F(OatDumpTest, TestDumpRawMappingTable) { - std::string error_msg; - ASSERT_TRUE(Exec(kModeArt, {"--dump:raw_mapping_table"}, &error_msg)) << error_msg; -} - -TEST_F(OatDumpTest, TestDumpRawGcMap) { - std::string error_msg; - ASSERT_TRUE(Exec(kModeArt, {"--dump:raw_gc_map"}, &error_msg)) << error_msg; -} - TEST_F(OatDumpTest, TestNoDumpVmap) { std::string error_msg; ASSERT_TRUE(Exec(kModeArt, {"--no-dump:vmap"}, &error_msg)) << error_msg; diff --git a/runtime/Android.mk b/runtime/Android.mk index 542a2c4bdb..c85907987b 100644 --- a/runtime/Android.mk +++ b/runtime/Android.mk @@ -149,6 +149,7 @@ LIBART_COMMON_SRC_FILES := \ native/java_lang_VMClassLoader.cc \ native/java_lang_ref_FinalizerReference.cc \ native/java_lang_ref_Reference.cc \ + native/java_lang_reflect_AbstractMethod.cc \ native/java_lang_reflect_Array.cc \ native/java_lang_reflect_Constructor.cc \ native/java_lang_reflect_Field.cc \ diff --git a/runtime/arch/stub_test.cc b/runtime/arch/stub_test.cc index 969a038523..75d9073cfb 100644 --- a/runtime/arch/stub_test.cc +++ b/runtime/arch/stub_test.cc @@ -1934,7 +1934,12 @@ TEST_F(StubTest, Fields64) { TestFields(self, this, Primitive::Type::kPrimLong); } -TEST_F(StubTest, IMT) { +// Disabled, b/27991555 . +// FIXME: Hacking the entry point to point to art_quick_to_interpreter_bridge is broken. +// The bridge calls through to GetCalleeSaveMethodCaller() which looks up the pre-header +// and gets a bogus OatQuickMethodHeader* pointing into our assembly code just before +// the bridge and uses that to check for inlined frames, crashing in the process. +TEST_F(StubTest, DISABLED_IMT) { #if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__mips__) || \ (defined(__x86_64__) && !defined(__APPLE__)) Thread* self = Thread::Current(); diff --git a/runtime/art_method.cc b/runtime/art_method.cc index f97ad51568..34d19d151b 100644 --- a/runtime/art_method.cc +++ b/runtime/art_method.cc @@ -31,7 +31,6 @@ #include "jit/jit_code_cache.h" #include "jit/profiling_info.h" #include "jni_internal.h" -#include "mapping_table.h" #include "mirror/abstract_method.h" #include "mirror/class-inl.h" #include "mirror/object_array-inl.h" diff --git a/runtime/base/hash_set.h b/runtime/base/hash_set.h index fc1a52f807..12d3be75d1 100644 --- a/runtime/base/hash_set.h +++ b/runtime/base/hash_set.h @@ -140,7 +140,7 @@ class HashSet { HashSet() : HashSet(kDefaultMinLoadFactor, kDefaultMaxLoadFactor) {} - HashSet(double min_load_factor, double max_load_factor) + HashSet(double min_load_factor, double max_load_factor) noexcept : num_elements_(0u), num_buckets_(0u), elements_until_expand_(0u), @@ -152,7 +152,7 @@ class HashSet { DCHECK_LT(max_load_factor, 1.0); } - explicit HashSet(const allocator_type& alloc) + explicit HashSet(const allocator_type& alloc) noexcept : allocfn_(alloc), hashfn_(), emptyfn_(), @@ -166,7 +166,7 @@ class HashSet { max_load_factor_(kDefaultMaxLoadFactor) { } - HashSet(const HashSet& other) + HashSet(const HashSet& other) noexcept : allocfn_(other.allocfn_), hashfn_(other.hashfn_), emptyfn_(other.emptyfn_), @@ -184,7 +184,9 @@ class HashSet { } } - HashSet(HashSet&& other) + // noexcept required so that the move constructor is used instead of copy constructor. + // b/27860101 + HashSet(HashSet&& other) noexcept : allocfn_(std::move(other.allocfn_)), hashfn_(std::move(other.hashfn_)), emptyfn_(std::move(other.emptyfn_)), @@ -206,7 +208,7 @@ class HashSet { // Construct from existing data. // Read from a block of memory, if make_copy_of_data is false, then data_ points to within the // passed in ptr_. - HashSet(const uint8_t* ptr, bool make_copy_of_data, size_t* read_count) { + HashSet(const uint8_t* ptr, bool make_copy_of_data, size_t* read_count) noexcept { uint64_t temp; size_t offset = 0; offset = ReadFromBytes(ptr, offset, &temp); @@ -256,12 +258,12 @@ class HashSet { DeallocateStorage(); } - HashSet& operator=(HashSet&& other) { + HashSet& operator=(HashSet&& other) noexcept { HashSet(std::move(other)).swap(*this); return *this; } - HashSet& operator=(const HashSet& other) { + HashSet& operator=(const HashSet& other) noexcept { HashSet(other).swap(*this); // NOLINT(runtime/explicit) - a case of lint gone mad. return *this; } @@ -298,6 +300,11 @@ class HashSet { return Size() == 0; } + // Return true if the hash set has ownership of the underlying data. + bool OwnsData() const { + return owns_data_; + } + // Erase algorithm: // Make an empty slot where the iterator is pointing. // Scan forwards until we hit another empty slot. diff --git a/runtime/base/mutex.h b/runtime/base/mutex.h index 293451c4bf..17e0339561 100644 --- a/runtime/base/mutex.h +++ b/runtime/base/mutex.h @@ -88,6 +88,8 @@ enum LockLevel { kOatFileManagerLock, kTracingUniqueMethodsLock, kTracingStreamingLock, + kDeoptimizedMethodsLock, + kClassLoaderClassesLock, kDefaultMutexLevel, kMarkSweepLargeObjectLock, kPinTableLock, @@ -96,7 +98,7 @@ enum LockLevel { kAllocatedThreadIdsLock, kMonitorPoolLock, kMethodVerifiersLock, - kClassLinkerClassesLock, + kClassLinkerClassesLock, // TODO rename. kBreakpointLock, kMonitorLock, kMonitorListLock, diff --git a/runtime/check_reference_map_visitor.h b/runtime/check_reference_map_visitor.h index 7595d14101..0e2f9f2030 100644 --- a/runtime/check_reference_map_visitor.h +++ b/runtime/check_reference_map_visitor.h @@ -18,7 +18,6 @@ #define ART_RUNTIME_CHECK_REFERENCE_MAP_VISITOR_H_ #include "art_method-inl.h" -#include "gc_map.h" #include "oat_quick_method_header.h" #include "scoped_thread_state_change.h" #include "stack_map.h" @@ -54,11 +53,8 @@ class CheckReferenceMapVisitor : public StackVisitor { void CheckReferences(int* registers, int number_of_references, uint32_t native_pc_offset) SHARED_REQUIRES(Locks::mutator_lock_) { - if (GetCurrentOatQuickMethodHeader()->IsOptimized()) { - CheckOptimizedMethod(registers, number_of_references, native_pc_offset); - } else { - CheckQuickMethod(registers, number_of_references, native_pc_offset); - } + CHECK(GetCurrentOatQuickMethodHeader()->IsOptimized()); + CheckOptimizedMethod(registers, number_of_references, native_pc_offset); } private: @@ -104,20 +100,6 @@ class CheckReferenceMapVisitor : public StackVisitor { } } } - - void CheckQuickMethod(int* registers, int number_of_references, uint32_t native_pc_offset) - SHARED_REQUIRES(Locks::mutator_lock_) { - ArtMethod* m = GetMethod(); - NativePcOffsetToReferenceMap map(GetCurrentOatQuickMethodHeader()->GetNativeGcMap()); - const uint8_t* ref_bitmap = map.FindBitMap(native_pc_offset); - CHECK(ref_bitmap); - for (int i = 0; i < number_of_references; ++i) { - int reg = registers[i]; - CHECK(reg < m->GetCodeItem()->registers_size_); - CHECK((*((ref_bitmap) + reg / 8) >> (reg % 8) ) & 0x01) - << "Error: Reg @" << i << " is not in GC map"; - } - } }; } // namespace art diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 706059369c..18def2df2e 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -3786,7 +3786,9 @@ void ClassLinker::VerifyClass(Thread* self, Handle<mirror::Class> klass, LogSeve while (old_status == mirror::Class::kStatusVerifying || old_status == mirror::Class::kStatusVerifyingAtRuntime) { lock.WaitIgnoringInterrupts(); - CHECK_GT(klass->GetStatus(), old_status); + CHECK(klass->IsErroneous() || (klass->GetStatus() > old_status)) + << "Class '" << PrettyClass(klass.Get()) << "' performed an illegal verification state " + << "transition from " << old_status << " to " << klass->GetStatus(); old_status = klass->GetStatus(); } @@ -5874,9 +5876,14 @@ ClassLinker::DefaultMethodSearchResult ClassLinker::FindDefaultMethodImplementat !target_name_comparator.HasSameNameAndSignature( current_method->GetInterfaceMethodIfProxy(image_pointer_size_))) { continue; + } else if (!current_method->IsPublic()) { + // The verifier should have caught the non-public method for dex version 37. Just warn and + // skip it since this is from before default-methods so we don't really need to care that it + // has code. + LOG(WARNING) << "Interface method " << PrettyMethod(current_method) << " is not public! " + << "This will be a fatal error in subsequent versions of android. " + << "Continuing anyway."; } - // The verifier should have caught the non-public method. - DCHECK(current_method->IsPublic()) << "Interface method is not public!"; if (UNLIKELY(chosen_iface.Get() != nullptr)) { // We have multiple default impls of the same method. This is a potential default conflict. // We need to check if this possibly conflicting method is either a superclass of the chosen diff --git a/runtime/class_table-inl.h b/runtime/class_table-inl.h index e512906507..42e320ae71 100644 --- a/runtime/class_table-inl.h +++ b/runtime/class_table-inl.h @@ -23,6 +23,7 @@ namespace art { template<class Visitor> void ClassTable::VisitRoots(Visitor& visitor) { + ReaderMutexLock mu(Thread::Current(), lock_); for (ClassSet& class_set : classes_) { for (GcRoot<mirror::Class>& root : class_set) { visitor.VisitRoot(root.AddressWithoutBarrier()); @@ -35,6 +36,7 @@ void ClassTable::VisitRoots(Visitor& visitor) { template<class Visitor> void ClassTable::VisitRoots(const Visitor& visitor) { + ReaderMutexLock mu(Thread::Current(), lock_); for (ClassSet& class_set : classes_) { for (GcRoot<mirror::Class>& root : class_set) { visitor.VisitRoot(root.AddressWithoutBarrier()); @@ -47,6 +49,7 @@ void ClassTable::VisitRoots(const Visitor& visitor) { template <typename Visitor> bool ClassTable::Visit(Visitor& visitor) { + ReaderMutexLock mu(Thread::Current(), lock_); for (ClassSet& class_set : classes_) { for (GcRoot<mirror::Class>& root : class_set) { if (!visitor(root.Read())) { diff --git a/runtime/class_table.cc b/runtime/class_table.cc index d815b1a7a3..8267c68b29 100644 --- a/runtime/class_table.cc +++ b/runtime/class_table.cc @@ -20,17 +20,19 @@ namespace art { -ClassTable::ClassTable() { +ClassTable::ClassTable() : lock_("Class loader classes", kClassLoaderClassesLock) { Runtime* const runtime = Runtime::Current(); classes_.push_back(ClassSet(runtime->GetHashTableMinLoadFactor(), runtime->GetHashTableMaxLoadFactor())); } void ClassTable::FreezeSnapshot() { + WriterMutexLock mu(Thread::Current(), lock_); classes_.push_back(ClassSet()); } bool ClassTable::Contains(mirror::Class* klass) { + ReaderMutexLock mu(Thread::Current(), lock_); for (ClassSet& class_set : classes_) { auto it = class_set.Find(GcRoot<mirror::Class>(klass)); if (it != class_set.end()) { @@ -41,6 +43,7 @@ bool ClassTable::Contains(mirror::Class* klass) { } mirror::Class* ClassTable::LookupByDescriptor(mirror::Class* klass) { + ReaderMutexLock mu(Thread::Current(), lock_); for (ClassSet& class_set : classes_) { auto it = class_set.Find(GcRoot<mirror::Class>(klass)); if (it != class_set.end()) { @@ -51,6 +54,7 @@ mirror::Class* ClassTable::LookupByDescriptor(mirror::Class* klass) { } mirror::Class* ClassTable::UpdateClass(const char* descriptor, mirror::Class* klass, size_t hash) { + WriterMutexLock mu(Thread::Current(), lock_); // Should only be updating latest table. auto existing_it = classes_.back().FindWithHash(descriptor, hash); if (kIsDebugBuild && existing_it == classes_.back().end()) { @@ -74,6 +78,7 @@ mirror::Class* ClassTable::UpdateClass(const char* descriptor, mirror::Class* kl } size_t ClassTable::NumZygoteClasses() const { + ReaderMutexLock mu(Thread::Current(), lock_); size_t sum = 0; for (size_t i = 0; i < classes_.size() - 1; ++i) { sum += classes_[i].Size(); @@ -82,10 +87,12 @@ size_t ClassTable::NumZygoteClasses() const { } size_t ClassTable::NumNonZygoteClasses() const { + ReaderMutexLock mu(Thread::Current(), lock_); return classes_.back().Size(); } mirror::Class* ClassTable::Lookup(const char* descriptor, size_t hash) { + ReaderMutexLock mu(Thread::Current(), lock_); for (ClassSet& class_set : classes_) { auto it = class_set.FindWithHash(descriptor, hash); if (it != class_set.end()) { @@ -96,14 +103,17 @@ mirror::Class* ClassTable::Lookup(const char* descriptor, size_t hash) { } void ClassTable::Insert(mirror::Class* klass) { + WriterMutexLock mu(Thread::Current(), lock_); classes_.back().Insert(GcRoot<mirror::Class>(klass)); } void ClassTable::InsertWithHash(mirror::Class* klass, size_t hash) { + WriterMutexLock mu(Thread::Current(), lock_); classes_.back().InsertWithHash(GcRoot<mirror::Class>(klass), hash); } bool ClassTable::Remove(const char* descriptor) { + WriterMutexLock mu(Thread::Current(), lock_); for (ClassSet& class_set : classes_) { auto it = class_set.Find(descriptor); if (it != class_set.end()) { @@ -137,6 +147,7 @@ uint32_t ClassTable::ClassDescriptorHashEquals::operator()(const char* descripto } bool ClassTable::InsertDexFile(mirror::Object* dex_file) { + WriterMutexLock mu(Thread::Current(), lock_); DCHECK(dex_file != nullptr); for (GcRoot<mirror::Object>& root : dex_files_) { if (root.Read() == dex_file) { @@ -148,6 +159,7 @@ bool ClassTable::InsertDexFile(mirror::Object* dex_file) { } size_t ClassTable::WriteToMemory(uint8_t* ptr) const { + ReaderMutexLock mu(Thread::Current(), lock_); ClassSet combined; // Combine all the class sets in case there are multiple, also adjusts load factor back to // default in case classes were pruned. @@ -173,6 +185,7 @@ size_t ClassTable::ReadFromMemory(uint8_t* ptr) { } void ClassTable::AddClassSet(ClassSet&& set) { + WriterMutexLock mu(Thread::Current(), lock_); classes_.insert(classes_.begin(), std::move(set)); } diff --git a/runtime/class_table.h b/runtime/class_table.h index 0e0e860b4f..eb784b5c71 100644 --- a/runtime/class_table.h +++ b/runtime/class_table.h @@ -71,87 +71,96 @@ class ClassTable { // Used by image writer for checking. bool Contains(mirror::Class* klass) - REQUIRES(Locks::classlinker_classes_lock_) + REQUIRES(!lock_) SHARED_REQUIRES(Locks::mutator_lock_); // Freeze the current class tables by allocating a new table and never updating or modifying the // existing table. This helps prevents dirty pages after caused by inserting after zygote fork. void FreezeSnapshot() - REQUIRES(Locks::classlinker_classes_lock_) + REQUIRES(!lock_) SHARED_REQUIRES(Locks::mutator_lock_); // Returns the number of classes in previous snapshots. - size_t NumZygoteClasses() const SHARED_REQUIRES(Locks::classlinker_classes_lock_); + size_t NumZygoteClasses() const REQUIRES(!lock_); // Returns all off the classes in the lastest snapshot. - size_t NumNonZygoteClasses() const SHARED_REQUIRES(Locks::classlinker_classes_lock_); + size_t NumNonZygoteClasses() const REQUIRES(!lock_); // Update a class in the table with the new class. Returns the existing class which was replaced. mirror::Class* UpdateClass(const char* descriptor, mirror::Class* new_klass, size_t hash) - REQUIRES(Locks::classlinker_classes_lock_) + REQUIRES(!lock_) SHARED_REQUIRES(Locks::mutator_lock_); // NO_THREAD_SAFETY_ANALYSIS for object marking requiring heap bitmap lock. template<class Visitor> void VisitRoots(Visitor& visitor) NO_THREAD_SAFETY_ANALYSIS - SHARED_REQUIRES(Locks::classlinker_classes_lock_, Locks::mutator_lock_); + REQUIRES(!lock_) + SHARED_REQUIRES(Locks::mutator_lock_); + template<class Visitor> void VisitRoots(const Visitor& visitor) NO_THREAD_SAFETY_ANALYSIS - SHARED_REQUIRES(Locks::classlinker_classes_lock_, Locks::mutator_lock_); + REQUIRES(!lock_) + SHARED_REQUIRES(Locks::mutator_lock_); // Stops visit if the visitor returns false. template <typename Visitor> bool Visit(Visitor& visitor) - SHARED_REQUIRES(Locks::classlinker_classes_lock_, Locks::mutator_lock_); + REQUIRES(!lock_) + SHARED_REQUIRES(Locks::mutator_lock_); // Return the first class that matches the descriptor. Returns null if there are none. mirror::Class* Lookup(const char* descriptor, size_t hash) - SHARED_REQUIRES(Locks::classlinker_classes_lock_, Locks::mutator_lock_); + REQUIRES(!lock_) + SHARED_REQUIRES(Locks::mutator_lock_); // Return the first class that matches the descriptor of klass. Returns null if there are none. mirror::Class* LookupByDescriptor(mirror::Class* klass) - SHARED_REQUIRES(Locks::classlinker_classes_lock_, Locks::mutator_lock_); + REQUIRES(!lock_) + SHARED_REQUIRES(Locks::mutator_lock_); void Insert(mirror::Class* klass) - REQUIRES(Locks::classlinker_classes_lock_) + REQUIRES(!lock_) SHARED_REQUIRES(Locks::mutator_lock_); + void InsertWithHash(mirror::Class* klass, size_t hash) - REQUIRES(Locks::classlinker_classes_lock_) + REQUIRES(!lock_) SHARED_REQUIRES(Locks::mutator_lock_); // Returns true if the class was found and removed, false otherwise. bool Remove(const char* descriptor) - REQUIRES(Locks::classlinker_classes_lock_) + REQUIRES(!lock_) SHARED_REQUIRES(Locks::mutator_lock_); // Return true if we inserted the dex file, false if it already exists. bool InsertDexFile(mirror::Object* dex_file) - REQUIRES(Locks::classlinker_classes_lock_) + REQUIRES(!lock_) SHARED_REQUIRES(Locks::mutator_lock_); // Combines all of the tables into one class set. size_t WriteToMemory(uint8_t* ptr) const - SHARED_REQUIRES(Locks::classlinker_classes_lock_, Locks::mutator_lock_); + REQUIRES(!lock_) + SHARED_REQUIRES(Locks::mutator_lock_); // Read a table from ptr and put it at the front of the class set. size_t ReadFromMemory(uint8_t* ptr) - REQUIRES(Locks::classlinker_classes_lock_) + REQUIRES(!lock_) SHARED_REQUIRES(Locks::mutator_lock_); // Add a class set to the front of classes. void AddClassSet(ClassSet&& set) - REQUIRES(Locks::classlinker_classes_lock_) + REQUIRES(!lock_) SHARED_REQUIRES(Locks::mutator_lock_); private: - // TODO: shard lock to have one per class loader. + // Lock to guard inserting and removing. + mutable ReaderWriterMutex lock_; // We have a vector to help prevent dirty pages after the zygote forks by calling FreezeSnapshot. - std::vector<ClassSet> classes_ GUARDED_BY(Locks::classlinker_classes_lock_); + std::vector<ClassSet> classes_ GUARDED_BY(lock_); // Dex files used by the class loader which may not be owned by the class loader. We keep these // live so that we do not have issues closing any of the dex files. - std::vector<GcRoot<mirror::Object>> dex_files_ GUARDED_BY(Locks::classlinker_classes_lock_); + std::vector<GcRoot<mirror::Object>> dex_files_ GUARDED_BY(lock_); }; } // namespace art diff --git a/runtime/dex_file.cc b/runtime/dex_file.cc index e63eaa2715..63f3f08bad 100644 --- a/runtime/dex_file.cc +++ b/runtime/dex_file.cc @@ -1351,6 +1351,17 @@ mirror::ObjectArray<mirror::Object>* DexFile::GetParameterAnnotations(ArtMethod* return ProcessAnnotationSetRefList(method_class, set_ref_list, size); } +mirror::ObjectArray<mirror::String>* DexFile::GetSignatureAnnotationForMethod(ArtMethod* method) + const { + const AnnotationSetItem* annotation_set = FindAnnotationSetForMethod(method); + if (annotation_set == nullptr) { + return nullptr; + } + StackHandleScope<1> hs(Thread::Current()); + Handle<mirror::Class> method_class(hs.NewHandle(method->GetDeclaringClass())); + return GetSignatureValue(method_class, annotation_set); +} + bool DexFile::IsMethodAnnotationPresent(ArtMethod* method, Handle<mirror::Class> annotation_class) const { const AnnotationSetItem* annotation_set = FindAnnotationSetForMethod(method); @@ -1548,6 +1559,15 @@ bool DexFile::GetInnerClassFlags(Handle<mirror::Class> klass, uint32_t* flags) c return true; } +mirror::ObjectArray<mirror::String>* DexFile::GetSignatureAnnotationForClass( + Handle<mirror::Class> klass) const { + const AnnotationSetItem* annotation_set = FindAnnotationSetForClass(klass); + if (annotation_set == nullptr) { + return nullptr; + } + return GetSignatureValue(klass, annotation_set); +} + bool DexFile::IsClassAnnotationPresent(Handle<mirror::Class> klass, Handle<mirror::Class> annotation_class) const { const AnnotationSetItem* annotation_set = FindAnnotationSetForClass(klass); diff --git a/runtime/dex_file.h b/runtime/dex_file.h index 1456636c3c..3a28422067 100644 --- a/runtime/dex_file.h +++ b/runtime/dex_file.h @@ -991,6 +991,8 @@ class DexFile { SHARED_REQUIRES(Locks::mutator_lock_); mirror::ObjectArray<mirror::Object>* GetParameterAnnotations(ArtMethod* method) const SHARED_REQUIRES(Locks::mutator_lock_); + mirror::ObjectArray<mirror::String>* GetSignatureAnnotationForMethod(ArtMethod* method) const + SHARED_REQUIRES(Locks::mutator_lock_); bool IsMethodAnnotationPresent(ArtMethod* method, Handle<mirror::Class> annotation_class) const SHARED_REQUIRES(Locks::mutator_lock_); @@ -1013,6 +1015,8 @@ class DexFile { SHARED_REQUIRES(Locks::mutator_lock_); bool GetInnerClassFlags(Handle<mirror::Class> klass, uint32_t* flags) const SHARED_REQUIRES(Locks::mutator_lock_); + mirror::ObjectArray<mirror::String>* GetSignatureAnnotationForClass(Handle<mirror::Class> klass) + const SHARED_REQUIRES(Locks::mutator_lock_); bool IsClassAnnotationPresent(Handle<mirror::Class> klass, Handle<mirror::Class> annotation_class) const SHARED_REQUIRES(Locks::mutator_lock_); diff --git a/runtime/dex_file_verifier.cc b/runtime/dex_file_verifier.cc index 811e76300a..681c5f977f 100644 --- a/runtime/dex_file_verifier.cc +++ b/runtime/dex_file_verifier.cc @@ -2626,6 +2626,23 @@ bool DexFileVerifier::CheckMethodAccessFlags(uint32_t method_index, // From here on out it is easier to mask out the bits we're supposed to ignore. method_access_flags &= kMethodAccessFlags; + // Interfaces are special. + if ((class_access_flags & kAccInterface) != 0) { + // Non-static interface methods must be public. + if ((method_access_flags & (kAccPublic | kAccStatic)) == 0) { + *error_msg = StringPrintf("Interface virtual method %" PRIu32 "(%s) is not public", + method_index, + GetMethodDescriptionOrError(begin_, header_, method_index).c_str()); + if (header_->GetVersion() >= 37) { + return false; + } else { + // Allow in older versions, but warn. + LOG(WARNING) << "This dex file is invalid and will be rejected in the future. Error is: " + << *error_msg; + } + } + } + // If there aren't any instructions, make sure that's expected. if (!has_code) { // Only native or abstract methods may not have code. @@ -2664,7 +2681,7 @@ bool DexFileVerifier::CheckMethodAccessFlags(uint32_t method_index, } // Interfaces are special. if ((class_access_flags & kAccInterface) != 0) { - // Interface methods must be public and abstract. + // Interface methods without code must be abstract. if ((method_access_flags & (kAccPublic | kAccAbstract)) != (kAccPublic | kAccAbstract)) { *error_msg = StringPrintf("Interface method %" PRIu32 "(%s) is not public and abstract", method_index, diff --git a/runtime/dex_file_verifier_test.cc b/runtime/dex_file_verifier_test.cc index 4a5ed5d713..344d186ad4 100644 --- a/runtime/dex_file_verifier_test.cc +++ b/runtime/dex_file_verifier_test.cc @@ -767,7 +767,7 @@ TEST_F(DexFileVerifierTest, MethodAccessFlagsInterfaces) { ApplyMaskToMethodFlags(dex_file, "foo", ~kAccPublic); }, - "Interface method 1(LInterfaceMethodFlags;.foo) is not public and abstract"); + "Interface virtual method 1(LInterfaceMethodFlags;.foo) is not public"); VerifyModification( kMethodFlagsInterface, @@ -817,7 +817,7 @@ TEST_F(DexFileVerifierTest, MethodAccessFlagsInterfaces) { ApplyMaskToMethodFlags(dex_file, "foo", ~kAccPublic); }, - "Interface method 1(LInterfaceMethodFlags;.foo) is not public and abstract"); + "Interface virtual method 1(LInterfaceMethodFlags;.foo) is not public"); VerifyModification( kMethodFlagsInterface, @@ -839,7 +839,7 @@ TEST_F(DexFileVerifierTest, MethodAccessFlagsInterfaces) { ApplyMaskToMethodFlags(dex_file, "foo", ~kAccPublic); OrMaskToMethodFlags(dex_file, "foo", kAccProtected); }, - "Interface method 1(LInterfaceMethodFlags;.foo) is not public and abstract"); + "Interface virtual method 1(LInterfaceMethodFlags;.foo) is not public"); constexpr uint32_t kAllMethodFlags = kAccPublic | diff --git a/runtime/entrypoints/entrypoint_utils.cc b/runtime/entrypoints/entrypoint_utils.cc index e46576e884..197caa1878 100644 --- a/runtime/entrypoints/entrypoint_utils.cc +++ b/runtime/entrypoints/entrypoint_utils.cc @@ -272,19 +272,19 @@ ArtMethod* GetCalleeSaveMethodCaller(ArtMethod** sp, if (LIKELY(caller_pc != reinterpret_cast<uintptr_t>(GetQuickInstrumentationExitPc()))) { if (outer_method != nullptr) { const OatQuickMethodHeader* current_code = outer_method->GetOatQuickMethodHeader(caller_pc); - if (current_code->IsOptimized()) { - uintptr_t native_pc_offset = current_code->NativeQuickPcOffset(caller_pc); - CodeInfo code_info = current_code->GetOptimizedCodeInfo(); - CodeInfoEncoding encoding = code_info.ExtractEncoding(); - StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset, encoding); - DCHECK(stack_map.IsValid()); - if (stack_map.HasInlineInfo(encoding.stack_map_encoding)) { - InlineInfo inline_info = code_info.GetInlineInfoOf(stack_map, encoding); - caller = GetResolvedMethod(outer_method, - inline_info, - encoding.inline_info_encoding, - inline_info.GetDepth(encoding.inline_info_encoding) - 1); - } + DCHECK(current_code != nullptr); + DCHECK(current_code->IsOptimized()); + uintptr_t native_pc_offset = current_code->NativeQuickPcOffset(caller_pc); + CodeInfo code_info = current_code->GetOptimizedCodeInfo(); + CodeInfoEncoding encoding = code_info.ExtractEncoding(); + StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset, encoding); + DCHECK(stack_map.IsValid()); + if (stack_map.HasInlineInfo(encoding.stack_map_encoding)) { + InlineInfo inline_info = code_info.GetInlineInfoOf(stack_map, encoding); + caller = GetResolvedMethod(outer_method, + inline_info, + encoding.inline_info_encoding, + inline_info.GetDepth(encoding.inline_info_encoding) - 1); } } if (kIsDebugBuild && do_caller_check) { diff --git a/runtime/gc/accounting/mod_union_table.cc b/runtime/gc/accounting/mod_union_table.cc index d16afd947e..4e40aea585 100644 --- a/runtime/gc/accounting/mod_union_table.cc +++ b/runtime/gc/accounting/mod_union_table.cc @@ -210,7 +210,11 @@ class AddToReferenceArrayVisitor { if (mod_union_table_->ShouldAddReference(root->AsMirrorPtr())) { *has_target_reference_ = true; // TODO: Add MarkCompressedReference callback here. - root->Assign(visitor_->MarkObject(root->AsMirrorPtr())); + mirror::Object* old_ref = root->AsMirrorPtr(); + mirror::Object* new_ref = visitor_->MarkObject(old_ref); + if (old_ref != new_ref) { + root->Assign(new_ref); + } } } diff --git a/runtime/gc/collector/mark_sweep.h b/runtime/gc/collector/mark_sweep.h index b61bef7317..c19107a626 100644 --- a/runtime/gc/collector/mark_sweep.h +++ b/runtime/gc/collector/mark_sweep.h @@ -231,7 +231,7 @@ class MarkSweep : public GarbageCollector { protected: // Returns object if the object is marked in the heap bitmap, otherwise null. virtual mirror::Object* IsMarked(mirror::Object* object) OVERRIDE - SHARED_REQUIRES(Locks::heap_bitmap_lock_); + SHARED_REQUIRES(Locks::heap_bitmap_lock_, Locks::mutator_lock_); void MarkObjectNonNull(mirror::Object* obj, mirror::Object* holder = nullptr, diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc index 01db90a401..c2f772f876 100644 --- a/runtime/gc/heap.cc +++ b/runtime/gc/heap.cc @@ -1304,6 +1304,13 @@ space::Space* Heap::FindSpaceFromObject(const mirror::Object* obj, bool fail_ok) } void Heap::ThrowOutOfMemoryError(Thread* self, size_t byte_count, AllocatorType allocator_type) { + // If we're in a stack overflow, do not create a new exception. It would require running the + // constructor, which will of course still be in a stack overflow. + if (self->IsHandlingStackOverflow()) { + self->SetException(Runtime::Current()->GetPreAllocatedOutOfMemoryError()); + return; + } + std::ostringstream oss; size_t total_bytes_free = GetFreeMemory(); oss << "Failed to allocate a " << byte_count << " byte allocation with " << total_bytes_free diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc index 22bf5f9358..a84b366687 100644 --- a/runtime/gc/space/image_space.cc +++ b/runtime/gc/space/image_space.cc @@ -407,7 +407,7 @@ ImageSpace* ImageSpace::CreateBootImage(const char* image_location, &is_global_cache); } - if (Runtime::Current()->IsZygote() && !secondary_image) { + if (is_zygote && !secondary_image) { MarkZygoteStart(image_isa, Runtime::Current()->GetZygoteMaxFailedBoots()); } @@ -444,7 +444,7 @@ ImageSpace* ImageSpace::CreateBootImage(const char* image_location, // Whether we can write to the cache. success = false; } else if (secondary_image) { - if (Runtime::Current()->IsZygote()) { + if (is_zygote) { // Secondary image is out of date. Clear cache and exit to let it retry from scratch. LOG(ERROR) << "Cannot patch secondary image '" << image_location << "', clearing dalvik_cache and restarting zygote."; @@ -503,7 +503,16 @@ ImageSpace* ImageSpace::CreateBootImage(const char* image_location, // descriptor (and the associated exclusive lock) to be released when // we leave Create. ScopedFlock image_lock; - image_lock.Init(image_filename->c_str(), error_msg); + // Should this be a RDWR lock? This is only a defensive measure, as at + // this point the image should exist. + // However, only the zygote can write into the global dalvik-cache, so + // restrict to zygote processes, or any process that isn't using + // /data/dalvik-cache (which we assume to be allowed to write there). + const bool rw_lock = is_zygote || !is_global_cache; + image_lock.Init(image_filename->c_str(), + rw_lock ? (O_CREAT | O_RDWR) : O_RDONLY /* flags */, + true /* block */, + error_msg); VLOG(startup) << "Using image file " << image_filename->c_str() << " for image location " << image_location; // If we are in /system we can assume the image is good. We can also diff --git a/runtime/gc/space/image_space_fs.h b/runtime/gc/space/image_space_fs.h index 5237466c00..eac52f7027 100644 --- a/runtime/gc/space/image_space_fs.h +++ b/runtime/gc/space/image_space_fs.h @@ -62,7 +62,7 @@ static void DeleteDirectoryContents(const std::string& dir, bool recurse) { if (recurse) { DeleteDirectoryContents(file, recurse); // Try to rmdir the directory. - if (TEMP_FAILURE_RETRY(rmdir(file.c_str())) != 0) { + if (rmdir(file.c_str()) != 0) { PLOG(ERROR) << "Unable to rmdir " << file; } } @@ -71,12 +71,12 @@ static void DeleteDirectoryContents(const std::string& dir, bool recurse) { } } else { // Try to unlink the file. - if (TEMP_FAILURE_RETRY(unlink(file.c_str())) != 0) { + if (unlink(file.c_str()) != 0) { PLOG(ERROR) << "Unable to unlink " << file; } } } - CHECK_EQ(0, TEMP_FAILURE_RETRY(closedir(c_dir))) << "Unable to close directory."; + CHECK_EQ(0, closedir(c_dir)) << "Unable to close directory."; } static bool HasContent(const char* dir) { @@ -95,10 +95,10 @@ static bool HasContent(const char* dir) { continue; } // Something here. - CHECK_EQ(0, TEMP_FAILURE_RETRY(closedir(c_dir))) << "Unable to close directory."; + CHECK_EQ(0, closedir(c_dir)) << "Unable to close directory."; return true; } - CHECK_EQ(0, TEMP_FAILURE_RETRY(closedir(c_dir))) << "Unable to close directory."; + CHECK_EQ(0, closedir(c_dir)) << "Unable to close directory."; return false; } @@ -115,7 +115,7 @@ static void DeleteEmptyDirectoriesUpTo(const std::string& dir, const char* stop_ } } if (OS::DirectoryExists(dir.c_str())) { - if (TEMP_FAILURE_RETRY(rmdir(dir.c_str())) != 0) { + if (rmdir(dir.c_str()) != 0) { PLOG(ERROR) << "Unable to rmdir " << dir; return; } @@ -136,7 +136,7 @@ static void MoveOTAArtifacts(const char* src, const char* trg) { return; } - if (TEMP_FAILURE_RETRY(rename(src, trg)) != 0) { + if (rename(src, trg) != 0) { PLOG(ERROR) << "Could not rename OTA cache " << src << " to target " << trg; } } diff --git a/runtime/gc_map.h b/runtime/gc_map.h deleted file mode 100644 index b4ccdd6d54..0000000000 --- a/runtime/gc_map.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (C) 2012 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_GC_MAP_H_ -#define ART_RUNTIME_GC_MAP_H_ - -#include <stdint.h> - -#include "base/logging.h" -#include "base/macros.h" - -namespace art { - -// Lightweight wrapper for native PC offset to reference bit maps. -class NativePcOffsetToReferenceMap { - public: - explicit NativePcOffsetToReferenceMap(const uint8_t* data) : data_(data) { - CHECK(data_ != nullptr); - } - - // The number of entries in the table. - size_t NumEntries() const { - return data_[2] | (data_[3] << 8); - } - - // Return address of bitmap encoding what are live references. - const uint8_t* GetBitMap(size_t index) const { - size_t entry_offset = index * EntryWidth(); - return &Table()[entry_offset + NativeOffsetWidth()]; - } - - // Get the native PC encoded in the table at the given index. - uintptr_t GetNativePcOffset(size_t index) const { - size_t entry_offset = index * EntryWidth(); - uintptr_t result = 0; - for (size_t i = 0; i < NativeOffsetWidth(); ++i) { - result |= Table()[entry_offset + i] << (i * 8); - } - return result; - } - - // Does the given offset have an entry? - bool HasEntry(uintptr_t native_pc_offset) { - for (size_t i = 0; i < NumEntries(); ++i) { - if (GetNativePcOffset(i) == native_pc_offset) { - return true; - } - } - return false; - } - - // Finds the bitmap associated with the native pc offset. - const uint8_t* FindBitMap(uintptr_t native_pc_offset) { - size_t num_entries = NumEntries(); - size_t index = Hash(native_pc_offset) % num_entries; - size_t misses = 0; - while (GetNativePcOffset(index) != native_pc_offset) { - index = (index + 1) % num_entries; - misses++; - DCHECK_LT(misses, num_entries) << "Failed to find offset: " << native_pc_offset; - } - return GetBitMap(index); - } - - static uint32_t Hash(uint32_t native_offset) { - uint32_t hash = native_offset; - hash ^= (hash >> 20) ^ (hash >> 12); - hash ^= (hash >> 7) ^ (hash >> 4); - return hash; - } - - // The number of bytes used to encode registers. - size_t RegWidth() const { - return (static_cast<size_t>(data_[0]) | (static_cast<size_t>(data_[1]) << 8)) >> 3; - } - - private: - // Skip the size information at the beginning of data. - const uint8_t* Table() const { - return data_ + 4; - } - - // Number of bytes used to encode a native offset. - size_t NativeOffsetWidth() const { - return data_[0] & 7; - } - - // The width of an entry in the table. - size_t EntryWidth() const { - return NativeOffsetWidth() + RegWidth(); - } - - const uint8_t* const data_; // The header and table data -}; - -} // namespace art - -#endif // ART_RUNTIME_GC_MAP_H_ diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc index a0c6bfbd83..34bc458575 100644 --- a/runtime/instrumentation.cc +++ b/runtime/instrumentation.cc @@ -80,7 +80,7 @@ Instrumentation::Instrumentation() have_exception_caught_listeners_(false), have_branch_listeners_(false), have_invoke_virtual_or_interface_listeners_(false), - deoptimized_methods_lock_("deoptimized methods lock"), + deoptimized_methods_lock_("deoptimized methods lock", kDeoptimizedMethodsLock), deoptimization_enabled_(false), interpreter_handler_table_(kMainHandlerTable), quick_alloc_entry_points_instrumentation_counter_(0), diff --git a/runtime/intern_table.cc b/runtime/intern_table.cc index 79f24a841b..eceb593e08 100644 --- a/runtime/intern_table.cc +++ b/runtime/intern_table.cc @@ -393,6 +393,10 @@ bool InternTable::StringHashEquals::operator()(const GcRoot<mirror::String>& a, size_t InternTable::Table::AddTableFromMemory(const uint8_t* ptr) { size_t read_count = 0; UnorderedSet set(ptr, /*make copy*/false, &read_count); + if (set.Empty()) { + // Avoid inserting empty sets. + return read_count; + } // TODO: Disable this for app images if app images have intern tables. static constexpr bool kCheckDuplicates = true; if (kCheckDuplicates) { @@ -400,7 +404,7 @@ size_t InternTable::Table::AddTableFromMemory(const uint8_t* ptr) { CHECK(Find(string.Read()) == nullptr) << "Already found " << string.Read()->ToModifiedUtf8(); } } - // Insert at the front since we insert into the back. + // Insert at the front since we add new interns into the back. tables_.insert(tables_.begin(), std::move(set)); return read_count; } diff --git a/runtime/interpreter/interpreter_goto_table_impl.cc b/runtime/interpreter/interpreter_goto_table_impl.cc index b55312fb00..12d6fdc00d 100644 --- a/runtime/interpreter/interpreter_goto_table_impl.cc +++ b/runtime/interpreter/interpreter_goto_table_impl.cc @@ -277,6 +277,7 @@ JValue ExecuteGotoImpl(Thread* self, const DexFile::CodeItem* code_item, ShadowF JValue result; self->AllowThreadSuspension(); HANDLE_MONITOR_CHECKS(); + instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation(); if (UNLIKELY(instrumentation->HasMethodExitListeners())) { instrumentation->MethodExitEvent(self, shadow_frame.GetThisObject(code_item->ins_size_), shadow_frame.GetMethod(), dex_pc, @@ -291,6 +292,7 @@ JValue ExecuteGotoImpl(Thread* self, const DexFile::CodeItem* code_item, ShadowF JValue result; self->AllowThreadSuspension(); HANDLE_MONITOR_CHECKS(); + instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation(); if (UNLIKELY(instrumentation->HasMethodExitListeners())) { instrumentation->MethodExitEvent(self, shadow_frame.GetThisObject(code_item->ins_size_), shadow_frame.GetMethod(), dex_pc, @@ -306,6 +308,7 @@ JValue ExecuteGotoImpl(Thread* self, const DexFile::CodeItem* code_item, ShadowF result.SetI(shadow_frame.GetVReg(inst->VRegA_11x(inst_data))); self->AllowThreadSuspension(); HANDLE_MONITOR_CHECKS(); + instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation(); if (UNLIKELY(instrumentation->HasMethodExitListeners())) { instrumentation->MethodExitEvent(self, shadow_frame.GetThisObject(code_item->ins_size_), shadow_frame.GetMethod(), dex_pc, @@ -320,6 +323,7 @@ JValue ExecuteGotoImpl(Thread* self, const DexFile::CodeItem* code_item, ShadowF result.SetJ(shadow_frame.GetVRegLong(inst->VRegA_11x(inst_data))); self->AllowThreadSuspension(); HANDLE_MONITOR_CHECKS(); + instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation(); if (UNLIKELY(instrumentation->HasMethodExitListeners())) { instrumentation->MethodExitEvent(self, shadow_frame.GetThisObject(code_item->ins_size_), shadow_frame.GetMethod(), dex_pc, @@ -355,6 +359,7 @@ JValue ExecuteGotoImpl(Thread* self, const DexFile::CodeItem* code_item, ShadowF } } result.SetL(obj_result); + instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation(); if (UNLIKELY(instrumentation->HasMethodExitListeners())) { instrumentation->MethodExitEvent(self, shadow_frame.GetThisObject(code_item->ins_size_), shadow_frame.GetMethod(), dex_pc, @@ -2553,6 +2558,7 @@ JValue ExecuteGotoImpl(Thread* self, const DexFile::CodeItem* code_item, ShadowF self->CheckSuspend(); UPDATE_HANDLER_TABLE(); } + instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation(); uint32_t found_dex_pc = FindNextInstructionFollowingException(self, shadow_frame, dex_pc, instrumentation); if (found_dex_pc == DexFile::kDexNoIndex) { diff --git a/runtime/interpreter/interpreter_switch_impl.cc b/runtime/interpreter/interpreter_switch_impl.cc index 0488dbf028..43889c6666 100644 --- a/runtime/interpreter/interpreter_switch_impl.cc +++ b/runtime/interpreter/interpreter_switch_impl.cc @@ -37,6 +37,7 @@ namespace interpreter { shadow_frame.GetLockCountData(). \ CheckAllMonitorsReleasedOrThrow<do_assignability_check>(self); \ if (interpret_one_instruction) { \ + /* Signal mterp to return to caller */ \ shadow_frame.SetDexPC(DexFile::kDexNoIndex); \ } \ return JValue(); /* Handled in caller. */ \ @@ -76,6 +77,10 @@ namespace interpreter { instrumentation->Branch(self, method, dex_pc, offset); \ JValue result; \ if (jit::Jit::MaybeDoOnStackReplacement(self, method, dex_pc, offset, &result)) { \ + if (interpret_one_instruction) { \ + /* OSR has completed execution of the method. Signal mterp to return to caller */ \ + shadow_frame.SetDexPC(DexFile::kDexNoIndex); \ + } \ return result; \ } \ } while (false) @@ -205,6 +210,7 @@ JValue ExecuteSwitchImpl(Thread* self, const DexFile::CodeItem* code_item, result); } if (interpret_one_instruction) { + /* Signal mterp to return to caller */ shadow_frame.SetDexPC(DexFile::kDexNoIndex); } return result; @@ -221,6 +227,7 @@ JValue ExecuteSwitchImpl(Thread* self, const DexFile::CodeItem* code_item, result); } if (interpret_one_instruction) { + /* Signal mterp to return to caller */ shadow_frame.SetDexPC(DexFile::kDexNoIndex); } return result; @@ -238,6 +245,7 @@ JValue ExecuteSwitchImpl(Thread* self, const DexFile::CodeItem* code_item, result); } if (interpret_one_instruction) { + /* Signal mterp to return to caller */ shadow_frame.SetDexPC(DexFile::kDexNoIndex); } return result; @@ -254,6 +262,7 @@ JValue ExecuteSwitchImpl(Thread* self, const DexFile::CodeItem* code_item, result); } if (interpret_one_instruction) { + /* Signal mterp to return to caller */ shadow_frame.SetDexPC(DexFile::kDexNoIndex); } return result; @@ -292,6 +301,7 @@ JValue ExecuteSwitchImpl(Thread* self, const DexFile::CodeItem* code_item, result); } if (interpret_one_instruction) { + /* Signal mterp to return to caller */ shadow_frame.SetDexPC(DexFile::kDexNoIndex); } return result; diff --git a/runtime/interpreter/unstarted_runtime.cc b/runtime/interpreter/unstarted_runtime.cc index 81be959cd5..4615ec9aa4 100644 --- a/runtime/interpreter/unstarted_runtime.cc +++ b/runtime/interpreter/unstarted_runtime.cc @@ -16,7 +16,11 @@ #include "unstarted_runtime.h" +#include <errno.h> +#include <stdlib.h> + #include <cmath> +#include <limits> #include <unordered_map> #include "ScopedLocalRef.h" @@ -282,6 +286,23 @@ void UnstartedRuntime::UnstartedClassGetDeclaredMethod( } } +// Special managed code cut-out to allow constructor lookup in a un-started runtime. +void UnstartedRuntime::UnstartedClassGetDeclaredConstructor( + Thread* self, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset) { + mirror::Class* klass = shadow_frame->GetVRegReference(arg_offset)->AsClass(); + if (klass == nullptr) { + ThrowNullPointerExceptionForMethodAccess(shadow_frame->GetMethod(), InvokeType::kVirtual); + return; + } + mirror::ObjectArray<mirror::Class>* args = + shadow_frame->GetVRegReference(arg_offset + 1)->AsObjectArray<mirror::Class>(); + if (Runtime::Current()->IsActiveTransaction()) { + result->SetL(mirror::Class::GetDeclaredConstructorInternal<true>(self, klass, args)); + } else { + result->SetL(mirror::Class::GetDeclaredConstructorInternal<false>(self, klass, args)); + } +} + void UnstartedRuntime::UnstartedClassGetEnclosingClass( Thread* self, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset) { StackHandleScope<1> hs(self); @@ -427,6 +448,8 @@ void UnstartedRuntime::UnstartedSystemArraycopy( dst_pos, src, src_pos, length, true /* throw_exception */); } } + } else if (src_type->IsPrimitiveByte()) { + PrimitiveArrayCopy<uint8_t>(self, src_array, src_pos, dst_array, dst_pos, length); } else if (src_type->IsPrimitiveChar()) { PrimitiveArrayCopy<uint16_t>(self, src_array, src_pos, dst_array, dst_pos, length); } else if (src_type->IsPrimitiveInt()) { @@ -437,6 +460,12 @@ void UnstartedRuntime::UnstartedSystemArraycopy( } } +void UnstartedRuntime::UnstartedSystemArraycopyByte( + Thread* self, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset) { + // Just forward. + UnstartedRuntime::UnstartedSystemArraycopy(self, shadow_frame, result, arg_offset); +} + void UnstartedRuntime::UnstartedSystemArraycopyChar( Thread* self, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset) { // Just forward. @@ -1025,6 +1054,24 @@ void UnstartedRuntime::UnstartedUnsafeGetObjectVolatile( result->SetL(value); } +void UnstartedRuntime::UnstartedUnsafePutObjectVolatile( + Thread* self, ShadowFrame* shadow_frame, JValue* result ATTRIBUTE_UNUSED, size_t arg_offset) + SHARED_REQUIRES(Locks::mutator_lock_) { + // Argument 0 is the Unsafe instance, skip. + mirror::Object* obj = shadow_frame->GetVRegReference(arg_offset + 1); + if (obj == nullptr) { + AbortTransactionOrFail(self, "Cannot access null object, retry at runtime."); + return; + } + int64_t offset = shadow_frame->GetVRegLong(arg_offset + 2); + mirror::Object* value = shadow_frame->GetVRegReference(arg_offset + 4); + if (Runtime::Current()->IsActiveTransaction()) { + obj->SetFieldObjectVolatile<true>(MemberOffset(offset), value); + } else { + obj->SetFieldObjectVolatile<false>(MemberOffset(offset), value); + } +} + void UnstartedRuntime::UnstartedUnsafePutOrderedObject( Thread* self, ShadowFrame* shadow_frame, JValue* result ATTRIBUTE_UNUSED, size_t arg_offset) SHARED_REQUIRES(Locks::mutator_lock_) { @@ -1044,6 +1091,93 @@ void UnstartedRuntime::UnstartedUnsafePutOrderedObject( } } +// A cutout for Integer.parseInt(String). Note: this code is conservative and will bail instead +// of correctly handling the corner cases. +void UnstartedRuntime::UnstartedIntegerParseInt( + Thread* self, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset) + SHARED_REQUIRES(Locks::mutator_lock_) { + mirror::Object* obj = shadow_frame->GetVRegReference(arg_offset); + if (obj == nullptr) { + AbortTransactionOrFail(self, "Cannot parse null string, retry at runtime."); + return; + } + + std::string string_value = obj->AsString()->ToModifiedUtf8(); + if (string_value.empty()) { + AbortTransactionOrFail(self, "Cannot parse empty string, retry at runtime."); + return; + } + + const char* c_str = string_value.c_str(); + char *end; + // Can we set errno to 0? Is this always a variable, and not a macro? + // Worst case, we'll incorrectly fail a transaction. Seems OK. + int64_t l = strtol(c_str, &end, 10); + + if ((errno == ERANGE && l == LONG_MAX) || l > std::numeric_limits<int32_t>::max() || + (errno == ERANGE && l == LONG_MIN) || l < std::numeric_limits<int32_t>::min()) { + AbortTransactionOrFail(self, "Cannot parse string %s, retry at runtime.", c_str); + return; + } + if (l == 0) { + // Check whether the string wasn't exactly zero. + if (string_value != "0") { + AbortTransactionOrFail(self, "Cannot parse string %s, retry at runtime.", c_str); + return; + } + } else if (*end != '\0') { + AbortTransactionOrFail(self, "Cannot parse string %s, retry at runtime.", c_str); + return; + } + + result->SetI(static_cast<int32_t>(l)); +} + +// A cutout for Long.parseLong. +// +// Note: for now use code equivalent to Integer.parseInt, as the full range may not be supported +// well. +void UnstartedRuntime::UnstartedLongParseLong( + Thread* self, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset) + SHARED_REQUIRES(Locks::mutator_lock_) { + mirror::Object* obj = shadow_frame->GetVRegReference(arg_offset); + if (obj == nullptr) { + AbortTransactionOrFail(self, "Cannot parse null string, retry at runtime."); + return; + } + + std::string string_value = obj->AsString()->ToModifiedUtf8(); + if (string_value.empty()) { + AbortTransactionOrFail(self, "Cannot parse empty string, retry at runtime."); + return; + } + + const char* c_str = string_value.c_str(); + char *end; + // Can we set errno to 0? Is this always a variable, and not a macro? + // Worst case, we'll incorrectly fail a transaction. Seems OK. + int64_t l = strtol(c_str, &end, 10); + + // Note: comparing against int32_t min/max is intentional here. + if ((errno == ERANGE && l == LONG_MAX) || l > std::numeric_limits<int32_t>::max() || + (errno == ERANGE && l == LONG_MIN) || l < std::numeric_limits<int32_t>::min()) { + AbortTransactionOrFail(self, "Cannot parse string %s, retry at runtime.", c_str); + return; + } + if (l == 0) { + // Check whether the string wasn't exactly zero. + if (string_value != "0") { + AbortTransactionOrFail(self, "Cannot parse string %s, retry at runtime.", c_str); + return; + } + } else if (*end != '\0') { + AbortTransactionOrFail(self, "Cannot parse string %s, retry at runtime.", c_str); + return; + } + + result->SetJ(l); +} + void UnstartedRuntime::UnstartedJNIVMRuntimeNewUnpaddedArray( Thread* self, ArtMethod* method ATTRIBUTE_UNUSED, mirror::Object* receiver ATTRIBUTE_UNUSED, diff --git a/runtime/interpreter/unstarted_runtime_list.h b/runtime/interpreter/unstarted_runtime_list.h index d669b757d2..a3ed5581f0 100644 --- a/runtime/interpreter/unstarted_runtime_list.h +++ b/runtime/interpreter/unstarted_runtime_list.h @@ -25,10 +25,12 @@ V(ClassNewInstance, "java.lang.Object java.lang.Class.newInstance()") \ V(ClassGetDeclaredField, "java.lang.reflect.Field java.lang.Class.getDeclaredField(java.lang.String)") \ V(ClassGetDeclaredMethod, "java.lang.reflect.Method java.lang.Class.getDeclaredMethodInternal(java.lang.String, java.lang.Class[])") \ + V(ClassGetDeclaredConstructor, "java.lang.reflect.Constructor java.lang.Class.getDeclaredConstructorInternal(java.lang.Class[])") \ V(ClassGetEnclosingClass, "java.lang.Class java.lang.Class.getEnclosingClass()") \ V(VmClassLoaderFindLoadedClass, "java.lang.Class java.lang.VMClassLoader.findLoadedClass(java.lang.ClassLoader, java.lang.String)") \ V(VoidLookupType, "java.lang.Class java.lang.Void.lookupType()") \ V(SystemArraycopy, "void java.lang.System.arraycopy(java.lang.Object, int, java.lang.Object, int, int)") \ + V(SystemArraycopyByte, "void java.lang.System.arraycopy(byte[], int, byte[], int, int)") \ V(SystemArraycopyChar, "void java.lang.System.arraycopy(char[], int, char[], int, int)") \ V(SystemArraycopyInt, "void java.lang.System.arraycopy(int[], int, int[], int, int)") \ V(SystemGetSecurityManager, "java.lang.SecurityManager java.lang.System.getSecurityManager()") \ @@ -55,7 +57,10 @@ V(UnsafeCompareAndSwapLong, "boolean sun.misc.Unsafe.compareAndSwapLong(java.lang.Object, long, long, long)") \ V(UnsafeCompareAndSwapObject, "boolean sun.misc.Unsafe.compareAndSwapObject(java.lang.Object, long, java.lang.Object, java.lang.Object)") \ V(UnsafeGetObjectVolatile, "java.lang.Object sun.misc.Unsafe.getObjectVolatile(java.lang.Object, long)") \ - V(UnsafePutOrderedObject, "void sun.misc.Unsafe.putOrderedObject(java.lang.Object, long, java.lang.Object)") + V(UnsafePutObjectVolatile, "void sun.misc.Unsafe.putObjectVolatile(java.lang.Object, long, java.lang.Object)") \ + V(UnsafePutOrderedObject, "void sun.misc.Unsafe.putOrderedObject(java.lang.Object, long, java.lang.Object)") \ + V(IntegerParseInt, "int java.lang.Integer.parseInt(java.lang.String)") \ + V(LongParseLong, "long java.lang.Long.parseLong(java.lang.String)") // Methods that are native. #define UNSTARTED_RUNTIME_JNI_LIST(V) \ diff --git a/runtime/interpreter/unstarted_runtime_test.cc b/runtime/interpreter/unstarted_runtime_test.cc index fb53b1d5ef..f40e4e34af 100644 --- a/runtime/interpreter/unstarted_runtime_test.cc +++ b/runtime/interpreter/unstarted_runtime_test.cc @@ -508,5 +508,100 @@ TEST_F(UnstartedRuntimeTest, SystemArrayCopyObjectArrayTest) { ShadowFrame::DeleteDeoptimizedFrame(tmp); } +TEST_F(UnstartedRuntimeTest, IntegerParseIntTest) { + Thread* self = Thread::Current(); + ScopedObjectAccess soa(self); + + ShadowFrame* tmp = ShadowFrame::CreateDeoptimizedFrame(10, nullptr, nullptr, 0); + + // Test string. Should be valid, and between minimal values of LONG_MIN and LONG_MAX (for all + // suffixes). + constexpr const char* test_string = "-2147483646"; + constexpr int32_t test_values[] = { + 6, + 46, + 646, + 3646, + 83646, + 483646, + 7483646, + 47483646, + 147483646, + 2147483646, + -2147483646 + }; + + static_assert(arraysize(test_values) == 11U, "test_values"); + CHECK_EQ(strlen(test_string), 11U); + + for (size_t i = 0; i <= 10; ++i) { + const char* test_value = &test_string[10 - i]; + + StackHandleScope<1> hs_str(self); + Handle<mirror::String> h_str( + hs_str.NewHandle(mirror::String::AllocFromModifiedUtf8(self, test_value))); + ASSERT_NE(h_str.Get(), nullptr); + ASSERT_FALSE(self->IsExceptionPending()); + + tmp->SetVRegReference(0, h_str.Get()); + + JValue result; + UnstartedIntegerParseInt(self, tmp, &result, 0); + + ASSERT_FALSE(self->IsExceptionPending()); + EXPECT_EQ(result.GetI(), test_values[i]); + } + + ShadowFrame::DeleteDeoptimizedFrame(tmp); +} + +// Right now the same as Integer.Parse +TEST_F(UnstartedRuntimeTest, LongParseLongTest) { + Thread* self = Thread::Current(); + ScopedObjectAccess soa(self); + + ShadowFrame* tmp = ShadowFrame::CreateDeoptimizedFrame(10, nullptr, nullptr, 0); + + // Test string. Should be valid, and between minimal values of LONG_MIN and LONG_MAX (for all + // suffixes). + constexpr const char* test_string = "-2147483646"; + constexpr int64_t test_values[] = { + 6, + 46, + 646, + 3646, + 83646, + 483646, + 7483646, + 47483646, + 147483646, + 2147483646, + -2147483646 + }; + + static_assert(arraysize(test_values) == 11U, "test_values"); + CHECK_EQ(strlen(test_string), 11U); + + for (size_t i = 0; i <= 10; ++i) { + const char* test_value = &test_string[10 - i]; + + StackHandleScope<1> hs_str(self); + Handle<mirror::String> h_str( + hs_str.NewHandle(mirror::String::AllocFromModifiedUtf8(self, test_value))); + ASSERT_NE(h_str.Get(), nullptr); + ASSERT_FALSE(self->IsExceptionPending()); + + tmp->SetVRegReference(0, h_str.Get()); + + JValue result; + UnstartedLongParseLong(self, tmp, &result, 0); + + ASSERT_FALSE(self->IsExceptionPending()); + EXPECT_EQ(result.GetJ(), test_values[i]); + } + + ShadowFrame::DeleteDeoptimizedFrame(tmp); +} + } // namespace interpreter } // namespace art diff --git a/runtime/jit/jit.cc b/runtime/jit/jit.cc index 73aaf0496e..025472792d 100644 --- a/runtime/jit/jit.cc +++ b/runtime/jit/jit.cc @@ -208,7 +208,7 @@ bool Jit::CompileMethod(ArtMethod* method, Thread* self, bool osr) { return false; } bool success = jit_compile_method_(jit_compiler_handle_, method_to_compile, self, osr); - code_cache_->DoneCompiling(method_to_compile, self); + code_cache_->DoneCompiling(method_to_compile, self, osr); return success; } diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc index 53d645ce29..820ae6acab 100644 --- a/runtime/jit/jit_code_cache.cc +++ b/runtime/jit/jit_code_cache.cc @@ -195,9 +195,7 @@ class ScopedCodeCacheWrite : ScopedTrace { uint8_t* JitCodeCache::CommitCode(Thread* self, ArtMethod* method, - const uint8_t* mapping_table, const uint8_t* vmap_table, - const uint8_t* gc_map, size_t frame_size_in_bytes, size_t core_spill_mask, size_t fp_spill_mask, @@ -206,9 +204,7 @@ uint8_t* JitCodeCache::CommitCode(Thread* self, bool osr) { uint8_t* result = CommitCodeInternal(self, method, - mapping_table, vmap_table, - gc_map, frame_size_in_bytes, core_spill_mask, fp_spill_mask, @@ -220,9 +216,7 @@ uint8_t* JitCodeCache::CommitCode(Thread* self, GarbageCollectCache(self); result = CommitCodeInternal(self, method, - mapping_table, vmap_table, - gc_map, frame_size_in_bytes, core_spill_mask, fp_spill_mask, @@ -254,8 +248,6 @@ void JitCodeCache::FreeCode(const void* code_ptr, ArtMethod* method ATTRIBUTE_UN // It does nothing if we are not using native debugger. DeleteJITCodeEntryForAddress(reinterpret_cast<uintptr_t>(code_ptr)); - FreeData(const_cast<uint8_t*>(method_header->GetNativeGcMap())); - FreeData(const_cast<uint8_t*>(method_header->GetMappingTable())); // Use the offset directly to prevent sanity check that the method is // compiled with optimizing. // TODO(ngeoffray): Clean up. @@ -314,9 +306,7 @@ void JitCodeCache::ClearGcRootsInInlineCaches(Thread* self) { uint8_t* JitCodeCache::CommitCodeInternal(Thread* self, ArtMethod* method, - const uint8_t* mapping_table, const uint8_t* vmap_table, - const uint8_t* gc_map, size_t frame_size_in_bytes, size_t core_spill_mask, size_t fp_spill_mask, @@ -346,9 +336,7 @@ uint8_t* JitCodeCache::CommitCodeInternal(Thread* self, std::copy(code, code + code_size, code_ptr); method_header = OatQuickMethodHeader::FromCodePointer(code_ptr); new (method_header) OatQuickMethodHeader( - (mapping_table == nullptr) ? 0 : code_ptr - mapping_table, (vmap_table == nullptr) ? 0 : code_ptr - vmap_table, - (gc_map == nullptr) ? 0 : code_ptr - gc_map, frame_size_in_bytes, core_spill_mask, fp_spill_mask, @@ -939,12 +927,12 @@ bool JitCodeCache::NotifyCompilationOf(ArtMethod* method, Thread* self, bool osr return false; } - if (info->IsMethodBeingCompiled()) { + if (info->IsMethodBeingCompiled(osr)) { VLOG(jit) << PrettyMethod(method) << " is already being compiled"; return false; } - info->SetIsMethodBeingCompiled(true); + info->SetIsMethodBeingCompiled(true, osr); return true; } @@ -964,10 +952,10 @@ void JitCodeCache::DoneCompilerUse(ArtMethod* method, Thread* self) { info->DecrementInlineUse(); } -void JitCodeCache::DoneCompiling(ArtMethod* method, Thread* self ATTRIBUTE_UNUSED) { +void JitCodeCache::DoneCompiling(ArtMethod* method, Thread* self ATTRIBUTE_UNUSED, bool osr) { ProfilingInfo* info = method->GetProfilingInfo(sizeof(void*)); - DCHECK(info->IsMethodBeingCompiled()); - info->SetIsMethodBeingCompiled(false); + DCHECK(info->IsMethodBeingCompiled(osr)); + info->SetIsMethodBeingCompiled(false, osr); } size_t JitCodeCache::GetMemorySizeOfCodePointer(const void* ptr) { diff --git a/runtime/jit/jit_code_cache.h b/runtime/jit/jit_code_cache.h index a54f04faa4..9f18c700d4 100644 --- a/runtime/jit/jit_code_cache.h +++ b/runtime/jit/jit_code_cache.h @@ -80,7 +80,7 @@ class JitCodeCache { SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!lock_); - void DoneCompiling(ArtMethod* method, Thread* self) + void DoneCompiling(ArtMethod* method, Thread* self, bool osr) SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!lock_); @@ -91,9 +91,7 @@ class JitCodeCache { // Allocate and write code and its metadata to the code cache. uint8_t* CommitCode(Thread* self, ArtMethod* method, - const uint8_t* mapping_table, const uint8_t* vmap_table, - const uint8_t* gc_map, size_t frame_size_in_bytes, size_t core_spill_mask, size_t fp_spill_mask, @@ -201,9 +199,7 @@ class JitCodeCache { // allocation fails. Return null if the allocation fails. uint8_t* CommitCodeInternal(Thread* self, ArtMethod* method, - const uint8_t* mapping_table, const uint8_t* vmap_table, - const uint8_t* gc_map, size_t frame_size_in_bytes, size_t core_spill_mask, size_t fp_spill_mask, diff --git a/runtime/jit/profiling_info.h b/runtime/jit/profiling_info.h index 55d627ab48..3a71bbaec1 100644 --- a/runtime/jit/profiling_info.h +++ b/runtime/jit/profiling_info.h @@ -119,12 +119,18 @@ class ProfilingInfo { InlineCache* GetInlineCache(uint32_t dex_pc); - bool IsMethodBeingCompiled() const { - return is_method_being_compiled_; + bool IsMethodBeingCompiled(bool osr) const { + return osr + ? is_osr_method_being_compiled_ + : is_method_being_compiled_; } - void SetIsMethodBeingCompiled(bool value) { - is_method_being_compiled_ = value; + void SetIsMethodBeingCompiled(bool value, bool osr) { + if (osr) { + is_osr_method_being_compiled_ = value; + } else { + is_method_being_compiled_ = value; + } } void SetSavedEntryPoint(const void* entry_point) { @@ -155,7 +161,8 @@ class ProfilingInfo { } bool IsInUseByCompiler() const { - return IsMethodBeingCompiled() || (current_inline_uses_ > 0); + return IsMethodBeingCompiled(/*osr*/ true) || IsMethodBeingCompiled(/*osr*/ false) || + (current_inline_uses_ > 0); } private: @@ -181,6 +188,7 @@ class ProfilingInfo { // is implicitly guarded by the JIT code cache lock. // TODO: Make the JIT code cache lock global. bool is_method_being_compiled_; + bool is_osr_method_being_compiled_; // When the compiler inlines the method associated to this ProfilingInfo, // it updates this counter so that the GC does not try to clear the inline caches. diff --git a/runtime/mem_map.cc b/runtime/mem_map.cc index 421641ce39..5d89c21803 100644 --- a/runtime/mem_map.cc +++ b/runtime/mem_map.cc @@ -426,7 +426,9 @@ MemMap* MemMap::MapFileAtAddress(uint8_t* expected_ptr, if (error_msg != nullptr) { auto saved_errno = errno; - PrintFileToLog("/proc/self/maps", LogSeverity::WARNING); + if (kIsDebugBuild || VLOG_IS_ON(oat)) { + PrintFileToLog("/proc/self/maps", LogSeverity::WARNING); + } *error_msg = StringPrintf("mmap(%p, %zd, 0x%x, 0x%x, %d, %" PRId64 ") of file '%s' failed: %s. See process maps in the log.", diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc index 7900eac4e0..42f003dc84 100644 --- a/runtime/mirror/class.cc +++ b/runtime/mirror/class.cc @@ -880,9 +880,10 @@ mirror::Class* Class::GetCommonSuperClass(Handle<Class> klass) { DCHECK(!IsInterface()); mirror::Class* common_super_class = this; while (!common_super_class->IsAssignableFrom(klass.Get())) { - common_super_class = common_super_class->GetSuperClass(); + mirror::Class* old_common = common_super_class; + common_super_class = old_common->GetSuperClass(); + DCHECK(common_super_class != nullptr) << PrettyClass(old_common); } - DCHECK(common_super_class != nullptr); return common_super_class; } @@ -1023,8 +1024,8 @@ bool Class::ProxyDescriptorEquals(const char* match) { // TODO: Move this to java_lang_Class.cc? ArtMethod* Class::GetDeclaredConstructor( - Thread* self, Handle<mirror::ObjectArray<mirror::Class>> args) { - for (auto& m : GetDirectMethods(sizeof(void*))) { + Thread* self, Handle<mirror::ObjectArray<mirror::Class>> args, size_t pointer_size) { + for (auto& m : GetDirectMethods(pointer_size)) { // Skip <clinit> which is a static constructor, as well as non constructors. if (m.IsStatic() || !m.IsConstructor()) { continue; @@ -1138,5 +1139,31 @@ mirror::Method* Class::GetDeclaredMethodInternal<true>(Thread* self, mirror::String* name, mirror::ObjectArray<mirror::Class>* args); +template <bool kTransactionActive> +mirror::Constructor* Class::GetDeclaredConstructorInternal( + Thread* self, + mirror::Class* klass, + mirror::ObjectArray<mirror::Class>* args) { + StackHandleScope<1> hs(self); + const size_t pointer_size = kTransactionActive + ? Runtime::Current()->GetClassLinker()->GetImagePointerSize() + : sizeof(void*); + ArtMethod* result = klass->GetDeclaredConstructor(self, hs.NewHandle(args), pointer_size); + return result != nullptr + ? mirror::Constructor::CreateFromArtMethod<kTransactionActive>(self, result) + : nullptr; +} + +// mirror::Constructor::CreateFromArtMethod<kTransactionActive>(self, result) + +template mirror::Constructor* Class::GetDeclaredConstructorInternal<false>( + Thread* self, + mirror::Class* klass, + mirror::ObjectArray<mirror::Class>* args); +template mirror::Constructor* Class::GetDeclaredConstructorInternal<true>( + Thread* self, + mirror::Class* klass, + mirror::ObjectArray<mirror::Class>* args); + } // namespace mirror } // namespace art diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h index 7082c886aa..57c3590a2e 100644 --- a/runtime/mirror/class.h +++ b/runtime/mirror/class.h @@ -299,7 +299,9 @@ class MANAGED Class FINAL : public Object { // Mutually exclusive from whether or not each method is allowed to skip access checks. void SetVerificationAttempted() SHARED_REQUIRES(Locks::mutator_lock_) { uint32_t flags = GetField32(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_)); - SetAccessFlags(flags | kAccVerificationAttempted); + if ((flags & kAccVerificationAttempted) == 0) { + SetAccessFlags(flags | kAccVerificationAttempted); + } } template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> @@ -766,6 +768,11 @@ class MANAGED Class FINAL : public Object { mirror::String* name, mirror::ObjectArray<mirror::Class>* args) SHARED_REQUIRES(Locks::mutator_lock_); + template <bool kTransactionActive = false> + static Constructor* GetDeclaredConstructorInternal(Thread* self, + mirror::Class* klass, + mirror::ObjectArray<mirror::Class>* args) + SHARED_REQUIRES(Locks::mutator_lock_); template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> ALWAYS_INLINE ArraySlice<ArtMethod> GetDeclaredVirtualMethodsSlice(size_t pointer_size) @@ -1213,7 +1220,7 @@ class MANAGED Class FINAL : public Object { // May cause thread suspension due to EqualParameters. ArtMethod* GetDeclaredConstructor( - Thread* self, Handle<mirror::ObjectArray<mirror::Class>> args) + Thread* self, Handle<mirror::ObjectArray<mirror::Class>> args, size_t pointer_size) SHARED_REQUIRES(Locks::mutator_lock_); // Used to initialize a class in the allocation code path to ensure it is guarded by a StoreStore diff --git a/runtime/mirror/class_loader-inl.h b/runtime/mirror/class_loader-inl.h index 84fa80f023..cc910b035a 100644 --- a/runtime/mirror/class_loader-inl.h +++ b/runtime/mirror/class_loader-inl.h @@ -34,7 +34,6 @@ inline void ClassLoader::VisitReferences(mirror::Class* klass, const Visitor& vi VisitInstanceFieldsReferences<kVerifyFlags, kReadBarrierOption>(klass, visitor); if (kVisitClasses) { // Visit classes loaded after. - ReaderMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_); ClassTable* const class_table = GetClassTable(); if (class_table != nullptr) { class_table->VisitRoots(visitor); diff --git a/runtime/mirror/method.cc b/runtime/mirror/method.cc index 97973e6277..9838b71688 100644 --- a/runtime/mirror/method.cc +++ b/runtime/mirror/method.cc @@ -96,14 +96,18 @@ void Constructor::VisitRoots(RootVisitor* visitor) { array_class_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass)); } +template <bool kTransactionActive> Constructor* Constructor::CreateFromArtMethod(Thread* self, ArtMethod* method) { DCHECK(method->IsConstructor()) << PrettyMethod(method); auto* ret = down_cast<Constructor*>(StaticClass()->AllocObject(self)); if (LIKELY(ret != nullptr)) { - static_cast<AbstractMethod*>(ret)->CreateFromArtMethod(method); + static_cast<AbstractMethod*>(ret)->CreateFromArtMethod<kTransactionActive>(method); } return ret; } +template Constructor* Constructor::CreateFromArtMethod<false>(Thread* self, ArtMethod* method); +template Constructor* Constructor::CreateFromArtMethod<true>(Thread* self, ArtMethod* method); + } // namespace mirror } // namespace art diff --git a/runtime/mirror/method.h b/runtime/mirror/method.h index 12a72fe443..0b569640eb 100644 --- a/runtime/mirror/method.h +++ b/runtime/mirror/method.h @@ -60,6 +60,7 @@ class MANAGED Method : public AbstractMethod { // C++ mirror of java.lang.reflect.Constructor. class MANAGED Constructor: public AbstractMethod { public: + template <bool kTransactionActive = false> static Constructor* CreateFromArtMethod(Thread* self, ArtMethod* method) SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); diff --git a/runtime/native/java_lang_Class.cc b/runtime/native/java_lang_Class.cc index bf24de5284..c1899afc49 100644 --- a/runtime/native/java_lang_Class.cc +++ b/runtime/native/java_lang_Class.cc @@ -322,15 +322,11 @@ static jobject Class_getDeclaredField(JNIEnv* env, jobject javaThis, jstring nam static jobject Class_getDeclaredConstructorInternal( JNIEnv* env, jobject javaThis, jobjectArray args) { ScopedFastNativeObjectAccess soa(env); - auto* klass = DecodeClass(soa, javaThis); - auto* params = soa.Decode<mirror::ObjectArray<mirror::Class>*>(args); - StackHandleScope<1> hs(soa.Self()); - auto* declared_constructor = klass->GetDeclaredConstructor(soa.Self(), hs.NewHandle(params)); - if (declared_constructor != nullptr) { - return soa.AddLocalReference<jobject>( - mirror::Constructor::CreateFromArtMethod(soa.Self(), declared_constructor)); - } - return nullptr; + mirror::Constructor* result = mirror::Class::GetDeclaredConstructorInternal( + soa.Self(), + DecodeClass(soa, javaThis), + soa.Decode<mirror::ObjectArray<mirror::Class>*>(args)); + return soa.AddLocalReference<jobject>(result); } static ALWAYS_INLINE inline bool MethodMatchesConstructor(ArtMethod* m, bool public_only) @@ -545,6 +541,17 @@ static jstring Class_getInnerClassName(JNIEnv* env, jobject javaThis) { return soa.AddLocalReference<jstring>(class_name); } +static jobjectArray Class_getSignatureAnnotation(JNIEnv* env, jobject javaThis) { + ScopedFastNativeObjectAccess soa(env); + StackHandleScope<1> hs(soa.Self()); + Handle<mirror::Class> klass(hs.NewHandle(DecodeClass(soa, javaThis))); + if (klass->IsProxyClass() || klass->GetDexCache() == nullptr) { + return nullptr; + } + return soa.AddLocalReference<jobjectArray>( + klass->GetDexFile().GetSignatureAnnotationForClass(klass)); +} + static jboolean Class_isAnonymousClass(JNIEnv* env, jobject javaThis) { ScopedFastNativeObjectAccess soa(env); StackHandleScope<1> hs(soa.Self()); @@ -608,7 +615,8 @@ static jobject Class_newInstance(JNIEnv* env, jobject javaThis) { } auto* constructor = klass->GetDeclaredConstructor( soa.Self(), - ScopedNullHandle<mirror::ObjectArray<mirror::Class>>()); + ScopedNullHandle<mirror::ObjectArray<mirror::Class>>(), + sizeof(void*)); if (UNLIKELY(constructor == nullptr)) { soa.Self()->ThrowNewExceptionF("Ljava/lang/InstantiationException;", "%s has no zero argument constructor", @@ -692,6 +700,7 @@ static JNINativeMethod gMethods[] = { NATIVE_METHOD(Class, getNameNative, "!()Ljava/lang/String;"), NATIVE_METHOD(Class, getProxyInterfaces, "!()[Ljava/lang/Class;"), NATIVE_METHOD(Class, getPublicDeclaredFields, "!()[Ljava/lang/reflect/Field;"), + NATIVE_METHOD(Class, getSignatureAnnotation, "!()[Ljava/lang/String;"), NATIVE_METHOD(Class, isAnonymousClass, "!()Z"), NATIVE_METHOD(Class, isDeclaredAnnotationPresent, "!(Ljava/lang/Class;)Z"), NATIVE_METHOD(Class, newInstance, "!()Ljava/lang/Object;"), diff --git a/runtime/native/java_lang_reflect_AbstractMethod.cc b/runtime/native/java_lang_reflect_AbstractMethod.cc new file mode 100644 index 0000000000..7e11c11438 --- /dev/null +++ b/runtime/native/java_lang_reflect_AbstractMethod.cc @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2016 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. + */ + +#include "java_lang_reflect_AbstractMethod.h" + +#include "art_method-inl.h" +#include "jni_internal.h" +#include "mirror/class-inl.h" +#include "mirror/object-inl.h" +#include "mirror/object_array-inl.h" +#include "reflection.h" +#include "scoped_fast_native_object_access.h" +#include "well_known_classes.h" + +namespace art { + +static jobjectArray AbstractMethod_getDeclaredAnnotations(JNIEnv* env, jobject javaMethod) { + ScopedFastNativeObjectAccess soa(env); + ArtMethod* method = ArtMethod::FromReflectedMethod(soa, javaMethod); + if (method->GetDeclaringClass()->IsProxyClass()) { + // Return an empty array instead of a null pointer. + mirror::Class* annotation_array_class = + soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_annotation_Annotation__array); + mirror::ObjectArray<mirror::Object>* empty_array = + mirror::ObjectArray<mirror::Object>::Alloc(soa.Self(), annotation_array_class, 0); + return soa.AddLocalReference<jobjectArray>(empty_array); + } + return soa.AddLocalReference<jobjectArray>(method->GetDexFile()->GetAnnotationsForMethod(method)); +} + +static jobjectArray AbstractMethod_getSignatureAnnotation(JNIEnv* env, jobject javaMethod) { + ScopedFastNativeObjectAccess soa(env); + ArtMethod* method = ArtMethod::FromReflectedMethod(soa, javaMethod); + if (method->GetDeclaringClass()->IsProxyClass()) { + return nullptr; + } + StackHandleScope<1> hs(soa.Self()); + return soa.AddLocalReference<jobjectArray>( + method->GetDexFile()->GetSignatureAnnotationForMethod(method)); +} + + +static jboolean AbstractMethod_isAnnotationPresentNative(JNIEnv* env, jobject javaMethod, + jclass annotationType) { + ScopedFastNativeObjectAccess soa(env); + ArtMethod* method = ArtMethod::FromReflectedMethod(soa, javaMethod); + if (method->GetDeclaringClass()->IsProxyClass()) { + return false; + } + StackHandleScope<1> hs(soa.Self()); + Handle<mirror::Class> klass(hs.NewHandle(soa.Decode<mirror::Class*>(annotationType))); + return method->GetDexFile()->IsMethodAnnotationPresent(method, klass); +} + +static JNINativeMethod gMethods[] = { + NATIVE_METHOD(AbstractMethod, getDeclaredAnnotations, "!()[Ljava/lang/annotation/Annotation;"), + NATIVE_METHOD(AbstractMethod, getSignatureAnnotation, "!()[Ljava/lang/String;"), + NATIVE_METHOD(AbstractMethod, isAnnotationPresentNative, "!(Ljava/lang/Class;)Z"), +}; + +void register_java_lang_reflect_AbstractMethod(JNIEnv* env) { + REGISTER_NATIVE_METHODS("java/lang/reflect/AbstractMethod"); +} + +} // namespace art diff --git a/runtime/native/java_lang_reflect_AbstractMethod.h b/runtime/native/java_lang_reflect_AbstractMethod.h new file mode 100644 index 0000000000..222e5a05d0 --- /dev/null +++ b/runtime/native/java_lang_reflect_AbstractMethod.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2016 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_NATIVE_JAVA_LANG_REFLECT_ABSTRACTMETHOD_H_ +#define ART_RUNTIME_NATIVE_JAVA_LANG_REFLECT_ABSTRACTMETHOD_H_ + +#include <jni.h> + +namespace art { + +void register_java_lang_reflect_AbstractMethod(JNIEnv* env); + +} // namespace art + +#endif // ART_RUNTIME_NATIVE_JAVA_LANG_REFLECT_ABSTRACTMETHOD_H_ diff --git a/runtime/native/java_lang_reflect_Method.cc b/runtime/native/java_lang_reflect_Method.cc index d7cf62e994..78999c2865 100644 --- a/runtime/native/java_lang_reflect_Method.cc +++ b/runtime/native/java_lang_reflect_Method.cc @@ -41,20 +41,6 @@ static jobject Method_getAnnotationNative(JNIEnv* env, jobject javaMethod, jclas method->GetDexFile()->GetAnnotationForMethod(method, klass)); } -static jobjectArray Method_getDeclaredAnnotations(JNIEnv* env, jobject javaMethod) { - ScopedFastNativeObjectAccess soa(env); - ArtMethod* method = ArtMethod::FromReflectedMethod(soa, javaMethod); - if (method->GetDeclaringClass()->IsProxyClass()) { - // Return an empty array instead of a null pointer. - mirror::Class* annotation_array_class = - soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_annotation_Annotation__array); - mirror::ObjectArray<mirror::Object>* empty_array = - mirror::ObjectArray<mirror::Object>::Alloc(soa.Self(), annotation_array_class, 0); - return soa.AddLocalReference<jobjectArray>(empty_array); - } - return soa.AddLocalReference<jobjectArray>(method->GetDexFile()->GetAnnotationsForMethod(method)); -} - static jobject Method_getDefaultValue(JNIEnv* env, jobject javaMethod) { ScopedFastNativeObjectAccess soa(env); ArtMethod* method = ArtMethod::FromReflectedMethod(soa, javaMethod); @@ -116,27 +102,13 @@ static jobject Method_invoke(JNIEnv* env, jobject javaMethod, jobject javaReceiv return InvokeMethod(soa, javaMethod, javaReceiver, javaArgs); } -static jboolean Method_isAnnotationPresentNative(JNIEnv* env, jobject javaMethod, - jclass annotationType) { - ScopedFastNativeObjectAccess soa(env); - ArtMethod* method = ArtMethod::FromReflectedMethod(soa, javaMethod); - if (method->GetDeclaringClass()->IsProxyClass()) { - return false; - } - StackHandleScope<1> hs(soa.Self()); - Handle<mirror::Class> klass(hs.NewHandle(soa.Decode<mirror::Class*>(annotationType))); - return method->GetDexFile()->IsMethodAnnotationPresent(method, klass); -} - static JNINativeMethod gMethods[] = { NATIVE_METHOD(Method, getAnnotationNative, "!(Ljava/lang/Class;)Ljava/lang/annotation/Annotation;"), - NATIVE_METHOD(Method, getDeclaredAnnotations, "!()[Ljava/lang/annotation/Annotation;"), NATIVE_METHOD(Method, getDefaultValue, "!()Ljava/lang/Object;"), NATIVE_METHOD(Method, getExceptionTypes, "!()[Ljava/lang/Class;"), NATIVE_METHOD(Method, getParameterAnnotationsNative, "!()[[Ljava/lang/annotation/Annotation;"), NATIVE_METHOD(Method, invoke, "!(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;"), - NATIVE_METHOD(Method, isAnnotationPresentNative, "!(Ljava/lang/Class;)Z"), }; void register_java_lang_reflect_Method(JNIEnv* env) { diff --git a/runtime/oat.h b/runtime/oat.h index 469a65f2de..543d99f2ad 100644 --- a/runtime/oat.h +++ b/runtime/oat.h @@ -32,7 +32,7 @@ class InstructionSetFeatures; class PACKED(4) OatHeader { public: static constexpr uint8_t kOatMagic[] = { 'o', 'a', 't', '\n' }; - static constexpr uint8_t kOatVersion[] = { '0', '7', '8', '\0' }; + static constexpr uint8_t kOatVersion[] = { '0', '7', '9', '\0' }; static constexpr const char* kImageLocationKey = "image-location"; static constexpr const char* kDex2OatCmdLineKey = "dex2oat-cmdline"; diff --git a/runtime/oat_file-inl.h b/runtime/oat_file-inl.h index 7b92120fde..d7d0c4f733 100644 --- a/runtime/oat_file-inl.h +++ b/runtime/oat_file-inl.h @@ -71,44 +71,6 @@ inline uint32_t OatFile::OatMethod::GetFpSpillMask() const { return reinterpret_cast<const OatQuickMethodHeader*>(code)[-1].frame_info_.FpSpillMask(); } -inline const uint8_t* OatFile::OatMethod::GetGcMap() const { - const void* code = EntryPointToCodePointer(GetOatPointer<const void*>(code_offset_)); - if (code == nullptr) { - return nullptr; - } - uint32_t offset = reinterpret_cast<const OatQuickMethodHeader*>(code)[-1].gc_map_offset_; - if (UNLIKELY(offset == 0u)) { - return nullptr; - } - return reinterpret_cast<const uint8_t*>(code) - offset; -} - -inline uint32_t OatFile::OatMethod::GetGcMapOffset() const { - const uint8_t* gc_map = GetGcMap(); - return static_cast<uint32_t>(gc_map != nullptr ? gc_map - begin_ : 0u); -} - -inline uint32_t OatFile::OatMethod::GetGcMapOffsetOffset() const { - const OatQuickMethodHeader* method_header = GetOatQuickMethodHeader(); - if (method_header == nullptr) { - return 0u; - } - return reinterpret_cast<const uint8_t*>(&method_header->gc_map_offset_) - begin_; -} - -inline uint32_t OatFile::OatMethod::GetMappingTableOffset() const { - const uint8_t* mapping_table = GetMappingTable(); - return static_cast<uint32_t>(mapping_table != nullptr ? mapping_table - begin_ : 0u); -} - -inline uint32_t OatFile::OatMethod::GetMappingTableOffsetOffset() const { - const OatQuickMethodHeader* method_header = GetOatQuickMethodHeader(); - if (method_header == nullptr) { - return 0u; - } - return reinterpret_cast<const uint8_t*>(&method_header->mapping_table_offset_) - begin_; -} - inline uint32_t OatFile::OatMethod::GetVmapTableOffset() const { const uint8_t* vmap_table = GetVmapTable(); return static_cast<uint32_t>(vmap_table != nullptr ? vmap_table - begin_ : 0u); @@ -122,18 +84,6 @@ inline uint32_t OatFile::OatMethod::GetVmapTableOffsetOffset() const { return reinterpret_cast<const uint8_t*>(&method_header->vmap_table_offset_) - begin_; } -inline const uint8_t* OatFile::OatMethod::GetMappingTable() const { - const void* code = EntryPointToCodePointer(GetOatPointer<const void*>(code_offset_)); - if (code == nullptr) { - return nullptr; - } - uint32_t offset = reinterpret_cast<const OatQuickMethodHeader*>(code)[-1].mapping_table_offset_; - if (UNLIKELY(offset == 0u)) { - return nullptr; - } - return reinterpret_cast<const uint8_t*>(code) - offset; -} - inline const uint8_t* OatFile::OatMethod::GetVmapTable() const { const void* code = EntryPointToCodePointer(GetOatPointer<const void*>(code_offset_)); if (code == nullptr) { diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc index 7c83715ff5..ccb8b2970b 100644 --- a/runtime/oat_file.cc +++ b/runtime/oat_file.cc @@ -50,7 +50,6 @@ #include "type_lookup_table.h" #include "utils.h" #include "utils/dex_cache_arrays_layout-inl.h" -#include "vmap_table.h" namespace art { @@ -173,7 +172,7 @@ bool OatFileBase::ComputeFields(uint8_t* requested_base, } if (requested_base != nullptr && begin_ != requested_base) { // Host can fail this check. Do not dump there to avoid polluting the output. - if (kIsTargetBuild) { + if (kIsTargetBuild && (kIsDebugBuild || VLOG_IS_ON(oat))) { PrintFileToLog("/proc/self/maps", LogSeverity::WARNING); } *error_msg = StringPrintf("Failed to find oatdata symbol at expected address: " diff --git a/runtime/oat_file.h b/runtime/oat_file.h index 705ba0d976..11a9d76dad 100644 --- a/runtime/oat_file.h +++ b/runtime/oat_file.h @@ -123,18 +123,10 @@ class OatFile { uint32_t GetCoreSpillMask() const; uint32_t GetFpSpillMask() const; - const uint8_t* GetMappingTable() const; - uint32_t GetMappingTableOffset() const; - uint32_t GetMappingTableOffsetOffset() const; - const uint8_t* GetVmapTable() const; uint32_t GetVmapTableOffset() const; uint32_t GetVmapTableOffsetOffset() const; - const uint8_t* GetGcMap() const; - uint32_t GetGcMapOffset() const; - uint32_t GetGcMapOffsetOffset() const; - // Create an OatMethod with offsets relative to the given base address OatMethod(const uint8_t* base, const uint32_t code_offset) : begin_(base), code_offset_(code_offset) { diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc index ce892f354c..78e372ad02 100644 --- a/runtime/oat_file_assistant.cc +++ b/runtime/oat_file_assistant.cc @@ -77,7 +77,7 @@ OatFileAssistant::OatFileAssistant(const char* dex_location, OatFileAssistant::~OatFileAssistant() { // Clean up the lock file. if (flock_.HasFile()) { - TEMP_FAILURE_RETRY(unlink(flock_.GetFile()->GetPath().c_str())); + unlink(flock_.GetFile()->GetPath().c_str()); } } @@ -109,7 +109,7 @@ bool OatFileAssistant::Lock(std::string* error_msg) { std::string lock_file_name = *OatFileName() + ".flock"; if (!flock_.Init(lock_file_name.c_str(), error_msg)) { - TEMP_FAILURE_RETRY(unlink(lock_file_name.c_str())); + unlink(lock_file_name.c_str()); return false; } return true; @@ -495,7 +495,7 @@ bool OatFileAssistant::GivenOatFileIsOutOfDate(const OatFile& file) { return true; } - if (file.GetOatHeader().GetImageFileLocationOatChecksum() != image_info->oat_checksum) { + if (file.GetOatHeader().GetImageFileLocationOatChecksum() != GetCombinedImageChecksum()) { VLOG(oat) << "Oat image checksum does not match image checksum."; return true; } @@ -613,7 +613,7 @@ OatFileAssistant::RelocateOatFile(const std::string* input_file, std::string* er if (!Exec(argv, error_msg)) { // Manually delete the file. This ensures there is no garbage left over if // the process unexpectedly died. - TEMP_FAILURE_RETRY(unlink(oat_file_name.c_str())); + unlink(oat_file_name.c_str()); return kUpdateFailed; } @@ -673,13 +673,13 @@ OatFileAssistant::GenerateOatFile(CompilerFilter::Filter target, std::string* er // Manually delete the file. This ensures there is no garbage left over if // the process unexpectedly died. oat_file->Erase(); - TEMP_FAILURE_RETRY(unlink(oat_file_name.c_str())); + unlink(oat_file_name.c_str()); return kUpdateFailed; } if (oat_file->FlushCloseOrErase() != 0) { *error_msg = "Unable to close oat file " + oat_file_name; - TEMP_FAILURE_RETRY(unlink(oat_file_name.c_str())); + unlink(oat_file_name.c_str()); return kUpdateFailed; } @@ -931,8 +931,7 @@ const OatFileAssistant::ImageInfo* OatFileAssistant::GetImageInfo() { cached_image_info_.patch_delta = image_header.GetPatchDelta(); } else { std::unique_ptr<ImageHeader> image_header( - gc::space::ImageSpace::ReadImageHeaderOrDie( - cached_image_info_.location.c_str(), isa_)); + gc::space::ImageSpace::ReadImageHeaderOrDie(cached_image_info_.location.c_str(), isa_)); cached_image_info_.oat_checksum = image_header->GetOatChecksum(); cached_image_info_.oat_data_begin = reinterpret_cast<uintptr_t>( image_header->GetOatDataBegin()); @@ -940,10 +939,39 @@ const OatFileAssistant::ImageInfo* OatFileAssistant::GetImageInfo() { } } image_info_load_succeeded_ = (!image_spaces.empty()); + + combined_image_checksum_ = CalculateCombinedImageChecksum(isa_); } return image_info_load_succeeded_ ? &cached_image_info_ : nullptr; } +// TODO: Use something better than xor. +uint32_t OatFileAssistant::CalculateCombinedImageChecksum(InstructionSet isa) { + uint32_t checksum = 0; + std::vector<gc::space::ImageSpace*> image_spaces = + Runtime::Current()->GetHeap()->GetBootImageSpaces(); + if (isa == kRuntimeISA) { + for (gc::space::ImageSpace* image_space : image_spaces) { + checksum ^= image_space->GetImageHeader().GetOatChecksum(); + } + } else { + for (gc::space::ImageSpace* image_space : image_spaces) { + std::string location = image_space->GetImageLocation(); + std::unique_ptr<ImageHeader> image_header( + gc::space::ImageSpace::ReadImageHeaderOrDie(location.c_str(), isa)); + checksum ^= image_header->GetOatChecksum(); + } + } + return checksum; +} + +uint32_t OatFileAssistant::GetCombinedImageChecksum() { + if (!image_info_load_attempted_) { + GetImageInfo(); + } + return combined_image_checksum_; +} + gc::space::ImageSpace* OatFileAssistant::OpenImageSpace(const OatFile* oat_file) { DCHECK(oat_file != nullptr); std::string art_file = ArtFileName(oat_file); diff --git a/runtime/oat_file_assistant.h b/runtime/oat_file_assistant.h index 17f72febea..d3228deac7 100644 --- a/runtime/oat_file_assistant.h +++ b/runtime/oat_file_assistant.h @@ -279,6 +279,8 @@ class OatFileAssistant { static bool DexFilenameToOdexFilename(const std::string& location, InstructionSet isa, std::string* odex_filename, std::string* error_msg); + static uint32_t CalculateCombinedImageChecksum(InstructionSet isa = kRuntimeISA); + private: struct ImageInfo { uint32_t oat_checksum = 0; @@ -352,6 +354,8 @@ class OatFileAssistant { // The caller shouldn't clean up or free the returned pointer. const ImageInfo* GetImageInfo(); + uint32_t GetCombinedImageChecksum(); + // To implement Lock(), we lock a dummy file where the oat file would go // (adding ".flock" to the target file name) and retain the lock for the // remaining lifetime of the OatFileAssistant object. @@ -423,6 +427,7 @@ class OatFileAssistant { bool image_info_load_attempted_ = false; bool image_info_load_succeeded_ = false; ImageInfo cached_image_info_; + uint32_t combined_image_checksum_ = 0; // For debugging only. // If this flag is set, the oat or odex file has been released to the user diff --git a/runtime/oat_file_assistant_test.cc b/runtime/oat_file_assistant_test.cc index bddfa4f21a..f50d1cb748 100644 --- a/runtime/oat_file_assistant_test.cc +++ b/runtime/oat_file_assistant_test.cc @@ -239,7 +239,8 @@ class OatFileAssistantTest : public CommonRuntimeTest { ASSERT_TRUE(!image_spaces.empty() && image_spaces[0] != nullptr); const ImageHeader& image_header = image_spaces[0]->GetImageHeader(); const OatHeader& oat_header = odex_file->GetOatHeader(); - EXPECT_EQ(image_header.GetOatChecksum(), oat_header.GetImageFileLocationOatChecksum()); + uint32_t combined_checksum = OatFileAssistant::CalculateCombinedImageChecksum(); + EXPECT_EQ(combined_checksum, oat_header.GetImageFileLocationOatChecksum()); EXPECT_NE(reinterpret_cast<uintptr_t>(image_header.GetOatDataBegin()), oat_header.GetImageFileLocationOatDataBegin()); EXPECT_NE(image_header.GetPatchDelta(), oat_header.GetImagePatchDelta()); diff --git a/runtime/oat_quick_method_header.cc b/runtime/oat_quick_method_header.cc index 07a112fb7f..0ab2bfe80e 100644 --- a/runtime/oat_quick_method_header.cc +++ b/runtime/oat_quick_method_header.cc @@ -17,23 +17,18 @@ #include "oat_quick_method_header.h" #include "art_method.h" -#include "mapping_table.h" #include "scoped_thread_state_change.h" #include "thread.h" namespace art { OatQuickMethodHeader::OatQuickMethodHeader( - uint32_t mapping_table_offset, uint32_t vmap_table_offset, - uint32_t gc_map_offset, uint32_t frame_size_in_bytes, uint32_t core_spill_mask, uint32_t fp_spill_mask, uint32_t code_size) - : mapping_table_offset_(mapping_table_offset), - vmap_table_offset_(vmap_table_offset), - gc_map_offset_(gc_map_offset), + : vmap_table_offset_(vmap_table_offset), frame_info_(frame_size_in_bytes, core_spill_mask, fp_spill_mask), code_size_(code_size) {} @@ -52,28 +47,8 @@ uint32_t OatQuickMethodHeader::ToDexPc(ArtMethod* method, return stack_map.GetDexPc(encoding.stack_map_encoding); } } else { - MappingTable table(GetMappingTable()); - // NOTE: Special methods (see Mir2Lir::GenSpecialCase()) have an empty mapping - // but they have no suspend checks and, consequently, we never call ToDexPc() for them. - if (table.TotalSize() == 0) { - DCHECK(method->IsNative()); - return DexFile::kDexNoIndex; - } - - // Assume the caller wants a pc-to-dex mapping so check here first. - typedef MappingTable::PcToDexIterator It; - for (It cur = table.PcToDexBegin(), end = table.PcToDexEnd(); cur != end; ++cur) { - if (cur.NativePcOffset() == sought_offset) { - return cur.DexPc(); - } - } - // Now check dex-to-pc mappings. - typedef MappingTable::DexToPcIterator It2; - for (It2 cur = table.DexToPcBegin(), end = table.DexToPcEnd(); cur != end; ++cur) { - if (cur.NativePcOffset() == sought_offset) { - return cur.DexPc(); - } - } + DCHECK(method->IsNative()); + return DexFile::kDexNoIndex; } if (abort_on_failure) { ScopedObjectAccess soa(Thread::Current()); @@ -91,44 +66,22 @@ uintptr_t OatQuickMethodHeader::ToNativeQuickPc(ArtMethod* method, bool is_for_catch_handler, bool abort_on_failure) const { const void* entry_point = GetEntryPoint(); - if (IsOptimized()) { - // Optimized code does not have a mapping table. Search for the dex-to-pc - // mapping in stack maps. - CodeInfo code_info = GetOptimizedCodeInfo(); - CodeInfoEncoding encoding = code_info.ExtractEncoding(); + DCHECK(!method->IsNative()); + DCHECK(IsOptimized()); + // Search for the dex-to-pc mapping in stack maps. + CodeInfo code_info = GetOptimizedCodeInfo(); + CodeInfoEncoding encoding = code_info.ExtractEncoding(); - // All stack maps are stored in the same CodeItem section, safepoint stack - // maps first, then catch stack maps. We use `is_for_catch_handler` to select - // the order of iteration. - StackMap stack_map = - LIKELY(is_for_catch_handler) ? code_info.GetCatchStackMapForDexPc(dex_pc, encoding) - : code_info.GetStackMapForDexPc(dex_pc, encoding); - if (stack_map.IsValid()) { - return reinterpret_cast<uintptr_t>(entry_point) + - stack_map.GetNativePcOffset(encoding.stack_map_encoding); - } - } else { - MappingTable table(GetMappingTable()); - if (table.TotalSize() == 0) { - DCHECK_EQ(dex_pc, 0U); - return 0; // Special no mapping/pc == 0 case - } - // Assume the caller wants a dex-to-pc mapping so check here first. - typedef MappingTable::DexToPcIterator It; - for (It cur = table.DexToPcBegin(), end = table.DexToPcEnd(); cur != end; ++cur) { - if (cur.DexPc() == dex_pc) { - return reinterpret_cast<uintptr_t>(entry_point) + cur.NativePcOffset(); - } - } - // Now check pc-to-dex mappings. - typedef MappingTable::PcToDexIterator It2; - for (It2 cur = table.PcToDexBegin(), end = table.PcToDexEnd(); cur != end; ++cur) { - if (cur.DexPc() == dex_pc) { - return reinterpret_cast<uintptr_t>(entry_point) + cur.NativePcOffset(); - } - } + // All stack maps are stored in the same CodeItem section, safepoint stack + // maps first, then catch stack maps. We use `is_for_catch_handler` to select + // the order of iteration. + StackMap stack_map = + LIKELY(is_for_catch_handler) ? code_info.GetCatchStackMapForDexPc(dex_pc, encoding) + : code_info.GetStackMapForDexPc(dex_pc, encoding); + if (stack_map.IsValid()) { + return reinterpret_cast<uintptr_t>(entry_point) + + stack_map.GetNativePcOffset(encoding.stack_map_encoding); } - if (abort_on_failure) { ScopedObjectAccess soa(Thread::Current()); LOG(FATAL) << "Failed to find native offset for dex pc 0x" << std::hex << dex_pc diff --git a/runtime/oat_quick_method_header.h b/runtime/oat_quick_method_header.h index daabc6ee09..abddc6d7a0 100644 --- a/runtime/oat_quick_method_header.h +++ b/runtime/oat_quick_method_header.h @@ -30,9 +30,7 @@ class ArtMethod; // OatQuickMethodHeader precedes the raw code chunk generated by the compiler. class PACKED(4) OatQuickMethodHeader { public: - OatQuickMethodHeader(uint32_t mapping_table_offset = 0U, - uint32_t vmap_table_offset = 0U, - uint32_t gc_map_offset = 0U, + OatQuickMethodHeader(uint32_t vmap_table_offset = 0U, uint32_t frame_size_in_bytes = 0U, uint32_t core_spill_mask = 0U, uint32_t fp_spill_mask = 0U, @@ -60,7 +58,7 @@ class PACKED(4) OatQuickMethodHeader { } bool IsOptimized() const { - return gc_map_offset_ == 0 && vmap_table_offset_ != 0; + return code_size_ != 0 && vmap_table_offset_ != 0; } const void* GetOptimizedCodeInfoPtr() const { @@ -81,14 +79,6 @@ class PACKED(4) OatQuickMethodHeader { return code_size_; } - const uint8_t* GetNativeGcMap() const { - return (gc_map_offset_ == 0) ? nullptr : code_ - gc_map_offset_; - } - - const uint8_t* GetMappingTable() const { - return (mapping_table_offset_ == 0) ? nullptr : code_ - mapping_table_offset_; - } - const uint8_t* GetVmapTable() const { CHECK(!IsOptimized()) << "Unimplemented vmap table for optimizing compiler"; return (vmap_table_offset_ == 0) ? nullptr : code_ - vmap_table_offset_; @@ -135,12 +125,8 @@ class PACKED(4) OatQuickMethodHeader { uint32_t ToDexPc(ArtMethod* method, const uintptr_t pc, bool abort_on_failure = true) const; - // The offset in bytes from the start of the mapping table to the end of the header. - uint32_t mapping_table_offset_; // The offset in bytes from the start of the vmap table to the end of the header. uint32_t vmap_table_offset_; - // The offset in bytes from the start of the gc map to the end of the header. - uint32_t gc_map_offset_; // The stack frame information. QuickMethodFrameInfo frame_info_; // The code size in bytes. diff --git a/runtime/reflection_test.cc b/runtime/reflection_test.cc index 62347203a9..a098bf05ab 100644 --- a/runtime/reflection_test.cc +++ b/runtime/reflection_test.cc @@ -506,8 +506,6 @@ class ReflectionTest : public CommonCompilerTest { }; TEST_F(ReflectionTest, StaticMainMethod) { - TEST_DISABLED_FOR_HEAP_REFERENCE_POISONING_WITH_QUICK(); - TEST_DISABLED_FOR_READ_BARRIER_WITH_QUICK(); TEST_DISABLED_FOR_READ_BARRIER_WITH_OPTIMIZING_FOR_UNSUPPORTED_INSTRUCTION_SETS(); ScopedObjectAccess soa(Thread::Current()); jobject jclass_loader = LoadDex("Main"); diff --git a/runtime/runtime.cc b/runtime/runtime.cc index 630d101653..d3454e891f 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -103,6 +103,7 @@ #include "native/java_lang_VMClassLoader.h" #include "native/java_lang_ref_FinalizerReference.h" #include "native/java_lang_ref_Reference.h" +#include "native/java_lang_reflect_AbstractMethod.h" #include "native/java_lang_reflect_Array.h" #include "native/java_lang_reflect_Constructor.h" #include "native/java_lang_reflect_Field.h" @@ -1349,6 +1350,7 @@ void Runtime::RegisterRuntimeNativeMethods(JNIEnv* env) { register_java_lang_DexCache(env); register_java_lang_Object(env); register_java_lang_ref_FinalizerReference(env); + register_java_lang_reflect_AbstractMethod(env); register_java_lang_reflect_Array(env); register_java_lang_reflect_Constructor(env); register_java_lang_reflect_Field(env); diff --git a/runtime/stack.cc b/runtime/stack.cc index c22eb92f54..56ef5aaa90 100644 --- a/runtime/stack.cc +++ b/runtime/stack.cc @@ -21,7 +21,6 @@ #include "base/hex_dump.h" #include "entrypoints/entrypoint_utils-inl.h" #include "entrypoints/runtime_asm_entrypoints.h" -#include "gc_map.h" #include "gc/space/image_space.h" #include "gc/space/space-inl.h" #include "jit/jit.h" @@ -36,7 +35,6 @@ #include "thread.h" #include "thread_list.h" #include "verify_object-inl.h" -#include "vmap_table.h" namespace art { @@ -215,33 +213,6 @@ size_t StackVisitor::GetNativePcOffset() const { return GetCurrentOatQuickMethodHeader()->NativeQuickPcOffset(cur_quick_frame_pc_); } -bool StackVisitor::IsReferenceVReg(ArtMethod* m, uint16_t vreg) { - DCHECK_EQ(m, GetMethod()); - // Process register map (which native and runtime methods don't have) - if (m->IsNative() || m->IsRuntimeMethod() || m->IsProxyMethod()) { - return false; - } - const OatQuickMethodHeader* method_header = GetCurrentOatQuickMethodHeader(); - if (method_header->IsOptimized()) { - return true; // TODO: Implement. - } - const uint8_t* native_gc_map = method_header->GetNativeGcMap(); - CHECK(native_gc_map != nullptr) << PrettyMethod(m); - const DexFile::CodeItem* code_item = m->GetCodeItem(); - // Can't be null or how would we compile its instructions? - DCHECK(code_item != nullptr) << PrettyMethod(m); - NativePcOffsetToReferenceMap map(native_gc_map); - size_t num_regs = std::min(map.RegWidth() * 8, static_cast<size_t>(code_item->registers_size_)); - const uint8_t* reg_bitmap = nullptr; - if (num_regs > 0) { - uintptr_t native_pc_offset = method_header->NativeQuickPcOffset(GetCurrentQuickFramePc()); - reg_bitmap = map.FindBitMap(native_pc_offset); - DCHECK(reg_bitmap != nullptr); - } - // Does this register hold a reference? - return vreg < num_regs && TestBitmap(vreg, reg_bitmap); -} - bool StackVisitor::GetVRegFromDebuggerShadowFrame(uint16_t vreg, VRegKind kind, uint32_t* val) const { @@ -273,11 +244,8 @@ bool StackVisitor::GetVReg(ArtMethod* m, uint16_t vreg, VRegKind kind, uint32_t* if (GetVRegFromDebuggerShadowFrame(vreg, kind, val)) { return true; } - if (cur_oat_quick_method_header_->IsOptimized()) { - return GetVRegFromOptimizedCode(m, vreg, kind, val); - } else { - return GetVRegFromQuickCode(m, vreg, kind, val); - } + DCHECK(cur_oat_quick_method_header_->IsOptimized()); + return GetVRegFromOptimizedCode(m, vreg, kind, val); } else { DCHECK(cur_shadow_frame_ != nullptr); if (kind == kReferenceVReg) { @@ -290,29 +258,6 @@ bool StackVisitor::GetVReg(ArtMethod* m, uint16_t vreg, VRegKind kind, uint32_t* } } -bool StackVisitor::GetVRegFromQuickCode(ArtMethod* m, uint16_t vreg, VRegKind kind, - uint32_t* val) const { - DCHECK_EQ(m, GetMethod()); - const OatQuickMethodHeader* method_header = GetCurrentOatQuickMethodHeader(); - QuickMethodFrameInfo frame_info = method_header->GetFrameInfo(); - const VmapTable vmap_table(method_header->GetVmapTable()); - uint32_t vmap_offset; - // TODO: IsInContext stops before spotting floating point registers. - if (vmap_table.IsInContext(vreg, kind, &vmap_offset)) { - bool is_float = (kind == kFloatVReg) || (kind == kDoubleLoVReg) || (kind == kDoubleHiVReg); - uint32_t spill_mask = is_float ? frame_info.FpSpillMask() : frame_info.CoreSpillMask(); - uint32_t reg = vmap_table.ComputeRegister(spill_mask, vmap_offset, kind); - return GetRegisterIfAccessible(reg, kind, val); - } else { - const DexFile::CodeItem* code_item = m->GetCodeItem(); - DCHECK(code_item != nullptr) << PrettyMethod(m); // Can't be null or how would we compile - // its instructions? - *val = *GetVRegAddrFromQuickCode(cur_quick_frame_, code_item, frame_info.CoreSpillMask(), - frame_info.FpSpillMask(), frame_info.FrameSizeInBytes(), vreg); - return true; - } -} - bool StackVisitor::GetVRegFromOptimizedCode(ArtMethod* m, uint16_t vreg, VRegKind kind, uint32_t* val) const { DCHECK_EQ(m, GetMethod()); @@ -432,11 +377,8 @@ bool StackVisitor::GetVRegPair(ArtMethod* m, uint16_t vreg, VRegKind kind_lo, if (cur_quick_frame_ != nullptr) { DCHECK(context_ != nullptr); // You can't reliably read registers without a context. DCHECK(m == GetMethod()); - if (cur_oat_quick_method_header_->IsOptimized()) { - return GetVRegPairFromOptimizedCode(m, vreg, kind_lo, kind_hi, val); - } else { - return GetVRegPairFromQuickCode(m, vreg, kind_lo, kind_hi, val); - } + DCHECK(cur_oat_quick_method_header_->IsOptimized()); + return GetVRegPairFromOptimizedCode(m, vreg, kind_lo, kind_hi, val); } else { DCHECK(cur_shadow_frame_ != nullptr); *val = cur_shadow_frame_->GetVRegLong(vreg); @@ -444,33 +386,6 @@ bool StackVisitor::GetVRegPair(ArtMethod* m, uint16_t vreg, VRegKind kind_lo, } } -bool StackVisitor::GetVRegPairFromQuickCode(ArtMethod* m, uint16_t vreg, VRegKind kind_lo, - VRegKind kind_hi, uint64_t* val) const { - DCHECK_EQ(m, GetMethod()); - const OatQuickMethodHeader* method_header = GetCurrentOatQuickMethodHeader(); - QuickMethodFrameInfo frame_info = method_header->GetFrameInfo(); - const VmapTable vmap_table(method_header->GetVmapTable()); - uint32_t vmap_offset_lo, vmap_offset_hi; - // TODO: IsInContext stops before spotting floating point registers. - if (vmap_table.IsInContext(vreg, kind_lo, &vmap_offset_lo) && - vmap_table.IsInContext(vreg + 1, kind_hi, &vmap_offset_hi)) { - bool is_float = (kind_lo == kDoubleLoVReg); - uint32_t spill_mask = is_float ? frame_info.FpSpillMask() : frame_info.CoreSpillMask(); - uint32_t reg_lo = vmap_table.ComputeRegister(spill_mask, vmap_offset_lo, kind_lo); - uint32_t reg_hi = vmap_table.ComputeRegister(spill_mask, vmap_offset_hi, kind_hi); - return GetRegisterPairIfAccessible(reg_lo, reg_hi, kind_lo, val); - } else { - const DexFile::CodeItem* code_item = m->GetCodeItem(); - DCHECK(code_item != nullptr) << PrettyMethod(m); // Can't be null or how would we compile - // its instructions? - uint32_t* addr = GetVRegAddrFromQuickCode( - cur_quick_frame_, code_item, frame_info.CoreSpillMask(), - frame_info.FpSpillMask(), frame_info.FrameSizeInBytes(), vreg); - *val = *reinterpret_cast<uint64_t*>(addr); - return true; - } -} - bool StackVisitor::GetVRegPairFromOptimizedCode(ArtMethod* m, uint16_t vreg, VRegKind kind_lo, VRegKind kind_hi, uint64_t* val) const { diff --git a/runtime/stack.h b/runtime/stack.h index 3659560555..51f7d6368b 100644 --- a/runtime/stack.h +++ b/runtime/stack.h @@ -634,9 +634,6 @@ class StackVisitor { bool GetNextMethodAndDexPc(ArtMethod** next_method, uint32_t* next_dex_pc) SHARED_REQUIRES(Locks::mutator_lock_); - bool IsReferenceVReg(ArtMethod* m, uint16_t vreg) - SHARED_REQUIRES(Locks::mutator_lock_); - bool GetVReg(ArtMethod* m, uint16_t vreg, VRegKind kind, uint32_t* val) const SHARED_REQUIRES(Locks::mutator_lock_); @@ -798,9 +795,6 @@ class StackVisitor { bool GetVRegFromDebuggerShadowFrame(uint16_t vreg, VRegKind kind, uint32_t* val) const SHARED_REQUIRES(Locks::mutator_lock_); - bool GetVRegFromQuickCode(ArtMethod* m, uint16_t vreg, VRegKind kind, - uint32_t* val) const - SHARED_REQUIRES(Locks::mutator_lock_); bool GetVRegFromOptimizedCode(ArtMethod* m, uint16_t vreg, VRegKind kind, uint32_t* val) const SHARED_REQUIRES(Locks::mutator_lock_); @@ -808,9 +802,6 @@ class StackVisitor { bool GetVRegPairFromDebuggerShadowFrame(uint16_t vreg, VRegKind kind_lo, VRegKind kind_hi, uint64_t* val) const SHARED_REQUIRES(Locks::mutator_lock_); - bool GetVRegPairFromQuickCode(ArtMethod* m, uint16_t vreg, VRegKind kind_lo, - VRegKind kind_hi, uint64_t* val) const - SHARED_REQUIRES(Locks::mutator_lock_); bool GetVRegPairFromOptimizedCode(ArtMethod* m, uint16_t vreg, VRegKind kind_lo, VRegKind kind_hi, uint64_t* val) const diff --git a/runtime/thread.cc b/runtime/thread.cc index 3ecb04185f..57ccabc09c 100644 --- a/runtime/thread.cc +++ b/runtime/thread.cc @@ -42,7 +42,6 @@ #include "dex_file-inl.h" #include "entrypoints/entrypoint_utils.h" #include "entrypoints/quick/quick_alloc_entrypoints.h" -#include "gc_map.h" #include "gc/accounting/card_table-inl.h" #include "gc/accounting/heap_bitmap-inl.h" #include "gc/allocator/rosalloc.h" @@ -72,7 +71,6 @@ #include "utils.h" #include "verifier/method_verifier.h" #include "verify_object-inl.h" -#include "vmap_table.h" #include "well_known_classes.h" #include "interpreter/interpreter.h" @@ -2765,83 +2763,36 @@ class ReferenceMapVisitor : public StackVisitor { // Process register map (which native and runtime methods don't have) if (!m->IsNative() && !m->IsRuntimeMethod() && !m->IsProxyMethod()) { const OatQuickMethodHeader* method_header = GetCurrentOatQuickMethodHeader(); - if (method_header->IsOptimized()) { - auto* vreg_base = reinterpret_cast<StackReference<mirror::Object>*>( - reinterpret_cast<uintptr_t>(cur_quick_frame)); - uintptr_t native_pc_offset = method_header->NativeQuickPcOffset(GetCurrentQuickFramePc()); - CodeInfo code_info = method_header->GetOptimizedCodeInfo(); - CodeInfoEncoding encoding = code_info.ExtractEncoding(); - StackMap map = code_info.GetStackMapForNativePcOffset(native_pc_offset, encoding); - DCHECK(map.IsValid()); - // Visit stack entries that hold pointers. - size_t number_of_bits = map.GetNumberOfStackMaskBits(encoding.stack_map_encoding); - for (size_t i = 0; i < number_of_bits; ++i) { - if (map.GetStackMaskBit(encoding.stack_map_encoding, i)) { - auto* ref_addr = vreg_base + i; - mirror::Object* ref = ref_addr->AsMirrorPtr(); - if (ref != nullptr) { - mirror::Object* new_ref = ref; - visitor_(&new_ref, -1, this); - if (ref != new_ref) { - ref_addr->Assign(new_ref); - } + DCHECK(method_header->IsOptimized()); + auto* vreg_base = reinterpret_cast<StackReference<mirror::Object>*>( + reinterpret_cast<uintptr_t>(cur_quick_frame)); + uintptr_t native_pc_offset = method_header->NativeQuickPcOffset(GetCurrentQuickFramePc()); + CodeInfo code_info = method_header->GetOptimizedCodeInfo(); + CodeInfoEncoding encoding = code_info.ExtractEncoding(); + StackMap map = code_info.GetStackMapForNativePcOffset(native_pc_offset, encoding); + DCHECK(map.IsValid()); + // Visit stack entries that hold pointers. + size_t number_of_bits = map.GetNumberOfStackMaskBits(encoding.stack_map_encoding); + for (size_t i = 0; i < number_of_bits; ++i) { + if (map.GetStackMaskBit(encoding.stack_map_encoding, i)) { + auto* ref_addr = vreg_base + i; + mirror::Object* ref = ref_addr->AsMirrorPtr(); + if (ref != nullptr) { + mirror::Object* new_ref = ref; + visitor_(&new_ref, -1, this); + if (ref != new_ref) { + ref_addr->Assign(new_ref); } } } - // Visit callee-save registers that hold pointers. - uint32_t register_mask = map.GetRegisterMask(encoding.stack_map_encoding); - for (size_t i = 0; i < BitSizeOf<uint32_t>(); ++i) { - if (register_mask & (1 << i)) { - mirror::Object** ref_addr = reinterpret_cast<mirror::Object**>(GetGPRAddress(i)); - if (*ref_addr != nullptr) { - visitor_(ref_addr, -1, this); - } - } - } - } else { - const uint8_t* native_gc_map = method_header->GetNativeGcMap(); - CHECK(native_gc_map != nullptr) << PrettyMethod(m); - const DexFile::CodeItem* code_item = m->GetCodeItem(); - // Can't be null or how would we compile its instructions? - DCHECK(code_item != nullptr) << PrettyMethod(m); - NativePcOffsetToReferenceMap map(native_gc_map); - size_t num_regs = map.RegWidth() * 8; - if (num_regs > 0) { - uintptr_t native_pc_offset = method_header->NativeQuickPcOffset(GetCurrentQuickFramePc()); - const uint8_t* reg_bitmap = map.FindBitMap(native_pc_offset); - DCHECK(reg_bitmap != nullptr); - const VmapTable vmap_table(method_header->GetVmapTable()); - QuickMethodFrameInfo frame_info = method_header->GetFrameInfo(); - // For all dex registers in the bitmap - DCHECK(cur_quick_frame != nullptr); - for (size_t reg = 0; reg < num_regs; ++reg) { - // Does this register hold a reference? - if (TestBitmap(reg, reg_bitmap)) { - uint32_t vmap_offset; - if (vmap_table.IsInContext(reg, kReferenceVReg, &vmap_offset)) { - int vmap_reg = vmap_table.ComputeRegister(frame_info.CoreSpillMask(), vmap_offset, - kReferenceVReg); - // This is sound as spilled GPRs will be word sized (ie 32 or 64bit). - mirror::Object** ref_addr = - reinterpret_cast<mirror::Object**>(GetGPRAddress(vmap_reg)); - if (*ref_addr != nullptr) { - visitor_(ref_addr, reg, this); - } - } else { - StackReference<mirror::Object>* ref_addr = - reinterpret_cast<StackReference<mirror::Object>*>(GetVRegAddrFromQuickCode( - cur_quick_frame, code_item, frame_info.CoreSpillMask(), - frame_info.FpSpillMask(), frame_info.FrameSizeInBytes(), reg)); - mirror::Object* ref = ref_addr->AsMirrorPtr(); - if (ref != nullptr) { - mirror::Object* new_ref = ref; - visitor_(&new_ref, reg, this); - if (ref != new_ref) { - ref_addr->Assign(new_ref); - } - } - } - } + } + // Visit callee-save registers that hold pointers. + uint32_t register_mask = map.GetRegisterMask(encoding.stack_map_encoding); + for (size_t i = 0; i < BitSizeOf<uint32_t>(); ++i) { + if (register_mask & (1 << i)) { + mirror::Object** ref_addr = reinterpret_cast<mirror::Object**>(GetGPRAddress(i)); + if (*ref_addr != nullptr) { + visitor_(ref_addr, -1, this); } } } diff --git a/runtime/vmap_table.h b/runtime/vmap_table.h deleted file mode 100644 index db9e1ea5cb..0000000000 --- a/runtime/vmap_table.h +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright (C) 2011 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_VMAP_TABLE_H_ -#define ART_RUNTIME_VMAP_TABLE_H_ - -#include "base/logging.h" -#include "leb128.h" -#include "stack.h" - -namespace art { - -class VmapTable { - public: - // For efficient encoding of special values, entries are adjusted by 2. - static constexpr uint16_t kEntryAdjustment = 2u; - static constexpr uint16_t kAdjustedFpMarker = static_cast<uint16_t>(0xffffu + kEntryAdjustment); - - explicit VmapTable(const uint8_t* table) : table_(table) { - } - - // Look up nth entry, not called from performance critical code. - uint16_t operator[](size_t n) const { - const uint8_t* table = table_; - size_t size = DecodeUnsignedLeb128(&table); - CHECK_LT(n, size); - uint16_t adjusted_entry = DecodeUnsignedLeb128(&table); - for (size_t i = 0; i < n; ++i) { - adjusted_entry = DecodeUnsignedLeb128(&table); - } - return adjusted_entry - kEntryAdjustment; - } - - size_t Size() const { - const uint8_t* table = table_; - return DecodeUnsignedLeb128(&table); - } - - // Is the dex register 'vreg' in the context or on the stack? Should not be called when the - // 'kind' is unknown or constant. - bool IsInContext(size_t vreg, VRegKind kind, uint32_t* vmap_offset) const { - DCHECK(kind == kReferenceVReg || kind == kIntVReg || kind == kFloatVReg || - kind == kLongLoVReg || kind == kLongHiVReg || kind == kDoubleLoVReg || - kind == kDoubleHiVReg || kind == kImpreciseConstant); - *vmap_offset = 0xEBAD0FF5; - // TODO: take advantage of the registers being ordered - // TODO: we treat kImpreciseConstant as an integer below, need to ensure that such values - // are never promoted to floating point registers. - bool is_float = (kind == kFloatVReg) || (kind == kDoubleLoVReg) || (kind == kDoubleHiVReg); - bool in_floats = false; - const uint8_t* table = table_; - uint16_t adjusted_vreg = vreg + kEntryAdjustment; - size_t end = DecodeUnsignedLeb128(&table); - bool high_reg = (kind == kLongHiVReg) || (kind == kDoubleHiVReg); - bool target64 = (kRuntimeISA == kArm64) || (kRuntimeISA == kX86_64) || (kRuntimeISA == kMips64); - if (target64 && high_reg) { - // Wide promoted registers are associated with the sreg of the low portion. - adjusted_vreg--; - } - for (size_t i = 0; i < end; ++i) { - // Stop if we find what we are are looking for. - uint16_t adjusted_entry = DecodeUnsignedLeb128(&table); - if ((adjusted_entry == adjusted_vreg) && (in_floats == is_float)) { - *vmap_offset = i; - return true; - } - // 0xffff is the marker for LR (return PC on x86), following it are spilled float registers. - if (adjusted_entry == kAdjustedFpMarker) { - in_floats = true; - } - } - return false; - } - - // Compute the register number that corresponds to the entry in the vmap (vmap_offset, computed - // by IsInContext above). If the kind is floating point then the result will be a floating point - // register number, otherwise it will be an integer register number. - uint32_t ComputeRegister(uint32_t spill_mask, uint32_t vmap_offset, VRegKind kind) const { - // Compute the register we need to load from the context. - DCHECK(kind == kReferenceVReg || kind == kIntVReg || kind == kFloatVReg || - kind == kLongLoVReg || kind == kLongHiVReg || kind == kDoubleLoVReg || - kind == kDoubleHiVReg || kind == kImpreciseConstant); - // TODO: we treat kImpreciseConstant as an integer below, need to ensure that such values - // are never promoted to floating point registers. - bool is_float = (kind == kFloatVReg) || (kind == kDoubleLoVReg) || (kind == kDoubleHiVReg); - uint32_t matches = 0; - if (UNLIKELY(is_float)) { - const uint8_t* table = table_; - DecodeUnsignedLeb128(&table); // Skip size. - while (DecodeUnsignedLeb128(&table) != kAdjustedFpMarker) { - matches++; - } - matches++; - } - CHECK_LT(vmap_offset - matches, static_cast<uint32_t>(POPCOUNT(spill_mask))); - uint32_t spill_shifts = 0; - while (matches != (vmap_offset + 1)) { - DCHECK_NE(spill_mask, 0u); - matches += spill_mask & 1; // Add 1 if the low bit is set - spill_mask >>= 1; - spill_shifts++; - } - spill_shifts--; // wind back one as we want the last match - return spill_shifts; - } - - private: - const uint8_t* const table_; -}; - -} // namespace art - -#endif // ART_RUNTIME_VMAP_TABLE_H_ diff --git a/test/004-ReferenceMap/stack_walk_refmap_jni.cc b/test/004-ReferenceMap/stack_walk_refmap_jni.cc index 2d26fa1ac9..284e5544fb 100644 --- a/test/004-ReferenceMap/stack_walk_refmap_jni.cc +++ b/test/004-ReferenceMap/stack_walk_refmap_jni.cc @@ -49,13 +49,7 @@ struct ReferenceMap2Visitor : public CheckReferenceMapVisitor { if (m_name.compare("f") == 0) { CHECK_REGS_CONTAIN_REFS(0x03U, true, 8); // v8: this CHECK_REGS_CONTAIN_REFS(0x06U, true, 8, 1); // v8: this, v1: x - if (!GetCurrentOatQuickMethodHeader()->IsOptimized()) { - CHECK_REGS_CONTAIN_REFS(0x08U, true, 8, 3, 1); // v8: this, v3: y, v1: x - } CHECK_REGS_CONTAIN_REFS(0x0cU, true, 8, 3, 1); // v8: this, v3: y, v1: x - if (!GetCurrentOatQuickMethodHeader()->IsOptimized()) { - CHECK_REGS_CONTAIN_REFS(0x0eU, true, 8, 3, 1); // v8: this, v3: y, v1: x - } CHECK_REGS_CONTAIN_REFS(0x10U, true, 8, 3, 1); // v8: this, v3: y, v1: x // v2 is added because of the instruction at DexPC 0024. Object merges with 0 is Object. See: // 0024: move-object v3, v2 @@ -68,15 +62,6 @@ struct ReferenceMap2Visitor : public CheckReferenceMapVisitor { CHECK_REGS_CONTAIN_REFS(0x14U, false, 2); // v2: y // Note that v0: ex can be eliminated because it's a dead merge of two different exceptions. CHECK_REGS_CONTAIN_REFS(0x18U, true, 8, 2, 1); // v8: this, v2: y, v1: x (dead v0: ex) - if (!GetCurrentOatQuickMethodHeader()->IsOptimized()) { - // v8: this, v4: x[1], v2: y, v1: x (dead v0: ex) - CHECK_REGS_CONTAIN_REFS(0x1aU, true, 8, 4, 2, 1); - // v8: this, v4: x[1], v2: y, v1: x (dead v0: ex) - CHECK_REGS_CONTAIN_REFS(0x1eU, true, 8, 4, 2, 1); - // v4 is removed from the root set because there is a "merge" operation. - // See 0016: if-nez v2, 0020. - CHECK_REGS_CONTAIN_REFS(0x20U, true, 8, 2, 1); // v8: this, v2: y, v1: x (dead v0: ex) - } CHECK_REGS_CONTAIN_REFS(0x22U, true, 8, 2, 1); // v8: this, v2: y, v1: x (dead v0: ex) if (!GetCurrentOatQuickMethodHeader()->IsOptimized()) { diff --git a/test/005-annotations/expected.txt b/test/005-annotations/expected.txt index 3d9fd8bcfc..ee5b0c74c5 100644 --- a/test/005-annotations/expected.txt +++ b/test/005-annotations/expected.txt @@ -93,6 +93,7 @@ annotations on TYPE class android.test.anno.FullyNoted(1): --> nombre is 'fubar' SimplyNoted.get(AnnoSimpleType) = @android.test.anno.AnnoSimpleType() +SimplyNoted.get(AnnoSimpleTypeInvis) = null SubNoted.get(AnnoSimpleType) = @android.test.anno.AnnoSimpleType() Package annotations: diff --git a/test/005-annotations/src/android/test/anno/TestAnnotations.java b/test/005-annotations/src/android/test/anno/TestAnnotations.java index bc89f1682c..d36d43e1ba 100644 --- a/test/005-annotations/src/android/test/anno/TestAnnotations.java +++ b/test/005-annotations/src/android/test/anno/TestAnnotations.java @@ -185,6 +185,9 @@ public class TestAnnotations { // this is expected to be non-null Annotation anno = SimplyNoted.class.getAnnotation(AnnoSimpleType.class); System.out.println("SimplyNoted.get(AnnoSimpleType) = " + anno); + // this is expected to be null + anno = SimplyNoted.class.getAnnotation(AnnoSimpleTypeInvis.class); + System.out.println("SimplyNoted.get(AnnoSimpleTypeInvis) = " + anno); // this is non-null if the @Inherited tag is present anno = SubNoted.class.getAnnotation(AnnoSimpleType.class); System.out.println("SubNoted.get(AnnoSimpleType) = " + anno); diff --git a/test/031-class-attributes/src/ClassAttrs.java b/test/031-class-attributes/src/ClassAttrs.java index c2e41c5b3e..38bd525b86 100644 --- a/test/031-class-attributes/src/ClassAttrs.java +++ b/test/031-class-attributes/src/ClassAttrs.java @@ -1,6 +1,7 @@ import otherpackage.OtherPackageClass; import java.io.Serializable; +import java.lang.reflect.AbstractMethod; import java.lang.reflect.AccessibleObject; import java.lang.reflect.Constructor; import java.lang.reflect.Field; @@ -221,8 +222,11 @@ public class ClassAttrs { public static String getSignatureAttribute(Object obj) { Method method; try { - Class c = Class.forName("libcore.reflect.AnnotationAccess"); - method = c.getDeclaredMethod("getSignature", java.lang.reflect.AnnotatedElement.class); + Class c = obj.getClass(); + if (c == Method.class || c == Constructor.class) { + c = AbstractMethod.class; + } + method = c.getDeclaredMethod("getSignatureAttribute"); method.setAccessible(true); } catch (Exception ex) { ex.printStackTrace(); @@ -230,7 +234,7 @@ public class ClassAttrs { } try { - return (String) method.invoke(null, obj); + return (String) method.invoke(obj); } catch (IllegalAccessException ex) { throw new RuntimeException(ex); } catch (InvocationTargetException ex) { diff --git a/test/570-checker-osr/src/Main.java b/test/570-checker-osr/src/Main.java index 1142d49eed..6514334af1 100644 --- a/test/570-checker-osr/src/Main.java +++ b/test/570-checker-osr/src/Main.java @@ -16,8 +16,28 @@ public class Main { public static void main(String[] args) { - new SubMain(); System.loadLibrary(args[0]); + Thread testThread = new Thread() { + public void run() { + performTest(); + } + }; + testThread.start(); + try { + testThread.join(20 * 1000); // 20s timeout. + } catch (InterruptedException ie) { + System.out.println("Interrupted."); + System.exit(1); + } + Thread.State state = testThread.getState(); + if (state != Thread.State.TERMINATED) { + System.out.println("Test timed out, current state: " + state); + System.exit(1); + } + } + + public static void performTest() { + new SubMain(); if ($noinline$returnInt() != 53) { throw new Error("Unexpected return value"); } diff --git a/tools/checker/match/file.py b/tools/checker/match/file.py index 6ff19d5197..520c4aedd7 100644 --- a/tools/checker/match/file.py +++ b/tools/checker/match/file.py @@ -172,8 +172,8 @@ def MatchFiles(checkerFile, c1File, targetArch, debuggableMode): # match a check group against the first output group of the same name. c1Pass = c1File.findPass(testCase.name) if c1Pass is None: - Logger.fail("Test case \"{}\" not found in the CFG file".format(testCase.name), - testCase.fileName, testCase.startLineNo) + Logger.fail("Test case not found in the CFG file", + testCase.fileName, testCase.startLineNo, testCase.name) Logger.startTest(testCase.name) try: diff --git a/tools/libcore_failures.txt b/tools/libcore_failures.txt index 2533ce284e..38b6ea60f0 100644 --- a/tools/libcore_failures.txt +++ b/tools/libcore_failures.txt @@ -267,6 +267,24 @@ "libcore.util.NativeAllocationRegistryTest#testNullArguments"] }, { + description: "libnativehelper_compat_libc++.so not found by dlopen on ARM64", + result: EXEC_FAILED, + modes: [device], + bug: 28082914, + names: ["libcore.java.lang.ThreadTest#testContextClassLoaderIsInherited", + "libcore.java.lang.ThreadTest#testContextClassLoaderIsNotNull", + "libcore.java.lang.ThreadTest#testGetAllStackTracesIncludesAllGroups", + "libcore.java.lang.ThreadTest#testGetStackTrace", + "libcore.java.lang.ThreadTest#testJavaContextClassLoader", + "libcore.java.lang.ThreadTest#testLeakingStartedThreads", + "libcore.java.lang.ThreadTest#testLeakingUnstartedThreads", + "libcore.java.lang.ThreadTest#testNativeThreadNames", + "libcore.java.lang.ThreadTest#testThreadInterrupted", + "libcore.java.lang.ThreadTest#testThreadSleep", + "libcore.java.lang.ThreadTest#testThreadSleepIllegalArguments", + "libcore.java.lang.ThreadTest#testThreadWakeup"] +}, +{ description: "Only work with --mode=activity", result: EXEC_FAILED, names: [ "libcore.java.io.FileTest#testJavaIoTmpdirMutable" ] |