diff options
68 files changed, 1353 insertions, 1707 deletions
diff --git a/adbconnection/adbconnection.cc b/adbconnection/adbconnection.cc index 8cd0d8bc9f..ad941481fd 100644 --- a/adbconnection/adbconnection.cc +++ b/adbconnection/adbconnection.cc @@ -489,7 +489,7 @@ bool AdbConnectionState::SetupAdbConnection() { int sleep_ms = 500; const int sleep_max_ms = 2*1000; - android::base::unique_fd sock(socket(AF_UNIX, SOCK_SEQPACKET, 0)); + android::base::unique_fd sock(socket(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0)); if (sock < 0) { PLOG(ERROR) << "Could not create ADB control socket"; return false; @@ -872,7 +872,7 @@ std::string AdbConnectionState::MakeAgentArg() { (ContainsArgument(opts, "server=y") ? "" : "server=y,") + // See the comment above for why we need to be suspend=n. Since the agent defaults to // suspend=y we will add it if it wasn't already present. - (ContainsArgument(opts, "suspend=n") ? "" : "suspend=n") + + (ContainsArgument(opts, "suspend=n") ? "" : "suspend=n,") + "transport=dt_fd_forward,address=" + std::to_string(remote_agent_control_sock_); } diff --git a/compiler/optimizing/stack_map_stream.cc b/compiler/optimizing/stack_map_stream.cc index d99beac59f..d80e2fc0e3 100644 --- a/compiler/optimizing/stack_map_stream.cc +++ b/compiler/optimizing/stack_map_stream.cc @@ -65,7 +65,7 @@ void StackMapStream::BeginStackMapEntry(uint32_t dex_pc, // and it might modify the data before that. Therefore, just store the pointer. // See ClearSpillSlotsFromLoopPhisInStackMap in code_generator.h. lazy_stack_masks_.push_back(stack_mask); - current_inline_infos_ = 0; + current_inline_infos_.clear(); current_dex_registers_.clear(); expected_num_dex_registers_ = num_dex_registers; @@ -84,9 +84,7 @@ void StackMapStream::BeginStackMapEntry(uint32_t dex_pc, CHECK_EQ(seen_stack_mask.LoadBit(b), stack_mask != nullptr && stack_mask->IsBitSet(b)); } CHECK_EQ(stack_map.HasInlineInfo(), (inlining_depth != 0)); - if (inlining_depth != 0) { - CHECK_EQ(code_info.GetInlineInfoOf(stack_map).GetDepth(), inlining_depth); - } + CHECK_EQ(code_info.GetInlineDepthOf(stack_map), inlining_depth); CHECK_EQ(stack_map.HasDexRegisterMap(), (num_dex_registers != 0)); }); } @@ -97,9 +95,11 @@ void StackMapStream::EndStackMapEntry() { in_stack_map_ = false; DCHECK_EQ(expected_num_dex_registers_, current_dex_registers_.size()); - // Mark the last inline info as last in the list for the stack map. - if (current_inline_infos_ > 0) { - inline_infos_[inline_infos_.size() - 1].is_last = InlineInfo::kLast; + // Generate index into the InlineInfo table. + if (!current_inline_infos_.empty()) { + current_inline_infos_.back().is_last = InlineInfo::kLast; + current_stack_map_.inline_info_index = + inline_infos_.Dedup(current_inline_infos_.data(), current_inline_infos_.size()); } stack_maps_.Add(current_stack_map_); @@ -162,30 +162,27 @@ void StackMapStream::BeginInlineInfoEntry(ArtMethod* method, uint32_t dex_method_index = method->GetDexMethodIndexUnchecked(); entry.method_info_index = method_infos_.Dedup(&dex_method_index); } - if (current_inline_infos_++ == 0) { - current_stack_map_.inline_info_index = inline_infos_.size(); - } - inline_infos_.Add(entry); + current_inline_infos_.push_back(entry); current_dex_registers_.clear(); expected_num_dex_registers_ = num_dex_registers; if (kVerifyStackMaps) { size_t stack_map_index = stack_maps_.size(); - size_t depth = current_inline_infos_ - 1; + size_t depth = current_inline_infos_.size() - 1; dchecks_.emplace_back([=](const CodeInfo& code_info) { StackMap stack_map = code_info.GetStackMapAt(stack_map_index); - InlineInfo inline_info = code_info.GetInlineInfoOf(stack_map); - CHECK_EQ(inline_info.GetDexPcAtDepth(depth), dex_pc); + InlineInfo inline_info = code_info.GetInlineInfoAtDepth(stack_map, depth); + CHECK_EQ(inline_info.GetDexPc(), dex_pc); bool encode_art_method = EncodeArtMethodInInlineInfo(method); - CHECK_EQ(inline_info.EncodesArtMethodAtDepth(depth), encode_art_method); + CHECK_EQ(inline_info.EncodesArtMethod(), encode_art_method); if (encode_art_method) { - CHECK_EQ(inline_info.GetArtMethodAtDepth(depth), method); + CHECK_EQ(inline_info.GetArtMethod(), method); } else { - CHECK_EQ(method_infos_[inline_info.GetMethodIndexIdxAtDepth(depth)], + CHECK_EQ(method_infos_[inline_info.GetMethodIndexIdx()], method->GetDexMethodIndexUnchecked()); } - CHECK_EQ(inline_info.HasDexRegisterMapAtDepth(depth), (num_dex_registers != 0)); + CHECK_EQ(inline_info.HasDexRegisterMap(), (num_dex_registers != 0)); }); } } @@ -222,9 +219,9 @@ void StackMapStream::CreateDexRegisterMap() { } uint32_t map_index = dex_register_maps_.Dedup(temp_dex_register_map_.data(), temp_dex_register_map_.size()); - if (current_inline_infos_ > 0) { - inline_infos_[inline_infos_.size() - 1].dex_register_mask_index = mask_index; - inline_infos_[inline_infos_.size() - 1].dex_register_map_index = map_index; + if (!current_inline_infos_.empty()) { + current_inline_infos_.back().dex_register_mask_index = mask_index; + current_inline_infos_.back().dex_register_map_index = map_index; } else { current_stack_map_.dex_register_mask_index = mask_index; current_stack_map_.dex_register_map_index = map_index; @@ -232,7 +229,7 @@ void StackMapStream::CreateDexRegisterMap() { if (kVerifyStackMaps) { size_t stack_map_index = stack_maps_.size(); - int32_t depth = current_inline_infos_ - 1; + int32_t depth = current_inline_infos_.size() - 1; // We need to make copy of the current registers for later (when the check is run). auto expected_dex_registers = std::make_shared<std::vector<DexRegisterLocation>>( current_dex_registers_.begin(), current_dex_registers_.end()); @@ -241,9 +238,7 @@ void StackMapStream::CreateDexRegisterMap() { size_t num_dex_registers = expected_dex_registers->size(); DexRegisterMap map = (depth == -1) ? code_info.GetDexRegisterMapOf(stack_map, num_dex_registers) - : code_info.GetDexRegisterMapAtDepth(depth, - code_info.GetInlineInfoOf(stack_map), - num_dex_registers); + : code_info.GetDexRegisterMapAtDepth(depth, stack_map, num_dex_registers); CHECK_EQ(map.size(), num_dex_registers); for (size_t r = 0; r < num_dex_registers; r++) { CHECK_EQ(expected_dex_registers->at(r), map.Get(r)); diff --git a/compiler/optimizing/stack_map_stream.h b/compiler/optimizing/stack_map_stream.h index c758bca951..d634c703ff 100644 --- a/compiler/optimizing/stack_map_stream.h +++ b/compiler/optimizing/stack_map_stream.h @@ -53,7 +53,7 @@ class StackMapStream : public ValueObject { lazy_stack_masks_(allocator->Adapter(kArenaAllocStackMapStream)), in_stack_map_(false), in_inline_info_(false), - current_inline_infos_(0), + current_inline_infos_(allocator->Adapter(kArenaAllocStackMapStream)), current_dex_registers_(allocator->Adapter(kArenaAllocStackMapStream)), temp_dex_register_mask_(allocator, 32, true, kArenaAllocStackMapStream), temp_dex_register_map_(allocator->Adapter(kArenaAllocStackMapStream)) { @@ -157,7 +157,7 @@ class StackMapStream : public ValueObject { bool in_stack_map_; bool in_inline_info_; StackMapEntry current_stack_map_; - uint32_t current_inline_infos_; + ScopedArenaVector<InlineInfoEntry> current_inline_infos_; ScopedArenaVector<DexRegisterLocation> current_dex_registers_; size_t expected_num_dex_registers_; diff --git a/compiler/optimizing/stack_map_test.cc b/compiler/optimizing/stack_map_test.cc index 262c240bc7..77aa3ef965 100644 --- a/compiler/optimizing/stack_map_test.cc +++ b/compiler/optimizing/stack_map_test.cc @@ -189,12 +189,13 @@ TEST(StackMapTest, Test2) { ASSERT_EQ(-2, location1.GetValue()); ASSERT_TRUE(stack_map.HasInlineInfo()); - InlineInfo inline_info = code_info.GetInlineInfoOf(stack_map); - ASSERT_EQ(2u, inline_info.GetDepth()); - ASSERT_EQ(3u, inline_info.GetDexPcAtDepth(0)); - ASSERT_EQ(2u, inline_info.GetDexPcAtDepth(1)); - ASSERT_TRUE(inline_info.EncodesArtMethodAtDepth(0)); - ASSERT_TRUE(inline_info.EncodesArtMethodAtDepth(1)); + InlineInfo inline_info0 = code_info.GetInlineInfoAtDepth(stack_map, 0); + InlineInfo inline_info1 = code_info.GetInlineInfoAtDepth(stack_map, 1); + ASSERT_EQ(2u, code_info.GetInlineDepthOf(stack_map)); + ASSERT_EQ(3u, inline_info0.GetDexPc()); + ASSERT_EQ(2u, inline_info1.GetDexPc()); + ASSERT_TRUE(inline_info0.EncodesArtMethod()); + ASSERT_TRUE(inline_info1.EncodesArtMethod()); } // Second stack map. @@ -361,8 +362,8 @@ TEST(StackMapTest, TestDeduplicateInlineInfoDexRegisterMap) { // Test that the inline info dex register map deduplicated to the same offset as the stack map // one. ASSERT_TRUE(stack_map.HasInlineInfo()); - InlineInfo inline_info = code_info.GetInlineInfoOf(stack_map); - EXPECT_EQ(inline_info.GetDexRegisterMapIndexAtDepth(0), + InlineInfo inline_info = code_info.GetInlineInfoAtDepth(stack_map, 0); + EXPECT_EQ(inline_info.GetDexRegisterMapIndex(), stack_map.GetDexRegisterMapIndex()); } } @@ -605,17 +606,18 @@ TEST(StackMapTest, InlineTest) { ASSERT_EQ(0, dex_registers0.GetStackOffsetInBytes(0)); ASSERT_EQ(4, dex_registers0.GetConstant(1)); - InlineInfo if0 = ci.GetInlineInfoOf(sm0); - ASSERT_EQ(2u, if0.GetDepth()); - ASSERT_EQ(2u, if0.GetDexPcAtDepth(0)); - ASSERT_TRUE(if0.EncodesArtMethodAtDepth(0)); - ASSERT_EQ(3u, if0.GetDexPcAtDepth(1)); - ASSERT_TRUE(if0.EncodesArtMethodAtDepth(1)); + InlineInfo if0_0 = ci.GetInlineInfoAtDepth(sm0, 0); + InlineInfo if0_1 = ci.GetInlineInfoAtDepth(sm0, 1); + ASSERT_EQ(2u, ci.GetInlineDepthOf(sm0)); + ASSERT_EQ(2u, if0_0.GetDexPc()); + ASSERT_TRUE(if0_0.EncodesArtMethod()); + ASSERT_EQ(3u, if0_1.GetDexPc()); + ASSERT_TRUE(if0_1.EncodesArtMethod()); - DexRegisterMap dex_registers1 = ci.GetDexRegisterMapAtDepth(0, if0, 1); + DexRegisterMap dex_registers1 = ci.GetDexRegisterMapAtDepth(0, sm0, 1); ASSERT_EQ(8, dex_registers1.GetStackOffsetInBytes(0)); - DexRegisterMap dex_registers2 = ci.GetDexRegisterMapAtDepth(1, if0, 3); + DexRegisterMap dex_registers2 = ci.GetDexRegisterMapAtDepth(1, sm0, 3); ASSERT_EQ(16, dex_registers2.GetStackOffsetInBytes(0)); ASSERT_EQ(20, dex_registers2.GetConstant(1)); ASSERT_EQ(15, dex_registers2.GetMachineRegister(2)); @@ -629,24 +631,26 @@ TEST(StackMapTest, InlineTest) { ASSERT_EQ(56, dex_registers0.GetStackOffsetInBytes(0)); ASSERT_EQ(0, dex_registers0.GetConstant(1)); - InlineInfo if1 = ci.GetInlineInfoOf(sm1); - ASSERT_EQ(3u, if1.GetDepth()); - ASSERT_EQ(2u, if1.GetDexPcAtDepth(0)); - ASSERT_TRUE(if1.EncodesArtMethodAtDepth(0)); - ASSERT_EQ(3u, if1.GetDexPcAtDepth(1)); - ASSERT_TRUE(if1.EncodesArtMethodAtDepth(1)); - ASSERT_EQ(5u, if1.GetDexPcAtDepth(2)); - ASSERT_TRUE(if1.EncodesArtMethodAtDepth(2)); - - DexRegisterMap dex_registers1 = ci.GetDexRegisterMapAtDepth(0, if1, 1); + InlineInfo if1_0 = ci.GetInlineInfoAtDepth(sm1, 0); + InlineInfo if1_1 = ci.GetInlineInfoAtDepth(sm1, 1); + InlineInfo if1_2 = ci.GetInlineInfoAtDepth(sm1, 2); + ASSERT_EQ(3u, ci.GetInlineDepthOf(sm1)); + ASSERT_EQ(2u, if1_0.GetDexPc()); + ASSERT_TRUE(if1_0.EncodesArtMethod()); + ASSERT_EQ(3u, if1_1.GetDexPc()); + ASSERT_TRUE(if1_1.EncodesArtMethod()); + ASSERT_EQ(5u, if1_2.GetDexPc()); + ASSERT_TRUE(if1_2.EncodesArtMethod()); + + DexRegisterMap dex_registers1 = ci.GetDexRegisterMapAtDepth(0, sm1, 1); ASSERT_EQ(12, dex_registers1.GetStackOffsetInBytes(0)); - DexRegisterMap dex_registers2 = ci.GetDexRegisterMapAtDepth(1, if1, 3); + DexRegisterMap dex_registers2 = ci.GetDexRegisterMapAtDepth(1, sm1, 3); ASSERT_EQ(80, dex_registers2.GetStackOffsetInBytes(0)); ASSERT_EQ(10, dex_registers2.GetConstant(1)); ASSERT_EQ(5, dex_registers2.GetMachineRegister(2)); - ASSERT_FALSE(if1.HasDexRegisterMapAtDepth(2)); + ASSERT_FALSE(if1_2.HasDexRegisterMap()); } { @@ -667,21 +671,23 @@ TEST(StackMapTest, InlineTest) { ASSERT_EQ(56, dex_registers0.GetStackOffsetInBytes(0)); ASSERT_EQ(0, dex_registers0.GetConstant(1)); - InlineInfo if2 = ci.GetInlineInfoOf(sm3); - ASSERT_EQ(3u, if2.GetDepth()); - ASSERT_EQ(2u, if2.GetDexPcAtDepth(0)); - ASSERT_TRUE(if2.EncodesArtMethodAtDepth(0)); - ASSERT_EQ(5u, if2.GetDexPcAtDepth(1)); - ASSERT_TRUE(if2.EncodesArtMethodAtDepth(1)); - ASSERT_EQ(10u, if2.GetDexPcAtDepth(2)); - ASSERT_TRUE(if2.EncodesArtMethodAtDepth(2)); + InlineInfo if2_0 = ci.GetInlineInfoAtDepth(sm3, 0); + InlineInfo if2_1 = ci.GetInlineInfoAtDepth(sm3, 1); + InlineInfo if2_2 = ci.GetInlineInfoAtDepth(sm3, 2); + ASSERT_EQ(3u, ci.GetInlineDepthOf(sm3)); + ASSERT_EQ(2u, if2_0.GetDexPc()); + ASSERT_TRUE(if2_0.EncodesArtMethod()); + ASSERT_EQ(5u, if2_1.GetDexPc()); + ASSERT_TRUE(if2_1.EncodesArtMethod()); + ASSERT_EQ(10u, if2_2.GetDexPc()); + ASSERT_TRUE(if2_2.EncodesArtMethod()); - ASSERT_FALSE(if2.HasDexRegisterMapAtDepth(0)); + ASSERT_FALSE(if2_0.HasDexRegisterMap()); - DexRegisterMap dex_registers1 = ci.GetDexRegisterMapAtDepth(1, if2, 1); + DexRegisterMap dex_registers1 = ci.GetDexRegisterMapAtDepth(1, sm3, 1); ASSERT_EQ(2, dex_registers1.GetMachineRegister(0)); - DexRegisterMap dex_registers2 = ci.GetDexRegisterMapAtDepth(2, if2, 2); + DexRegisterMap dex_registers2 = ci.GetDexRegisterMapAtDepth(2, sm3, 2); ASSERT_FALSE(dex_registers2.IsDexRegisterLive(0)); ASSERT_EQ(3, dex_registers2.GetMachineRegister(1)); } diff --git a/dex2oat/linker/image_writer.cc b/dex2oat/linker/image_writer.cc index 028de34e96..dc0709013c 100644 --- a/dex2oat/linker/image_writer.cc +++ b/dex2oat/linker/image_writer.cc @@ -1342,6 +1342,14 @@ ObjectArray<Object>* ImageWriter::CreateImageRoots(size_t oat_index) const { ObjectArray<Object>::Alloc(self, object_array_class.Get(), image_roots_size))); image_roots->Set<false>(ImageHeader::kDexCaches, dex_caches.Get()); image_roots->Set<false>(ImageHeader::kClassRoots, class_linker->GetClassRoots()); + image_roots->Set<false>(ImageHeader::kOomeWhenThrowingException, + runtime->GetPreAllocatedOutOfMemoryErrorWhenThrowingException()); + image_roots->Set<false>(ImageHeader::kOomeWhenThrowingOome, + runtime->GetPreAllocatedOutOfMemoryErrorWhenThrowingOOME()); + image_roots->Set<false>(ImageHeader::kOomeWhenHandlingStackOverflow, + runtime->GetPreAllocatedOutOfMemoryErrorWhenHandlingStackOverflow()); + image_roots->Set<false>(ImageHeader::kNoClassDefFoundError, + runtime->GetPreAllocatedNoClassDefFoundError()); // image_roots[ImageHeader::kClassLoader] will be set later for app image. static_assert(ImageHeader::kClassLoader + 1u == ImageHeader::kImageRootsMax, "Class loader should be the last image root."); diff --git a/dex2oat/linker/oat_writer.cc b/dex2oat/linker/oat_writer.cc index 4046dc101f..99516684e8 100644 --- a/dex2oat/linker/oat_writer.cc +++ b/dex2oat/linker/oat_writer.cc @@ -4032,13 +4032,13 @@ bool OatWriter::WriteTypeLookupTables( // TypeLookupTable allocates its own and OatDexFile takes ownership. const DexFile& dex_file = *opened_dex_files[i]; { - std::unique_ptr<TypeLookupTable> type_lookup_table = - TypeLookupTable::Create(dex_file, /* storage */ nullptr); + TypeLookupTable type_lookup_table = TypeLookupTable::Create(dex_file); type_lookup_table_oat_dex_files_.push_back( std::make_unique<art::OatDexFile>(std::move(type_lookup_table))); dex_file.SetOatDexFile(type_lookup_table_oat_dex_files_.back().get()); } - TypeLookupTable* const table = type_lookup_table_oat_dex_files_.back()->GetTypeLookupTable(); + const TypeLookupTable& table = type_lookup_table_oat_dex_files_.back()->GetTypeLookupTable(); + DCHECK(table.Valid()); // Type tables are required to be 4 byte aligned. size_t initial_offset = oat_size_; @@ -4057,9 +4057,9 @@ bool OatWriter::WriteTypeLookupTables( DCHECK_EQ(oat_data_offset_ + rodata_offset, static_cast<size_t>(oat_rodata->Seek(0u, kSeekCurrent))); - DCHECK_EQ(table_size, table->RawDataLength()); + DCHECK_EQ(table_size, table.RawDataLength()); - if (!oat_rodata->WriteFully(table->RawData(), table_size)) { + if (!oat_rodata->WriteFully(table.RawData(), table_size)) { PLOG(ERROR) << "Failed to write lookup table." << " File: " << oat_dex_file->GetLocation() << " Output: " << oat_rodata->GetLocation(); diff --git a/libdexfile/dex/class_accessor-inl.h b/libdexfile/dex/class_accessor-inl.h index 49ca98d47f..3bb9e93e5a 100644 --- a/libdexfile/dex/class_accessor-inl.h +++ b/libdexfile/dex/class_accessor-inl.h @@ -37,30 +37,26 @@ inline ClassAccessor::ClassAccessor(const DexFile& dex_file, const DexFile::Clas num_direct_methods_(ptr_pos_ != nullptr ? DecodeUnsignedLeb128(&ptr_pos_) : 0u), num_virtual_methods_(ptr_pos_ != nullptr ? DecodeUnsignedLeb128(&ptr_pos_) : 0u) {} -inline const uint8_t* ClassAccessor::Method::Read(const uint8_t* ptr) { - index_ += DecodeUnsignedLeb128(&ptr); - access_flags_ = DecodeUnsignedLeb128(&ptr); - code_off_ = DecodeUnsignedLeb128(&ptr); - return ptr; +inline void ClassAccessor::Method::Read() { + index_ += DecodeUnsignedLeb128(&ptr_pos_); + access_flags_ = DecodeUnsignedLeb128(&ptr_pos_); + code_off_ = DecodeUnsignedLeb128(&ptr_pos_); } -inline const uint8_t* ClassAccessor::Field::Read(const uint8_t* ptr) { - index_ += DecodeUnsignedLeb128(&ptr); - access_flags_ = DecodeUnsignedLeb128(&ptr); - return ptr; +inline void ClassAccessor::Field::Read() { + index_ += DecodeUnsignedLeb128(&ptr_pos_); + access_flags_ = DecodeUnsignedLeb128(&ptr_pos_); } template <typename DataType, typename Visitor> -inline const uint8_t* ClassAccessor::VisitMembers(size_t count, - const Visitor& visitor, - const uint8_t* ptr, - DataType* data) const { +inline void ClassAccessor::VisitMembers(size_t count, + const Visitor& visitor, + DataType* data) const { DCHECK(data != nullptr); for ( ; count != 0; --count) { - ptr = data->Read(ptr); + data->Read(); visitor(*data); } - return ptr; } template <typename StaticFieldVisitor, @@ -72,15 +68,15 @@ inline void ClassAccessor::VisitFieldsAndMethods( const InstanceFieldVisitor& instance_field_visitor, const DirectMethodVisitor& direct_method_visitor, const VirtualMethodVisitor& virtual_method_visitor) const { - Field field(dex_file_); - const uint8_t* ptr = VisitMembers(num_static_fields_, static_field_visitor, ptr_pos_, &field); + Field field(dex_file_, ptr_pos_); + VisitMembers(num_static_fields_, static_field_visitor, &field); field.NextSection(); - ptr = VisitMembers(num_instance_fields_, instance_field_visitor, ptr, &field); + VisitMembers(num_instance_fields_, instance_field_visitor, &field); - Method method(dex_file_, /*is_static_or_direct*/ true); - ptr = VisitMembers(num_direct_methods_, direct_method_visitor, ptr, &method); + Method method(dex_file_, field.ptr_pos_, /*is_static_or_direct*/ true); + VisitMembers(num_direct_methods_, direct_method_visitor, &method); method.NextSection(); - ptr = VisitMembers(num_virtual_methods_, virtual_method_visitor, ptr, &method); + VisitMembers(num_virtual_methods_, virtual_method_visitor, &method); } template <typename DirectMethodVisitor, @@ -119,23 +115,64 @@ inline const DexFile::CodeItem* ClassAccessor::Method::GetCodeItem() const { return dex_file_.GetCodeItem(code_off_); } +inline IterationRange<ClassAccessor::DataIterator<ClassAccessor::Field>> + ClassAccessor::GetFieldsInternal(size_t count) const { + return { DataIterator<Field>(dex_file_, 0u, num_static_fields_, count, ptr_pos_), + DataIterator<Field>(dex_file_, count, num_static_fields_, count, ptr_pos_) }; +} + +// Return an iteration range for the first <count> methods. +inline IterationRange<ClassAccessor::DataIterator<ClassAccessor::Method>> + ClassAccessor::GetMethodsInternal(size_t count) const { + // Skip over the fields. + Field field(dex_file_, ptr_pos_); + VisitMembers(NumFields(), VoidFunctor(), &field); + // Return the iterator pair. + return { DataIterator<Method>(dex_file_, 0u, num_direct_methods_, count, field.ptr_pos_), + DataIterator<Method>(dex_file_, count, num_direct_methods_, count, field.ptr_pos_) }; +} + inline IterationRange<ClassAccessor::DataIterator<ClassAccessor::Field>> ClassAccessor::GetFields() const { - const uint32_t limit = num_static_fields_ + num_instance_fields_; - return { DataIterator<Field>(dex_file_, 0u, num_static_fields_, limit, ptr_pos_), - DataIterator<Field>(dex_file_, limit, num_static_fields_, limit, ptr_pos_) }; + return GetFieldsInternal(num_static_fields_ + num_instance_fields_); +} + +inline IterationRange<ClassAccessor::DataIterator<ClassAccessor::Field>> + ClassAccessor::GetStaticFields() const { + return GetFieldsInternal(num_static_fields_); +} + + +inline IterationRange<ClassAccessor::DataIterator<ClassAccessor::Field>> + ClassAccessor::GetInstanceFields() const { + IterationRange<ClassAccessor::DataIterator<ClassAccessor::Field>> fields = GetFields(); + // Skip the static fields. + return { std::next(fields.begin(), NumStaticFields()), fields.end() }; } inline IterationRange<ClassAccessor::DataIterator<ClassAccessor::Method>> ClassAccessor::GetMethods() const { - // Skip over the fields. - Field field(dex_file_); - const size_t skip_count = num_static_fields_ + num_instance_fields_; - const uint8_t* ptr_pos = VisitMembers(skip_count, VoidFunctor(), ptr_pos_, &field); - // Return the iterator pair for all the methods. - const uint32_t limit = num_direct_methods_ + num_virtual_methods_; - return { DataIterator<Method>(dex_file_, 0u, num_direct_methods_, limit, ptr_pos), - DataIterator<Method>(dex_file_, limit, num_direct_methods_, limit, ptr_pos) }; + return GetMethodsInternal(NumMethods()); +} + +inline IterationRange<ClassAccessor::DataIterator<ClassAccessor::Method>> + ClassAccessor::GetDirectMethods() const { + return GetMethodsInternal(NumDirectMethods()); +} + +inline IterationRange<ClassAccessor::DataIterator<ClassAccessor::Method>> + ClassAccessor::GetVirtualMethods() const { + IterationRange<DataIterator<Method>> methods = GetMethods(); + // Skip the direct fields. + return { std::next(methods.begin(), NumDirectMethods()), methods.end() }; +} + +inline void ClassAccessor::Field::UnHideAccessFlags() const { + DexFile::UnHideAccessFlags(const_cast<uint8_t*>(ptr_pos_), GetAccessFlags(), /*is_method*/ false); +} + +inline void ClassAccessor::Method::UnHideAccessFlags() const { + DexFile::UnHideAccessFlags(const_cast<uint8_t*>(ptr_pos_), GetAccessFlags(), /*is_method*/ true); } } // namespace art diff --git a/libdexfile/dex/class_accessor.h b/libdexfile/dex/class_accessor.h index dda6e1c1a6..4f0fd32e31 100644 --- a/libdexfile/dex/class_accessor.h +++ b/libdexfile/dex/class_accessor.h @@ -20,6 +20,7 @@ #include "base/utils.h" #include "code_item_accessors.h" #include "dex_file.h" +#include "hidden_api_access_flags.h" #include "invoke_type.h" #include "method_reference.h" #include "modifiers.h" @@ -33,12 +34,18 @@ class ClassAccessor { private: class BaseItem { public: + explicit BaseItem(const uint8_t* ptr_pos) : ptr_pos_(ptr_pos) {} + uint32_t GetIndex() const { return index_; } uint32_t GetAccessFlags() const { - return access_flags_; + return HiddenApiAccessFlags::RemoveFromDex(access_flags_); + } + + HiddenApiAccessFlags::ApiList DecodeHiddenAccessFlags() const { + return HiddenApiAccessFlags::DecodeFromDex(access_flags_); } bool IsFinal() const { @@ -46,6 +53,8 @@ class ClassAccessor { } protected: + // Internal data pointer for reading. + const uint8_t* ptr_pos_ = nullptr; uint32_t index_ = 0u; uint32_t access_flags_ = 0u; }; @@ -76,13 +85,18 @@ class ClassAccessor { return is_static_or_direct_; } + // Unhide the hidden API access flags at the iterator position. TODO: Deprecate. + void UnHideAccessFlags() const; + private: explicit Method(const DexFile& dex_file, + const uint8_t* ptr_pos, bool is_static_or_direct = true) - : dex_file_(dex_file), + : BaseItem(ptr_pos), + dex_file_(dex_file), is_static_or_direct_(is_static_or_direct) {} - const uint8_t* Read(const uint8_t* ptr); + void Read(); InvokeType GetDirectMethodInvokeType() const { return (GetAccessFlags() & kAccStatic) != 0 ? kStatic : kDirect; @@ -99,6 +113,7 @@ class ClassAccessor { } } + // Move to virtual method section. void NextSection() { DCHECK(is_static_or_direct_) << "Already in the virtual methods section"; is_static_or_direct_ = false; @@ -115,20 +130,31 @@ class ClassAccessor { // A decoded version of the field of a class_data_item. class Field : public BaseItem { public: - explicit Field(const DexFile& dex_file) : dex_file_(dex_file) {} + explicit Field(const DexFile& dex_file, + const uint8_t* ptr_pos) : BaseItem(ptr_pos), dex_file_(dex_file) {} const DexFile& GetDexFile() const { return dex_file_; } + bool IsStatic() const { + return is_static_; + } + + // Unhide the hidden API access flags at the iterator position. TODO: Deprecate. + void UnHideAccessFlags() const; + private: - const uint8_t* Read(const uint8_t* ptr); + void Read(); + // Move to instance fields section. void NextSection() { index_ = 0u; + is_static_ = false; } const DexFile& dex_file_; + bool is_static_ = true; friend class ClassAccessor; }; @@ -144,11 +170,10 @@ class ClassAccessor { uint32_t partition_pos, uint32_t iterator_end, const uint8_t* ptr_pos) - : data_(dex_file), + : data_(dex_file, ptr_pos), position_(position), partition_pos_(partition_pos), - iterator_end_(iterator_end), - ptr_pos_(ptr_pos) { + iterator_end_(iterator_end) { ReadData(); } @@ -205,8 +230,7 @@ class ClassAccessor { if (position_ == partition_pos_) { data_.NextSection(); } - DCHECK(ptr_pos_ != nullptr); - ptr_pos_ = data_.Read(ptr_pos_); + data_.Read(); } } @@ -217,8 +241,6 @@ class ClassAccessor { const uint32_t partition_pos_; // At iterator_end_, the iterator is no longer valid. const uint32_t iterator_end_; - // Internal data pointer. - const uint8_t* ptr_pos_; }; // Not explicit specifically for range-based loops. @@ -252,9 +274,21 @@ class ClassAccessor { // Return the iteration range for all the fields. IterationRange<DataIterator<Field>> GetFields() const; + // Return the iteration range for all the static fields. + IterationRange<DataIterator<Field>> GetStaticFields() const; + + // Return the iteration range for all the instance fields. + IterationRange<DataIterator<Field>> GetInstanceFields() const; + // Return the iteration range for all the methods. IterationRange<DataIterator<Method>> GetMethods() const; + // Return the iteration range for the direct methods. + IterationRange<DataIterator<Method>> GetDirectMethods() const; + + // Return the iteration range for the virtual methods. + IterationRange<DataIterator<Method>> GetVirtualMethods() const; + uint32_t NumStaticFields() const { return num_static_fields_; } @@ -263,6 +297,10 @@ class ClassAccessor { return num_instance_fields_; } + uint32_t NumFields() const { + return NumStaticFields() + NumInstanceFields(); + } + uint32_t NumDirectMethods() const { return num_direct_methods_; } @@ -285,14 +323,22 @@ class ClassAccessor { return dex_file_; } + bool HasClassData() const { + return ptr_pos_ != nullptr; + } + protected: // Template visitor to reduce copy paste for visiting elements. // No thread safety analysis since the visitor may require capabilities. template <typename DataType, typename Visitor> - const uint8_t* VisitMembers(size_t count, - const Visitor& visitor, - const uint8_t* ptr, - DataType* data) const NO_THREAD_SAFETY_ANALYSIS; + void VisitMembers(size_t count, const Visitor& visitor, DataType* data) const + NO_THREAD_SAFETY_ANALYSIS; + + // Return an iteration range for the first <count> fields. + IterationRange<DataIterator<Field>> GetFieldsInternal(size_t count) const; + + // Return an iteration range for the first <count> methods. + IterationRange<DataIterator<Method>> GetMethodsInternal(size_t count) const; const DexFile& dex_file_; const dex::TypeIndex descriptor_index_ = {}; diff --git a/libdexfile/dex/class_accessor_test.cc b/libdexfile/dex/class_accessor_test.cc index 95380d8140..d0533c1811 100644 --- a/libdexfile/dex/class_accessor_test.cc +++ b/libdexfile/dex/class_accessor_test.cc @@ -38,18 +38,27 @@ TEST_F(ClassAccessorTest, TestVisiting) { auto fields = accessor.GetFields(); auto method_it = methods.begin(); auto field_it = fields.begin(); + auto instance_fields = accessor.GetInstanceFields(); + auto instance_field_it = instance_fields.begin(); accessor.VisitFieldsAndMethods( // Static fields. [&](const ClassAccessor::Field& field) { + EXPECT_TRUE(field.IsStatic()); + EXPECT_TRUE(field_it->IsStatic()); EXPECT_EQ(field.GetIndex(), field_it->GetIndex()); EXPECT_EQ(field.GetAccessFlags(), field_it->GetAccessFlags()); ++field_it; }, // Instance fields. [&](const ClassAccessor::Field& field) { + EXPECT_FALSE(field.IsStatic()); + EXPECT_FALSE(field_it->IsStatic()); EXPECT_EQ(field.GetIndex(), field_it->GetIndex()); EXPECT_EQ(field.GetAccessFlags(), field_it->GetAccessFlags()); + EXPECT_EQ(field.GetIndex(), instance_field_it->GetIndex()); + EXPECT_EQ(field.GetAccessFlags(), instance_field_it->GetAccessFlags()); ++field_it; + ++instance_field_it; }, // Direct methods. [&](const ClassAccessor::Method& method) { @@ -71,6 +80,7 @@ TEST_F(ClassAccessorTest, TestVisiting) { }); ASSERT_TRUE(field_it == fields.end()); ASSERT_TRUE(method_it == methods.end()); + ASSERT_TRUE(instance_field_it == instance_fields.end()); } EXPECT_EQ(class_def_idx, dex_file->NumClassDefs()); } diff --git a/libdexfile/dex/dex_file.cc b/libdexfile/dex/dex_file.cc index 9de260c862..f570158dfb 100644 --- a/libdexfile/dex/dex_file.cc +++ b/libdexfile/dex/dex_file.cc @@ -45,19 +45,18 @@ static_assert(std::is_trivially_copyable<dex::StringIndex>::value, "StringIndex static_assert(sizeof(dex::TypeIndex) == sizeof(uint16_t), "TypeIndex size is wrong"); static_assert(std::is_trivially_copyable<dex::TypeIndex>::value, "TypeIndex not trivial"); -void DexFile::UnHideAccessFlags(ClassDataItemIterator& class_it) { - uint8_t* data = const_cast<uint8_t*>(class_it.DataPointer()); - uint32_t new_flag = class_it.GetMemberAccessFlags(); - bool is_method = class_it.IsAtMethod(); +void DexFile::UnHideAccessFlags(uint8_t* data_ptr, + uint32_t new_access_flags, + bool is_method) { // Go back 1 uleb to start. - data = ReverseSearchUnsignedLeb128(data); + data_ptr = ReverseSearchUnsignedLeb128(data_ptr); if (is_method) { // Methods have another uleb field before the access flags - data = ReverseSearchUnsignedLeb128(data); + data_ptr = ReverseSearchUnsignedLeb128(data_ptr); } - DCHECK_EQ(HiddenApiAccessFlags::RemoveFromDex(DecodeUnsignedLeb128WithoutMovingCursor(data)), - new_flag); - UpdateUnsignedLeb128(data, new_flag); + DCHECK_EQ(HiddenApiAccessFlags::RemoveFromDex(DecodeUnsignedLeb128WithoutMovingCursor(data_ptr)), + new_access_flags); + UpdateUnsignedLeb128(data_ptr, new_access_flags); } uint32_t DexFile::CalculateChecksum() const { diff --git a/libdexfile/dex/dex_file.h b/libdexfile/dex/dex_file.h index f1f8b505bd..ed219808d2 100644 --- a/libdexfile/dex/dex_file.h +++ b/libdexfile/dex/dex_file.h @@ -1010,8 +1010,8 @@ class DexFile { return container_.get(); } - // Changes the dex file pointed to by class_it to not have any hiddenapi flags. - static void UnHideAccessFlags(ClassDataItemIterator& class_it); + // Changes the dex class data pointed to by data_ptr it to not have any hiddenapi flags. + static void UnHideAccessFlags(uint8_t* data_ptr, uint32_t new_access_flags, bool is_method); inline IterationRange<ClassIterator> GetClasses() const; diff --git a/libdexfile/dex/type_lookup_table.cc b/libdexfile/dex/type_lookup_table.cc index ca5ec2f798..00ec358b02 100644 --- a/libdexfile/dex/type_lookup_table.cc +++ b/libdexfile/dex/type_lookup_table.cc @@ -20,72 +20,43 @@ #include <memory> #include "base/bit_utils.h" +#include "base/leb128.h" #include "dex/dex_file-inl.h" #include "dex/utf-inl.h" namespace art { -static uint16_t MakeData(uint16_t class_def_idx, uint32_t hash, uint32_t mask) { - uint16_t hash_mask = static_cast<uint16_t>(~mask); - return (static_cast<uint16_t>(hash) & hash_mask) | class_def_idx; +static inline bool ModifiedUtf8StringEquals(const char* lhs, const char* rhs) { + return CompareModifiedUtf8ToModifiedUtf8AsUtf16CodePointValues(lhs, rhs) == 0; } -TypeLookupTable::~TypeLookupTable() { - if (!owns_entries_) { - // We don't actually own the entries, don't let the unique_ptr release them. - entries_.release(); +TypeLookupTable TypeLookupTable::Create(const DexFile& dex_file) { + uint32_t num_class_defs = dex_file.NumClassDefs(); + if (UNLIKELY(!SupportedSize(num_class_defs))) { + return TypeLookupTable(); } -} - -uint32_t TypeLookupTable::RawDataLength(uint32_t num_class_defs) { - return SupportedSize(num_class_defs) ? RoundUpToPowerOfTwo(num_class_defs) * sizeof(Entry) : 0u; -} - -uint32_t TypeLookupTable::CalculateMask(uint32_t num_class_defs) { - return SupportedSize(num_class_defs) ? RoundUpToPowerOfTwo(num_class_defs) - 1u : 0u; -} - -bool TypeLookupTable::SupportedSize(uint32_t num_class_defs) { - return num_class_defs != 0u && num_class_defs <= std::numeric_limits<uint16_t>::max(); -} - -std::unique_ptr<TypeLookupTable> TypeLookupTable::Create(const DexFile& dex_file, - uint8_t* storage) { - const uint32_t num_class_defs = dex_file.NumClassDefs(); - return std::unique_ptr<TypeLookupTable>(SupportedSize(num_class_defs) - ? new TypeLookupTable(dex_file, storage) - : nullptr); -} - -std::unique_ptr<TypeLookupTable> TypeLookupTable::Open(const uint8_t* dex_file_pointer, - const uint8_t* raw_data, - uint32_t num_class_defs) { - return std::unique_ptr<TypeLookupTable>( - new TypeLookupTable(dex_file_pointer, raw_data, num_class_defs)); -} + size_t mask_bits = CalculateMaskBits(num_class_defs); + size_t size = 1u << mask_bits; + std::unique_ptr<Entry[]> owned_entries(new Entry[size]); + Entry* entries = owned_entries.get(); -TypeLookupTable::TypeLookupTable(const DexFile& dex_file, uint8_t* storage) - : dex_data_begin_(dex_file.DataBegin()), - raw_data_length_(RawDataLength(dex_file.NumClassDefs())), - mask_(CalculateMask(dex_file.NumClassDefs())), - entries_(storage != nullptr ? reinterpret_cast<Entry*>(storage) : new Entry[mask_ + 1]), - owns_entries_(storage == nullptr) { static_assert(alignof(Entry) == 4u, "Expecting Entry to be 4-byte aligned."); - DCHECK_ALIGNED(storage, alignof(Entry)); + const uint32_t mask = Entry::GetMask(mask_bits); std::vector<uint16_t> conflict_class_defs; // The first stage. Put elements on their initial positions. If an initial position is already // occupied then delay the insertion of the element to the second stage to reduce probing // distance. - for (size_t i = 0; i < dex_file.NumClassDefs(); ++i) { - const DexFile::ClassDef& class_def = dex_file.GetClassDef(i); + for (size_t class_def_idx = 0; class_def_idx < dex_file.NumClassDefs(); ++class_def_idx) { + const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_idx); const DexFile::TypeId& type_id = dex_file.GetTypeId(class_def.class_idx_); const DexFile::StringId& str_id = dex_file.GetStringId(type_id.descriptor_idx_); const uint32_t hash = ComputeModifiedUtf8Hash(dex_file.GetStringData(str_id)); - Entry entry; - entry.str_offset = str_id.string_data_off_; - entry.data = MakeData(i, hash, GetSizeMask()); - if (!SetOnInitialPos(entry, hash)) { - conflict_class_defs.push_back(i); + const uint32_t pos = hash & mask; + if (entries[pos].IsEmpty()) { + entries[pos] = Entry(str_id.string_data_off_, hash, class_def_idx, mask_bits); + DCHECK(entries[pos].IsLast(mask_bits)); + } else { + conflict_class_defs.push_back(class_def_idx); } } // The second stage. The initial position of these elements had a collision. Put these elements @@ -95,51 +66,111 @@ TypeLookupTable::TypeLookupTable(const DexFile& dex_file, uint8_t* storage) const DexFile::TypeId& type_id = dex_file.GetTypeId(class_def.class_idx_); const DexFile::StringId& str_id = dex_file.GetStringId(type_id.descriptor_idx_); const uint32_t hash = ComputeModifiedUtf8Hash(dex_file.GetStringData(str_id)); - Entry entry; - entry.str_offset = str_id.string_data_off_; - entry.data = MakeData(class_def_idx, hash, GetSizeMask()); - Insert(entry, hash); + // Find the last entry in the chain. + uint32_t tail_pos = hash & mask; + DCHECK(!entries[tail_pos].IsEmpty()); + while (!entries[tail_pos].IsLast(mask_bits)) { + tail_pos = (tail_pos + entries[tail_pos].GetNextPosDelta(mask_bits)) & mask; + DCHECK(!entries[tail_pos].IsEmpty()); + } + // Find an empty entry for insertion. + uint32_t insert_pos = tail_pos; + do { + insert_pos = (insert_pos + 1) & mask; + } while (!entries[insert_pos].IsEmpty()); + // Insert and chain the new entry. + entries[insert_pos] = Entry(str_id.string_data_off_, hash, class_def_idx, mask_bits); + entries[tail_pos].SetNextPosDelta((insert_pos - tail_pos) & mask, mask_bits); + DCHECK(entries[insert_pos].IsLast(mask_bits)); + DCHECK(!entries[tail_pos].IsLast(mask_bits)); } -} -TypeLookupTable::TypeLookupTable(const uint8_t* dex_file_pointer, - const uint8_t* raw_data, - uint32_t num_class_defs) - : dex_data_begin_(dex_file_pointer), - raw_data_length_(RawDataLength(num_class_defs)), - mask_(CalculateMask(num_class_defs)), - entries_(reinterpret_cast<Entry*>(const_cast<uint8_t*>(raw_data))), - owns_entries_(false) {} - -bool TypeLookupTable::SetOnInitialPos(const Entry& entry, uint32_t hash) { - const uint32_t pos = hash & GetSizeMask(); - if (!entries_[pos].IsEmpty()) { - return false; - } - entries_[pos] = entry; - entries_[pos].next_pos_delta = 0; - return true; + return TypeLookupTable(dex_file.DataBegin(), mask_bits, entries, std::move(owned_entries)); } -void TypeLookupTable::Insert(const Entry& entry, uint32_t hash) { - uint32_t pos = FindLastEntryInBucket(hash & GetSizeMask()); - uint32_t next_pos = (pos + 1) & GetSizeMask(); - while (!entries_[next_pos].IsEmpty()) { - next_pos = (next_pos + 1) & GetSizeMask(); - } - const uint32_t delta = (next_pos >= pos) ? (next_pos - pos) : (next_pos + Size() - pos); - entries_[pos].next_pos_delta = delta; - entries_[next_pos] = entry; - entries_[next_pos].next_pos_delta = 0; +TypeLookupTable TypeLookupTable::Open(const uint8_t* dex_data_pointer, + const uint8_t* raw_data, + uint32_t num_class_defs) { + DCHECK_ALIGNED(raw_data, alignof(Entry)); + const Entry* entries = reinterpret_cast<const Entry*>(raw_data); + size_t mask_bits = CalculateMaskBits(num_class_defs); + return TypeLookupTable(dex_data_pointer, mask_bits, entries, /* owned_entries */ nullptr); } -uint32_t TypeLookupTable::FindLastEntryInBucket(uint32_t pos) const { +uint32_t TypeLookupTable::Lookup(const char* str, uint32_t hash) const { + uint32_t mask = Entry::GetMask(mask_bits_); + uint32_t pos = hash & mask; + // Thanks to special insertion algorithm, the element at position pos can be empty + // or start of the right bucket, or anywhere in the wrong bucket's chain. const Entry* entry = &entries_[pos]; - while (!entry->IsLast()) { - pos = (pos + entry->next_pos_delta) & GetSizeMask(); + if (entry->IsEmpty()) { + return dex::kDexNoIndex; + } + // Look for the partial hash match first, even if traversing the wrong bucket's chain. + uint32_t compared_hash_bits = (hash << mask_bits_) >> (2 * mask_bits_); + while (compared_hash_bits != entry->GetHashBits(mask_bits_)) { + if (entry->IsLast(mask_bits_)) { + return dex::kDexNoIndex; + } + pos = (pos + entry->GetNextPosDelta(mask_bits_)) & mask; entry = &entries_[pos]; + DCHECK(!entry->IsEmpty()); + } + // Found partial hash match, compare strings (expecting this to succeed). + const char* first_checked_str = GetStringData(*entry); + if (ModifiedUtf8StringEquals(str, first_checked_str)) { + return entry->GetClassDefIdx(mask_bits_); + } + // If we're at the end of the chain, return before doing further expensive work. + if (entry->IsLast(mask_bits_)) { + return dex::kDexNoIndex; + } + // Check if we're traversing the right bucket. This is important if the compared + // partial hash has only a few bits (i.e. it can match frequently). + if (((ComputeModifiedUtf8Hash(first_checked_str) ^ hash) & mask) != 0u) { + return dex::kDexNoIndex; // Low hash bits mismatch. } - return pos; + // Continue looking for the string in the rest of the chain. + do { + pos = (pos + entry->GetNextPosDelta(mask_bits_)) & mask; + entry = &entries_[pos]; + DCHECK(!entry->IsEmpty()); + if (compared_hash_bits == entry->GetHashBits(mask_bits_) && + ModifiedUtf8StringEquals(str, GetStringData(*entry))) { + return entry->GetClassDefIdx(mask_bits_); + } + } while (!entry->IsLast(mask_bits_)); + // Not found. + return dex::kDexNoIndex; +} + +uint32_t TypeLookupTable::RawDataLength(uint32_t num_class_defs) { + return SupportedSize(num_class_defs) ? RoundUpToPowerOfTwo(num_class_defs) * sizeof(Entry) : 0u; +} + +uint32_t TypeLookupTable::CalculateMaskBits(uint32_t num_class_defs) { + return SupportedSize(num_class_defs) ? MinimumBitsToStore(num_class_defs - 1u) : 0u; +} + +bool TypeLookupTable::SupportedSize(uint32_t num_class_defs) { + return num_class_defs != 0u && num_class_defs <= std::numeric_limits<uint16_t>::max(); +} + +TypeLookupTable::TypeLookupTable(const uint8_t* dex_data_pointer, + uint32_t mask_bits, + const Entry* entries, + std::unique_ptr<Entry[]> owned_entries) + : dex_data_begin_(dex_data_pointer), + mask_bits_(mask_bits), + entries_(entries), + owned_entries_(std::move(owned_entries)) {} + +const char* TypeLookupTable::GetStringData(const Entry& entry) const { + DCHECK(dex_data_begin_ != nullptr); + const uint8_t* ptr = dex_data_begin_ + entry.GetStringOffset(); + // Skip string length. + DecodeUnsignedLeb128(&ptr); + return reinterpret_cast<const char*>(ptr); } } // namespace art diff --git a/libdexfile/dex/type_lookup_table.h b/libdexfile/dex/type_lookup_table.h index 0ba2b75dc6..7005d34b88 100644 --- a/libdexfile/dex/type_lookup_table.h +++ b/libdexfile/dex/type_lookup_table.h @@ -17,9 +17,8 @@ #ifndef ART_LIBDEXFILE_DEX_TYPE_LOOKUP_TABLE_H_ #define ART_LIBDEXFILE_DEX_TYPE_LOOKUP_TABLE_H_ -#include "base/leb128.h" +#include "base/logging.h" #include "dex/dex_file_types.h" -#include "dex/utf.h" namespace art { @@ -34,140 +33,146 @@ class DexFile; */ class TypeLookupTable { public: - ~TypeLookupTable(); + // Method creates lookup table for dex file. + static TypeLookupTable Create(const DexFile& dex_file); + + // Method opens lookup table from binary data. Lookups will traverse strings and other + // data contained in dex_file as well. Lookup table does not own raw_data or dex_file. + static TypeLookupTable Open(const uint8_t* dex_data_pointer, + const uint8_t* raw_data, + uint32_t num_class_defs); + + // Create an invalid lookup table. + TypeLookupTable() + : dex_data_begin_(nullptr), + mask_bits_(0u), + entries_(nullptr), + owned_entries_(nullptr) {} + + TypeLookupTable(TypeLookupTable&& src) noexcept = default; + TypeLookupTable& operator=(TypeLookupTable&& src) noexcept = default; + + ~TypeLookupTable() { + // Implicit deallocation by std::unique_ptr<> destructor. + } + + // Returns whether the TypeLookupTable is valid. + bool Valid() const { + return entries_ != nullptr; + } // Return the number of buckets in the lookup table. uint32_t Size() const { - return mask_ + 1; + DCHECK(Valid()); + return 1u << mask_bits_; } // Method search class_def_idx by class descriptor and it's hash. // If no data found then the method returns dex::kDexNoIndex. - uint32_t Lookup(const char* str, uint32_t hash) const { - uint32_t pos = hash & GetSizeMask(); - // Thanks to special insertion algorithm, the element at position pos can be empty or start of - // bucket. - const Entry* entry = &entries_[pos]; - while (!entry->IsEmpty()) { - if (CmpHashBits(entry->data, hash) && IsStringsEquals(str, entry->str_offset)) { - return GetClassDefIdx(entry->data); - } - if (entry->IsLast()) { - return dex::kDexNoIndex; - } - pos = (pos + entry->next_pos_delta) & GetSizeMask(); - entry = &entries_[pos]; - } - return dex::kDexNoIndex; - } - - // Method creates lookup table for dex file - static std::unique_ptr<TypeLookupTable> Create(const DexFile& dex_file, - uint8_t* storage = nullptr); - - // Method opens lookup table from binary data. Lookups will traverse strings and other - // data contained in dex_file as well. Lookup table does not own raw_data or dex_file. - static std::unique_ptr<TypeLookupTable> Open(const uint8_t* dex_file_pointer, - const uint8_t* raw_data, - uint32_t num_class_defs); + uint32_t Lookup(const char* str, uint32_t hash) const; // Method returns pointer to binary data of lookup table. Used by the oat writer. const uint8_t* RawData() const { - return reinterpret_cast<const uint8_t*>(entries_.get()); + DCHECK(Valid()); + return reinterpret_cast<const uint8_t*>(entries_); } // Method returns length of binary data. Used by the oat writer. - uint32_t RawDataLength() const { return raw_data_length_; } + uint32_t RawDataLength() const { + DCHECK(Valid()); + return Size() * sizeof(Entry); + } // Method returns length of binary data for the specified number of class definitions. static uint32_t RawDataLength(uint32_t num_class_defs); private: - /** - * To find element we need to compare strings. - * It is faster to compare first hashes and then strings itself. - * But we have no full hash of element of table. But we can use 2 ideas. - * 1. All minor bits of hash inside one bucket are equals. - * 2. If dex file contains N classes and size of hash table is 2^n (where N <= 2^n) - * then 16-n bits are free. So we can encode part of element's hash into these bits. - * So hash of element can be divided on three parts: - * XXXX XXXX XXXX YYYY YZZZ ZZZZ ZZZZZ - * Z - a part of hash encoded in bucket (these bits of has are same for all elements in bucket) - - * n bits - * Y - a part of hash that we can write into free 16-n bits (because only n bits used to store - * class_def_idx) - * X - a part of has that we can't use without increasing increase - * So the data element of Entry used to store class_def_idx and part of hash of the entry. - */ - struct Entry { - uint32_t str_offset; - uint16_t data; - uint16_t next_pos_delta; - - Entry() : str_offset(0), data(0), next_pos_delta(0) {} + /** + * To find element we need to compare strings. + * It is faster to compare first hashes and then strings itself. + * But we have no full hash of element of table. But we can use 2 ideas. + * 1. All minor bits of hash inside one bucket are equal. + * (TODO: We're not actually using this, are we?) + * 2. If the dex file contains N classes and the size of the hash table is 2^n (where N <= 2^n) + * then we need n bits for the class def index and n bits for the next position delta. + * So we can encode part of element's hash into the remaining 32-2*n (n <= 16) bits which + * would be otherwise wasted as a padding. + * So hash of element can be divided on three parts: + * XXXX XXXX XXXY YYYY YYYY YZZZ ZZZZ ZZZZ (example with n=11) + * Z - a part of hash encoded implicitly in the bucket index + * (these bits are same for all elements in bucket) + * Y - a part of hash that we can write into free 32-2*n bits + * X - a part of hash that we can't use without increasing the size of the entry + * So the `data` element of Entry is used to store the next position delta, class_def_index + * and a part of hash of the entry. + */ + class Entry { + public: + Entry() : str_offset_(0u), data_(0u) {} + Entry(uint32_t str_offset, uint32_t hash, uint32_t class_def_index, uint32_t mask_bits) + : str_offset_(str_offset), + data_(((hash & ~GetMask(mask_bits)) | class_def_index) << mask_bits) { + DCHECK_EQ(class_def_index & ~GetMask(mask_bits), 0u); + } + + void SetNextPosDelta(uint32_t next_pos_delta, uint32_t mask_bits) { + DCHECK_EQ(GetNextPosDelta(mask_bits), 0u); + DCHECK_EQ(next_pos_delta & ~GetMask(mask_bits), 0u); + DCHECK_NE(next_pos_delta, 0u); + data_ |= next_pos_delta; + } bool IsEmpty() const { - return str_offset == 0; + return str_offset_ == 0u; } - bool IsLast() const { - return next_pos_delta == 0; + bool IsLast(uint32_t mask_bits) const { + return GetNextPosDelta(mask_bits) == 0u; } - }; - static uint32_t CalculateMask(uint32_t num_class_defs); - static bool SupportedSize(uint32_t num_class_defs); + uint32_t GetStringOffset() const { + return str_offset_; + } - // Construct from a dex file. - explicit TypeLookupTable(const DexFile& dex_file, uint8_t* storage); - - // Construct from a dex file with existing data. - TypeLookupTable(const uint8_t* dex_file_pointer, - const uint8_t* raw_data, - uint32_t num_class_defs); - - bool IsStringsEquals(const char* str, uint32_t str_offset) const { - const uint8_t* ptr = dex_data_begin_ + str_offset; - CHECK(dex_data_begin_ != nullptr); - // Skip string length. - DecodeUnsignedLeb128(&ptr); - return CompareModifiedUtf8ToModifiedUtf8AsUtf16CodePointValues( - str, reinterpret_cast<const char*>(ptr)) == 0; - } + uint32_t GetNextPosDelta(uint32_t mask_bits) const { + return data_ & GetMask(mask_bits); + } - // Method extracts hash bits from element's data and compare them with - // the corresponding bits of the specified hash - bool CmpHashBits(uint32_t data, uint32_t hash) const { - uint32_t mask = static_cast<uint16_t>(~GetSizeMask()); - return (hash & mask) == (data & mask); - } + uint32_t GetClassDefIdx(uint32_t mask_bits) const { + return (data_ >> mask_bits) & GetMask(mask_bits); + } - uint32_t GetClassDefIdx(uint32_t data) const { - return data & mask_; - } + uint32_t GetHashBits(uint32_t mask_bits) const { + DCHECK_LE(mask_bits, 16u); + return data_ >> (2u * mask_bits); + } - uint32_t GetSizeMask() const { - return mask_; - } + static uint32_t GetMask(uint32_t mask_bits) { + DCHECK_LE(mask_bits, 16u); + return ~(std::numeric_limits<uint32_t>::max() << mask_bits); + } - // Attempt to set an entry on its hash's slot. If there is already something there, return false. - // Otherwise return true. - bool SetOnInitialPos(const Entry& entry, uint32_t hash); + private: + uint32_t str_offset_; + uint32_t data_; + }; - // Insert an entry, probes until there is an empty slot. - void Insert(const Entry& entry, uint32_t hash); + static uint32_t CalculateMaskBits(uint32_t num_class_defs); + static bool SupportedSize(uint32_t num_class_defs); - // Find the last entry in a chain. - uint32_t FindLastEntryInBucket(uint32_t cur_pos) const; + // Construct the TypeLookupTable. + TypeLookupTable(const uint8_t* dex_data_pointer, + uint32_t mask_bits, + const Entry* entries, + std::unique_ptr<Entry[]> owned_entries); - const uint8_t* dex_data_begin_; - const uint32_t raw_data_length_; - const uint32_t mask_; - std::unique_ptr<Entry[]> entries_; - // owns_entries_ specifies if the lookup table owns the entries_ array. - const bool owns_entries_; + const char* GetStringData(const Entry& entry) const; - DISALLOW_IMPLICIT_CONSTRUCTORS(TypeLookupTable); + const uint8_t* dex_data_begin_; + uint32_t mask_bits_; + const Entry* entries_; + // `owned_entries_` is either null (not owning `entries_`) or same pointer as `entries_`. + std::unique_ptr<Entry[]> owned_entries_; }; } // namespace art diff --git a/libdexfile/dex/type_lookup_table_test.cc b/libdexfile/dex/type_lookup_table_test.cc index 6c3d291332..4316be0bd6 100644 --- a/libdexfile/dex/type_lookup_table_test.cc +++ b/libdexfile/dex/type_lookup_table_test.cc @@ -30,20 +30,20 @@ class TypeLookupTableTest : public CommonArtTestWithParam<DescriptorClassDefIdxP TEST_F(TypeLookupTableTest, CreateLookupTable) { std::unique_ptr<const DexFile> dex_file(OpenTestDexFile("Lookup")); - std::unique_ptr<TypeLookupTable> table(TypeLookupTable::Create(*dex_file)); - ASSERT_NE(nullptr, table.get()); - ASSERT_NE(nullptr, table->RawData()); - ASSERT_EQ(32U, table->RawDataLength()); + TypeLookupTable table = TypeLookupTable::Create(*dex_file); + ASSERT_TRUE(table.Valid()); + ASSERT_NE(nullptr, table.RawData()); + ASSERT_EQ(32U, table.RawDataLength()); } TEST_P(TypeLookupTableTest, Find) { std::unique_ptr<const DexFile> dex_file(OpenTestDexFile("Lookup")); - std::unique_ptr<TypeLookupTable> table(TypeLookupTable::Create(*dex_file)); - ASSERT_NE(nullptr, table.get()); + TypeLookupTable table(TypeLookupTable::Create(*dex_file)); + ASSERT_TRUE(table.Valid()); auto pair = GetParam(); const char* descriptor = pair.first; size_t hash = ComputeModifiedUtf8Hash(descriptor); - uint32_t class_def_idx = table->Lookup(descriptor, hash); + uint32_t class_def_idx = table.Lookup(descriptor, hash); ASSERT_EQ(pair.second, class_def_idx); } diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc index 7ac9e984ff..7b72e189b9 100644 --- a/oatdump/oatdump.cc +++ b/oatdump/oatdump.cc @@ -105,6 +105,10 @@ const char* image_methods_descriptions_[] = { const char* image_roots_descriptions_[] = { "kDexCaches", "kClassRoots", + "kOomeWhenThrowingException", + "kOomeWhenThrowingOome", + "kOomeWhenHandlingStackOverflow", + "kNoClassDefFoundError", "kClassLoader", }; @@ -1942,17 +1946,17 @@ class ImageDumper { os << "COMPILE PIC: " << (image_header_.CompilePic() ? "yes" : "no") << "\n\n"; { - os << "ROOTS: " << reinterpret_cast<void*>(image_header_.GetImageRoots()) << "\n"; + os << "ROOTS: " << reinterpret_cast<void*>(image_header_.GetImageRoots().Ptr()) << "\n"; static_assert(arraysize(image_roots_descriptions_) == static_cast<size_t>(ImageHeader::kImageRootsMax), "sizes must match"); DCHECK_LE(image_header_.GetImageRoots()->GetLength(), ImageHeader::kImageRootsMax); for (int32_t i = 0, size = image_header_.GetImageRoots()->GetLength(); i != size; ++i) { ImageHeader::ImageRoot image_root = static_cast<ImageHeader::ImageRoot>(i); const char* image_root_description = image_roots_descriptions_[i]; - mirror::Object* image_root_object = image_header_.GetImageRoot(image_root); - indent_os << StringPrintf("%s: %p\n", image_root_description, image_root_object); + ObjPtr<mirror::Object> image_root_object = image_header_.GetImageRoot(image_root); + indent_os << StringPrintf("%s: %p\n", image_root_description, image_root_object.Ptr()); if (image_root_object != nullptr && image_root_object->IsObjectArray()) { - mirror::ObjectArray<mirror::Object>* image_root_object_array + ObjPtr<mirror::ObjectArray<mirror::Object>> image_root_object_array = image_root_object->AsObjectArray<mirror::Object>(); ScopedIndentation indent2(&vios_); for (int j = 0; j < image_root_object_array->GetLength(); j++) { diff --git a/openjdkjvmti/fixed_up_dex_file.cc b/openjdkjvmti/fixed_up_dex_file.cc index fcbafe7e71..a660fb56c4 100644 --- a/openjdkjvmti/fixed_up_dex_file.cc +++ b/openjdkjvmti/fixed_up_dex_file.cc @@ -31,6 +31,7 @@ #include "base/leb128.h" #include "fixed_up_dex_file.h" +#include "dex/class_accessor-inl.h" #include "dex/dex_file-inl.h" #include "dex/dex_file_loader.h" #include "dex/dex_file_verifier.h" @@ -51,14 +52,12 @@ static void RecomputeDexChecksum(art::DexFile* dex_file) { } static void UnhideApis(const art::DexFile& target_dex_file) { - for (uint32_t i = 0; i < target_dex_file.NumClassDefs(); ++i) { - const uint8_t* class_data = target_dex_file.GetClassData(target_dex_file.GetClassDef(i)); - if (class_data != nullptr) { - for (art::ClassDataItemIterator class_it(target_dex_file, class_data); - class_it.HasNext(); - class_it.Next()) { - art::DexFile::UnHideAccessFlags(class_it); - } + for (art::ClassAccessor accessor : target_dex_file.GetClasses()) { + for (const art::ClassAccessor::Field& field : accessor.GetFields()) { + field.UnHideAccessFlags(); + } + for (const art::ClassAccessor::Method& method : accessor.GetMethods()) { + method.UnHideAccessFlags(); } } } diff --git a/patchoat/patchoat.cc b/patchoat/patchoat.cc index a6d3903f19..3c0b3e42c9 100644 --- a/patchoat/patchoat.cc +++ b/patchoat/patchoat.cc @@ -973,7 +973,7 @@ bool PatchOat::PatchImage(bool primary_image) { ImageHeader* image_header = reinterpret_cast<ImageHeader*>(image_->Begin()); CHECK_GT(image_->Size(), sizeof(ImageHeader)); // These are the roots from the original file. - auto* img_roots = image_header->GetImageRoots(); + mirror::ObjectArray<mirror::Object>* img_roots = image_header->GetImageRoots().Ptr(); image_header->RelocateImage(delta_); PatchArtFields(image_header); diff --git a/runtime/art_field-inl.h b/runtime/art_field-inl.h index baa5102f5d..c5fb7d5f40 100644 --- a/runtime/art_field-inl.h +++ b/runtime/art_field-inl.h @@ -21,7 +21,7 @@ #include <android-base/logging.h> -#include "class_linker.h" +#include "class_linker-inl.h" #include "dex/dex_file-inl.h" #include "dex/primitive.h" #include "gc/accounting/card_table-inl.h" @@ -339,16 +339,11 @@ inline const DexFile* ArtField::GetDexFile() REQUIRES_SHARED(Locks::mutator_lock return GetDexCache<kWithoutReadBarrier>()->GetDexFile(); } -inline ObjPtr<mirror::String> ArtField::GetStringName(Thread* self, bool resolve) { - auto dex_field_index = GetDexFieldIndex(); +inline ObjPtr<mirror::String> ArtField::ResolveNameString() { + uint32_t dex_field_index = GetDexFieldIndex(); CHECK_NE(dex_field_index, dex::kDexNoIndex); - ObjPtr<mirror::DexCache> dex_cache = GetDexCache(); - const DexFile::FieldId& field_id = dex_cache->GetDexFile()->GetFieldId(dex_field_index); - ObjPtr<mirror::String> name = dex_cache->GetResolvedString(field_id.name_idx_); - if (resolve && name == nullptr) { - name = ResolveGetStringName(self, field_id.name_idx_, dex_cache); - } - return name; + const DexFile::FieldId& field_id = GetDexFile()->GetFieldId(dex_field_index); + return Runtime::Current()->GetClassLinker()->ResolveString(field_id.name_idx_, this); } template <typename Visitor> diff --git a/runtime/art_field.cc b/runtime/art_field.cc index b867621f02..6cbd9e4cfc 100644 --- a/runtime/art_field.cc +++ b/runtime/art_field.cc @@ -52,13 +52,6 @@ ObjPtr<mirror::Class> ArtField::ProxyFindSystemClass(const char* descriptor) { return klass; } -ObjPtr<mirror::String> ArtField::ResolveGetStringName(Thread* self, - dex::StringIndex string_idx, - ObjPtr<mirror::DexCache> dex_cache) { - StackHandleScope<1> hs(self); - return Runtime::Current()->GetClassLinker()->ResolveString(string_idx, hs.NewHandle(dex_cache)); -} - std::string ArtField::PrettyField(ArtField* f, bool with_type) { if (f == nullptr) { return "null"; diff --git a/runtime/art_field.h b/runtime/art_field.h index 784a862425..123595c6fe 100644 --- a/runtime/art_field.h +++ b/runtime/art_field.h @@ -201,8 +201,7 @@ class ArtField FINAL { const char* GetName() REQUIRES_SHARED(Locks::mutator_lock_); // Resolves / returns the name from the dex cache. - ObjPtr<mirror::String> GetStringName(Thread* self, bool resolve) - REQUIRES_SHARED(Locks::mutator_lock_); + ObjPtr<mirror::String> ResolveNameString() REQUIRES_SHARED(Locks::mutator_lock_); const char* GetTypeDescriptor() REQUIRES_SHARED(Locks::mutator_lock_); @@ -241,10 +240,6 @@ class ArtField FINAL { ObjPtr<mirror::Class> ProxyFindSystemClass(const char* descriptor) REQUIRES_SHARED(Locks::mutator_lock_); - ObjPtr<mirror::String> ResolveGetStringName(Thread* self, - dex::StringIndex string_idx, - ObjPtr<mirror::DexCache> dex_cache) - REQUIRES_SHARED(Locks::mutator_lock_); void GetAccessFlagsDCheck() REQUIRES_SHARED(Locks::mutator_lock_); void GetOffsetDCheck() REQUIRES_SHARED(Locks::mutator_lock_); diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h index ec66966869..18595cf17a 100644 --- a/runtime/art_method-inl.h +++ b/runtime/art_method-inl.h @@ -245,6 +245,12 @@ inline const char* ArtMethod::GetName() { } } +inline ObjPtr<mirror::String> ArtMethod::ResolveNameString() { + DCHECK(!IsProxyMethod()); + const DexFile::MethodId& method_id = GetDexFile()->GetMethodId(GetDexMethodIndex()); + return Runtime::Current()->GetClassLinker()->ResolveString(method_id.name_idx_, this); +} + inline const DexFile::CodeItem* ArtMethod::GetCodeItem() { return GetDexFile()->GetCodeItem(GetCodeItemOffset()); } diff --git a/runtime/art_method.cc b/runtime/art_method.cc index 151c36f3bc..45bf66446a 100644 --- a/runtime/art_method.cc +++ b/runtime/art_method.cc @@ -26,6 +26,7 @@ #include "class_linker-inl.h" #include "class_root.h" #include "debugger.h" +#include "dex/class_accessor-inl.h" #include "dex/descriptors_names.h" #include "dex/dex_file-inl.h" #include "dex/dex_file_exception_helpers.h" @@ -142,16 +143,6 @@ uint16_t ArtMethod::FindObsoleteDexClassDefIndex() { return dex_file->GetIndexForClassDef(*class_def); } -ObjPtr<mirror::String> ArtMethod::GetNameAsString(Thread* self) { - CHECK(!IsProxyMethod()); - StackHandleScope<1> hs(self); - Handle<mirror::DexCache> dex_cache(hs.NewHandle(GetDexCache())); - auto* dex_file = dex_cache->GetDexFile(); - uint32_t dex_method_idx = GetDexMethodIndex(); - const DexFile::MethodId& method_id = dex_file->GetMethodId(dex_method_idx); - return Runtime::Current()->GetClassLinker()->ResolveString(method_id.name_idx_, dex_cache); -} - void ArtMethod::ThrowInvocationTimeError() { DCHECK(!IsInvokable()); // NOTE: IsDefaultConflicting must be first since the actual method might or might not be abstract @@ -434,28 +425,14 @@ bool ArtMethod::IsPolymorphicSignature() { static uint32_t GetOatMethodIndexFromMethodIndex(const DexFile& dex_file, uint16_t class_def_idx, uint32_t method_idx) { - const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_idx); - const uint8_t* class_data = dex_file.GetClassData(class_def); - CHECK(class_data != nullptr); - ClassDataItemIterator it(dex_file, class_data); - it.SkipAllFields(); - // Process methods - size_t class_def_method_index = 0; - while (it.HasNextDirectMethod()) { - if (it.GetMemberIndex() == method_idx) { - return class_def_method_index; - } - class_def_method_index++; - it.Next(); - } - while (it.HasNextVirtualMethod()) { - if (it.GetMemberIndex() == method_idx) { + ClassAccessor accessor(dex_file, dex_file.GetClassDef(class_def_idx)); + uint32_t class_def_method_index = 0u; + for (const ClassAccessor::Method& method : accessor.GetMethods()) { + if (method.GetIndex() == method_idx) { return class_def_method_index; } class_def_method_index++; - it.Next(); } - DCHECK(!it.HasNext()); LOG(FATAL) << "Failed to find method index " << method_idx << " in " << dex_file.GetLocation(); UNREACHABLE(); } diff --git a/runtime/art_method.h b/runtime/art_method.h index 012d706756..09debb0c50 100644 --- a/runtime/art_method.h +++ b/runtime/art_method.h @@ -589,7 +589,7 @@ class ArtMethod FINAL { ALWAYS_INLINE const char* GetName() REQUIRES_SHARED(Locks::mutator_lock_); - ObjPtr<mirror::String> GetNameAsString(Thread* self) REQUIRES_SHARED(Locks::mutator_lock_); + ObjPtr<mirror::String> ResolveNameString() REQUIRES_SHARED(Locks::mutator_lock_); const DexFile::CodeItem* GetCodeItem() REQUIRES_SHARED(Locks::mutator_lock_); diff --git a/runtime/class_linker-inl.h b/runtime/class_linker-inl.h index 664b917543..2536b23416 100644 --- a/runtime/class_linker-inl.h +++ b/runtime/class_linker-inl.h @@ -61,6 +61,54 @@ inline ObjPtr<mirror::Class> ClassLinker::FindArrayClass(Thread* self, return array_class; } +inline ObjPtr<mirror::String> ClassLinker::ResolveString(dex::StringIndex string_idx, + ArtField* referrer) { + Thread::PoisonObjectPointersIfDebug(); + DCHECK(!Thread::Current()->IsExceptionPending()); + // We do not need the read barrier for getting the DexCache for the initial resolved type + // lookup as both from-space and to-space copies point to the same native resolved types array. + ObjPtr<mirror::String> resolved = + referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedString(string_idx); + if (resolved == nullptr) { + resolved = DoResolveString(string_idx, referrer->GetDexCache()); + } + return resolved; +} + +inline ObjPtr<mirror::String> ClassLinker::ResolveString(dex::StringIndex string_idx, + ArtMethod* referrer) { + Thread::PoisonObjectPointersIfDebug(); + DCHECK(!Thread::Current()->IsExceptionPending()); + // We do not need the read barrier for getting the DexCache for the initial resolved type + // lookup as both from-space and to-space copies point to the same native resolved types array. + ObjPtr<mirror::String> resolved = + referrer->GetDexCache<kWithoutReadBarrier>()->GetResolvedString(string_idx); + if (resolved == nullptr) { + resolved = DoResolveString(string_idx, referrer->GetDexCache()); + } + return resolved; +} + +inline ObjPtr<mirror::String> ClassLinker::ResolveString(dex::StringIndex string_idx, + Handle<mirror::DexCache> dex_cache) { + Thread::PoisonObjectPointersIfDebug(); + DCHECK(!Thread::Current()->IsExceptionPending()); + ObjPtr<mirror::String> resolved = dex_cache->GetResolvedString(string_idx); + if (resolved == nullptr) { + resolved = DoResolveString(string_idx, dex_cache); + } + return resolved; +} + +inline ObjPtr<mirror::String> ClassLinker::LookupString(dex::StringIndex string_idx, + ObjPtr<mirror::DexCache> dex_cache) { + ObjPtr<mirror::String> resolved = dex_cache->GetResolvedString(string_idx); + if (resolved == nullptr) { + resolved = DoLookupString(string_idx, dex_cache); + } + return resolved; +} + inline ObjPtr<mirror::Class> ClassLinker::ResolveType(dex::TypeIndex type_idx, ObjPtr<mirror::Class> referrer) { if (kObjPtrPoisoning) { diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 67987963e1..be636d80a8 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -56,6 +56,7 @@ #include "compiler_callbacks.h" #include "debug_print.h" #include "debugger.h" +#include "dex/class_accessor-inl.h" #include "dex/descriptors_names.h" #include "dex/dex_file-inl.h" #include "dex/dex_file_exception_helpers.h" @@ -197,8 +198,7 @@ static void HandleEarlierVerifyError(Thread* self, } } else { // Previous error has been stored as an instance. Just rethrow. - ObjPtr<mirror::Class> throwable_class = - self->DecodeJObject(WellKnownClasses::java_lang_Throwable)->AsClass(); + ObjPtr<mirror::Class> throwable_class = GetClassRoot<mirror::Throwable>(class_linker); ObjPtr<mirror::Class> error_class = obj->GetClass(); CHECK(throwable_class->IsAssignableFrom(error_class)); self->SetException(obj->AsThrowable()); @@ -376,7 +376,6 @@ ClassLinker::ClassLinker(InternTable* intern_table) : boot_class_table_(new ClassTable()), failed_dex_cache_class_lookups_(0), class_roots_(nullptr), - array_iftable_(nullptr), find_array_class_cache_next_victim_(0), init_done_(false), log_new_roots_(false), @@ -512,6 +511,10 @@ bool ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b // Fill in the empty iftable. Needs to be done after the kObjectArrayClass root is set. java_lang_Object->SetIfTable(AllocIfTable(self, 0)); + // Create array interface entries to populate once we can load system classes. + object_array_class->SetIfTable(AllocIfTable(self, 2)); + DCHECK_EQ(GetArrayIfTable(), object_array_class->GetIfTable()); + // Setup the primitive type classes. SetClassRoot(ClassRoot::kPrimitiveBoolean, CreatePrimitiveClass(self, Primitive::kPrimBoolean)); SetClassRoot(ClassRoot::kPrimitiveByte, CreatePrimitiveClass(self, Primitive::kPrimByte)); @@ -523,9 +526,6 @@ bool ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b SetClassRoot(ClassRoot::kPrimitiveDouble, CreatePrimitiveClass(self, Primitive::kPrimDouble)); SetClassRoot(ClassRoot::kPrimitiveVoid, CreatePrimitiveClass(self, Primitive::kPrimVoid)); - // Create array interface entries to populate once we can load system classes. - array_iftable_ = GcRoot<mirror::IfTable>(AllocIfTable(self, 2)); - // Create int array type for native pointer arrays (for example vtables) on 32-bit archs. Handle<mirror::Class> int_array_class(hs.NewHandle( AllocClass(self, java_lang_Class.Get(), mirror::Array::ClassSize(image_pointer_size_)))); @@ -639,8 +639,8 @@ bool ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b CHECK(java_io_Serializable != nullptr); // We assume that Cloneable/Serializable don't have superinterfaces -- normally we'd have to // crawl up and explicitly list all of the supers as well. - array_iftable_.Read()->SetInterface(0, java_lang_Cloneable.Get()); - array_iftable_.Read()->SetInterface(1, java_io_Serializable.Get()); + object_array_class->GetIfTable()->SetInterface(0, java_lang_Cloneable.Get()); + object_array_class->GetIfTable()->SetInterface(1, java_io_Serializable.Get()); // Sanity check Class[] and Object[]'s interfaces. GetDirectInterface may cause thread // suspension. @@ -841,7 +841,7 @@ void ClassLinker::FinishInit(Thread* self) { // if possible add new checks there to catch errors early } - CHECK(!array_iftable_.IsNull()); + CHECK(GetArrayIfTable() != nullptr); // disable the slow paths in FindClass and CreatePrimitiveClass now // that Object, Class, and Object[] are setup @@ -1000,11 +1000,6 @@ bool ClassLinker::InitFromBootImage(std::string* error_msg) { runtime->SetSentinel(heap->AllocNonMovableObject<true>( self, java_lang_Object, java_lang_Object->GetObjectSize(), VoidFunctor())); - // reinit array_iftable_ from any array class instance, they should be == - array_iftable_ = - GcRoot<mirror::IfTable>(GetClassRoot(ClassRoot::kObjectArrayClass, this)->GetIfTable()); - DCHECK_EQ(array_iftable_.Read(), GetClassRoot(ClassRoot::kBooleanArrayClass, this)->GetIfTable()); - for (gc::space::ImageSpace* image_space : spaces) { // Boot class loader, use a null handle. std::vector<std::unique_ptr<const DexFile>> dex_files; @@ -1931,7 +1926,6 @@ void ClassLinker::VisitClassRoots(RootVisitor* visitor, VisitRootFlags flags) { void ClassLinker::VisitRoots(RootVisitor* visitor, VisitRootFlags flags) { class_roots_.VisitRootIfNonNull(visitor, RootInfo(kRootVMInternal)); VisitClassRoots(visitor, flags); - array_iftable_.VisitRootIfNonNull(visitor, RootInfo(kRootVMInternal)); // Instead of visiting the find_array_class_cache_ drop it so that it doesn't prevent class // unloading if we are marking roots. DropFindArrayClassCache(); @@ -2730,52 +2724,50 @@ ObjPtr<mirror::Class> ClassLinker::DefineClass(Thread* self, uint32_t ClassLinker::SizeOfClassWithoutEmbeddedTables(const DexFile& dex_file, const DexFile::ClassDef& dex_class_def) { - const uint8_t* class_data = dex_file.GetClassData(dex_class_def); size_t num_ref = 0; size_t num_8 = 0; size_t num_16 = 0; size_t num_32 = 0; size_t num_64 = 0; - if (class_data != nullptr) { - // We allow duplicate definitions of the same field in a class_data_item - // but ignore the repeated indexes here, b/21868015. - uint32_t last_field_idx = dex::kDexNoIndex; - for (ClassDataItemIterator it(dex_file, class_data); it.HasNextStaticField(); it.Next()) { - uint32_t field_idx = it.GetMemberIndex(); - // Ordering enforced by DexFileVerifier. - DCHECK(last_field_idx == dex::kDexNoIndex || last_field_idx <= field_idx); - if (UNLIKELY(field_idx == last_field_idx)) { - continue; - } - last_field_idx = field_idx; - const DexFile::FieldId& field_id = dex_file.GetFieldId(field_idx); - const char* descriptor = dex_file.GetFieldTypeDescriptor(field_id); - char c = descriptor[0]; - switch (c) { - case 'L': - case '[': - num_ref++; - break; - case 'J': - case 'D': - num_64++; - break; - case 'I': - case 'F': - num_32++; - break; - case 'S': - case 'C': - num_16++; - break; - case 'B': - case 'Z': - num_8++; - break; - default: - LOG(FATAL) << "Unknown descriptor: " << c; - UNREACHABLE(); - } + ClassAccessor accessor(dex_file, dex_class_def); + // We allow duplicate definitions of the same field in a class_data_item + // but ignore the repeated indexes here, b/21868015. + uint32_t last_field_idx = dex::kDexNoIndex; + for (const ClassAccessor::Field& field : accessor.GetStaticFields()) { + uint32_t field_idx = field.GetIndex(); + // Ordering enforced by DexFileVerifier. + DCHECK(last_field_idx == dex::kDexNoIndex || last_field_idx <= field_idx); + if (UNLIKELY(field_idx == last_field_idx)) { + continue; + } + last_field_idx = field_idx; + const DexFile::FieldId& field_id = dex_file.GetFieldId(field_idx); + const char* descriptor = dex_file.GetFieldTypeDescriptor(field_id); + char c = descriptor[0]; + switch (c) { + case 'L': + case '[': + num_ref++; + break; + case 'J': + case 'D': + num_64++; + break; + case 'I': + case 'F': + num_32++; + break; + case 'S': + case 'C': + num_16++; + break; + case 'B': + case 'Z': + num_8++; + break; + default: + LOG(FATAL) << "Unknown descriptor: " << c; + UNREACHABLE(); } } return mirror::Class::ComputeClassSize(false, @@ -2873,17 +2865,15 @@ void ClassLinker::FixupStaticTrampolines(ObjPtr<mirror::Class> klass) { const DexFile& dex_file = klass->GetDexFile(); const DexFile::ClassDef* dex_class_def = klass->GetClassDef(); CHECK(dex_class_def != nullptr); - const uint8_t* class_data = dex_file.GetClassData(*dex_class_def); + ClassAccessor accessor(dex_file, *dex_class_def); // There should always be class data if there were direct methods. - CHECK(class_data != nullptr) << klass->PrettyDescriptor(); - ClassDataItemIterator it(dex_file, class_data); - it.SkipAllFields(); + CHECK(accessor.HasClassData()) << klass->PrettyDescriptor(); bool has_oat_class; OatFile::OatClass oat_class = OatFile::FindOatClass(dex_file, klass->GetDexClassDefIndex(), &has_oat_class); // Link the code of methods skipped by LinkCode. - for (size_t method_index = 0; it.HasNextDirectMethod(); ++method_index, it.Next()) { + for (size_t method_index = 0; method_index < accessor.NumDirectMethods(); ++method_index) { ArtMethod* method = klass->GetDirectMethod(method_index, image_pointer_size_); if (!method->IsStatic()) { // Only update static methods. @@ -2992,17 +2982,6 @@ void ClassLinker::SetupClass(const DexFile& dex_file, klass->SetDexTypeIndex(dex_class_def.class_idx_); } -void ClassLinker::LoadClass(Thread* self, - const DexFile& dex_file, - const DexFile::ClassDef& dex_class_def, - Handle<mirror::Class> klass) { - const uint8_t* class_data = dex_file.GetClassData(dex_class_def); - if (class_data == nullptr) { - return; // no fields or methods - for example a marker interface - } - LoadClassMembers(self, dex_file, class_data, klass); -} - LengthPrefixedArray<ArtField>* ClassLinker::AllocArtFieldArray(Thread* self, LinearAlloc* allocator, size_t length) { @@ -3061,10 +3040,15 @@ LinearAlloc* ClassLinker::GetOrCreateAllocatorForClassLoader(ObjPtr<mirror::Clas return allocator; } -void ClassLinker::LoadClassMembers(Thread* self, - const DexFile& dex_file, - const uint8_t* class_data, - Handle<mirror::Class> klass) { +void ClassLinker::LoadClass(Thread* self, + const DexFile& dex_file, + const DexFile::ClassDef& dex_class_def, + Handle<mirror::Class> klass) { + ClassAccessor accessor(dex_file, dex_class_def); + if (!accessor.HasClassData()) { + return; + } + Runtime* const runtime = Runtime::Current(); { // Note: We cannot have thread suspension until the field and method arrays are setup or else // Class::VisitFieldRoots may miss some fields or methods. @@ -3073,45 +3057,79 @@ void ClassLinker::LoadClassMembers(Thread* self, // We allow duplicate definitions of the same field in a class_data_item // but ignore the repeated indexes here, b/21868015. LinearAlloc* const allocator = GetAllocatorForClassLoader(klass->GetClassLoader()); - ClassDataItemIterator it(dex_file, class_data); LengthPrefixedArray<ArtField>* sfields = AllocArtFieldArray(self, allocator, - it.NumStaticFields()); - size_t num_sfields = 0; - uint32_t last_field_idx = 0u; - for (; it.HasNextStaticField(); it.Next()) { - uint32_t field_idx = it.GetMemberIndex(); - DCHECK_GE(field_idx, last_field_idx); // Ordering enforced by DexFileVerifier. - if (num_sfields == 0 || LIKELY(field_idx > last_field_idx)) { - DCHECK_LT(num_sfields, it.NumStaticFields()); - LoadField(it, klass, &sfields->At(num_sfields)); - ++num_sfields; - last_field_idx = field_idx; - } - } - - // Load instance fields. + accessor.NumStaticFields()); LengthPrefixedArray<ArtField>* ifields = AllocArtFieldArray(self, allocator, - it.NumInstanceFields()); + accessor.NumInstanceFields()); + size_t num_sfields = 0u; size_t num_ifields = 0u; - last_field_idx = 0u; - for (; it.HasNextInstanceField(); it.Next()) { - uint32_t field_idx = it.GetMemberIndex(); - DCHECK_GE(field_idx, last_field_idx); // Ordering enforced by DexFileVerifier. - if (num_ifields == 0 || LIKELY(field_idx > last_field_idx)) { - DCHECK_LT(num_ifields, it.NumInstanceFields()); - LoadField(it, klass, &ifields->At(num_ifields)); - ++num_ifields; - last_field_idx = field_idx; - } - } + uint32_t last_static_field_idx = 0u; + uint32_t last_instance_field_idx = 0u; + + // Methods + bool has_oat_class = false; + const OatFile::OatClass oat_class = (runtime->IsStarted() && !runtime->IsAotCompiler()) + ? OatFile::FindOatClass(dex_file, klass->GetDexClassDefIndex(), &has_oat_class) + : OatFile::OatClass::Invalid(); + const OatFile::OatClass* oat_class_ptr = has_oat_class ? &oat_class : nullptr; + klass->SetMethodsPtr( + AllocArtMethodArray(self, allocator, accessor.NumMethods()), + accessor.NumDirectMethods(), + accessor.NumVirtualMethods()); + size_t class_def_method_index = 0; + uint32_t last_dex_method_index = dex::kDexNoIndex; + size_t last_class_def_method_index = 0; - if (UNLIKELY(num_sfields != it.NumStaticFields()) || - UNLIKELY(num_ifields != it.NumInstanceFields())) { + // Use the visitor since the ranged based loops are bit slower from seeking. Seeking to the + // methods needs to decode all of the fields. + accessor.VisitFieldsAndMethods([&]( + const ClassAccessor::Field& field) REQUIRES_SHARED(Locks::mutator_lock_) { + uint32_t field_idx = field.GetIndex(); + DCHECK_GE(field_idx, last_static_field_idx); // Ordering enforced by DexFileVerifier. + if (num_sfields == 0 || LIKELY(field_idx > last_static_field_idx)) { + LoadField(field, klass, &sfields->At(num_sfields)); + ++num_sfields; + last_static_field_idx = field_idx; + } + }, [&](const ClassAccessor::Field& field) REQUIRES_SHARED(Locks::mutator_lock_) { + uint32_t field_idx = field.GetIndex(); + DCHECK_GE(field_idx, last_instance_field_idx); // Ordering enforced by DexFileVerifier. + if (num_ifields == 0 || LIKELY(field_idx > last_instance_field_idx)) { + LoadField(field, klass, &ifields->At(num_ifields)); + ++num_ifields; + last_instance_field_idx = field_idx; + } + }, [&](const ClassAccessor::Method& method) REQUIRES_SHARED(Locks::mutator_lock_) { + ArtMethod* art_method = klass->GetDirectMethodUnchecked(class_def_method_index, + image_pointer_size_); + LoadMethod(dex_file, method, klass, art_method); + LinkCode(this, art_method, oat_class_ptr, class_def_method_index); + uint32_t it_method_index = method.GetIndex(); + if (last_dex_method_index == it_method_index) { + // duplicate case + art_method->SetMethodIndex(last_class_def_method_index); + } else { + art_method->SetMethodIndex(class_def_method_index); + last_dex_method_index = it_method_index; + last_class_def_method_index = class_def_method_index; + } + ++class_def_method_index; + }, [&](const ClassAccessor::Method& method) REQUIRES_SHARED(Locks::mutator_lock_) { + ArtMethod* art_method = klass->GetVirtualMethodUnchecked( + class_def_method_index - accessor.NumDirectMethods(), + image_pointer_size_); + LoadMethod(dex_file, method, klass, art_method); + LinkCode(this, art_method, oat_class_ptr, class_def_method_index); + ++class_def_method_index; + }); + + if (UNLIKELY(num_ifields + num_sfields != accessor.NumFields())) { LOG(WARNING) << "Duplicate fields in class " << klass->PrettyDescriptor() - << " (unique static fields: " << num_sfields << "/" << it.NumStaticFields() - << ", unique instance fields: " << num_ifields << "/" << it.NumInstanceFields() << ")"; + << " (unique static fields: " << num_sfields << "/" << accessor.NumStaticFields() + << ", unique instance fields: " << num_ifields << "/" << accessor.NumInstanceFields() + << ")"; // NOTE: Not shrinking the over-allocated sfields/ifields, just setting size. if (sfields != nullptr) { sfields->SetSize(num_sfields); @@ -3125,87 +3143,49 @@ void ClassLinker::LoadClassMembers(Thread* self, DCHECK_EQ(klass->NumStaticFields(), num_sfields); klass->SetIFieldsPtr(ifields); DCHECK_EQ(klass->NumInstanceFields(), num_ifields); - // Load methods. - bool has_oat_class = false; - const OatFile::OatClass oat_class = - (Runtime::Current()->IsStarted() && !Runtime::Current()->IsAotCompiler()) - ? OatFile::FindOatClass(dex_file, klass->GetDexClassDefIndex(), &has_oat_class) - : OatFile::OatClass::Invalid(); - const OatFile::OatClass* oat_class_ptr = has_oat_class ? &oat_class : nullptr; - klass->SetMethodsPtr( - AllocArtMethodArray(self, allocator, it.NumDirectMethods() + it.NumVirtualMethods()), - it.NumDirectMethods(), - it.NumVirtualMethods()); - size_t class_def_method_index = 0; - uint32_t last_dex_method_index = dex::kDexNoIndex; - size_t last_class_def_method_index = 0; - // TODO These should really use the iterators. - for (size_t i = 0; it.HasNextDirectMethod(); i++, it.Next()) { - ArtMethod* method = klass->GetDirectMethodUnchecked(i, image_pointer_size_); - LoadMethod(dex_file, it, klass, method); - LinkCode(this, method, oat_class_ptr, class_def_method_index); - uint32_t it_method_index = it.GetMemberIndex(); - if (last_dex_method_index == it_method_index) { - // duplicate case - method->SetMethodIndex(last_class_def_method_index); - } else { - method->SetMethodIndex(class_def_method_index); - last_dex_method_index = it_method_index; - last_class_def_method_index = class_def_method_index; - } - class_def_method_index++; - } - for (size_t i = 0; it.HasNextVirtualMethod(); i++, it.Next()) { - ArtMethod* method = klass->GetVirtualMethodUnchecked(i, image_pointer_size_); - LoadMethod(dex_file, it, klass, method); - DCHECK_EQ(class_def_method_index, it.NumDirectMethods() + i); - LinkCode(this, method, oat_class_ptr, class_def_method_index); - class_def_method_index++; - } - DCHECK(!it.HasNext()); } // Ensure that the card is marked so that remembered sets pick up native roots. Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(klass.Get()); self->AllowThreadSuspension(); } -void ClassLinker::LoadField(const ClassDataItemIterator& it, +void ClassLinker::LoadField(const ClassAccessor::Field& field, Handle<mirror::Class> klass, ArtField* dst) { - const uint32_t field_idx = it.GetMemberIndex(); + const uint32_t field_idx = field.GetIndex(); dst->SetDexFieldIndex(field_idx); dst->SetDeclaringClass(klass.Get()); // Get access flags from the DexFile. If this is a boot class path class, // also set its runtime hidden API access flags. - uint32_t access_flags = it.GetFieldAccessFlags(); + uint32_t access_flags = field.GetAccessFlags(); if (klass->IsBootStrapClassLoaded()) { access_flags = - HiddenApiAccessFlags::EncodeForRuntime(access_flags, it.DecodeHiddenAccessFlags()); + HiddenApiAccessFlags::EncodeForRuntime(access_flags, field.DecodeHiddenAccessFlags()); } dst->SetAccessFlags(access_flags); } void ClassLinker::LoadMethod(const DexFile& dex_file, - const ClassDataItemIterator& it, + const ClassAccessor::Method& method, Handle<mirror::Class> klass, ArtMethod* dst) { - uint32_t dex_method_idx = it.GetMemberIndex(); + const uint32_t dex_method_idx = method.GetIndex(); const DexFile::MethodId& method_id = dex_file.GetMethodId(dex_method_idx); const char* method_name = dex_file.StringDataByIdx(method_id.name_idx_); ScopedAssertNoThreadSuspension ants("LoadMethod"); dst->SetDexMethodIndex(dex_method_idx); dst->SetDeclaringClass(klass.Get()); - dst->SetCodeItemOffset(it.GetMethodCodeItemOffset()); + dst->SetCodeItemOffset(method.GetCodeItemOffset()); // Get access flags from the DexFile. If this is a boot class path class, // also set its runtime hidden API access flags. - uint32_t access_flags = it.GetMethodAccessFlags(); + uint32_t access_flags = method.GetAccessFlags(); if (klass->IsBootStrapClassLoaded()) { access_flags = - HiddenApiAccessFlags::EncodeForRuntime(access_flags, it.DecodeHiddenAccessFlags()); + HiddenApiAccessFlags::EncodeForRuntime(access_flags, method.DecodeHiddenAccessFlags()); } if (UNLIKELY(strcmp("finalize", method_name) == 0)) { @@ -3380,6 +3360,7 @@ ObjPtr<mirror::DexCache> ClassLinker::EnsureSameClassLoader( void ClassLinker::RegisterExistingDexCache(ObjPtr<mirror::DexCache> dex_cache, ObjPtr<mirror::ClassLoader> class_loader) { + SCOPED_TRACE << __FUNCTION__ << " " << dex_cache->GetDexFile()->GetLocation(); Thread* self = Thread::Current(); StackHandleScope<2> hs(self); Handle<mirror::DexCache> h_dex_cache(hs.NewHandle(dex_cache)); @@ -3401,6 +3382,10 @@ void ClassLinker::RegisterExistingDexCache(ObjPtr<mirror::DexCache> dex_cache, WriterMutexLock mu(self, *Locks::classlinker_classes_lock_); table = InsertClassTableForClassLoader(h_class_loader.Get()); } + // Avoid a deadlock between a garbage collecting thread running a checkpoint, + // a thread holding the dex lock and blocking on a condition variable regarding + // weak references access, and a thread blocking on the dex lock. + gc::ScopedGCCriticalSection gcs(self, gc::kGcCauseClassLinker, gc::kCollectorTypeClassLinker); WriterMutexLock mu(self, *Locks::dex_lock_); RegisterDexFileLocked(*dex_file, h_dex_cache.Get(), h_class_loader.Get()); table->InsertStrongRoot(h_dex_cache.Get()); @@ -3423,6 +3408,7 @@ ObjPtr<mirror::DexCache> ClassLinker::RegisterDexFile(const DexFile& dex_file, if (old_dex_cache != nullptr) { return EnsureSameClassLoader(self, old_dex_cache, old_data, class_loader); } + SCOPED_TRACE << __FUNCTION__ << " " << dex_file.GetLocation(); LinearAlloc* const linear_alloc = GetOrCreateAllocatorForClassLoader(class_loader); DCHECK(linear_alloc != nullptr); ClassTable* table; @@ -3441,6 +3427,10 @@ ObjPtr<mirror::DexCache> ClassLinker::RegisterDexFile(const DexFile& dex_file, dex_file))); Handle<mirror::String> h_location(hs.NewHandle(location)); { + // Avoid a deadlock between a garbage collecting thread running a checkpoint, + // a thread holding the dex lock and blocking on a condition variable regarding + // weak references access, and a thread blocking on the dex lock. + gc::ScopedGCCriticalSection gcs(self, gc::kGcCauseClassLinker, gc::kCollectorTypeClassLinker); WriterMutexLock mu(self, *Locks::dex_lock_); old_data = FindDexCacheDataLocked(dex_file); old_dex_cache = DecodeDexCache(self, old_data); @@ -3553,6 +3543,10 @@ ObjPtr<mirror::Class> ClassLinker::CreatePrimitiveClass(Thread* self, Primitive: return h_class.Get(); } +inline ObjPtr<mirror::IfTable> ClassLinker::GetArrayIfTable() { + return GetClassRoot<mirror::ObjectArray<mirror::Object>>(this)->GetIfTable(); +} + // Create an array class (i.e. the class object for the array, not the // array itself). "descriptor" looks like "[C" or "[[[[B" or // "[Ljava/lang/String;". @@ -3680,7 +3674,7 @@ ObjPtr<mirror::Class> ClassLinker::CreateArrayClass(Thread* self, // Use the single, global copies of "interfaces" and "iftable" // (remember not to free them for arrays). { - ObjPtr<mirror::IfTable> array_iftable = array_iftable_.Read(); + ObjPtr<mirror::IfTable> array_iftable = GetArrayIfTable(); CHECK(array_iftable != nullptr); new_class->SetIfTable(array_iftable); } @@ -4772,24 +4766,29 @@ bool ClassLinker::InitializeClass(Thread* self, Handle<mirror::Class> klass, this, *dex_class_def); const DexFile& dex_file = *dex_cache->GetDexFile(); - const uint8_t* class_data = dex_file.GetClassData(*dex_class_def); - ClassDataItemIterator field_it(dex_file, class_data); + if (value_it.HasNext()) { - DCHECK(field_it.HasNextStaticField()); + ClassAccessor accessor(dex_file, *dex_class_def); CHECK(can_init_statics); - for ( ; value_it.HasNext(); value_it.Next(), field_it.Next()) { - ArtField* field = ResolveField( - field_it.GetMemberIndex(), dex_cache, class_loader, /* is_static */ true); + for (const ClassAccessor::Field& field : accessor.GetStaticFields()) { + if (!value_it.HasNext()) { + break; + } + ArtField* art_field = ResolveField(field.GetIndex(), + dex_cache, + class_loader, + /* is_static */ true); if (Runtime::Current()->IsActiveTransaction()) { - value_it.ReadValueToField<true>(field); + value_it.ReadValueToField<true>(art_field); } else { - value_it.ReadValueToField<false>(field); + value_it.ReadValueToField<false>(art_field); } if (self->IsExceptionPending()) { break; } - DCHECK(!value_it.HasNext() || field_it.HasNextStaticField()); + value_it.Next(); } + DCHECK(self->IsExceptionPending() || !value_it.HasNext()); } } @@ -7665,14 +7664,15 @@ void ClassLinker::CreateReferenceInstanceOffsets(Handle<mirror::Class> klass) { klass->SetReferenceInstanceOffsets(reference_offsets); } -ObjPtr<mirror::String> ClassLinker::ResolveString(dex::StringIndex string_idx, - Handle<mirror::DexCache> dex_cache) { - DCHECK(dex_cache != nullptr); - Thread::PoisonObjectPointersIfDebug(); - ObjPtr<mirror::String> resolved = dex_cache->GetResolvedString(string_idx); - if (resolved != nullptr) { - return resolved; - } +ObjPtr<mirror::String> ClassLinker::DoResolveString(dex::StringIndex string_idx, + ObjPtr<mirror::DexCache> dex_cache) { + StackHandleScope<1> hs(Thread::Current()); + Handle<mirror::DexCache> h_dex_cache(hs.NewHandle(dex_cache)); + return DoResolveString(string_idx, h_dex_cache); +} + +ObjPtr<mirror::String> ClassLinker::DoResolveString(dex::StringIndex string_idx, + Handle<mirror::DexCache> dex_cache) { const DexFile& dex_file = *dex_cache->GetDexFile(); uint32_t utf16_length; const char* utf8_data = dex_file.StringDataAndUtf16LengthByIdx(string_idx, &utf16_length); @@ -7683,13 +7683,9 @@ ObjPtr<mirror::String> ClassLinker::ResolveString(dex::StringIndex string_idx, return string; } -ObjPtr<mirror::String> ClassLinker::LookupString(dex::StringIndex string_idx, - ObjPtr<mirror::DexCache> dex_cache) { +ObjPtr<mirror::String> ClassLinker::DoLookupString(dex::StringIndex string_idx, + ObjPtr<mirror::DexCache> dex_cache) { DCHECK(dex_cache != nullptr); - ObjPtr<mirror::String> resolved = dex_cache->GetResolvedString(string_idx); - if (resolved != nullptr) { - return resolved; - } const DexFile& dex_file = *dex_cache->GetDexFile(); uint32_t utf16_length; const char* utf8_data = dex_file.StringDataAndUtf16LengthByIdx(string_idx, &utf16_length); diff --git a/runtime/class_linker.h b/runtime/class_linker.h index 58ce6eb25c..30c242399d 100644 --- a/runtime/class_linker.h +++ b/runtime/class_linker.h @@ -27,6 +27,7 @@ #include "base/enums.h" #include "base/macros.h" #include "base/mutex.h" +#include "dex/class_accessor.h" #include "dex/dex_cache_resolved_classes.h" #include "dex/dex_file.h" #include "dex/dex_file_types.h" @@ -203,6 +204,16 @@ class ClassLinker { REQUIRES(!Locks::classlinker_classes_lock_) REQUIRES_SHARED(Locks::mutator_lock_); + // Resolve a String with the given index from the DexFile associated with the given `referrer`, + // storing the result in the DexCache. The `referrer` is used to identify the target DexCache + // to use for resolution. + ObjPtr<mirror::String> ResolveString(dex::StringIndex string_idx, + ArtField* referrer) + REQUIRES_SHARED(Locks::mutator_lock_); + ObjPtr<mirror::String> ResolveString(dex::StringIndex string_idx, + ArtMethod* referrer) + REQUIRES_SHARED(Locks::mutator_lock_); + // Resolve a String with the given index from the DexFile associated with the given DexCache, // storing the result in the DexCache. ObjPtr<mirror::String> ResolveString(dex::StringIndex string_idx, @@ -825,18 +836,14 @@ class ClassLinker { const DexFile::ClassDef& dex_class_def, Handle<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_); - void LoadClassMembers(Thread* self, - const DexFile& dex_file, - const uint8_t* class_data, - Handle<mirror::Class> klass) - REQUIRES_SHARED(Locks::mutator_lock_); - void LoadField(const ClassDataItemIterator& it, Handle<mirror::Class> klass, ArtField* dst) + void LoadField(const ClassAccessor::Field& field, Handle<mirror::Class> klass, ArtField* dst) REQUIRES_SHARED(Locks::mutator_lock_); void LoadMethod(const DexFile& dex_file, - const ClassDataItemIterator& it, - Handle<mirror::Class> klass, ArtMethod* dst) + const ClassAccessor::Method& method, + Handle<mirror::Class> klass, + ArtMethod* dst) REQUIRES_SHARED(Locks::mutator_lock_); void FixupStaticTrampolines(ObjPtr<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_); @@ -885,6 +892,19 @@ class ClassLinker { ObjPtr<mirror::ClassLoader> class_loader) REQUIRES_SHARED(Locks::mutator_lock_); + // Implementation of ResolveString() called when the string was not found in the dex cache. + ObjPtr<mirror::String> DoResolveString(dex::StringIndex string_idx, + ObjPtr<mirror::DexCache> dex_cache) + REQUIRES_SHARED(Locks::mutator_lock_); + ObjPtr<mirror::String> DoResolveString(dex::StringIndex string_idx, + Handle<mirror::DexCache> dex_cache) + REQUIRES_SHARED(Locks::mutator_lock_); + + // Implementation of LookupString() called when the string was not found in the dex cache. + ObjPtr<mirror::String> DoLookupString(dex::StringIndex string_idx, + ObjPtr<mirror::DexCache> dex_cache) + REQUIRES_SHARED(Locks::mutator_lock_); + // Implementation of ResolveType() called when the type was not found in the dex cache. ObjPtr<mirror::Class> DoResolveType(dex::TypeIndex type_idx, ObjPtr<mirror::Class> referrer) @@ -1252,6 +1272,8 @@ class ClassLinker { ObjPtr<mirror::ClassLoader> class_loader) REQUIRES_SHARED(Locks::mutator_lock_); + ObjPtr<mirror::IfTable> GetArrayIfTable() REQUIRES_SHARED(Locks::mutator_lock_); + std::vector<const DexFile*> boot_class_path_; std::vector<std::unique_ptr<const DexFile>> boot_dex_files_; @@ -1281,9 +1303,6 @@ class ClassLinker { // Well known mirror::Class roots. GcRoot<mirror::ObjectArray<mirror::Class>> class_roots_; - // The interface table used by all arrays. - GcRoot<mirror::IfTable> array_iftable_; - // A cache of the last FindArrayClass results. The cache serves to avoid creating array class // descriptors for the sake of performing FindClass. static constexpr size_t kFindArrayCacheSize = 16; diff --git a/runtime/entrypoints/entrypoint_utils-inl.h b/runtime/entrypoints/entrypoint_utils-inl.h index c533f9ca66..4a3d3b0da6 100644 --- a/runtime/entrypoints/entrypoint_utils-inl.h +++ b/runtime/entrypoints/entrypoint_utils-inl.h @@ -46,22 +46,24 @@ namespace art { inline ArtMethod* GetResolvedMethod(ArtMethod* outer_method, const MethodInfo& method_info, - const InlineInfo& inline_info, + const CodeInfo& code_info, + const StackMap& stack_map, uint8_t inlining_depth) REQUIRES_SHARED(Locks::mutator_lock_) { DCHECK(!outer_method->IsObsolete()); + InlineInfo inline_info = code_info.GetInlineInfoAtDepth(stack_map, inlining_depth); // This method is being used by artQuickResolutionTrampoline, before it sets up // the passed parameters in a GC friendly way. Therefore we must never be // suspended while executing it. ScopedAssertNoThreadSuspension sants(__FUNCTION__); - if (inline_info.EncodesArtMethodAtDepth(inlining_depth)) { - return inline_info.GetArtMethodAtDepth(inlining_depth); + if (inline_info.EncodesArtMethod()) { + return inline_info.GetArtMethod(); } - uint32_t method_index = inline_info.GetMethodIndexAtDepth(method_info, inlining_depth); - if (inline_info.GetDexPcAtDepth(inlining_depth) == static_cast<uint32_t>(-1)) { + uint32_t method_index = inline_info.GetMethodIndex(method_info); + if (inline_info.GetDexPc() == static_cast<uint32_t>(-1)) { // "charAt" special case. It is the only non-leaf method we inline across dex files. ArtMethod* inlined_method = jni::DecodeArtMethod(WellKnownClasses::java_lang_String_charAt); DCHECK_EQ(inlined_method->GetDexMethodIndex(), method_index); @@ -72,9 +74,10 @@ inline ArtMethod* GetResolvedMethod(ArtMethod* outer_method, ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); ArtMethod* method = outer_method; for (uint32_t depth = 0, end = inlining_depth + 1u; depth != end; ++depth) { - DCHECK(!inline_info.EncodesArtMethodAtDepth(depth)); - DCHECK_NE(inline_info.GetDexPcAtDepth(depth), static_cast<uint32_t>(-1)); - method_index = inline_info.GetMethodIndexAtDepth(method_info, depth); + inline_info = code_info.GetInlineInfoAtDepth(stack_map, depth); + DCHECK(!inline_info.EncodesArtMethod()); + DCHECK_NE(inline_info.GetDexPc(), static_cast<uint32_t>(-1)); + method_index = inline_info.GetMethodIndex(method_info); ArtMethod* inlined_method = class_linker->LookupResolvedMethod(method_index, method->GetDexCache(), method->GetClassLoader()); @@ -743,33 +746,6 @@ inline ObjPtr<mirror::Class> ResolveVerifyAndClinit(dex::TypeIndex type_idx, return h_class.Get(); } -static inline ObjPtr<mirror::String> ResolveString(ClassLinker* class_linker, - dex::StringIndex string_idx, - ArtMethod* referrer) - REQUIRES_SHARED(Locks::mutator_lock_) { - Thread::PoisonObjectPointersIfDebug(); - ObjPtr<mirror::String> string = referrer->GetDexCache()->GetResolvedString(string_idx); - if (UNLIKELY(string == nullptr)) { - StackHandleScope<1> hs(Thread::Current()); - Handle<mirror::DexCache> dex_cache(hs.NewHandle(referrer->GetDexCache())); - string = class_linker->ResolveString(string_idx, dex_cache); - } - return string; -} - -inline ObjPtr<mirror::String> ResolveStringFromCode(ArtMethod* referrer, - dex::StringIndex string_idx) { - Thread::PoisonObjectPointersIfDebug(); - ObjPtr<mirror::String> string = referrer->GetDexCache()->GetResolvedString(string_idx); - if (UNLIKELY(string == nullptr)) { - StackHandleScope<1> hs(Thread::Current()); - Handle<mirror::DexCache> dex_cache(hs.NewHandle(referrer->GetDexCache())); - ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); - string = class_linker->ResolveString(string_idx, dex_cache); - } - return string; -} - inline void UnlockJniSynchronizedMethod(jobject locked, Thread* self) { // Save any pending exception over monitor exit call. mirror::Throwable* saved_exception = nullptr; diff --git a/runtime/entrypoints/entrypoint_utils.cc b/runtime/entrypoints/entrypoint_utils.cc index 7f9b385a0a..e71d1fa38a 100644 --- a/runtime/entrypoints/entrypoint_utils.cc +++ b/runtime/entrypoints/entrypoint_utils.cc @@ -205,12 +205,9 @@ static inline ArtMethod* DoGetCalleeSaveMethodCaller(ArtMethod* outer_method, MethodInfo method_info = current_code->GetOptimizedMethodInfo(); StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset); DCHECK(stack_map.IsValid()); - if (stack_map.HasInlineInfo()) { - InlineInfo inline_info = code_info.GetInlineInfoOf(stack_map); - caller = GetResolvedMethod(outer_method, - method_info, - inline_info, - inline_info.GetDepth() - 1); + uint32_t depth = code_info.GetInlineDepthOf(stack_map); + if (depth != 0) { + caller = GetResolvedMethod(outer_method, method_info, code_info, stack_map, depth - 1); } } if (kIsDebugBuild && do_caller_check) { diff --git a/runtime/entrypoints/entrypoint_utils.h b/runtime/entrypoints/entrypoint_utils.h index 1f4475f6ff..9d70b03dfa 100644 --- a/runtime/entrypoints/entrypoint_utils.h +++ b/runtime/entrypoints/entrypoint_utils.h @@ -162,11 +162,6 @@ ObjPtr<mirror::MethodType> ResolveMethodTypeFromCode(ArtMethod* referrer, dex::P REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); -inline ObjPtr<mirror::String> ResolveStringFromCode(ArtMethod* referrer, - dex::StringIndex string_idx) - REQUIRES_SHARED(Locks::mutator_lock_) - REQUIRES(!Roles::uninterruptible_); - // TODO: annotalysis disabled as monitor semantics are maintained in Java code. inline void UnlockJniSynchronizedMethod(jobject locked, Thread* self) NO_THREAD_SAFETY_ANALYSIS REQUIRES(!Roles::uninterruptible_); diff --git a/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc b/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc index fa536c77a9..62756123e1 100644 --- a/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc @@ -210,7 +210,8 @@ extern "C" mirror::String* artResolveStringFromCode(int32_t string_idx, Thread* auto caller_and_outer = GetCalleeSaveMethodCallerAndOuterMethod(self, CalleeSaveType::kSaveEverything); ArtMethod* caller = caller_and_outer.caller; - ObjPtr<mirror::String> result = ResolveStringFromCode(caller, dex::StringIndex(string_idx)); + ObjPtr<mirror::String> result = + Runtime::Current()->GetClassLinker()->ResolveString(dex::StringIndex(string_idx), caller); if (LIKELY(result != nullptr) && CanReferenceBss(caller_and_outer.outer_method, caller)) { StoreStringInBss(caller_and_outer.outer_method, dex::StringIndex(string_idx), result); } diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc index a59faeae9b..af6a936d40 100644 --- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc @@ -344,9 +344,10 @@ class QuickArgumentVisitor { CodeInfo code_info(current_code); StackMap stack_map = code_info.GetStackMapForNativePcOffset(outer_pc_offset); DCHECK(stack_map.IsValid()); - if (stack_map.HasInlineInfo()) { - InlineInfo inline_info = code_info.GetInlineInfoOf(stack_map); - return inline_info.GetDexPcAtDepth(inline_info.GetDepth()-1); + uint32_t depth = code_info.GetInlineDepthOf(stack_map); + if (depth != 0) { + InlineInfo inline_info = code_info.GetInlineInfoAtDepth(stack_map, depth - 1); + return inline_info.GetDexPc(); } else { return stack_map.GetDexPc(); } @@ -1231,17 +1232,17 @@ static void DumpB74410240DebugData(ArtMethod** sp) REQUIRES_SHARED(Locks::mutato LOG(FATAL_WITHOUT_ABORT) << " instruction: " << DumpInstruction(outer_method, dex_pc); ArtMethod* caller = outer_method; - if (stack_map.HasInlineInfo()) { - InlineInfo inline_info = code_info.GetInlineInfoOf(stack_map); - size_t depth = inline_info.GetDepth(); + uint32_t depth = code_info.GetInlineDepthOf(stack_map); + if (depth != 0) { for (size_t d = 0; d < depth; ++d) { + InlineInfo inline_info = code_info.GetInlineInfoAtDepth(stack_map, d); const char* tag = ""; - dex_pc = inline_info.GetDexPcAtDepth(d); - if (inline_info.EncodesArtMethodAtDepth(d)) { + dex_pc = inline_info.GetDexPc(); + if (inline_info.EncodesArtMethod()) { tag = "encoded "; - caller = inline_info.GetArtMethodAtDepth(d); + caller = inline_info.GetArtMethod(); } else { - uint32_t method_index = inline_info.GetMethodIndexAtDepth(method_info, d); + uint32_t method_index = inline_info.GetMethodIndex(method_info); if (dex_pc == static_cast<uint32_t>(-1)) { tag = "special "; CHECK_EQ(d + 1u, depth); diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc index dbe09e8c5b..e754fbcbae 100644 --- a/runtime/gc/space/image_space.cc +++ b/runtime/gc/space/image_space.cc @@ -1287,7 +1287,7 @@ class ImageSpaceLoader { bitmap->VisitMarkedRange(objects_begin, objects_end, fixup_object_visitor); // Fixup image roots. CHECK(app_image.InSource(reinterpret_cast<uintptr_t>( - image_header.GetImageRoots<kWithoutReadBarrier>()))); + image_header.GetImageRoots<kWithoutReadBarrier>().Ptr()))); image_header.RelocateImageObjects(app_image.Delta()); CHECK_EQ(image_header.GetImageBegin(), target_base); // Fix up dex cache DexFile pointers. diff --git a/runtime/image-inl.h b/runtime/image-inl.h index 3a66a34cb3..c527f6fbcc 100644 --- a/runtime/image-inl.h +++ b/runtime/image-inl.h @@ -23,18 +23,19 @@ #include "imt_conflict_table.h" #include "imtable.h" #include "mirror/object_array-inl.h" +#include "obj_ptr-inl.h" #include "read_barrier-inl.h" namespace art { template <ReadBarrierOption kReadBarrierOption> -inline mirror::Object* ImageHeader::GetImageRoot(ImageRoot image_root) const { - mirror::ObjectArray<mirror::Object>* image_roots = GetImageRoots<kReadBarrierOption>(); +inline ObjPtr<mirror::Object> ImageHeader::GetImageRoot(ImageRoot image_root) const { + ObjPtr<mirror::ObjectArray<mirror::Object>> image_roots = GetImageRoots<kReadBarrierOption>(); return image_roots->Get<kVerifyNone, kReadBarrierOption>(static_cast<int32_t>(image_root)); } template <ReadBarrierOption kReadBarrierOption> -inline mirror::ObjectArray<mirror::Object>* ImageHeader::GetImageRoots() const { +inline ObjPtr<mirror::ObjectArray<mirror::Object>> ImageHeader::GetImageRoots() const { // Need a read barrier as it's not visited during root scan. // Pass in the address of the local variable to the read barrier // rather than image_roots_ because it won't move (asserted below) diff --git a/runtime/image.cc b/runtime/image.cc index 7ad2e7bf95..17fc664bd7 100644 --- a/runtime/image.cc +++ b/runtime/image.cc @@ -26,7 +26,7 @@ namespace art { const uint8_t ImageHeader::kImageMagic[] = { 'a', 'r', 't', '\n' }; -const uint8_t ImageHeader::kImageVersion[] = { '0', '6', '0', '\0' }; // ClassRoot::MethodHandle. +const uint8_t ImageHeader::kImageVersion[] = { '0', '6', '1', '\0' }; // Pre-allocated Throwables. ImageHeader::ImageHeader(uint32_t image_begin, uint32_t image_size, diff --git a/runtime/image.h b/runtime/image.h index 8acd5bc4c4..c6fc052a60 100644 --- a/runtime/image.h +++ b/runtime/image.h @@ -27,6 +27,7 @@ namespace art { class ArtField; class ArtMethod; +template <class MirrorType> class ObjPtr; namespace linker { class ImageWriter; @@ -206,7 +207,11 @@ class PACKED(4) ImageHeader { enum ImageRoot { kDexCaches, kClassRoots, - kClassLoader, // App image only. + kOomeWhenThrowingException, // Pre-allocated OOME when throwing exception. + kOomeWhenThrowingOome, // Pre-allocated OOME when throwing OOME. + kOomeWhenHandlingStackOverflow, // Pre-allocated OOME when handling StackOverflowError. + kNoClassDefFoundError, // Pre-allocated NoClassDefFoundError. + kClassLoader, // App image only. kImageRootsMax, }; @@ -277,11 +282,11 @@ class PACKED(4) ImageHeader { } template <ReadBarrierOption kReadBarrierOption = kWithReadBarrier> - mirror::Object* GetImageRoot(ImageRoot image_root) const + ObjPtr<mirror::Object> GetImageRoot(ImageRoot image_root) const REQUIRES_SHARED(Locks::mutator_lock_); template <ReadBarrierOption kReadBarrierOption = kWithReadBarrier> - mirror::ObjectArray<mirror::Object>* GetImageRoots() const + ObjPtr<mirror::ObjectArray<mirror::Object>> GetImageRoots() const REQUIRES_SHARED(Locks::mutator_lock_); void RelocateImage(off_t delta); diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc index 90e89cf3db..27f761a144 100644 --- a/runtime/interpreter/interpreter_common.cc +++ b/runtime/interpreter/interpreter_common.cc @@ -945,11 +945,9 @@ static bool GetArgumentForBootstrapMethod(Thread* self, return true; } case EncodedArrayValueIterator::ValueType::kString: { - StackHandleScope<1> hs(self); - Handle<mirror::DexCache> dex_cache(hs.NewHandle(referrer->GetDexCache())); dex::StringIndex index(static_cast<uint32_t>(encoded_value->GetI())); ClassLinker* cl = Runtime::Current()->GetClassLinker(); - ObjPtr<mirror::String> o = cl->ResolveString(index, dex_cache); + ObjPtr<mirror::String> o = cl->ResolveString(index, referrer); if (UNLIKELY(o.IsNull())) { DCHECK(self->IsExceptionPending()); return false; diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h index 0ee780d32d..60bf50546f 100644 --- a/runtime/interpreter/interpreter_common.h +++ b/runtime/interpreter/interpreter_common.h @@ -340,12 +340,8 @@ static inline ObjPtr<mirror::String> ResolveString(Thread* self, } } ArtMethod* method = shadow_frame.GetMethod(); - ObjPtr<mirror::String> string_ptr = method->GetDexCache()->GetResolvedString(string_idx); - if (UNLIKELY(string_ptr == nullptr)) { - StackHandleScope<1> hs(self); - Handle<mirror::DexCache> dex_cache(hs.NewHandle(method->GetDexCache())); - string_ptr = Runtime::Current()->GetClassLinker()->ResolveString(string_idx, dex_cache); - } + ObjPtr<mirror::String> string_ptr = + Runtime::Current()->GetClassLinker()->ResolveString(string_idx, method); return string_ptr; } diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc index 31a83f8e48..44b0c2b007 100644 --- a/runtime/mirror/class.cc +++ b/runtime/mirror/class.cc @@ -419,7 +419,7 @@ bool Class::IsInSamePackage(ObjPtr<Class> that) { } bool Class::IsThrowableClass() { - return WellKnownClasses::ToClass(WellKnownClasses::java_lang_Throwable)->IsAssignableFrom(this); + return GetClassRoot<mirror::Throwable>()->IsAssignableFrom(this); } void Class::SetClassLoader(ObjPtr<ClassLoader> new_class_loader) { @@ -1269,7 +1269,7 @@ ObjPtr<Method> Class::GetDeclaredMethodInternal( for (auto& m : h_klass->GetDeclaredVirtualMethods(kPointerSize)) { auto* np_method = m.GetInterfaceMethodIfProxy(kPointerSize); // May cause thread suspension. - ObjPtr<String> np_name = np_method->GetNameAsString(self); + ObjPtr<String> np_name = np_method->ResolveNameString(); if (!np_name->Equals(h_method_name.Get()) || !np_method->EqualParameters(h_args)) { if (UNLIKELY(self->IsExceptionPending())) { return nullptr; @@ -1291,7 +1291,7 @@ ObjPtr<Method> Class::GetDeclaredMethodInternal( } auto* np_method = m.GetInterfaceMethodIfProxy(kPointerSize); // May cause thread suspension. - ObjPtr<String> np_name = np_method->GetNameAsString(self); + ObjPtr<String> np_name = np_method->ResolveNameString(); if (np_name == nullptr) { self->AssertPendingException(); return nullptr; diff --git a/runtime/mirror/object-inl.h b/runtime/mirror/object-inl.h index e022db86fd..ee4f53b695 100644 --- a/runtime/mirror/object-inl.h +++ b/runtime/mirror/object-inl.h @@ -114,10 +114,6 @@ inline void Object::NotifyAll(Thread* self) { Monitor::NotifyAll(self, this); } -inline void Object::Wait(Thread* self) { - Monitor::Wait(self, this, 0, 0, true, kWaiting); -} - inline void Object::Wait(Thread* self, int64_t ms, int32_t ns) { Monitor::Wait(self, this, ms, ns, true, kTimedWaiting); } diff --git a/runtime/mirror/object.h b/runtime/mirror/object.h index 8584b8a56f..a89d6323a5 100644 --- a/runtime/mirror/object.h +++ b/runtime/mirror/object.h @@ -176,7 +176,6 @@ class MANAGED LOCKABLE Object { UNLOCK_FUNCTION(); void Notify(Thread* self) REQUIRES_SHARED(Locks::mutator_lock_); void NotifyAll(Thread* self) REQUIRES_SHARED(Locks::mutator_lock_); - void Wait(Thread* self) REQUIRES_SHARED(Locks::mutator_lock_); void Wait(Thread* self, int64_t timeout, int32_t nanos) REQUIRES_SHARED(Locks::mutator_lock_); template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, diff --git a/runtime/native/dalvik_system_VMRuntime.cc b/runtime/native/dalvik_system_VMRuntime.cc index 8aed4a806c..3227c69305 100644 --- a/runtime/native/dalvik_system_VMRuntime.cc +++ b/runtime/native/dalvik_system_VMRuntime.cc @@ -32,6 +32,7 @@ extern "C" void android_set_application_target_sdk_version(uint32_t version); #include "class_linker-inl.h" #include "common_throws.h" #include "debugger.h" +#include "dex/class_accessor-inl.h" #include "dex/dex_file-inl.h" #include "dex/dex_file_types.h" #include "gc/accounting/card_table-inl.h" @@ -573,30 +574,12 @@ static void VMRuntime_preloadDexCaches(JNIEnv* env, jobject) { } if (kPreloadDexCachesFieldsAndMethods) { - for (size_t class_def_index = 0; - class_def_index < dex_file->NumClassDefs(); - class_def_index++) { - const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index); - const uint8_t* class_data = dex_file->GetClassData(class_def); - if (class_data == nullptr) { - continue; + for (ClassAccessor accessor : dex_file->GetClasses()) { + for (const ClassAccessor::Field& field : accessor.GetFields()) { + PreloadDexCachesResolveField(dex_cache, field.GetIndex(), field.IsStatic()); } - ClassDataItemIterator it(*dex_file, class_data); - for (; it.HasNextStaticField(); it.Next()) { - uint32_t field_idx = it.GetMemberIndex(); - PreloadDexCachesResolveField(dex_cache, field_idx, true); - } - for (; it.HasNextInstanceField(); it.Next()) { - uint32_t field_idx = it.GetMemberIndex(); - PreloadDexCachesResolveField(dex_cache, field_idx, false); - } - for (; it.HasNextDirectMethod(); it.Next()) { - uint32_t method_idx = it.GetMemberIndex(); - PreloadDexCachesResolveMethod(dex_cache, method_idx); - } - for (; it.HasNextVirtualMethod(); it.Next()) { - uint32_t method_idx = it.GetMemberIndex(); - PreloadDexCachesResolveMethod(dex_cache, method_idx); + for (const ClassAccessor::Method& method : accessor.GetMethods()) { + PreloadDexCachesResolveMethod(dex_cache, method.GetIndex()); } } } diff --git a/runtime/native/java_lang_Object.cc b/runtime/native/java_lang_Object.cc index 208ccf6a82..48540f877d 100644 --- a/runtime/native/java_lang_Object.cc +++ b/runtime/native/java_lang_Object.cc @@ -41,11 +41,6 @@ static void Object_notifyAll(JNIEnv* env, jobject java_this) { soa.Decode<mirror::Object>(java_this)->NotifyAll(soa.Self()); } -static void Object_wait(JNIEnv* env, jobject java_this) { - ScopedFastNativeObjectAccess soa(env); - soa.Decode<mirror::Object>(java_this)->Wait(soa.Self()); -} - static void Object_waitJI(JNIEnv* env, jobject java_this, jlong ms, jint ns) { ScopedFastNativeObjectAccess soa(env); soa.Decode<mirror::Object>(java_this)->Wait(soa.Self(), ms, ns); @@ -61,7 +56,6 @@ static JNINativeMethod gMethods[] = { FAST_NATIVE_METHOD(Object, internalClone, "()Ljava/lang/Object;"), FAST_NATIVE_METHOD(Object, notify, "()V"), FAST_NATIVE_METHOD(Object, notifyAll, "()V"), - OVERLOADED_FAST_NATIVE_METHOD(Object, wait, "()V", wait), OVERLOADED_FAST_NATIVE_METHOD(Object, wait, "(JI)V", waitJI), FAST_NATIVE_METHOD(Object, identityHashCodeNative, "(Ljava/lang/Object;)I"), }; diff --git a/runtime/native/java_lang_reflect_Executable.cc b/runtime/native/java_lang_reflect_Executable.cc index a40cb9b2e6..a10db9115f 100644 --- a/runtime/native/java_lang_reflect_Executable.cc +++ b/runtime/native/java_lang_reflect_Executable.cc @@ -320,7 +320,7 @@ static jstring Executable_getMethodNameInternal(JNIEnv* env, jobject javaMethod) ScopedFastNativeObjectAccess soa(env); ArtMethod* method = ArtMethod::FromReflectedMethod(soa, javaMethod); method = method->GetInterfaceMethodIfProxy(kRuntimePointerSize); - return soa.AddLocalReference<jstring>(method->GetNameAsString(soa.Self())); + return soa.AddLocalReference<jstring>(method->ResolveNameString()); } static jclass Executable_getMethodReturnTypeInternal(JNIEnv* env, jobject javaMethod) { diff --git a/runtime/native/java_lang_reflect_Field.cc b/runtime/native/java_lang_reflect_Field.cc index 8766692a8c..895b2f9fd7 100644 --- a/runtime/native/java_lang_reflect_Field.cc +++ b/runtime/native/java_lang_reflect_Field.cc @@ -464,8 +464,7 @@ static jlong Field_getArtField(JNIEnv* env, jobject javaField) { static jstring Field_getNameInternal(JNIEnv* env, jobject javaField) { ScopedFastNativeObjectAccess soa(env); ArtField* field = soa.Decode<mirror::Field>(javaField)->GetArtField(); - return soa.AddLocalReference<jstring>( - field->GetStringName(soa.Self(), true /* resolve */)); + return soa.AddLocalReference<jstring>(field->ResolveNameString()); } static jobjectArray Field_getDeclaredAnnotations(JNIEnv* env, jobject javaField) { diff --git a/runtime/oat.h b/runtime/oat.h index e7e5848dd6..72eb27d69e 100644 --- a/runtime/oat.h +++ b/runtime/oat.h @@ -32,8 +32,8 @@ class InstructionSetFeatures; class PACKED(4) OatHeader { public: static constexpr uint8_t kOatMagic[] = { 'o', 'a', 't', '\n' }; - // Last oat version changed reason: Rewrite dex register map encoding. - static constexpr uint8_t kOatVersion[] = { '1', '4', '6', '\0' }; + // Last oat version changed reason: Rewrite TypeLookupTable. + static constexpr uint8_t kOatVersion[] = { '1', '4', '7', '\0' }; static constexpr const char* kImageLocationKey = "image-location"; static constexpr const char* kDex2OatCmdLineKey = "dex2oat-cmdline"; diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc index ffbc26c647..2b05b0e3dd 100644 --- a/runtime/oat_file.cc +++ b/runtime/oat_file.cc @@ -1687,6 +1687,7 @@ OatFile::OatDexFile::OatDexFile(const OatFile* oat_file, type_bss_mapping_(type_bss_mapping_data), string_bss_mapping_(string_bss_mapping_data), oat_class_offsets_pointer_(oat_class_offsets_pointer), + lookup_table_(), dex_layout_sections_(dex_layout_sections) { // Initialize TypeLookupTable. if (lookup_table_data_ != nullptr) { @@ -1706,7 +1707,7 @@ OatFile::OatDexFile::OatDexFile(const OatFile* oat_file, } } -OatFile::OatDexFile::OatDexFile(std::unique_ptr<TypeLookupTable>&& lookup_table) +OatFile::OatDexFile::OatDexFile(TypeLookupTable&& lookup_table) : lookup_table_(std::move(lookup_table)) {} OatFile::OatDexFile::~OatDexFile() {} @@ -1783,9 +1784,9 @@ const DexFile::ClassDef* OatFile::OatDexFile::FindClassDef(const DexFile& dex_fi DCHECK_EQ(ComputeModifiedUtf8Hash(descriptor), hash); bool used_lookup_table = false; const DexFile::ClassDef* lookup_table_classdef = nullptr; - if (LIKELY((oat_dex_file != nullptr) && (oat_dex_file->GetTypeLookupTable() != nullptr))) { + if (LIKELY((oat_dex_file != nullptr) && oat_dex_file->GetTypeLookupTable().Valid())) { used_lookup_table = true; - const uint32_t class_def_idx = oat_dex_file->GetTypeLookupTable()->Lookup(descriptor, hash); + const uint32_t class_def_idx = oat_dex_file->GetTypeLookupTable().Lookup(descriptor, hash); lookup_table_classdef = (class_def_idx != dex::kDexNoIndex) ? &dex_file.GetClassDef(class_def_idx) : nullptr; @@ -1796,6 +1797,7 @@ const DexFile::ClassDef* OatFile::OatDexFile::FindClassDef(const DexFile& dex_fi // Fast path for rare no class defs case. const uint32_t num_class_defs = dex_file.NumClassDefs(); if (num_class_defs == 0) { + DCHECK(!used_lookup_table); return nullptr; } const DexFile::TypeId* type_id = dex_file.FindTypeId(descriptor); diff --git a/runtime/oat_file.h b/runtime/oat_file.h index 8e18cee729..d72b6a8971 100644 --- a/runtime/oat_file.h +++ b/runtime/oat_file.h @@ -514,14 +514,14 @@ class OatDexFile FINAL { // Madvise the dex file based on the state we are moving to. static void MadviseDexFile(const DexFile& dex_file, MadviseState state); - TypeLookupTable* GetTypeLookupTable() const { - return lookup_table_.get(); + const TypeLookupTable& GetTypeLookupTable() const { + return lookup_table_; } ~OatDexFile(); // Create only with a type lookup table, used by the compiler to speed up compilation. - explicit OatDexFile(std::unique_ptr<TypeLookupTable>&& lookup_table); + explicit OatDexFile(TypeLookupTable&& lookup_table); // Return the dex layout sections. const DexLayoutSections* GetDexLayoutSections() const { @@ -553,7 +553,7 @@ class OatDexFile FINAL { const IndexBssMapping* const type_bss_mapping_ = nullptr; const IndexBssMapping* const string_bss_mapping_ = nullptr; const uint32_t* const oat_class_offsets_pointer_ = 0u; - mutable std::unique_ptr<TypeLookupTable> lookup_table_; + TypeLookupTable lookup_table_; const DexLayoutSections* const dex_layout_sections_ = nullptr; friend class OatFile; diff --git a/runtime/quick_exception_handler.cc b/runtime/quick_exception_handler.cc index 4f4abf7f7f..23ccf6ad58 100644 --- a/runtime/quick_exception_handler.cc +++ b/runtime/quick_exception_handler.cc @@ -406,7 +406,7 @@ class DeoptimizeStackVisitor FINAL : public StackVisitor { BitMemoryRegion stack_mask = code_info.GetStackMaskOf(stack_map); DexRegisterMap vreg_map = IsInInlinedFrame() ? code_info.GetDexRegisterMapAtDepth(GetCurrentInliningDepth() - 1, - code_info.GetInlineInfoOf(stack_map), + stack_map, number_of_vregs) : code_info.GetDexRegisterMapOf(stack_map, number_of_vregs); diff --git a/runtime/reference_table_test.cc b/runtime/reference_table_test.cc index 0cb5e565e9..1d54d21187 100644 --- a/runtime/reference_table_test.cc +++ b/runtime/reference_table_test.cc @@ -290,7 +290,7 @@ TEST_F(ReferenceTableTest, SummaryOrder) { } { - // Differently sized byte arrays. Should be sorted by identical (non-unique cound). + // Differently sized byte arrays. Should be sorted by identical (non-unique count). StackHandleScope<1> hs(soa.Self()); Handle<mirror::ByteArray> b1_1 = hs.NewHandle(mirror::ByteArray::Alloc(soa.Self(), 1)); rt.Add(b1_1.Get()); diff --git a/runtime/runtime.cc b/runtime/runtime.cc index 0d9d16cd01..1e327fc8ed 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -1090,6 +1090,17 @@ void Runtime::SetSentinel(mirror::Object* sentinel) { sentinel_ = GcRoot<mirror::Object>(sentinel); } +static inline void InitPreAllocatedException(Thread* self, + GcRoot<mirror::Throwable>* exception, + const char* exception_class_descriptor, + const char* msg) + REQUIRES_SHARED(Locks::mutator_lock_) { + DCHECK_EQ(self, Thread::Current()); + self->ThrowNewException(exception_class_descriptor, msg); + *exception = GcRoot<mirror::Throwable>(self->GetException()); + self->ClearException(); +} + bool Runtime::Init(RuntimeArgumentMap&& runtime_options_in) { // (b/30160149): protect subprocesses from modifications to LD_LIBRARY_PATH, etc. // Take a snapshot of the environment at the time the runtime was created, for use by Exec, etc. @@ -1505,34 +1516,54 @@ bool Runtime::Init(RuntimeArgumentMap&& runtime_options_in) { // TODO: move this to just be an Trace::Start argument Trace::SetDefaultClockSource(runtime_options.GetOrDefault(Opt::ProfileClock)); - // Pre-allocate an OutOfMemoryError for the case when we fail to - // allocate the exception to be thrown. - InitPreAllocatedException(self, - &Runtime::pre_allocated_OutOfMemoryError_when_throwing_exception_, - "Ljava/lang/OutOfMemoryError;", - "OutOfMemoryError thrown while trying to throw an exception; " - "no stack trace available"); - // Pre-allocate an OutOfMemoryError for the double-OOME case. - InitPreAllocatedException(self, - &Runtime::pre_allocated_OutOfMemoryError_when_throwing_oome_, - "Ljava/lang/OutOfMemoryError;", - "OutOfMemoryError thrown while trying to throw OutOfMemoryError; " - "no stack trace available"); - // Pre-allocate an OutOfMemoryError for the case when we fail to - // allocate while handling a stack overflow. - InitPreAllocatedException(self, - &Runtime::pre_allocated_OutOfMemoryError_when_handling_stack_overflow_, - "Ljava/lang/OutOfMemoryError;", - "OutOfMemoryError thrown while trying to handle a stack overflow; " - "no stack trace available"); - - // Pre-allocate a NoClassDefFoundError for the common case of failing to find a system class - // ahead of checking the application's class loader. - InitPreAllocatedException(self, - &Runtime::pre_allocated_NoClassDefFoundError_, - "Ljava/lang/NoClassDefFoundError;", - "Class not found using the boot class loader; " - "no stack trace available"); + if (GetHeap()->HasBootImageSpace()) { + const ImageHeader& image_header = GetHeap()->GetBootImageSpaces()[0]->GetImageHeader(); + pre_allocated_OutOfMemoryError_when_throwing_exception_ = GcRoot<mirror::Throwable>( + image_header.GetImageRoot(ImageHeader::kOomeWhenThrowingException)->AsThrowable()); + DCHECK(pre_allocated_OutOfMemoryError_when_throwing_exception_.Read()->GetClass() + ->DescriptorEquals("Ljava/lang/OutOfMemoryError;")); + pre_allocated_OutOfMemoryError_when_throwing_oome_ = GcRoot<mirror::Throwable>( + image_header.GetImageRoot(ImageHeader::kOomeWhenThrowingOome)->AsThrowable()); + DCHECK(pre_allocated_OutOfMemoryError_when_throwing_oome_.Read()->GetClass() + ->DescriptorEquals("Ljava/lang/OutOfMemoryError;")); + pre_allocated_OutOfMemoryError_when_handling_stack_overflow_ = GcRoot<mirror::Throwable>( + image_header.GetImageRoot(ImageHeader::kOomeWhenHandlingStackOverflow)->AsThrowable()); + DCHECK(pre_allocated_OutOfMemoryError_when_handling_stack_overflow_.Read()->GetClass() + ->DescriptorEquals("Ljava/lang/OutOfMemoryError;")); + pre_allocated_NoClassDefFoundError_ = GcRoot<mirror::Throwable>( + image_header.GetImageRoot(ImageHeader::kNoClassDefFoundError)->AsThrowable()); + DCHECK(pre_allocated_NoClassDefFoundError_.Read()->GetClass() + ->DescriptorEquals("Ljava/lang/NoClassDefFoundError;")); + } else { + // Pre-allocate an OutOfMemoryError for the case when we fail to + // allocate the exception to be thrown. + InitPreAllocatedException(self, + &pre_allocated_OutOfMemoryError_when_throwing_exception_, + "Ljava/lang/OutOfMemoryError;", + "OutOfMemoryError thrown while trying to throw an exception; " + "no stack trace available"); + // Pre-allocate an OutOfMemoryError for the double-OOME case. + InitPreAllocatedException(self, + &pre_allocated_OutOfMemoryError_when_throwing_oome_, + "Ljava/lang/OutOfMemoryError;", + "OutOfMemoryError thrown while trying to throw OutOfMemoryError; " + "no stack trace available"); + // Pre-allocate an OutOfMemoryError for the case when we fail to + // allocate while handling a stack overflow. + InitPreAllocatedException(self, + &pre_allocated_OutOfMemoryError_when_handling_stack_overflow_, + "Ljava/lang/OutOfMemoryError;", + "OutOfMemoryError thrown while trying to handle a stack overflow; " + "no stack trace available"); + + // Pre-allocate a NoClassDefFoundError for the common case of failing to find a system class + // ahead of checking the application's class loader. + InitPreAllocatedException(self, + &pre_allocated_NoClassDefFoundError_, + "Ljava/lang/NoClassDefFoundError;", + "Class not found using the boot class loader; " + "no stack trace available"); + } // Runtime initialization is largely done now. // We load plugins first since that can modify the runtime state slightly. @@ -1682,16 +1713,6 @@ void Runtime::AttachAgent(JNIEnv* env, const std::string& agent_arg, jobject cla } } -void Runtime::InitPreAllocatedException(Thread* self, - GcRoot<mirror::Throwable> Runtime::* exception, - const char* exception_class_descriptor, - const char* msg) { - DCHECK_EQ(self, Thread::Current()); - self->ThrowNewException(exception_class_descriptor, msg); - this->*exception = GcRoot<mirror::Throwable>(self->GetException()); - self->ClearException(); -} - void Runtime::InitNativeMethods() { VLOG(startup) << "Runtime::InitNativeMethods entering"; Thread* self = Thread::Current(); @@ -2048,9 +2069,10 @@ void Runtime::VisitImageRoots(RootVisitor* visitor) { auto* image_space = space->AsImageSpace(); const auto& image_header = image_space->GetImageHeader(); for (int32_t i = 0, size = image_header.GetImageRoots()->GetLength(); i != size; ++i) { - auto* obj = image_header.GetImageRoot(static_cast<ImageHeader::ImageRoot>(i)); + mirror::Object* obj = + image_header.GetImageRoot(static_cast<ImageHeader::ImageRoot>(i)).Ptr(); if (obj != nullptr) { - auto* after_obj = obj; + mirror::Object* after_obj = obj; visitor->VisitRoot(&after_obj, RootInfo(kRootStickyClass)); CHECK_EQ(after_obj, obj); } diff --git a/runtime/runtime.h b/runtime/runtime.h index 10f72e7c5b..d85490c0a6 100644 --- a/runtime/runtime.h +++ b/runtime/runtime.h @@ -774,11 +774,6 @@ class Runtime { bool Init(RuntimeArgumentMap&& runtime_options) SHARED_TRYLOCK_FUNCTION(true, Locks::mutator_lock_); - void InitPreAllocatedException(Thread* self, - GcRoot<mirror::Throwable> Runtime::* exception, - const char* exception_class_descriptor, - const char* msg) - REQUIRES_SHARED(Locks::mutator_lock_); void InitNativeMethods() REQUIRES(!Locks::mutator_lock_); void RegisterRuntimeNativeMethods(JNIEnv* env); diff --git a/runtime/stack.cc b/runtime/stack.cc index 6da7dcb697..bd0d5d680e 100644 --- a/runtime/stack.cc +++ b/runtime/stack.cc @@ -76,14 +76,14 @@ StackVisitor::StackVisitor(Thread* thread, } } -static InlineInfo GetCurrentInlineInfo(CodeInfo& code_info, - const OatQuickMethodHeader* method_header, - uintptr_t cur_quick_frame_pc) +static StackMap GetCurrentStackMap(CodeInfo& code_info, + const OatQuickMethodHeader* method_header, + uintptr_t cur_quick_frame_pc) REQUIRES_SHARED(Locks::mutator_lock_) { uint32_t native_pc_offset = method_header->NativeQuickPcOffset(cur_quick_frame_pc); StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset); DCHECK(stack_map.IsValid()); - return code_info.GetInlineInfoOf(stack_map); + return stack_map; } ArtMethod* StackVisitor::GetMethod() const { @@ -94,14 +94,13 @@ ArtMethod* StackVisitor::GetMethod() const { size_t depth_in_stack_map = current_inlining_depth_ - 1; const OatQuickMethodHeader* method_header = GetCurrentOatQuickMethodHeader(); CodeInfo code_info(method_header); - InlineInfo inline_info = GetCurrentInlineInfo(code_info, - method_header, - cur_quick_frame_pc_); + StackMap stack_map = GetCurrentStackMap(code_info, method_header, cur_quick_frame_pc_); MethodInfo method_info = method_header->GetOptimizedMethodInfo(); DCHECK(walk_kind_ != StackWalkKind::kSkipInlinedFrames); return GetResolvedMethod(*GetCurrentQuickFrame(), method_info, - inline_info, + code_info, + stack_map, depth_in_stack_map); } else { return *cur_quick_frame_; @@ -118,8 +117,8 @@ uint32_t StackVisitor::GetDexPc(bool abort_on_failure) const { const OatQuickMethodHeader* method_header = GetCurrentOatQuickMethodHeader(); CodeInfo code_info(method_header); size_t depth_in_stack_map = current_inlining_depth_ - 1; - return GetCurrentInlineInfo(code_info, method_header, cur_quick_frame_pc_). - GetDexPcAtDepth(depth_in_stack_map); + StackMap stack_map = GetCurrentStackMap(code_info, method_header, cur_quick_frame_pc_); + return code_info.GetInlineInfoAtDepth(stack_map, depth_in_stack_map).GetDexPc(); } else if (cur_oat_quick_method_header_ == nullptr) { return dex::kDexNoIndex; } else { @@ -237,9 +236,7 @@ bool StackVisitor::GetVRegFromOptimizedCode(ArtMethod* m, uint16_t vreg, VRegKin size_t depth_in_stack_map = current_inlining_depth_ - 1; DexRegisterMap dex_register_map = IsInInlinedFrame() - ? code_info.GetDexRegisterMapAtDepth(depth_in_stack_map, - code_info.GetInlineInfoOf(stack_map), - number_of_dex_registers) + ? code_info.GetDexRegisterMapAtDepth(depth_in_stack_map, stack_map, number_of_dex_registers) : code_info.GetDexRegisterMapOf(stack_map, number_of_dex_registers); if (!dex_register_map.IsValid()) { @@ -825,9 +822,8 @@ void StackVisitor::WalkStack(bool include_transitions) { cur_oat_quick_method_header_->NativeQuickPcOffset(cur_quick_frame_pc_); StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset); if (stack_map.IsValid() && stack_map.HasInlineInfo()) { - InlineInfo inline_info = code_info.GetInlineInfoOf(stack_map); DCHECK_EQ(current_inlining_depth_, 0u); - for (current_inlining_depth_ = inline_info.GetDepth(); + for (current_inlining_depth_ = code_info.GetInlineDepthOf(stack_map); current_inlining_depth_ != 0; --current_inlining_depth_) { bool should_continue = VisitFrame(); diff --git a/runtime/stack_map.cc b/runtime/stack_map.cc index 923bb3559a..a5749b84a7 100644 --- a/runtime/stack_map.cc +++ b/runtime/stack_map.cc @@ -146,38 +146,39 @@ void StackMap::Dump(VariableIndentationOutputStream* vios, } vios->Stream() << ")\n"; DumpDexRegisterMap(vios, code_info.GetDexRegisterMapOf(*this, number_of_dex_registers)); - if (HasInlineInfo()) { - InlineInfo inline_info = code_info.GetInlineInfoOf(*this); + uint32_t depth = code_info.GetInlineDepthOf(*this); + for (size_t d = 0; d < depth; d++) { + InlineInfo inline_info = code_info.GetInlineInfoAtDepth(*this, d); // We do not know the length of the dex register maps of inlined frames // at this level, so we just pass null to `InlineInfo::Dump` to tell // it not to look at these maps. - inline_info.Dump(vios, code_info, method_info, nullptr); + inline_info.Dump(vios, code_info, *this, method_info, 0); } } void InlineInfo::Dump(VariableIndentationOutputStream* vios, const CodeInfo& code_info, + const StackMap& stack_map, const MethodInfo& method_info, - uint16_t number_of_dex_registers[]) const { - for (size_t i = 0; i < GetDepth(); ++i) { + uint16_t number_of_dex_registers) const { + uint32_t depth = Row() - stack_map.GetInlineInfoIndex(); + vios->Stream() + << "InlineInfo[" << Row() << "]" + << " (depth=" << depth + << std::hex + << ", dex_pc=0x" << GetDexPc(); + if (EncodesArtMethod()) { + ScopedObjectAccess soa(Thread::Current()); + vios->Stream() << ", method=" << GetArtMethod()->PrettyMethod(); + } else { vios->Stream() - << "InlineInfo[" << Row() + i << "]" - << " (depth=" << i - << std::hex - << ", dex_pc=0x" << GetDexPcAtDepth(i); - if (EncodesArtMethodAtDepth(i)) { - ScopedObjectAccess soa(Thread::Current()); - vios->Stream() << ", method=" << GetArtMethodAtDepth(i)->PrettyMethod(); - } else { - vios->Stream() - << std::dec - << ", method_index=" << GetMethodIndexAtDepth(method_info, i); - } - vios->Stream() << ")\n"; - if (number_of_dex_registers != nullptr) { - uint16_t vregs = number_of_dex_registers[i]; - DumpDexRegisterMap(vios, code_info.GetDexRegisterMapAtDepth(i, *this, vregs)); - } + << std::dec + << ", method_index=" << GetMethodIndex(method_info); + } + vios->Stream() << ")\n"; + if (number_of_dex_registers != 0) { + uint16_t vregs = number_of_dex_registers; + DumpDexRegisterMap(vios, code_info.GetDexRegisterMapAtDepth(depth, stack_map, vregs)); } } diff --git a/runtime/stack_map.h b/runtime/stack_map.h index 9aac204e70..b04197e160 100644 --- a/runtime/stack_map.h +++ b/runtime/stack_map.h @@ -222,54 +222,47 @@ class InlineInfo : public BitTable<7>::Accessor { InlineInfo(const BitTable<kCount>* table, uint32_t row) : BitTable<kCount>::Accessor(table, row) {} - ALWAYS_INLINE InlineInfo AtDepth(uint32_t depth) const { - return InlineInfo(table_, this->row_ + depth); - } - - uint32_t GetDepth() const { - size_t depth = 0; - while (AtDepth(depth++).Get<kIsLast>() == kMore) { } - return depth; - } + uint32_t GetIsLast() const { return Get<kIsLast>(); } - uint32_t GetMethodIndexIdxAtDepth(uint32_t depth) const { - DCHECK(!EncodesArtMethodAtDepth(depth)); - return AtDepth(depth).Get<kMethodIndexIdx>(); + uint32_t GetMethodIndexIdx() const { + DCHECK(!EncodesArtMethod()); + return Get<kMethodIndexIdx>(); } - uint32_t GetMethodIndexAtDepth(const MethodInfo& method_info, uint32_t depth) const { - return method_info.GetMethodIndex(GetMethodIndexIdxAtDepth(depth)); + uint32_t GetMethodIndex(const MethodInfo& method_info) const { + return method_info.GetMethodIndex(GetMethodIndexIdx()); } - uint32_t GetDexPcAtDepth(uint32_t depth) const { - return AtDepth(depth).Get<kDexPc>(); + uint32_t GetDexPc() const { + return Get<kDexPc>(); } - bool EncodesArtMethodAtDepth(uint32_t depth) const { - return AtDepth(depth).Get<kArtMethodLo>() != kNoValue; + bool EncodesArtMethod() const { + return Get<kArtMethodLo>() != kNoValue; } - ArtMethod* GetArtMethodAtDepth(uint32_t depth) const { - uint64_t lo = AtDepth(depth).Get<kArtMethodLo>(); - uint64_t hi = AtDepth(depth).Get<kArtMethodHi>(); + ArtMethod* GetArtMethod() const { + uint64_t lo = Get<kArtMethodLo>(); + uint64_t hi = Get<kArtMethodHi>(); return reinterpret_cast<ArtMethod*>((hi << 32) | lo); } - uint32_t GetDexRegisterMaskIndexAtDepth(uint32_t depth) const { - return AtDepth(depth).Get<kDexRegisterMaskIndex>(); + uint32_t GetDexRegisterMaskIndex() const { + return Get<kDexRegisterMaskIndex>(); } - uint32_t GetDexRegisterMapIndexAtDepth(uint32_t depth) const { - return AtDepth(depth).Get<kDexRegisterMapIndex>(); + uint32_t GetDexRegisterMapIndex() const { + return Get<kDexRegisterMapIndex>(); } - bool HasDexRegisterMapAtDepth(uint32_t depth) const { - return GetDexRegisterMapIndexAtDepth(depth) != kNoValue; + bool HasDexRegisterMap() const { + return GetDexRegisterMapIndex() != kNoValue; } void Dump(VariableIndentationOutputStream* vios, const CodeInfo& info, + const StackMap& stack_map, const MethodInfo& method_info, - uint16_t* number_of_dex_registers) const; + uint16_t number_of_dex_registers) const; }; class InvokeInfo : public BitTable<3>::Accessor { @@ -417,10 +410,11 @@ class CodeInfo { } ALWAYS_INLINE DexRegisterMap GetDexRegisterMapAtDepth(uint8_t depth, - InlineInfo inline_info, + StackMap stack_map, size_t num_dex_registers) const { - return DecodeDexRegisterMap(inline_info.GetDexRegisterMaskIndexAtDepth(depth), - inline_info.GetDexRegisterMapIndexAtDepth(depth), + InlineInfo inline_info = GetInlineInfoAtDepth(stack_map, depth); + return DecodeDexRegisterMap(inline_info.GetDexRegisterMaskIndex(), + inline_info.GetDexRegisterMapIndex(), num_dex_registers); } @@ -428,10 +422,19 @@ class CodeInfo { return InlineInfo(&inline_infos_, index); } - InlineInfo GetInlineInfoOf(StackMap stack_map) const { - DCHECK(stack_map.HasInlineInfo()); + uint32_t GetInlineDepthOf(StackMap stack_map) const { + uint32_t depth = 0; uint32_t index = stack_map.GetInlineInfoIndex(); - return GetInlineInfo(index); + if (index != StackMap::kNoValue) { + while (GetInlineInfo(index + depth++).GetIsLast() == InlineInfo::kMore) { } + } + return depth; + } + + InlineInfo GetInlineInfoAtDepth(StackMap stack_map, uint32_t depth) const { + DCHECK(stack_map.HasInlineInfo()); + DCHECK_LT(depth, GetInlineDepthOf(stack_map)); + return GetInlineInfo(stack_map.GetInlineInfoIndex() + depth); } StackMap GetStackMapForDexPc(uint32_t dex_pc) const { @@ -473,7 +476,6 @@ class CodeInfo { stack_map.GetNativePcOffset(kRuntimeISA)) { DCHECK_EQ(other.GetDexRegisterMapIndex(), stack_map.GetDexRegisterMapIndex()); - DCHECK(!stack_map.HasInlineInfo()); if (i < e - 2) { // Make sure there are not three identical stack maps following each other. DCHECK_NE( diff --git a/runtime/vdex_file.cc b/runtime/vdex_file.cc index 838d7f14bc..32aa86dc93 100644 --- a/runtime/vdex_file.cc +++ b/runtime/vdex_file.cc @@ -28,6 +28,7 @@ #include "base/stl_util.h" #include "base/unix_file/fd_file.h" #include "dex/art_dex_file_loader.h" +#include "dex/class_accessor-inl.h" #include "dex/dex_file.h" #include "dex/dex_file_loader.h" #include "dex/hidden_api_access_flags.h" @@ -283,30 +284,25 @@ void VdexFile::UnquickenDexFile(const DexFile& target_dex_file, std::unordered_set<const DexFile::CodeItem*> unquickened_code_item; CompactOffsetTable::Accessor accessor(GetQuickenInfoOffsetTable(source_dex_begin, quickening_info)); - for (uint32_t i = 0; i < target_dex_file.NumClassDefs(); ++i) { - const DexFile::ClassDef& class_def = target_dex_file.GetClassDef(i); - const uint8_t* class_data = target_dex_file.GetClassData(class_def); - if (class_data != nullptr) { - for (ClassDataItemIterator class_it(target_dex_file, class_data); - class_it.HasNext(); - class_it.Next()) { - if (class_it.IsAtMethod()) { - const DexFile::CodeItem* code_item = class_it.GetMethodCodeItem(); - if (code_item != nullptr && unquickened_code_item.emplace(code_item).second) { - const uint32_t offset = accessor.GetOffset(class_it.GetMemberIndex()); - // Offset being 0 means not quickened. - if (offset != 0u) { - ArrayRef<const uint8_t> quicken_data = GetQuickeningInfoAt(quickening_info, offset); - optimizer::ArtDecompileDEX( - target_dex_file, - *code_item, - quicken_data, - decompile_return_instruction); - } - } + for (ClassAccessor class_accessor : target_dex_file.GetClasses()) { + for (const ClassAccessor::Method& method : class_accessor.GetMethods()) { + const DexFile::CodeItem* code_item = method.GetCodeItem(); + if (code_item != nullptr && unquickened_code_item.emplace(code_item).second) { + const uint32_t offset = accessor.GetOffset(method.GetIndex()); + // Offset being 0 means not quickened. + if (offset != 0u) { + ArrayRef<const uint8_t> quicken_data = GetQuickeningInfoAt(quickening_info, offset); + optimizer::ArtDecompileDEX( + target_dex_file, + *code_item, + quicken_data, + decompile_return_instruction); } - DexFile::UnHideAccessFlags(class_it); } + method.UnHideAccessFlags(); + } + for (const ClassAccessor::Field& field : class_accessor.GetFields()) { + field.UnHideAccessFlags(); } } } diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc index f57f757f0b..59617481eb 100644 --- a/runtime/verifier/method_verifier.cc +++ b/runtime/verifier/method_verifier.cc @@ -35,6 +35,7 @@ #include "class_linker.h" #include "class_root.h" #include "compiler_callbacks.h" +#include "dex/class_accessor-inl.h" #include "dex/descriptors_names.h" #include "dex/dex_file-inl.h" #include "dex/dex_file_exception_helpers.h" @@ -190,11 +191,6 @@ FailureKind MethodVerifier::VerifyClass(Thread* self, error); } -template <bool kDirect> -static bool HasNextMethod(ClassDataItemIterator* it) { - return kDirect ? it->HasNextDirectMethod() : it->HasNextVirtualMethod(); -} - static FailureKind FailureKindMax(FailureKind fk1, FailureKind fk2) { static_assert(FailureKind::kNoFailure < FailureKind::kSoftFailure && FailureKind::kSoftFailure < FailureKind::kHardFailure, @@ -207,45 +203,51 @@ void MethodVerifier::FailureData::Merge(const MethodVerifier::FailureData& fd) { types |= fd.types; } -template <bool kDirect> -MethodVerifier::FailureData MethodVerifier::VerifyMethods(Thread* self, - ClassLinker* linker, - const DexFile* dex_file, - const DexFile::ClassDef& class_def, - ClassDataItemIterator* it, - Handle<mirror::DexCache> dex_cache, - Handle<mirror::ClassLoader> class_loader, - CompilerCallbacks* callbacks, - bool allow_soft_failures, - HardFailLogMode log_level, - bool need_precise_constants, - std::string* error_string) { - DCHECK(it != nullptr); +FailureKind MethodVerifier::VerifyClass(Thread* self, + const DexFile* dex_file, + Handle<mirror::DexCache> dex_cache, + Handle<mirror::ClassLoader> class_loader, + const DexFile::ClassDef& class_def, + CompilerCallbacks* callbacks, + bool allow_soft_failures, + HardFailLogMode log_level, + std::string* error) { + SCOPED_TRACE << "VerifyClass " << PrettyDescriptor(dex_file->GetClassDescriptor(class_def)); + // A class must not be abstract and final. + if ((class_def.access_flags_ & (kAccAbstract | kAccFinal)) == (kAccAbstract | kAccFinal)) { + *error = "Verifier rejected class "; + *error += PrettyDescriptor(dex_file->GetClassDescriptor(class_def)); + *error += ": class is abstract and final."; + return FailureKind::kHardFailure; + } + + ClassAccessor accessor(*dex_file, class_def); + + int64_t previous_method_idx[2] = { -1, -1 }; MethodVerifier::FailureData failure_data; + ClassLinker* const linker = Runtime::Current()->GetClassLinker(); - int64_t previous_method_idx = -1; - while (HasNextMethod<kDirect>(it)) { + for (const ClassAccessor::Method& method : accessor.GetMethods()) { + int64_t* previous_idx = &previous_method_idx[method.IsStaticOrDirect() ? 0u : 1u]; self->AllowThreadSuspension(); - uint32_t method_idx = it->GetMemberIndex(); - if (method_idx == previous_method_idx) { + const uint32_t method_idx = method.GetIndex(); + if (method_idx == *previous_idx) { // smali can create dex files with two encoded_methods sharing the same method_idx // http://code.google.com/p/smali/issues/detail?id=119 - it->Next(); continue; } - previous_method_idx = method_idx; - InvokeType type = it->GetMethodInvokeType(class_def); - ArtMethod* method = linker->ResolveMethod<ClassLinker::ResolveMode::kNoChecks>( + *previous_idx = method_idx; + const InvokeType type = method.GetInvokeType(class_def.access_flags_); + ArtMethod* resolved_method = linker->ResolveMethod<ClassLinker::ResolveMode::kNoChecks>( method_idx, dex_cache, class_loader, /* referrer */ nullptr, type); - if (method == nullptr) { + if (resolved_method == nullptr) { DCHECK(self->IsExceptionPending()); // We couldn't resolve the method, but continue regardless. self->ClearException(); } else { - DCHECK(method->GetDeclaringClassUnchecked() != nullptr) << type; + DCHECK(resolved_method->GetDeclaringClassUnchecked() != nullptr) << type; } - StackHandleScope<1> hs(self); std::string hard_failure_msg; MethodVerifier::FailureData result = VerifyMethod(self, method_idx, @@ -253,99 +255,39 @@ MethodVerifier::FailureData MethodVerifier::VerifyMethods(Thread* self, dex_cache, class_loader, class_def, - it->GetMethodCodeItem(), - method, - it->GetMethodAccessFlags(), + method.GetCodeItem(), + resolved_method, + method.GetAccessFlags(), callbacks, allow_soft_failures, log_level, - need_precise_constants, + /*need_precise_constants*/ false, &hard_failure_msg); if (result.kind == FailureKind::kHardFailure) { if (failure_data.kind == FailureKind::kHardFailure) { // If we logged an error before, we need a newline. - *error_string += "\n"; + *error += "\n"; } else { // If we didn't log a hard failure before, print the header of the message. - *error_string += "Verifier rejected class "; - *error_string += PrettyDescriptor(dex_file->GetClassDescriptor(class_def)); - *error_string += ":"; + *error += "Verifier rejected class "; + *error += PrettyDescriptor(dex_file->GetClassDescriptor(class_def)); + *error += ":"; } - *error_string += " "; - *error_string += hard_failure_msg; + *error += " "; + *error += hard_failure_msg; } failure_data.Merge(result); - it->Next(); - } - - return failure_data; -} - -FailureKind MethodVerifier::VerifyClass(Thread* self, - const DexFile* dex_file, - Handle<mirror::DexCache> dex_cache, - Handle<mirror::ClassLoader> class_loader, - const DexFile::ClassDef& class_def, - CompilerCallbacks* callbacks, - bool allow_soft_failures, - HardFailLogMode log_level, - std::string* error) { - SCOPED_TRACE << "VerifyClass " << PrettyDescriptor(dex_file->GetClassDescriptor(class_def)); - - // A class must not be abstract and final. - if ((class_def.access_flags_ & (kAccAbstract | kAccFinal)) == (kAccAbstract | kAccFinal)) { - *error = "Verifier rejected class "; - *error += PrettyDescriptor(dex_file->GetClassDescriptor(class_def)); - *error += ": class is abstract and final."; - return FailureKind::kHardFailure; } - const uint8_t* class_data = dex_file->GetClassData(class_def); - if (class_data == nullptr) { - // empty class, probably a marker interface - return FailureKind::kNoFailure; - } - ClassDataItemIterator it(*dex_file, class_data); - it.SkipAllFields(); - ClassLinker* linker = Runtime::Current()->GetClassLinker(); - // Direct methods. - MethodVerifier::FailureData data1 = VerifyMethods<true>(self, - linker, - dex_file, - class_def, - &it, - dex_cache, - class_loader, - callbacks, - allow_soft_failures, - log_level, - false /* need precise constants */, - error); - // Virtual methods. - MethodVerifier::FailureData data2 = VerifyMethods<false>(self, - linker, - dex_file, - class_def, - &it, - dex_cache, - class_loader, - callbacks, - allow_soft_failures, - log_level, - false /* need precise constants */, - error); - - data1.Merge(data2); - - if (data1.kind == FailureKind::kNoFailure) { + if (failure_data.kind == FailureKind::kNoFailure) { return FailureKind::kNoFailure; } else { - if ((data1.types & VERIFY_ERROR_LOCKING) != 0) { + if ((failure_data.types & VERIFY_ERROR_LOCKING) != 0) { // Print a warning about expected slow-down. Use a string temporary to print one contiguous // warning. std::string tmp = StringPrintf("Class %s failed lock verification and will run slower.", - PrettyDescriptor(dex_file->GetClassDescriptor(class_def)).c_str()); + PrettyDescriptor(accessor.GetDescriptor()).c_str()); if (!gPrintedDxMonitorText) { tmp = tmp + "\nCommon causes for lock verification issues are non-optimized dex code\n" "and incorrect proguard optimizations."; @@ -353,7 +295,7 @@ FailureKind MethodVerifier::VerifyClass(Thread* self, } LOG(WARNING) << tmp; } - return data1.kind; + return failure_data.kind; } } @@ -1924,15 +1866,11 @@ bool MethodVerifier::CodeFlowVerifyMethod() { static uint32_t GetFirstFinalInstanceFieldIndex(const DexFile& dex_file, dex::TypeIndex type_idx) { const DexFile::ClassDef* class_def = dex_file.FindClassDef(type_idx); DCHECK(class_def != nullptr); - const uint8_t* class_data = dex_file.GetClassData(*class_def); - DCHECK(class_data != nullptr); - ClassDataItemIterator it(dex_file, class_data); - it.SkipStaticFields(); - while (it.HasNextInstanceField()) { - if ((it.GetFieldAccessFlags() & kAccFinal) != 0) { - return it.GetMemberIndex(); - } - it.Next(); + ClassAccessor accessor(dex_file, *class_def); + for (const ClassAccessor::Field& field : accessor.GetInstanceFields()) { + if (field.IsFinal()) { + return field.GetIndex(); + } } return dex::kDexNoIndex; } diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h index ae7481c6b1..9890af9d95 100644 --- a/runtime/verifier/method_verifier.h +++ b/runtime/verifier/method_verifier.h @@ -275,23 +275,6 @@ class MethodVerifier { void Merge(const FailureData& src); }; - // Verify all direct or virtual methods of a class. The method assumes that the iterator is - // positioned correctly, and the iterator will be updated. - template <bool kDirect> - static FailureData VerifyMethods(Thread* self, - ClassLinker* linker, - const DexFile* dex_file, - const DexFile::ClassDef& class_def, - ClassDataItemIterator* it, - Handle<mirror::DexCache> dex_cache, - Handle<mirror::ClassLoader> class_loader, - CompilerCallbacks* callbacks, - bool allow_soft_failures, - HardFailLogMode log_level, - bool need_precise_constants, - std::string* error_string) - REQUIRES_SHARED(Locks::mutator_lock_); - /* * Perform verification on a single method. * diff --git a/test/911-get-stack-trace/check b/test/911-get-stack-trace/check deleted file mode 100644 index ee00266b36..0000000000 --- a/test/911-get-stack-trace/check +++ /dev/null @@ -1,31 +0,0 @@ -#!/bin/bash -# -# Copyright (C) 2017 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. - -if [[ "$DX" == 'd8' ]]; then - patch -p0 expected.txt < expected_d8.diff -fi - -./default-check "$@" -if [[ "$?" == "0" ]]; then - exit 0; -fi - -# We cannot always correctly determine if D8 was used because of (b/68406220). -# So we are just going to try to see it matches the expect output of D8 no -# matter what. -patch -p0 expected.txt < expected_d8.diff - -./default-check "$@" diff --git a/test/911-get-stack-trace/expected.txt b/test/911-get-stack-trace/expected.txt index 8177f494ac..b0a400ab75 100644 --- a/test/911-get-stack-trace/expected.txt +++ b/test/911-get-stack-trace/expected.txt @@ -9,19 +9,19 @@ From top baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - doTest ()V 34 25 + doTest ()V 33 25 run ()V 0 25 --------- print (Ljava/lang/Thread;II)V 0 38 @@ -29,19 +29,19 @@ From top baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - doTest ()V 38 26 + doTest ()V 37 26 run ()V 0 25 --------- getStackTrace (Ljava/lang/Thread;II)[[Ljava/lang/String; -1 -2 @@ -54,12 +54,12 @@ From top baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 From bottom --------- run ()V 0 25 --------- - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 doTest ()V 60 32 @@ -67,7 +67,7 @@ From bottom --------- bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 @@ -76,68 +76,76 @@ From bottom ################################ From top --------- - wait ()V -1 -2 + wait (JI)V -1 -2 + wait (J)V 1 442 + wait ()V 2 568 printOrWait (IILart/ControlData;)V 24 47 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 run ()V 4 28 --------- + wait (J)V 1 442 + wait ()V 2 568 printOrWait (IILart/ControlData;)V 24 47 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 run ()V 4 28 --------- - wait ()V -1 -2 + wait (JI)V -1 -2 + wait (J)V 1 442 + wait ()V 2 568 printOrWait (IILart/ControlData;)V 24 47 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 --------- + wait ()V 2 568 + printOrWait (IILart/ControlData;)V 24 47 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 From bottom --------- run ()V 4 28 --------- foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 run ()V 4 28 --------- - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 ########################### @@ -145,20 +153,20 @@ From bottom ########################### From top --------- - printOrWait (IILart/ControlData;)V 44 54 + printOrWait (IILart/ControlData;)V 45 54 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 run ()V 4 61 @@ -166,29 +174,29 @@ From top baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 run ()V 4 61 --------- - printOrWait (IILart/ControlData;)V 44 54 + printOrWait (IILart/ControlData;)V 45 54 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 --------- bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 From bottom @@ -196,15 +204,15 @@ From bottom run ()V 4 61 --------- foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 run ()V 4 61 --------- - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 ################################ @@ -263,7 +271,9 @@ main <not printed> --------- AllTraces Thread 0 - wait ()V -1 -2 + wait (JI)V -1 -2 + wait (J)V 1 442 + wait ()V 2 568 printOrWait (IILart/ControlData;)V 24 47 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 @@ -271,7 +281,9 @@ AllTraces Thread 0 --------- AllTraces Thread 1 - wait ()V -1 -2 + wait (JI)V -1 -2 + wait (J)V 1 442 + wait ()V 2 568 printOrWait (IILart/ControlData;)V 24 47 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 @@ -279,7 +291,9 @@ AllTraces Thread 1 --------- AllTraces Thread 2 - wait ()V -1 -2 + wait (JI)V -1 -2 + wait (J)V 1 442 + wait ()V 2 568 printOrWait (IILart/ControlData;)V 24 47 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 @@ -287,7 +301,9 @@ AllTraces Thread 2 --------- AllTraces Thread 3 - wait ()V -1 -2 + wait (JI)V -1 -2 + wait (J)V 1 442 + wait ()V 2 568 printOrWait (IILart/ControlData;)V 24 47 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 @@ -295,7 +311,9 @@ AllTraces Thread 3 --------- AllTraces Thread 4 - wait ()V -1 -2 + wait (JI)V -1 -2 + wait (J)V 1 442 + wait ()V 2 568 printOrWait (IILart/ControlData;)V 24 47 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 @@ -303,7 +321,9 @@ AllTraces Thread 4 --------- AllTraces Thread 5 - wait ()V -1 -2 + wait (JI)V -1 -2 + wait (J)V 1 442 + wait ()V 2 568 printOrWait (IILart/ControlData;)V 24 47 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 @@ -311,7 +331,9 @@ AllTraces Thread 5 --------- AllTraces Thread 6 - wait ()V -1 -2 + wait (JI)V -1 -2 + wait (J)V 1 442 + wait ()V 2 568 printOrWait (IILart/ControlData;)V 24 47 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 @@ -319,7 +341,9 @@ AllTraces Thread 6 --------- AllTraces Thread 7 - wait ()V -1 -2 + wait (JI)V -1 -2 + wait (J)V 1 442 + wait ()V 2 568 printOrWait (IILart/ControlData;)V 24 47 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 @@ -327,7 +351,9 @@ AllTraces Thread 7 --------- AllTraces Thread 8 - wait ()V -1 -2 + wait (JI)V -1 -2 + wait (J)V 1 442 + wait ()V 2 568 printOrWait (IILart/ControlData;)V 24 47 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 @@ -335,7 +361,9 @@ AllTraces Thread 8 --------- AllTraces Thread 9 - wait ()V -1 -2 + wait (JI)V -1 -2 + wait (J)V 1 442 + wait ()V 2 568 printOrWait (IILart/ControlData;)V 24 47 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 @@ -360,7 +388,7 @@ Signal Catcher Test911 getAllStackTraces (I)[[Ljava/lang/Object; -1 -2 printAll (I)V 0 75 - doTest ()V 122 59 + doTest ()V 120 59 run ()V 24 37 --------- @@ -368,210 +396,230 @@ main <not printed> --------- AllTraces Thread 0 - wait ()V -1 -2 + wait (JI)V -1 -2 + wait (J)V 1 442 + wait ()V 2 568 printOrWait (IILart/ControlData;)V 24 47 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 run ()V 4 47 --------- AllTraces Thread 1 - wait ()V -1 -2 + wait (JI)V -1 -2 + wait (J)V 1 442 + wait ()V 2 568 printOrWait (IILart/ControlData;)V 24 47 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 run ()V 4 47 --------- AllTraces Thread 2 - wait ()V -1 -2 + wait (JI)V -1 -2 + wait (J)V 1 442 + wait ()V 2 568 printOrWait (IILart/ControlData;)V 24 47 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 run ()V 4 47 --------- AllTraces Thread 3 - wait ()V -1 -2 + wait (JI)V -1 -2 + wait (J)V 1 442 + wait ()V 2 568 printOrWait (IILart/ControlData;)V 24 47 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 run ()V 4 47 --------- AllTraces Thread 4 - wait ()V -1 -2 + wait (JI)V -1 -2 + wait (J)V 1 442 + wait ()V 2 568 printOrWait (IILart/ControlData;)V 24 47 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 run ()V 4 47 --------- AllTraces Thread 5 - wait ()V -1 -2 + wait (JI)V -1 -2 + wait (J)V 1 442 + wait ()V 2 568 printOrWait (IILart/ControlData;)V 24 47 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 run ()V 4 47 --------- AllTraces Thread 6 - wait ()V -1 -2 + wait (JI)V -1 -2 + wait (J)V 1 442 + wait ()V 2 568 printOrWait (IILart/ControlData;)V 24 47 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 run ()V 4 47 --------- AllTraces Thread 7 - wait ()V -1 -2 + wait (JI)V -1 -2 + wait (J)V 1 442 + wait ()V 2 568 printOrWait (IILart/ControlData;)V 24 47 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 run ()V 4 47 --------- AllTraces Thread 8 - wait ()V -1 -2 + wait (JI)V -1 -2 + wait (J)V 1 442 + wait ()V 2 568 printOrWait (IILart/ControlData;)V 24 47 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 run ()V 4 47 --------- AllTraces Thread 9 - wait ()V -1 -2 + wait (JI)V -1 -2 + wait (J)V 1 442 + wait ()V 2 568 printOrWait (IILart/ControlData;)V 24 47 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 run ()V 4 47 @@ -595,7 +643,7 @@ Signal Catcher Test911 getAllStackTraces (I)[[Ljava/lang/Object; -1 -2 printAll (I)V 0 75 - doTest ()V 127 61 + doTest ()V 125 61 run ()V 24 37 --------- @@ -627,12 +675,14 @@ ThreadListTraces Thread 8 Test911 getThreadListStackTraces ([Ljava/lang/Thread;I)[[Ljava/lang/Object; -1 -2 printList ([Ljava/lang/Thread;I)V 0 68 - doTest ()V 112 54 + doTest ()V 110 54 run ()V 32 41 --------- ThreadListTraces Thread 0 - wait ()V -1 -2 + wait (JI)V -1 -2 + wait (J)V 1 442 + wait ()V 2 568 printOrWait (IILart/ControlData;)V 24 47 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 @@ -640,7 +690,9 @@ ThreadListTraces Thread 0 --------- ThreadListTraces Thread 2 - wait ()V -1 -2 + wait (JI)V -1 -2 + wait (J)V 1 442 + wait ()V 2 568 printOrWait (IILart/ControlData;)V 24 47 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 @@ -648,7 +700,9 @@ ThreadListTraces Thread 2 --------- ThreadListTraces Thread 4 - wait ()V -1 -2 + wait (JI)V -1 -2 + wait (J)V 1 442 + wait ()V 2 568 printOrWait (IILart/ControlData;)V 24 47 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 @@ -656,7 +710,9 @@ ThreadListTraces Thread 4 --------- ThreadListTraces Thread 6 - wait ()V -1 -2 + wait (JI)V -1 -2 + wait (J)V 1 442 + wait ()V 2 568 printOrWait (IILart/ControlData;)V 24 47 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 @@ -664,7 +720,9 @@ ThreadListTraces Thread 6 --------- ThreadListTraces Thread 8 - wait ()V -1 -2 + wait (JI)V -1 -2 + wait (J)V 1 442 + wait ()V 2 568 printOrWait (IILart/ControlData;)V 24 47 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 @@ -674,110 +732,120 @@ ThreadListTraces Thread 8 Test911 getThreadListStackTraces ([Ljava/lang/Thread;I)[[Ljava/lang/Object; -1 -2 printList ([Ljava/lang/Thread;I)V 0 68 - doTest ()V 117 56 + doTest ()V 115 56 run ()V 32 41 --------- ThreadListTraces Thread 0 - wait ()V -1 -2 + wait (JI)V -1 -2 + wait (J)V 1 442 + wait ()V 2 568 printOrWait (IILart/ControlData;)V 24 47 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 run ()V 4 37 --------- ThreadListTraces Thread 2 - wait ()V -1 -2 + wait (JI)V -1 -2 + wait (J)V 1 442 + wait ()V 2 568 printOrWait (IILart/ControlData;)V 24 47 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 run ()V 4 37 --------- ThreadListTraces Thread 4 - wait ()V -1 -2 + wait (JI)V -1 -2 + wait (J)V 1 442 + wait ()V 2 568 printOrWait (IILart/ControlData;)V 24 47 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 run ()V 4 37 --------- ThreadListTraces Thread 6 - wait ()V -1 -2 + wait (JI)V -1 -2 + wait (J)V 1 442 + wait ()V 2 568 printOrWait (IILart/ControlData;)V 24 47 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 run ()V 4 37 --------- ThreadListTraces Thread 8 - wait ()V -1 -2 + wait (JI)V -1 -2 + wait (J)V 1 442 + wait ()V 2 568 printOrWait (IILart/ControlData;)V 24 47 baz (IIILart/ControlData;)Ljava/lang/Object; 2 32 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 - baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 + baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 bar (IIILart/ControlData;)J 0 26 foo (IIILart/ControlData;)I 0 21 run ()V 4 37 @@ -789,7 +857,7 @@ ThreadListTraces Thread 8 4 JVMTI_ERROR_ILLEGAL_ARGUMENT [public static native java.lang.Object[] art.Frames.getFrameLocation(java.lang.Thread,int), ffffffff] -[public static void art.Frames.doTestSameThread(), 35] +[public static void art.Frames.doTestSameThread(), 40] [public static void art.Frames.doTest() throws java.lang.Exception, 0] [public void art.Test911$1.run(), 28] JVMTI_ERROR_NO_MORE_FRAMES @@ -797,23 +865,25 @@ JVMTI_ERROR_NO_MORE_FRAMES ################################ ### Other thread (suspended) ### ################################ -18 +20 JVMTI_ERROR_ILLEGAL_ARGUMENT -[public final native void java.lang.Object.wait() throws java.lang.InterruptedException, ffffffff] +[public final native void java.lang.Object.wait(long,int) throws java.lang.InterruptedException, ffffffff] +[public final void java.lang.Object.wait(long) throws java.lang.InterruptedException, 1] +[public final void java.lang.Object.wait() throws java.lang.InterruptedException, 2] [private static void art.Recurse.printOrWait(int,int,art.ControlData), 18] [private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 2] [private static long art.Recurse.bar(int,int,int,art.ControlData), 0] [public static int art.Recurse.foo(int,int,int,art.ControlData), 0] -[private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 9] +[private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 8] [private static long art.Recurse.bar(int,int,int,art.ControlData), 0] [public static int art.Recurse.foo(int,int,int,art.ControlData), 0] -[private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 9] +[private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 8] [private static long art.Recurse.bar(int,int,int,art.ControlData), 0] [public static int art.Recurse.foo(int,int,int,art.ControlData), 0] -[private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 9] +[private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 8] [private static long art.Recurse.bar(int,int,int,art.ControlData), 0] [public static int art.Recurse.foo(int,int,int,art.ControlData), 0] -[private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 9] +[private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 8] [private static long art.Recurse.bar(int,int,int,art.ControlData), 0] [public static int art.Recurse.foo(int,int,int,art.ControlData), 0] [public void art.Frames$1.run(), 4] @@ -824,20 +894,20 @@ JVMTI_ERROR_NO_MORE_FRAMES ########################### 17 JVMTI_ERROR_ILLEGAL_ARGUMENT -[private static void art.Recurse.printOrWait(int,int,art.ControlData), 2c] +[private static void art.Recurse.printOrWait(int,int,art.ControlData), 2d] [private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 2] [private static long art.Recurse.bar(int,int,int,art.ControlData), 0] [public static int art.Recurse.foo(int,int,int,art.ControlData), 0] -[private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 9] +[private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 8] [private static long art.Recurse.bar(int,int,int,art.ControlData), 0] [public static int art.Recurse.foo(int,int,int,art.ControlData), 0] -[private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 9] +[private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 8] [private static long art.Recurse.bar(int,int,int,art.ControlData), 0] [public static int art.Recurse.foo(int,int,int,art.ControlData), 0] -[private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 9] +[private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 8] [private static long art.Recurse.bar(int,int,int,art.ControlData), 0] [public static int art.Recurse.foo(int,int,int,art.ControlData), 0] -[private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 9] +[private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 8] [private static long art.Recurse.bar(int,int,int,art.ControlData), 0] [public static int art.Recurse.foo(int,int,int,art.ControlData), 0] [public void art.Frames$2.run(), 4] diff --git a/test/911-get-stack-trace/expected_d8.diff b/test/911-get-stack-trace/expected_d8.diff deleted file mode 100644 index c12015a832..0000000000 --- a/test/911-get-stack-trace/expected_d8.diff +++ /dev/null @@ -1,456 +0,0 @@ -12c12 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -15c15 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -18c18 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -21c21 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -24c24 -< doTest ()V 34 25 ---- -> doTest ()V 33 25 -32c32 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -35c35 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -38c38 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -41c41 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -44c44 -< doTest ()V 38 26 ---- -> doTest ()V 37 26 -57c57 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -62c62 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -70c70 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -84c84 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -87c87 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -90c90 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -93c93 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -102c102 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -105c105 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -108c108 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -111c111 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -125c125 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -132c132 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -137c137 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -140c140 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -148c148 -< printOrWait (IILart/ControlData;)V 44 54 ---- -> printOrWait (IILart/ControlData;)V 45 54 -152c152 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -155c155 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -158c158 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -161c161 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -169c169 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -172c172 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -175c175 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -178c178 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -183c183 -< printOrWait (IILart/ControlData;)V 44 54 ---- -> printOrWait (IILart/ControlData;)V 45 54 -187c187 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -191c191 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -199c199 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -204c204 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -207c207 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -363c363 -< doTest ()V 122 59 ---- -> doTest ()V 120 59 -376c376 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -379c379 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -382c382 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -385c385 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -397c397 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -400c400 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -403c403 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -406c406 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -418c418 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -421c421 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -424c424 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -427c427 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -439c439 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -442c442 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -445c445 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -448c448 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -460c460 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -463c463 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -466c466 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -469c469 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -481c481 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -484c484 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -487c487 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -490c490 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -502c502 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -505c505 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -508c508 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -511c511 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -523c523 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -526c526 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -529c529 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -532c532 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -544c544 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -547c547 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -550c550 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -553c553 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -565c565 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -568c568 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -571c571 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -574c574 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -598c598 -< doTest ()V 127 61 ---- -> doTest ()V 125 61 -630c630 -< doTest ()V 112 54 ---- -> doTest ()V 110 54 -677c677 -< doTest ()V 117 56 ---- -> doTest ()V 115 56 -687c687 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -690c690 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -693c693 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -696c696 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -708c708 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -711c711 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -714c714 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -717c717 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -729c729 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -732c732 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -735c735 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -738c738 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -750c750 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -753c753 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -756c756 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -759c759 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -771c771 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -774c774 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -777c777 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -780c780 -< baz (IIILart/ControlData;)Ljava/lang/Object; 9 34 ---- -> baz (IIILart/ControlData;)Ljava/lang/Object; 8 34 -792c792 -< [public static void art.Frames.doTestSameThread(), 35] ---- -> [public static void art.Frames.doTestSameThread(), 40] -807c807 -< [private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 9] ---- -> [private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 8] -810c810 -< [private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 9] ---- -> [private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 8] -813c813 -< [private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 9] ---- -> [private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 8] -816c816 -< [private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 9] ---- -> [private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 8] -827c827 -< [private static void art.Recurse.printOrWait(int,int,art.ControlData), 2c] ---- -> [private static void art.Recurse.printOrWait(int,int,art.ControlData), 2d] -831c831 -< [private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 9] ---- -> [private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 8] -834c834 -< [private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 9] ---- -> [private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 8] -837c837 -< [private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 9] ---- -> [private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 8] -840c840 -< [private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 9] ---- -> [private static java.lang.Object art.Recurse.baz(int,int,int,art.ControlData), 8] diff --git a/test/911-get-stack-trace/src/art/AllTraces.java b/test/911-get-stack-trace/src/art/AllTraces.java index d73f78bba1..507925c29e 100644 --- a/test/911-get-stack-trace/src/art/AllTraces.java +++ b/test/911-get-stack-trace/src/art/AllTraces.java @@ -56,7 +56,7 @@ public class AllTraces { printAll(0); - printAll(5); + printAll(7); printAll(25); diff --git a/test/911-get-stack-trace/src/art/OtherThread.java b/test/911-get-stack-trace/src/art/OtherThread.java index 675bff55a6..3f5ae59e18 100644 --- a/test/911-get-stack-trace/src/art/OtherThread.java +++ b/test/911-get-stack-trace/src/art/OtherThread.java @@ -36,8 +36,8 @@ public class OtherThread { System.out.println("From top"); PrintThread.print(t, 0, 25); PrintThread.print(t, 1, 25); - PrintThread.print(t, 0, 5); - PrintThread.print(t, 2, 5); + PrintThread.print(t, 0, 7); + PrintThread.print(t, 2, 7); System.out.println("From bottom"); PrintThread.print(t, -1, 25); diff --git a/test/911-get-stack-trace/src/art/ThreadListTraces.java b/test/911-get-stack-trace/src/art/ThreadListTraces.java index 0de93de706..9b27e72f22 100644 --- a/test/911-get-stack-trace/src/art/ThreadListTraces.java +++ b/test/911-get-stack-trace/src/art/ThreadListTraces.java @@ -51,7 +51,7 @@ public class ThreadListTraces { printList(list, 0); - printList(list, 5); + printList(list, 7); printList(list, 25); diff --git a/test/knownfailures.json b/test/knownfailures.json index 493582fa48..ed98d233c3 100644 --- a/test/knownfailures.json +++ b/test/knownfailures.json @@ -362,6 +362,12 @@ }, { "test_patterns": ["616-cha.*"], + "description": ["cha tests rely on knowing the exact set of optimizations available. ", + "Debuggable runtimes change the set of optimizations."], + "variant": "debuggable" + }, + { + "test_patterns": ["616-cha.*"], "description": ["cha tests rely on knowing more about the state of the JIT then is possible with jvmti-stress"], "variant": "jvmti-stress & jit | redefine-stress & jit" }, diff --git a/test/testrunner/target_config.py b/test/testrunner/target_config.py index e0757abbe0..71f4cc0731 100644 --- a/test/testrunner/target_config.py +++ b/test/testrunner/target_config.py @@ -44,7 +44,7 @@ target_config = { 'run-test' : ['--interp-ac'] }, 'art-jit' : { - 'run-test' : ['--jit'] + 'run-test' : ['--jit', '--debuggable', '--ndebuggable'] }, 'art-jit-on-first-use' : { 'run-test' : ['--jit', diff --git a/tools/dexanalyze/dexanalyze.cc b/tools/dexanalyze/dexanalyze.cc index 7d7e5f28b3..7a9b8fb018 100644 --- a/tools/dexanalyze/dexanalyze.cc +++ b/tools/dexanalyze/dexanalyze.cc @@ -116,12 +116,14 @@ class DexAnalyze { } } - bool ProcessDexFile(const DexFile& dex_file) { + bool ProcessDexFiles(const std::vector<std::unique_ptr<const DexFile>>& dex_files) { for (std::unique_ptr<Experiment>& experiment : experiments_) { - experiment->ProcessDexFile(dex_file); + experiment->ProcessDexFiles(dex_files); } - total_size_ += dex_file.Size(); - ++dex_count_; + for (const std::unique_ptr<const DexFile>& dex_file : dex_files) { + total_size_ += dex_file->Size(); + } + dex_count_ += dex_files.size(); return true; } @@ -169,18 +171,16 @@ class DexAnalyze { LOG(ERROR) << "OpenAll failed for " + filename << " with " << error_msg << std::endl; return kExitCodeFailedToOpenDex; } - for (std::unique_ptr<const DexFile>& dex_file : dex_files) { - if (options.dump_per_input_dex_) { - Analysis current(&options); - if (!current.ProcessDexFile(*dex_file)) { - LOG(ERROR) << "Failed to process " << filename << " with error " << error_msg; - return kExitCodeFailedToProcessDex; - } - LOG(INFO) << "Analysis for " << dex_file->GetLocation() << std::endl; - current.Dump(LOG_STREAM(INFO)); + if (options.dump_per_input_dex_) { + Analysis current(&options); + if (!current.ProcessDexFiles(dex_files)) { + LOG(ERROR) << "Failed to process " << filename << " with error " << error_msg; + return kExitCodeFailedToProcessDex; } - cumulative.ProcessDexFile(*dex_file); + LOG(INFO) << "Analysis for " << filename << std::endl; + current.Dump(LOG_STREAM(INFO)); } + cumulative.ProcessDexFiles(dex_files); } LOG(INFO) << "Cumulative analysis for " << cumulative.dex_count_ << " DEX files" << std::endl; cumulative.Dump(LOG_STREAM(INFO)); diff --git a/tools/dexanalyze/dexanalyze_experiments.cc b/tools/dexanalyze/dexanalyze_experiments.cc index 1a3b89cbc7..244f45bbe6 100644 --- a/tools/dexanalyze/dexanalyze_experiments.cc +++ b/tools/dexanalyze/dexanalyze_experiments.cc @@ -75,86 +75,95 @@ static size_t PrefixLen(const std::string& a, const std::string& b) { return len; } -void AnalyzeDebugInfo::ProcessDexFile(const DexFile& dex_file) { +void Experiment::ProcessDexFiles(const std::vector<std::unique_ptr<const DexFile>>& dex_files) { + for (const std::unique_ptr<const DexFile>& dex_file : dex_files) { + ProcessDexFile(*dex_file); + } +} + +void AnalyzeDebugInfo::ProcessDexFiles( + const std::vector<std::unique_ptr<const DexFile>>& dex_files) { std::set<const uint8_t*> seen; std::vector<size_t> counts(256, 0u); std::vector<size_t> opcode_counts(256, 0u); std::set<std::vector<uint8_t>> unique_non_header; - for (ClassAccessor accessor : dex_file.GetClasses()) { - for (const ClassAccessor::Method& method : accessor.GetMethods()) { - CodeItemDebugInfoAccessor code_item(dex_file, method.GetCodeItem(), method.GetIndex()); - const uint8_t* debug_info = dex_file.GetDebugInfoStream(code_item.DebugInfoOffset()); - if (debug_info != nullptr && seen.insert(debug_info).second) { - const uint8_t* stream = debug_info; - DecodeUnsignedLeb128(&stream); // line_start - uint32_t parameters_size = DecodeUnsignedLeb128(&stream); - for (uint32_t i = 0; i < parameters_size; ++i) { - DecodeUnsignedLeb128P1(&stream); // Parameter name. - } - bool done = false; - const uint8_t* after_header_start = stream; - while (!done) { - const uint8_t* const op_start = stream; - uint8_t opcode = *stream++; - ++opcode_counts[opcode]; - ++total_opcode_bytes_; - switch (opcode) { - case DexFile::DBG_END_SEQUENCE: - ++total_end_seq_bytes_; - done = true; - break; - case DexFile::DBG_ADVANCE_PC: - DecodeUnsignedLeb128(&stream); // addr_diff - total_advance_pc_bytes_ += stream - op_start; - break; - case DexFile::DBG_ADVANCE_LINE: - DecodeSignedLeb128(&stream); // line_diff - total_advance_line_bytes_ += stream - op_start; - break; - case DexFile::DBG_START_LOCAL: - DecodeUnsignedLeb128(&stream); // register_num - DecodeUnsignedLeb128P1(&stream); // name_idx - DecodeUnsignedLeb128P1(&stream); // type_idx - total_start_local_bytes_ += stream - op_start; - break; - case DexFile::DBG_START_LOCAL_EXTENDED: - DecodeUnsignedLeb128(&stream); // register_num - DecodeUnsignedLeb128P1(&stream); // name_idx - DecodeUnsignedLeb128P1(&stream); // type_idx - DecodeUnsignedLeb128P1(&stream); // sig_idx - total_start_local_extended_bytes_ += stream - op_start; - break; - case DexFile::DBG_END_LOCAL: - DecodeUnsignedLeb128(&stream); // register_num - total_end_local_bytes_ += stream - op_start; - break; - case DexFile::DBG_RESTART_LOCAL: - DecodeUnsignedLeb128(&stream); // register_num - total_restart_local_bytes_ += stream - op_start; - break; - case DexFile::DBG_SET_PROLOGUE_END: - case DexFile::DBG_SET_EPILOGUE_BEGIN: - total_epilogue_bytes_ += stream - op_start; - break; - case DexFile::DBG_SET_FILE: { - DecodeUnsignedLeb128P1(&stream); // name_idx - total_set_file_bytes_ += stream - op_start; - break; - } - default: { - total_other_bytes_ += stream - op_start; - break; + for (const std::unique_ptr<const DexFile>& dex_file : dex_files) { + for (ClassAccessor accessor : dex_file->GetClasses()) { + for (const ClassAccessor::Method& method : accessor.GetMethods()) { + CodeItemDebugInfoAccessor code_item(*dex_file, method.GetCodeItem(), method.GetIndex()); + const uint8_t* debug_info = dex_file->GetDebugInfoStream(code_item.DebugInfoOffset()); + if (debug_info != nullptr && seen.insert(debug_info).second) { + const uint8_t* stream = debug_info; + DecodeUnsignedLeb128(&stream); // line_start + uint32_t parameters_size = DecodeUnsignedLeb128(&stream); + for (uint32_t i = 0; i < parameters_size; ++i) { + DecodeUnsignedLeb128P1(&stream); // Parameter name. + } + bool done = false; + const uint8_t* after_header_start = stream; + while (!done) { + const uint8_t* const op_start = stream; + uint8_t opcode = *stream++; + ++opcode_counts[opcode]; + ++total_opcode_bytes_; + switch (opcode) { + case DexFile::DBG_END_SEQUENCE: + ++total_end_seq_bytes_; + done = true; + break; + case DexFile::DBG_ADVANCE_PC: + DecodeUnsignedLeb128(&stream); // addr_diff + total_advance_pc_bytes_ += stream - op_start; + break; + case DexFile::DBG_ADVANCE_LINE: + DecodeSignedLeb128(&stream); // line_diff + total_advance_line_bytes_ += stream - op_start; + break; + case DexFile::DBG_START_LOCAL: + DecodeUnsignedLeb128(&stream); // register_num + DecodeUnsignedLeb128P1(&stream); // name_idx + DecodeUnsignedLeb128P1(&stream); // type_idx + total_start_local_bytes_ += stream - op_start; + break; + case DexFile::DBG_START_LOCAL_EXTENDED: + DecodeUnsignedLeb128(&stream); // register_num + DecodeUnsignedLeb128P1(&stream); // name_idx + DecodeUnsignedLeb128P1(&stream); // type_idx + DecodeUnsignedLeb128P1(&stream); // sig_idx + total_start_local_extended_bytes_ += stream - op_start; + break; + case DexFile::DBG_END_LOCAL: + DecodeUnsignedLeb128(&stream); // register_num + total_end_local_bytes_ += stream - op_start; + break; + case DexFile::DBG_RESTART_LOCAL: + DecodeUnsignedLeb128(&stream); // register_num + total_restart_local_bytes_ += stream - op_start; + break; + case DexFile::DBG_SET_PROLOGUE_END: + case DexFile::DBG_SET_EPILOGUE_BEGIN: + total_epilogue_bytes_ += stream - op_start; + break; + case DexFile::DBG_SET_FILE: { + DecodeUnsignedLeb128P1(&stream); // name_idx + total_set_file_bytes_ += stream - op_start; + break; + } + default: { + total_other_bytes_ += stream - op_start; + break; + } } } - } - const size_t bytes = stream - debug_info; - total_bytes_ += bytes; - total_non_header_bytes_ += stream - after_header_start; - if (unique_non_header.insert(std::vector<uint8_t>(after_header_start, stream)).second) { - total_unique_non_header_bytes_ += stream - after_header_start; - } - for (size_t i = 0; i < bytes; ++i) { - ++counts[debug_info[i]]; + const size_t bytes = stream - debug_info; + total_bytes_ += bytes; + total_non_header_bytes_ += stream - after_header_start; + if (unique_non_header.insert(std::vector<uint8_t>(after_header_start, stream)).second) { + total_unique_non_header_bytes_ += stream - after_header_start; + } + for (size_t i = 0; i < bytes; ++i) { + ++counts[debug_info[i]]; + } } } } diff --git a/tools/dexanalyze/dexanalyze_experiments.h b/tools/dexanalyze/dexanalyze_experiments.h index a2621c85ca..2be53d6216 100644 --- a/tools/dexanalyze/dexanalyze_experiments.h +++ b/tools/dexanalyze/dexanalyze_experiments.h @@ -18,7 +18,9 @@ #define ART_TOOLS_DEXANALYZE_DEXANALYZE_EXPERIMENTS_H_ #include <iosfwd> +#include <memory> #include <set> +#include <vector> namespace art { @@ -30,7 +32,8 @@ std::string Percent(uint64_t value, uint64_t max); class Experiment { public: virtual ~Experiment() {} - virtual void ProcessDexFile(const DexFile& dex_file) = 0; + virtual void ProcessDexFiles(const std::vector<std::unique_ptr<const DexFile>>& dex_files); + virtual void ProcessDexFile(const DexFile&) {} virtual void Dump(std::ostream& os, uint64_t total_size) const = 0; }; @@ -54,7 +57,7 @@ class AnalyzeStrings : public Experiment { // Analyze debug info sizes. class AnalyzeDebugInfo : public Experiment { public: - void ProcessDexFile(const DexFile& dex_file); + void ProcessDexFiles(const std::vector<std::unique_ptr<const DexFile>>& dex_files); void Dump(std::ostream& os, uint64_t total_size) const; private: @@ -112,7 +115,7 @@ class CountDexIndices : public Experiment { size_t total_super_ = 0; }; -// Measure various code metrics including args per invoke-virtual, fill/spill move paterns. +// Measure various code metrics including args per invoke-virtual, fill/spill move patterns. class CodeMetrics : public Experiment { public: void ProcessDexFile(const DexFile& dex_file); |