diff options
70 files changed, 1130 insertions, 1026 deletions
diff --git a/compiler/dex/dex_to_dex_compiler.cc b/compiler/dex/dex_to_dex_compiler.cc index 68155d844a..fb6a72b1c5 100644 --- a/compiler/dex/dex_to_dex_compiler.cc +++ b/compiler/dex/dex_to_dex_compiler.cc @@ -635,13 +635,13 @@ void DexToDexCompiler::SetDexFiles(const std::vector<const DexFile*>& dex_files) std::unordered_set<const DexFile::CodeItem*> seen_code_items; for (const DexFile* dex_file : dex_files) { for (ClassAccessor accessor : dex_file->GetClasses()) { - accessor.VisitMethods([&](const ClassAccessor::Method& method) { + for (const ClassAccessor::Method& method : accessor.GetMethods()) { const DexFile::CodeItem* code_item = method.GetCodeItem(); // Detect the shared code items. if (!seen_code_items.insert(code_item).second) { shared_code_items_.insert(code_item); } - }); + } } } VLOG(compiler) << "Shared code items " << shared_code_items_.size(); diff --git a/compiler/dex/dex_to_dex_decompiler_test.cc b/compiler/dex/dex_to_dex_decompiler_test.cc index 082e6091d2..75de238211 100644 --- a/compiler/dex/dex_to_dex_decompiler_test.cc +++ b/compiler/dex/dex_to_dex_decompiler_test.cc @@ -85,10 +85,9 @@ class DexToDexDecompilerTest : public CommonCompilerTest { for (uint32_t i = 0; i < updated_dex_file->NumClassDefs(); ++i) { // Unquicken each method. ClassAccessor accessor(*updated_dex_file, updated_dex_file->GetClassDef(i)); - accessor.VisitMethods([&](const ClassAccessor::Method& method) { + for (const ClassAccessor::Method& method : accessor.GetMethods()) { CompiledMethod* compiled_method = compiler_driver_->GetCompiledMethod( - MethodReference(updated_dex_file, - method.GetIndex())); + method.GetReference()); ArrayRef<const uint8_t> table; if (compiled_method != nullptr) { table = compiled_method->GetVmapTable(); @@ -97,7 +96,7 @@ class DexToDexDecompilerTest : public CommonCompilerTest { *accessor.GetCodeItem(method), table, /* decompile_return_instruction */ true); - }); + } } // Make sure after unquickening we go back to the same contents as the original dex file. diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index decb330f3b..16f2d0f2cc 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -790,8 +790,7 @@ static void ResolveConstStrings(CompilerDriver* driver, // FIXME: Make sure that inlining honors this. b/26687569 continue; } - accessor.VisitMethods([&](const ClassAccessor::Method& method) - REQUIRES_SHARED(Locks::mutator_lock_) { + for (const ClassAccessor::Method& method : accessor.GetMethods()) { // Resolve const-strings in the code. Done to have deterministic allocation behavior. Right // now this is single-threaded for simplicity. // TODO: Collect the relevant string indices in parallel, then allocate them sequentially @@ -812,7 +811,7 @@ static void ResolveConstStrings(CompilerDriver* driver, break; } } - }); + } } } } @@ -880,10 +879,9 @@ static void InitializeTypeCheckBitstrings(CompilerDriver* driver, } // Direct and virtual methods. - accessor.VisitMethods([&](const ClassAccessor::Method& method) - REQUIRES_SHARED(Locks::mutator_lock_) { + for (const ClassAccessor::Method& method : accessor.GetMethods()) { InitializeTypeCheckBitstrings(driver, class_linker, dex_cache, *dex_file, method); - }); + } } } } @@ -1949,9 +1947,9 @@ bool CompilerDriver::FastVerify(jobject jclass_loader, // - We're only going to compile methods that did verify. // - Quickening will not do checkcast ellision. // TODO(ngeoffray): Reconsider this once we refactor compiler filters. - accessor.VisitMethods([&](const ClassAccessor::Method& method) { + for (const ClassAccessor::Method& method : accessor.GetMethods()) { verification_results_->CreateVerifiedMethodFor(method.GetReference()); - }); + } } } else if (!compiler_only_verifies) { // Make sure later compilation stages know they should not try to verify @@ -2747,12 +2745,12 @@ static void CompileDexFile(CompilerDriver* driver, // Compile direct and virtual methods. int64_t previous_method_idx = -1; - accessor.VisitMethods([&](const ClassAccessor::Method& method) { + for (const ClassAccessor::Method& method : accessor.GetMethods()) { const uint32_t method_idx = method.GetIndex(); if (method_idx == previous_method_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 - return; + continue; } previous_method_idx = method_idx; compile_fn(soa.Self(), @@ -2767,7 +2765,7 @@ static void CompileDexFile(CompilerDriver* driver, dex_to_dex_compilation_level, compilation_enabled, dex_cache); - }); + } }; context.ForAllLambda(0, dex_file.NumClassDefs(), compile, thread_count); } diff --git a/compiler/exception_test.cc b/compiler/exception_test.cc index c139fcf1d8..da1db4593b 100644 --- a/compiler/exception_test.cc +++ b/compiler/exception_test.cc @@ -68,47 +68,38 @@ class ExceptionTest : public CommonRuntimeTest { fake_code_.push_back(0x70 | i); } + const uint32_t native_pc_offset = 4u; + CHECK_ALIGNED_PARAM(native_pc_offset, GetInstructionSetInstructionAlignment(kRuntimeISA)); + MallocArenaPool pool; ArenaStack arena_stack(&pool); ScopedArenaAllocator allocator(&arena_stack); StackMapStream stack_maps(&allocator, kRuntimeISA); stack_maps.BeginStackMapEntry(kDexPc, - /* native_pc_offset */ 3u, + native_pc_offset, /* register_mask */ 0u, /* sp_mask */ nullptr, /* num_dex_registers */ 0u, /* inlining_depth */ 0u); stack_maps.EndStackMapEntry(); - size_t stack_maps_size = stack_maps.PrepareForFillIn(); - size_t stack_maps_offset = stack_maps_size + sizeof(OatQuickMethodHeader); + const size_t stack_maps_size = stack_maps.PrepareForFillIn(); + const size_t header_size = sizeof(OatQuickMethodHeader); + const size_t code_alignment = GetInstructionSetAlignment(kRuntimeISA); + const size_t code_offset = RoundUp(stack_maps_size + header_size, code_alignment); - fake_header_code_and_maps_.resize(stack_maps_offset + fake_code_.size()); + fake_header_code_and_maps_.resize(code_offset + fake_code_.size()); MemoryRegion stack_maps_region(&fake_header_code_and_maps_[0], stack_maps_size); stack_maps.FillInCodeInfo(stack_maps_region); - OatQuickMethodHeader method_header(stack_maps_offset, 0u, 4 * sizeof(void*), 0u, 0u, code_size); - memcpy(&fake_header_code_and_maps_[stack_maps_size], &method_header, sizeof(method_header)); + OatQuickMethodHeader method_header(code_offset, 0u, 4 * sizeof(void*), 0u, 0u, code_size); + memcpy(&fake_header_code_and_maps_[code_offset - header_size], &method_header, header_size); std::copy(fake_code_.begin(), fake_code_.end(), - fake_header_code_and_maps_.begin() + stack_maps_offset); - - // Align the code. - const size_t alignment = GetInstructionSetAlignment(kRuntimeISA); - fake_header_code_and_maps_.reserve(fake_header_code_and_maps_.size() + alignment); - const void* unaligned_code_ptr = - fake_header_code_and_maps_.data() + (fake_header_code_and_maps_.size() - code_size); - size_t offset = dchecked_integral_cast<size_t>(reinterpret_cast<uintptr_t>(unaligned_code_ptr)); - size_t padding = RoundUp(offset, alignment) - offset; - // Make sure no resizing takes place. - CHECK_GE(fake_header_code_and_maps_.capacity(), fake_header_code_and_maps_.size() + padding); - fake_header_code_and_maps_.insert(fake_header_code_and_maps_.begin(), padding, 0); - const void* code_ptr = reinterpret_cast<const uint8_t*>(unaligned_code_ptr) + padding; - CHECK_EQ(code_ptr, - static_cast<const void*>(fake_header_code_and_maps_.data() + - (fake_header_code_and_maps_.size() - code_size))); + fake_header_code_and_maps_.begin() + code_offset); + const void* code_ptr = fake_header_code_and_maps_.data() + code_offset; if (kRuntimeISA == InstructionSet::kArm) { // Check that the Thumb2 adjustment will be a NOP, see EntryPointToCodePointer(). - CHECK_ALIGNED(stack_maps_offset, 2); + CHECK_ALIGNED(code_ptr, 2); } method_f_ = my_klass_->FindClassMethod("f", "()I", kRuntimePointerSize); diff --git a/compiler/optimizing/intrinsics_arm_vixl.cc b/compiler/optimizing/intrinsics_arm_vixl.cc index 5287b4b2fa..fecf1ccbfa 100644 --- a/compiler/optimizing/intrinsics_arm_vixl.cc +++ b/compiler/optimizing/intrinsics_arm_vixl.cc @@ -25,7 +25,7 @@ #include "mirror/array-inl.h" #include "mirror/object_array-inl.h" #include "mirror/reference.h" -#include "mirror/string.h" +#include "mirror/string-inl.h" #include "scoped_thread_state_change-inl.h" #include "thread-current-inl.h" diff --git a/compiler/optimizing/stack_map_stream.cc b/compiler/optimizing/stack_map_stream.cc index c6e375a1b2..b40ea3768a 100644 --- a/compiler/optimizing/stack_map_stream.cc +++ b/compiler/optimizing/stack_map_stream.cc @@ -48,10 +48,6 @@ void StackMapStream::BeginStackMapEntry(uint32_t dex_pc, ArenaBitVector::Create(allocator_, num_dex_registers, true, kArenaAllocStackMapStream); current_entry_.dex_register_entry.live_dex_registers_mask->ClearAllBits(); } - if (sp_mask != nullptr) { - stack_mask_max_ = std::max(stack_mask_max_, sp_mask->GetHighestBitSet()); - } - current_dex_register_ = 0; } @@ -217,11 +213,32 @@ size_t StackMapStream::PrepareForFillIn() { PrepareMethodIndices(); // Dedup stack masks. Needs to be done first as it modifies the stack map entry. - size_t stack_mask_bits = stack_mask_max_ + 1; // Need room for max element too. - size_t num_stack_masks = PrepareStackMasks(stack_mask_bits); + BitmapTableBuilder stack_mask_builder(allocator_); + for (StackMapEntry& stack_map : stack_maps_) { + BitVector* mask = stack_map.sp_mask; + size_t num_bits = (mask != nullptr) ? mask->GetNumberOfBits() : 0; + if (num_bits != 0) { + stack_map.stack_mask_index = stack_mask_builder.Dedup(mask->GetRawStorage(), num_bits); + } else { + stack_map.stack_mask_index = StackMap::kNoValue; + } + } // Dedup register masks. Needs to be done first as it modifies the stack map entry. - size_t num_register_masks = PrepareRegisterMasks(); + BitTableBuilder<std::array<uint32_t, RegisterMask::kCount>> register_mask_builder(allocator_); + for (StackMapEntry& stack_map : stack_maps_) { + uint32_t register_mask = stack_map.register_mask; + if (register_mask != 0) { + uint32_t shift = LeastSignificantBit(register_mask); + std::array<uint32_t, RegisterMask::kCount> entry = { + register_mask >> shift, + shift, + }; + stack_map.register_mask_index = register_mask_builder.Dedup(&entry); + } else { + stack_map.register_mask_index = StackMap::kNoValue; + } + } // Write dex register maps. MemoryRegion dex_register_map_region = @@ -301,31 +318,8 @@ size_t StackMapStream::PrepareForFillIn() { stack_map_builder.Encode(&out_, &bit_offset); invoke_info_builder.Encode(&out_, &bit_offset); inline_info_builder.Encode(&out_, &bit_offset); - - // Write register masks table. - BitTableBuilder<uint32_t> register_mask_builder(allocator_); - for (size_t i = 0; i < num_register_masks; ++i) { - register_mask_builder.Add(register_masks_[i]); - } register_mask_builder.Encode(&out_, &bit_offset); - - // Write stack masks table. - EncodeVarintBits(&out_, &bit_offset, stack_mask_bits); - out_.resize(BitsToBytesRoundUp(bit_offset + stack_mask_bits * num_stack_masks)); - BitMemoryRegion stack_mask_region(MemoryRegion(out_.data(), out_.size()), - bit_offset, - stack_mask_bits * num_stack_masks); - if (stack_mask_bits > 0) { - for (size_t i = 0; i < num_stack_masks; ++i) { - size_t stack_mask_bytes = BitsToBytesRoundUp(stack_mask_bits); - BitMemoryRegion src(MemoryRegion(&stack_masks_[i * stack_mask_bytes], stack_mask_bytes)); - BitMemoryRegion dst = stack_mask_region.Subregion(i * stack_mask_bits, stack_mask_bits); - for (size_t bit_index = 0; bit_index < stack_mask_bits; bit_index += BitSizeOf<uint32_t>()) { - size_t num_bits = std::min<size_t>(stack_mask_bits - bit_index, BitSizeOf<uint32_t>()); - dst.StoreBits(bit_index, src.LoadBits(bit_index, num_bits), num_bits); - } - } - } + stack_mask_builder.Encode(&out_, &bit_offset); return UnsignedLeb128Size(out_.size()) + out_.size(); } @@ -448,17 +442,6 @@ void StackMapStream::CheckDexRegisterMap(const CodeInfo& code_info, } } -size_t StackMapStream::PrepareRegisterMasks() { - register_masks_.resize(stack_maps_.size(), 0u); - ScopedArenaUnorderedMap<uint32_t, size_t> dedupe(allocator_->Adapter(kArenaAllocStackMapStream)); - for (StackMapEntry& stack_map : stack_maps_) { - const size_t index = dedupe.size(); - stack_map.register_mask_index = dedupe.emplace(stack_map.register_mask, index).first->second; - register_masks_[index] = stack_map.register_mask; - } - return dedupe.size(); -} - void StackMapStream::PrepareMethodIndices() { CHECK(method_indices_.empty()); method_indices_.resize(stack_maps_.size() + inline_infos_.size()); @@ -481,35 +464,10 @@ void StackMapStream::PrepareMethodIndices() { method_indices_.resize(dedupe.size()); } - -size_t StackMapStream::PrepareStackMasks(size_t entry_size_in_bits) { - // Preallocate memory since we do not want it to move (the dedup map will point into it). - const size_t byte_entry_size = RoundUp(entry_size_in_bits, kBitsPerByte) / kBitsPerByte; - stack_masks_.resize(byte_entry_size * stack_maps_.size(), 0u); - // For deduplicating we store the stack masks as byte packed for simplicity. We can bit pack later - // when copying out from stack_masks_. - ScopedArenaUnorderedMap<MemoryRegion, - size_t, - FNVHash<MemoryRegion>, - MemoryRegion::ContentEquals> dedup( - stack_maps_.size(), allocator_->Adapter(kArenaAllocStackMapStream)); - for (StackMapEntry& stack_map : stack_maps_) { - size_t index = dedup.size(); - MemoryRegion stack_mask(stack_masks_.data() + index * byte_entry_size, byte_entry_size); - BitMemoryRegion stack_mask_bits(stack_mask); - for (size_t i = 0; i < entry_size_in_bits; i++) { - stack_mask_bits.StoreBit(i, stack_map.sp_mask != nullptr && stack_map.sp_mask->IsBitSet(i)); - } - stack_map.stack_mask_index = dedup.emplace(stack_mask, index).first->second; - } - return dedup.size(); -} - // Check that all StackMapStream inputs are correctly encoded by trying to read them back. void StackMapStream::CheckCodeInfo(MemoryRegion region) const { CodeInfo code_info(region); DCHECK_EQ(code_info.GetNumberOfStackMaps(), stack_maps_.size()); - DCHECK_EQ(code_info.GetNumberOfStackMaskBits(), static_cast<uint32_t>(stack_mask_max_ + 1)); DCHECK_EQ(code_info.GetNumberOfLocationCatalogEntries(), location_catalog_entries_.size()); size_t invoke_info_index = 0; for (size_t s = 0; s < stack_maps_.size(); ++s) { @@ -522,18 +480,15 @@ void StackMapStream::CheckCodeInfo(MemoryRegion region) const { DCHECK_EQ(stack_map.GetDexPc(), entry.dex_pc); DCHECK_EQ(stack_map.GetRegisterMaskIndex(), entry.register_mask_index); DCHECK_EQ(code_info.GetRegisterMaskOf(stack_map), entry.register_mask); - const size_t num_stack_mask_bits = code_info.GetNumberOfStackMaskBits(); DCHECK_EQ(stack_map.GetStackMaskIndex(), entry.stack_mask_index); BitMemoryRegion stack_mask = code_info.GetStackMaskOf(stack_map); if (entry.sp_mask != nullptr) { DCHECK_GE(stack_mask.size_in_bits(), entry.sp_mask->GetNumberOfBits()); - for (size_t b = 0; b < num_stack_mask_bits; b++) { - DCHECK_EQ(stack_mask.LoadBit(b), entry.sp_mask->IsBitSet(b)); + for (size_t b = 0; b < stack_mask.size_in_bits(); b++) { + DCHECK_EQ(stack_mask.LoadBit(b), entry.sp_mask->IsBitSet(b)) << b; } } else { - for (size_t b = 0; b < num_stack_mask_bits; b++) { - DCHECK_EQ(stack_mask.LoadBit(b), 0u); - } + DCHECK_EQ(stack_mask.size_in_bits(), 0u); } if (entry.dex_method_index != dex::kDexNoIndex) { InvokeInfo invoke_info = code_info.GetInvokeInfo(invoke_info_index); diff --git a/compiler/optimizing/stack_map_stream.h b/compiler/optimizing/stack_map_stream.h index ea97cf6530..19863d882a 100644 --- a/compiler/optimizing/stack_map_stream.h +++ b/compiler/optimizing/stack_map_stream.h @@ -68,11 +68,8 @@ class StackMapStream : public ValueObject { location_catalog_entries_indices_(allocator->Adapter(kArenaAllocStackMapStream)), dex_register_locations_(allocator->Adapter(kArenaAllocStackMapStream)), inline_infos_(allocator->Adapter(kArenaAllocStackMapStream)), - stack_masks_(allocator->Adapter(kArenaAllocStackMapStream)), - register_masks_(allocator->Adapter(kArenaAllocStackMapStream)), method_indices_(allocator->Adapter(kArenaAllocStackMapStream)), dex_register_entries_(allocator->Adapter(kArenaAllocStackMapStream)), - stack_mask_max_(-1), out_(allocator->Adapter(kArenaAllocStackMapStream)), dex_map_hash_to_stack_map_indices_(std::less<uint32_t>(), allocator->Adapter(kArenaAllocStackMapStream)), @@ -171,12 +168,6 @@ class StackMapStream : public ValueObject { private: size_t ComputeDexRegisterLocationCatalogSize() const; - // Returns the number of unique stack masks. - size_t PrepareStackMasks(size_t entry_size_in_bits); - - // Returns the number of unique register masks. - size_t PrepareRegisterMasks(); - // Prepare and deduplicate method indices. void PrepareMethodIndices(); @@ -217,11 +208,8 @@ class StackMapStream : public ValueObject { // A set of concatenated maps of Dex register locations indices to `location_catalog_entries_`. ScopedArenaVector<size_t> dex_register_locations_; ScopedArenaVector<InlineInfoEntry> inline_infos_; - ScopedArenaVector<uint8_t> stack_masks_; - ScopedArenaVector<uint32_t> register_masks_; ScopedArenaVector<uint32_t> method_indices_; ScopedArenaVector<DexRegisterMapEntry> dex_register_entries_; - int stack_mask_max_; ScopedArenaVector<uint8_t> out_; diff --git a/compiler/optimizing/stack_map_test.cc b/compiler/optimizing/stack_map_test.cc index 9db7588b3a..c372bb9b22 100644 --- a/compiler/optimizing/stack_map_test.cc +++ b/compiler/optimizing/stack_map_test.cc @@ -32,10 +32,10 @@ static bool CheckStackMask( const StackMap& stack_map, const BitVector& bit_vector) { BitMemoryRegion stack_mask = code_info.GetStackMaskOf(stack_map); - if (bit_vector.GetNumberOfBits() > code_info.GetNumberOfStackMaskBits()) { + if (bit_vector.GetNumberOfBits() > stack_mask.size_in_bits()) { return false; } - for (size_t i = 0; i < code_info.GetNumberOfStackMaskBits(); ++i) { + for (size_t i = 0; i < stack_mask.size_in_bits(); ++i) { if (stack_mask.LoadBit(i) != bit_vector.IsBitSet(i)) { return false; } diff --git a/compiler/verifier_deps_test.cc b/compiler/verifier_deps_test.cc index 103862beff..c0892ff466 100644 --- a/compiler/verifier_deps_test.cc +++ b/compiler/verifier_deps_test.cc @@ -155,8 +155,7 @@ class VerifierDepsTest : public CommonCompilerTest { bool has_failures = true; bool found_method = false; - accessor.VisitMethods([&](const ClassAccessor::Method& method) - REQUIRES_SHARED(Locks::mutator_lock_) { + for (const ClassAccessor::Method& method : accessor.GetMethods()) { ArtMethod* resolved_method = class_linker_->ResolveMethod<ClassLinker::ResolveMode::kNoChecks>( method.GetIndex(), @@ -186,7 +185,7 @@ class VerifierDepsTest : public CommonCompilerTest { has_failures = verifier.HasFailures(); found_method = true; } - }); + } CHECK(found_method) << "Expected to find method " << method_name; return !has_failures; } diff --git a/libdexfile/Android.bp b/libdexfile/Android.bp index 3818624d7a..06fd19e2fe 100644 --- a/libdexfile/Android.bp +++ b/libdexfile/Android.bp @@ -112,6 +112,7 @@ art_cc_test { ], srcs: [ "dex/art_dex_file_loader_test.cc", + "dex/class_accessor_test.cc", "dex/code_item_accessors_test.cc", "dex/compact_dex_file_test.cc", "dex/compact_offset_table_test.cc", diff --git a/libdexfile/dex/class_accessor-inl.h b/libdexfile/dex/class_accessor-inl.h index a082142366..49ca98d47f 100644 --- a/libdexfile/dex/class_accessor-inl.h +++ b/libdexfile/dex/class_accessor-inl.h @@ -50,6 +50,19 @@ inline const uint8_t* ClassAccessor::Field::Read(const uint8_t* ptr) { return ptr; } +template <typename DataType, typename Visitor> +inline const uint8_t* ClassAccessor::VisitMembers(size_t count, + const Visitor& visitor, + const uint8_t* ptr, + DataType* data) const { + DCHECK(data != nullptr); + for ( ; count != 0; --count) { + ptr = data->Read(ptr); + visitor(*data); + } + return ptr; +} + template <typename StaticFieldVisitor, typename InstanceFieldVisitor, typename DirectMethodVisitor, @@ -59,35 +72,15 @@ inline void ClassAccessor::VisitFieldsAndMethods( const InstanceFieldVisitor& instance_field_visitor, const DirectMethodVisitor& direct_method_visitor, const VirtualMethodVisitor& virtual_method_visitor) const { - const uint8_t* ptr = ptr_pos_; - { - Field data; - for (size_t i = 0; i < num_static_fields_; ++i) { - ptr = data.Read(ptr); - static_field_visitor(data); - } - } - { - Field data; - for (size_t i = 0; i < num_instance_fields_; ++i) { - ptr = data.Read(ptr); - instance_field_visitor(data); - } - } - { - Method data(dex_file_, /*is_static_or_direct*/ true); - for (size_t i = 0; i < num_direct_methods_; ++i) { - ptr = data.Read(ptr); - direct_method_visitor(data); - } - } - { - Method data(dex_file_, /*is_static_or_direct*/ false); - for (size_t i = 0; i < num_virtual_methods_; ++i) { - ptr = data.Read(ptr); - virtual_method_visitor(data); - } - } + Field field(dex_file_); + const uint8_t* ptr = VisitMembers(num_static_fields_, static_field_visitor, ptr_pos_, &field); + field.NextSection(); + ptr = VisitMembers(num_instance_fields_, instance_field_visitor, ptr, &field); + + Method method(dex_file_, /*is_static_or_direct*/ true); + ptr = VisitMembers(num_direct_methods_, direct_method_visitor, ptr, &method); + method.NextSection(); + ptr = VisitMembers(num_virtual_methods_, virtual_method_visitor, ptr, &method); } template <typename DirectMethodVisitor, @@ -110,12 +103,6 @@ inline void ClassAccessor::VisitFields(const StaticFieldVisitor& static_field_vi VoidFunctor()); } -// Visit direct and virtual methods. -template <typename MethodVisitor> -inline void ClassAccessor::VisitMethods(const MethodVisitor& method_visitor) const { - VisitMethods(method_visitor, method_visitor); -} - inline const DexFile::CodeItem* ClassAccessor::GetCodeItem(const Method& method) const { return dex_file_.GetCodeItem(method.GetCodeItemOffset()); } @@ -132,6 +119,25 @@ inline const DexFile::CodeItem* ClassAccessor::Method::GetCodeItem() const { return dex_file_.GetCodeItem(code_off_); } +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_) }; +} + +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) }; +} + } // namespace art #endif // ART_LIBDEXFILE_DEX_CLASS_ACCESSOR_INL_H_ diff --git a/libdexfile/dex/class_accessor.h b/libdexfile/dex/class_accessor.h index 72bc50b98c..dda6e1c1a6 100644 --- a/libdexfile/dex/class_accessor.h +++ b/libdexfile/dex/class_accessor.h @@ -45,7 +45,7 @@ class ClassAccessor { return (GetAccessFlags() & kAccFinal) != 0; } - public: + protected: uint32_t index_ = 0u; uint32_t access_flags_ = 0u; }; @@ -72,8 +72,13 @@ class ClassAccessor { const DexFile::CodeItem* GetCodeItem() const; + bool IsStaticOrDirect() const { + return is_static_or_direct_; + } + private: - explicit Method(const DexFile& dex_file, bool is_static_or_direct) + explicit Method(const DexFile& dex_file, + bool is_static_or_direct = true) : dex_file_(dex_file), is_static_or_direct_(is_static_or_direct) {} @@ -94,8 +99,14 @@ class ClassAccessor { } } + void NextSection() { + DCHECK(is_static_or_direct_) << "Already in the virtual methods section"; + is_static_or_direct_ = false; + index_ = 0u; + } + const DexFile& dex_file_; - const bool is_static_or_direct_; + bool is_static_or_direct_ = true; uint32_t code_off_ = 0u; friend class ClassAccessor; @@ -103,12 +114,113 @@ 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) {} + + const DexFile& GetDexFile() const { + return dex_file_; + } + private: const uint8_t* Read(const uint8_t* ptr); + void NextSection() { + index_ = 0u; + } + + const DexFile& dex_file_; friend class ClassAccessor; }; + template <typename DataType> + class DataIterator : public std::iterator<std::forward_iterator_tag, DataType> { + public: + using value_type = typename std::iterator<std::forward_iterator_tag, DataType>::value_type; + using difference_type = + typename std::iterator<std::forward_iterator_tag, value_type>::difference_type; + + DataIterator(const DexFile& dex_file, + uint32_t position, + uint32_t partition_pos, + uint32_t iterator_end, + const uint8_t* ptr_pos) + : data_(dex_file), + position_(position), + partition_pos_(partition_pos), + iterator_end_(iterator_end), + ptr_pos_(ptr_pos) { + ReadData(); + } + + bool IsValid() const { + return position_ < iterator_end_; + } + + // Value after modification. + DataIterator& operator++() { + ++position_; + ReadData(); + return *this; + } + + const value_type& operator*() const { + return data_; + } + + const value_type* operator->() const { + return &data_; + } + + bool operator==(const DataIterator& rhs) const { + DCHECK_EQ(&data_.dex_file_, &rhs.data_.dex_file_) << "Comparing different dex files."; + return position_ == rhs.position_; + } + + bool operator!=(const DataIterator& rhs) const { + return !(*this == rhs); + } + + bool operator<(const DataIterator& rhs) const { + DCHECK_EQ(&data_.dex_file_, &rhs.data_.dex_file_) << "Comparing different dex files."; + return position_ < rhs.position_; + } + + bool operator>(const DataIterator& rhs) const { + return rhs < *this; + } + + bool operator<=(const DataIterator& rhs) const { + return !(rhs < *this); + } + + bool operator>=(const DataIterator& rhs) const { + return !(*this < rhs); + } + + private: + // Read data at current position. + void ReadData() { + if (IsValid()) { + // At the end of the first section, go to the next section. + if (position_ == partition_pos_) { + data_.NextSection(); + } + DCHECK(ptr_pos_ != nullptr); + ptr_pos_ = data_.Read(ptr_pos_); + } + } + + DataType data_; + // Iterator position. + uint32_t position_; + // At partition_pos_, we go to the next section. + 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. ALWAYS_INLINE ClassAccessor(const ClassIteratorData& data); @@ -118,7 +230,6 @@ class ClassAccessor { const DexFile::CodeItem* GetCodeItem(const Method& method) const; // Iterator data is not very iterator friendly, use visitors to get around this. - // No thread safety analysis since the visitor may require capabilities. template <typename StaticFieldVisitor, typename InstanceFieldVisitor, typename DirectMethodVisitor, @@ -126,8 +237,7 @@ class ClassAccessor { void VisitFieldsAndMethods(const StaticFieldVisitor& static_field_visitor, const InstanceFieldVisitor& instance_field_visitor, const DirectMethodVisitor& direct_method_visitor, - const VirtualMethodVisitor& virtual_method_visitor) const - NO_THREAD_SAFETY_ANALYSIS; + const VirtualMethodVisitor& virtual_method_visitor) const; template <typename DirectMethodVisitor, typename VirtualMethodVisitor> @@ -139,9 +249,11 @@ class ClassAccessor { void VisitFields(const StaticFieldVisitor& static_field_visitor, const InstanceFieldVisitor& instance_field_visitor) const; - // Visit direct and virtual methods. - template <typename MethodVisitor> - void VisitMethods(const MethodVisitor& method_visitor) const; + // Return the iteration range for all the fields. + IterationRange<DataIterator<Field>> GetFields() const; + + // Return the iteration range for all the methods. + IterationRange<DataIterator<Method>> GetMethods() const; uint32_t NumStaticFields() const { return num_static_fields_; @@ -159,6 +271,10 @@ class ClassAccessor { return num_virtual_methods_; } + uint32_t NumMethods() const { + return NumDirectMethods() + NumVirtualMethods(); + } + const char* GetDescriptor() const; dex::TypeIndex GetClassIdx() const { @@ -170,6 +286,14 @@ class ClassAccessor { } 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; + const DexFile& dex_file_; const dex::TypeIndex descriptor_index_ = {}; const uint8_t* ptr_pos_ = nullptr; // Pointer into stream of class_data_item. diff --git a/libdexfile/dex/class_accessor_test.cc b/libdexfile/dex/class_accessor_test.cc new file mode 100644 index 0000000000..95380d8140 --- /dev/null +++ b/libdexfile/dex/class_accessor_test.cc @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "dex/class_accessor-inl.h" + +#include "base/common_art_test.h" + +namespace art { + +class ClassAccessorTest : public CommonArtTest {}; + +TEST_F(ClassAccessorTest, TestVisiting) { + std::vector<std::unique_ptr<const DexFile>> dex_files( + OpenDexFiles(GetLibCoreDexFileNames()[0].c_str())); + ASSERT_GT(dex_files.size(), 0u); + for (const std::unique_ptr<const DexFile>& dex_file : dex_files) { + uint32_t class_def_idx = 0u; + ASSERT_GT(dex_file->NumClassDefs(), 0u); + for (ClassAccessor accessor : dex_file->GetClasses()) { + const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_idx); + EXPECT_EQ(accessor.GetDescriptor(), dex_file->StringByTypeIdx(class_def.class_idx_)); + ++class_def_idx; + // Check iterators against visitors. + auto methods = accessor.GetMethods(); + auto fields = accessor.GetFields(); + auto method_it = methods.begin(); + auto field_it = fields.begin(); + accessor.VisitFieldsAndMethods( + // Static fields. + [&](const ClassAccessor::Field& field) { + EXPECT_EQ(field.GetIndex(), field_it->GetIndex()); + EXPECT_EQ(field.GetAccessFlags(), field_it->GetAccessFlags()); + ++field_it; + }, + // Instance fields. + [&](const ClassAccessor::Field& field) { + EXPECT_EQ(field.GetIndex(), field_it->GetIndex()); + EXPECT_EQ(field.GetAccessFlags(), field_it->GetAccessFlags()); + ++field_it; + }, + // Direct methods. + [&](const ClassAccessor::Method& method) { + EXPECT_TRUE(method.IsStaticOrDirect()); + EXPECT_EQ(method.IsStaticOrDirect(), method_it->IsStaticOrDirect()); + EXPECT_EQ(method.GetIndex(), method_it->GetIndex()); + EXPECT_EQ(method.GetAccessFlags(), method_it->GetAccessFlags()); + EXPECT_EQ(method.GetCodeItem(), method_it->GetCodeItem()); + ++method_it; + }, + // Virtual methods. + [&](const ClassAccessor::Method& method) { + EXPECT_FALSE(method.IsStaticOrDirect()); + EXPECT_EQ(method.IsStaticOrDirect(), method_it->IsStaticOrDirect()); + EXPECT_EQ(method.GetIndex(), method_it->GetIndex()); + EXPECT_EQ(method.GetAccessFlags(), method_it->GetAccessFlags()); + EXPECT_EQ(method.GetCodeItem(), method_it->GetCodeItem()); + ++method_it; + }); + ASSERT_TRUE(field_it == fields.end()); + ASSERT_TRUE(method_it == methods.end()); + } + EXPECT_EQ(class_def_idx, dex_file->NumClassDefs()); + } +} + +} // namespace art diff --git a/libprofile/profile/profile_compilation_info_test.cc b/libprofile/profile/profile_compilation_info_test.cc index ead7cba60b..42c3320ea5 100644 --- a/libprofile/profile/profile_compilation_info_test.cc +++ b/libprofile/profile/profile_compilation_info_test.cc @@ -17,20 +17,14 @@ #include <gtest/gtest.h> #include <stdio.h> -#include "art_method-inl.h" +#include "base/arena_allocator.h" +#include "base/common_art_test.h" #include "base/unix_file/fd_file.h" -#include "class_linker-inl.h" -#include "common_runtime_test.h" #include "dex/dex_file.h" #include "dex/dex_file_loader.h" #include "dex/method_reference.h" #include "dex/type_reference.h" -#include "handle_scope-inl.h" -#include "linear_alloc.h" -#include "mirror/class-inl.h" -#include "mirror/class_loader.h" #include "profile/profile_compilation_info.h" -#include "scoped_thread_state_change-inl.h" #include "ziparchive/zip_writer.h" namespace art { @@ -39,31 +33,14 @@ using Hotness = ProfileCompilationInfo::MethodHotness; static constexpr size_t kMaxMethodIds = 65535; -class ProfileCompilationInfoTest : public CommonRuntimeTest { +class ProfileCompilationInfoTest : public CommonArtTest { public: - void PostRuntimeCreate() OVERRIDE { - allocator_.reset(new ArenaAllocator(Runtime::Current()->GetArenaPool())); + void SetUp() OVERRIDE { + CommonArtTest::SetUp(); + allocator_.reset(new ArenaAllocator(&pool_)); } protected: - std::vector<ArtMethod*> GetVirtualMethods(jobject class_loader, - const std::string& clazz) { - ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); - Thread* self = Thread::Current(); - ScopedObjectAccess soa(self); - StackHandleScope<1> hs(self); - Handle<mirror::ClassLoader> h_loader( - hs.NewHandle(self->DecodeJObject(class_loader)->AsClassLoader())); - ObjPtr<mirror::Class> klass = class_linker->FindClass(self, clazz.c_str(), h_loader); - - const auto pointer_size = class_linker->GetImagePointerSize(); - std::vector<ArtMethod*> methods; - for (auto& m : klass->GetVirtualMethods(pointer_size)) { - methods.push_back(&m); - } - return methods; - } - bool AddMethod(const std::string& dex_location, uint32_t checksum, uint16_t method_index, @@ -97,89 +74,6 @@ class ProfileCompilationInfoTest : public CommonRuntimeTest { return static_cast<uint32_t>(file.GetFd()); } - bool SaveProfilingInfo( - const std::string& filename, - const std::vector<ArtMethod*>& methods, - const std::set<DexCacheResolvedClasses>& resolved_classes, - Hotness::Flag flags) { - ProfileCompilationInfo info; - std::vector<ProfileMethodInfo> profile_methods; - ScopedObjectAccess soa(Thread::Current()); - for (ArtMethod* method : methods) { - profile_methods.emplace_back( - MethodReference(method->GetDexFile(), method->GetDexMethodIndex())); - } - if (!info.AddMethods(profile_methods, flags) || !info.AddClasses(resolved_classes)) { - return false; - } - if (info.GetNumberOfMethods() != profile_methods.size()) { - return false; - } - ProfileCompilationInfo file_profile; - if (!file_profile.Load(filename, false)) { - return false; - } - if (!info.MergeWith(file_profile)) { - return false; - } - - return info.Save(filename, nullptr); - } - - // Saves the given art methods to a profile backed by 'filename' and adds - // some fake inline caches to it. The added inline caches are returned in - // the out map `profile_methods_map`. - bool SaveProfilingInfoWithFakeInlineCaches( - const std::string& filename, - const std::vector<ArtMethod*>& methods, - Hotness::Flag flags, - /*out*/ SafeMap<ArtMethod*, ProfileMethodInfo>* profile_methods_map) { - ProfileCompilationInfo info; - std::vector<ProfileMethodInfo> profile_methods; - ScopedObjectAccess soa(Thread::Current()); - for (ArtMethod* method : methods) { - std::vector<ProfileMethodInfo::ProfileInlineCache> caches; - // Monomorphic - for (uint16_t dex_pc = 0; dex_pc < 11; dex_pc++) { - std::vector<TypeReference> classes; - classes.emplace_back(method->GetDexFile(), dex::TypeIndex(0)); - caches.emplace_back(dex_pc, /*is_missing_types*/false, classes); - } - // Polymorphic - for (uint16_t dex_pc = 11; dex_pc < 22; dex_pc++) { - std::vector<TypeReference> classes; - for (uint16_t k = 0; k < InlineCache::kIndividualCacheSize / 2; k++) { - classes.emplace_back(method->GetDexFile(), dex::TypeIndex(k)); - } - caches.emplace_back(dex_pc, /*is_missing_types*/false, classes); - } - // Megamorphic - for (uint16_t dex_pc = 22; dex_pc < 33; dex_pc++) { - std::vector<TypeReference> classes; - for (uint16_t k = 0; k < 2 * InlineCache::kIndividualCacheSize; k++) { - classes.emplace_back(method->GetDexFile(), dex::TypeIndex(k)); - } - caches.emplace_back(dex_pc, /*is_missing_types*/false, classes); - } - // Missing types - for (uint16_t dex_pc = 33; dex_pc < 44; dex_pc++) { - std::vector<TypeReference> classes; - caches.emplace_back(dex_pc, /*is_missing_types*/true, classes); - } - ProfileMethodInfo pmi(MethodReference(method->GetDexFile(), - method->GetDexMethodIndex()), - caches); - profile_methods.push_back(pmi); - profile_methods_map->Put(method, pmi); - } - - if (!info.AddMethods(profile_methods, flags) - || info.GetNumberOfMethods() != profile_methods.size()) { - return false; - } - return info.Save(filename, nullptr); - } - // Creates an inline cache which will be destructed at the end of the test. ProfileCompilationInfo::InlineCacheMap* CreateInlineCacheMap() { used_inline_caches.emplace_back(new ProfileCompilationInfo::InlineCacheMap( @@ -187,35 +81,6 @@ class ProfileCompilationInfoTest : public CommonRuntimeTest { return used_inline_caches.back().get(); } - ProfileCompilationInfo::OfflineProfileMethodInfo ConvertProfileMethodInfo( - const ProfileMethodInfo& pmi) { - ProfileCompilationInfo::InlineCacheMap* ic_map = CreateInlineCacheMap(); - ProfileCompilationInfo::OfflineProfileMethodInfo offline_pmi(ic_map); - SafeMap<DexFile*, uint8_t> dex_map; // dex files to profile index - for (const auto& inline_cache : pmi.inline_caches) { - ProfileCompilationInfo::DexPcData& dex_pc_data = - ic_map->FindOrAdd( - inline_cache.dex_pc, ProfileCompilationInfo::DexPcData(allocator_.get()))->second; - if (inline_cache.is_missing_types) { - dex_pc_data.SetIsMissingTypes(); - } - for (const auto& class_ref : inline_cache.classes) { - uint8_t dex_profile_index = dex_map.FindOrAdd(const_cast<DexFile*>(class_ref.dex_file), - static_cast<uint8_t>(dex_map.size()))->second; - dex_pc_data.AddClass(dex_profile_index, class_ref.TypeIndex()); - if (dex_profile_index >= offline_pmi.dex_references.size()) { - // This is a new dex. - const std::string& dex_key = ProfileCompilationInfo::GetProfileDexFileKey( - class_ref.dex_file->GetLocation()); - offline_pmi.dex_references.emplace_back(dex_key, - class_ref.dex_file->GetLocationChecksum(), - class_ref.dex_file->NumMethodIds()); - } - } - } - return offline_pmi; - } - // Creates an offline profile used for testing inline caches. ProfileCompilationInfo::OfflineProfileMethodInfo GetOfflineProfileMethodInfo() { ProfileCompilationInfo::InlineCacheMap* ic_map = CreateInlineCacheMap(); @@ -261,7 +126,7 @@ class ProfileCompilationInfoTest : public CommonRuntimeTest { ProfileCompilationInfo::InlineCacheMap* ic_map = const_cast<ProfileCompilationInfo::InlineCacheMap*>(pmi->inline_caches); for (auto it : *ic_map) { - for (uint16_t k = 0; k <= 2 * InlineCache::kIndividualCacheSize; k++) { + for (uint16_t k = 0; k <= 2 * ProfileCompilationInfo::kIndividualInlineCacheSize; k++) { it.second.AddClass(0, dex::TypeIndex(k)); } } @@ -327,6 +192,7 @@ class ProfileCompilationInfoTest : public CommonRuntimeTest { static constexpr int kProfileMagicSize = 4; static constexpr int kProfileVersionSize = 4; + MallocArenaPool pool_; std::unique_ptr<ArenaAllocator> allocator_; // Cache of inline caches generated during tests. @@ -335,61 +201,6 @@ class ProfileCompilationInfoTest : public CommonRuntimeTest { std::vector<std::unique_ptr<ProfileCompilationInfo::InlineCacheMap>> used_inline_caches; }; -TEST_F(ProfileCompilationInfoTest, SaveArtMethods) { - ScratchFile profile; - - Thread* self = Thread::Current(); - jobject class_loader; - { - ScopedObjectAccess soa(self); - class_loader = LoadDex("ProfileTestMultiDex"); - } - ASSERT_NE(class_loader, nullptr); - - // Save virtual methods from Main. - std::set<DexCacheResolvedClasses> resolved_classes; - std::vector<ArtMethod*> main_methods = GetVirtualMethods(class_loader, "LMain;"); - ASSERT_TRUE(SaveProfilingInfo( - profile.GetFilename(), main_methods, resolved_classes, Hotness::kFlagPostStartup)); - - // Check that what we saved is in the profile. - ProfileCompilationInfo info1; - ASSERT_TRUE(info1.Load(GetFd(profile))); - ASSERT_EQ(info1.GetNumberOfMethods(), main_methods.size()); - { - ScopedObjectAccess soa(self); - for (ArtMethod* m : main_methods) { - Hotness h = info1.GetMethodHotness(MethodReference(m->GetDexFile(), m->GetDexMethodIndex())); - ASSERT_TRUE(h.IsHot()); - ASSERT_TRUE(h.IsPostStartup()); - } - } - - // Save virtual methods from Second. - std::vector<ArtMethod*> second_methods = GetVirtualMethods(class_loader, "LSecond;"); - ASSERT_TRUE(SaveProfilingInfo( - profile.GetFilename(), second_methods, resolved_classes, Hotness::kFlagStartup)); - - // Check that what we saved is in the profile (methods form Main and Second). - ProfileCompilationInfo info2; - ASSERT_TRUE(profile.GetFile()->ResetOffset()); - ASSERT_TRUE(info2.Load(GetFd(profile))); - ASSERT_EQ(info2.GetNumberOfMethods(), main_methods.size() + second_methods.size()); - { - ScopedObjectAccess soa(self); - for (ArtMethod* m : main_methods) { - Hotness h = info2.GetMethodHotness(MethodReference(m->GetDexFile(), m->GetDexMethodIndex())); - ASSERT_TRUE(h.IsHot()); - ASSERT_TRUE(h.IsPostStartup()); - } - for (ArtMethod* m : second_methods) { - Hotness h = info2.GetMethodHotness(MethodReference(m->GetDexFile(), m->GetDexMethodIndex())); - ASSERT_TRUE(h.IsHot()); - ASSERT_TRUE(h.IsStartup()); - } - } -} - TEST_F(ProfileCompilationInfoTest, SaveFd) { ScratchFile profile; @@ -722,48 +533,6 @@ TEST_F(ProfileCompilationInfoTest, MissingTypesInlineCaches) { ASSERT_TRUE(*loaded_pmi1 == pmi_extra); } -TEST_F(ProfileCompilationInfoTest, SaveArtMethodsWithInlineCaches) { - ScratchFile profile; - - Thread* self = Thread::Current(); - jobject class_loader; - { - ScopedObjectAccess soa(self); - class_loader = LoadDex("ProfileTestMultiDex"); - } - ASSERT_NE(class_loader, nullptr); - - // Save virtual methods from Main. - std::set<DexCacheResolvedClasses> resolved_classes; - std::vector<ArtMethod*> main_methods = GetVirtualMethods(class_loader, "LMain;"); - - SafeMap<ArtMethod*, ProfileMethodInfo> profile_methods_map; - ASSERT_TRUE(SaveProfilingInfoWithFakeInlineCaches( - profile.GetFilename(), main_methods, Hotness::kFlagStartup, &profile_methods_map)); - - // Check that what we saved is in the profile. - ProfileCompilationInfo info; - ASSERT_TRUE(info.Load(GetFd(profile))); - ASSERT_EQ(info.GetNumberOfMethods(), main_methods.size()); - { - ScopedObjectAccess soa(self); - for (ArtMethod* m : main_methods) { - Hotness h = info.GetMethodHotness(MethodReference(m->GetDexFile(), m->GetDexMethodIndex())); - ASSERT_TRUE(h.IsHot()); - ASSERT_TRUE(h.IsStartup()); - const ProfileMethodInfo& pmi = profile_methods_map.find(m)->second; - std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> offline_pmi = - info.GetMethod(m->GetDexFile()->GetLocation(), - m->GetDexFile()->GetLocationChecksum(), - m->GetDexMethodIndex()); - ASSERT_TRUE(offline_pmi != nullptr); - ProfileCompilationInfo::OfflineProfileMethodInfo converted_pmi = - ConvertProfileMethodInfo(pmi); - ASSERT_EQ(converted_pmi, *offline_pmi); - } - } -} - TEST_F(ProfileCompilationInfoTest, InvalidChecksumInInlineCache) { ScratchFile profile; diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc index fcd6bfd46c..6688cc1bb9 100644 --- a/oatdump/oatdump.cc +++ b/oatdump/oatdump.cc @@ -45,6 +45,7 @@ #include "debug/debug_info.h" #include "debug/elf_debug_writer.h" #include "debug/method_debug_info.h" +#include "dex/class_accessor-inl.h" #include "dex/code_item_accessors-inl.h" #include "dex/descriptors_names.h" #include "dex/dex_file-inl.h" @@ -268,25 +269,18 @@ class OatSymbolizer FINAL { void WalkOatClass(const OatFile::OatClass& oat_class, const DexFile& dex_file, uint32_t 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) { // empty class such as a marker interface? - return; - } + ClassAccessor accessor(dex_file, dex_file.GetClassDef(class_def_index)); // Note: even if this is an interface or a native class, we still have to walk it, as there // might be a static initializer. - ClassDataItemIterator it(dex_file, class_data); uint32_t class_method_idx = 0; - it.SkipAllFields(); - for (; it.HasNextMethod(); it.Next()) { + for (const ClassAccessor::Method& method : accessor.GetMethods()) { WalkOatMethod(oat_class.GetOatMethod(class_method_idx++), dex_file, class_def_index, - it.GetMemberIndex(), - it.GetMethodCodeItem(), - it.GetMethodAccessFlags()); + method.GetIndex(), + method.GetCodeItem(), + method.GetAccessFlags()); } - DCHECK(!it.HasNext()); } void WalkOatMethod(const OatFile::OatMethod& oat_method, @@ -904,21 +898,15 @@ class OatDumper { continue; } offsets_.insert(reinterpret_cast<uintptr_t>(&dex_file->GetHeader())); - 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); + uint32_t class_def_index = 0u; + for (ClassAccessor accessor : dex_file->GetClasses()) { const OatFile::OatClass oat_class = oat_dex_file->GetOatClass(class_def_index); - const uint8_t* class_data = dex_file->GetClassData(class_def); - if (class_data != nullptr) { - ClassDataItemIterator it(*dex_file, class_data); - it.SkipAllFields(); - uint32_t class_method_index = 0; - while (it.HasNextMethod()) { - AddOffsets(oat_class.GetOatMethod(class_method_index++)); - it.Next(); - } + for (uint32_t class_method_index = 0; + class_method_index < accessor.NumMethods(); + ++class_method_index) { + AddOffsets(oat_class.GetOatMethod(class_method_index)); } + ++class_def_index; } } @@ -1731,7 +1719,7 @@ class OatDumper { // Stack masks stats_.AddBits( Stats::kByteKindCodeInfoStackMasks, - code_info.stack_masks_.size_in_bits()); + code_info.stack_masks_.DataBitSize()); // Register masks stats_.AddBits( diff --git a/openjdkjvmti/ti_class.cc b/openjdkjvmti/ti_class.cc index 726e47ed5f..9bea18a763 100644 --- a/openjdkjvmti/ti_class.cc +++ b/openjdkjvmti/ti_class.cc @@ -71,9 +71,11 @@ #include "scoped_thread_state_change-inl.h" #include "thread-current-inl.h" #include "thread_list.h" +#include "ti_class_definition.h" #include "ti_class_loader-inl.h" #include "ti_phase.h" #include "ti_redefine.h" +#include "transform.h" #include "well_known_classes.h" namespace openjdkjvmti { @@ -713,7 +715,7 @@ jvmtiError ClassUtil::GetClassSignature(jvmtiEnv* env, if (!klass->IsProxyClass() && klass->GetDexCache() != nullptr) { art::StackHandleScope<1> hs(soa.Self()); art::Handle<art::mirror::Class> h_klass = hs.NewHandle(klass); - art::mirror::ObjectArray<art::mirror::String>* str_array = + art::ObjPtr<art::mirror::ObjectArray<art::mirror::String>> str_array = art::annotations::GetSignatureAnnotationForClass(h_klass); if (str_array != nullptr) { std::ostringstream oss; diff --git a/openjdkjvmti/ti_class_loader.h b/openjdkjvmti/ti_class_loader.h index a3857e595a..577c28585e 100644 --- a/openjdkjvmti/ti_class_loader.h +++ b/openjdkjvmti/ti_class_loader.h @@ -36,32 +36,19 @@ #include <jni.h> -#include "art_jvmti.h" -#include "art_method.h" -#include "base/array_slice.h" #include "base/globals.h" -#include "base/mem_map.h" -#include "class_linker.h" -#include "dex/dex_file.h" -#include "dex/utf.h" -#include "gc_root-inl.h" -#include "jni/jni_env_ext-inl.h" +#include "base/mutex.h" #include "jvmti.h" -#include "linear_alloc.h" -#include "mirror/array-inl.h" #include "mirror/array.h" -#include "mirror/class-inl.h" -#include "mirror/class.h" -#include "mirror/class_loader-inl.h" -#include "mirror/string-inl.h" -#include "oat_file.h" -#include "obj_ptr.h" -#include "scoped_thread_state_change-inl.h" -#include "stack.h" -#include "thread_list.h" -#include "ti_class_definition.h" -#include "transform.h" -#include "utils/dex_cache_arrays_layout-inl.h" + +namespace art { + +class DexFile; +template <class MirrorType> class Handle; +template <class MirrorType> class ObjPtr; +class Thread; + +} // namespace art namespace openjdkjvmti { diff --git a/openjdkjvmti/ti_field.cc b/openjdkjvmti/ti_field.cc index 328e2a1e40..2a860d9f43 100644 --- a/openjdkjvmti/ti_field.cc +++ b/openjdkjvmti/ti_field.cc @@ -91,7 +91,7 @@ jvmtiError FieldUtil::GetFieldName(jvmtiEnv* env, if (generic_ptr != nullptr) { *generic_ptr = nullptr; if (!art_field->GetDeclaringClass()->IsProxyClass()) { - art::mirror::ObjectArray<art::mirror::String>* str_array = + art::ObjPtr<art::mirror::ObjectArray<art::mirror::String>> str_array = art::annotations::GetSignatureAnnotationForField(art_field); if (str_array != nullptr) { std::ostringstream oss; diff --git a/openjdkjvmti/ti_method.cc b/openjdkjvmti/ti_method.cc index c0c312c490..d0b7224f93 100644 --- a/openjdkjvmti/ti_method.cc +++ b/openjdkjvmti/ti_method.cc @@ -345,7 +345,7 @@ jvmtiError MethodUtil::GetMethodName(jvmtiEnv* env, if (generic_ptr != nullptr) { *generic_ptr = nullptr; if (!art_method->GetDeclaringClass()->IsProxyClass()) { - art::mirror::ObjectArray<art::mirror::String>* str_array = + art::ObjPtr<art::mirror::ObjectArray<art::mirror::String>> str_array = art::annotations::GetSignatureAnnotationForMethod(art_method); if (str_array != nullptr) { std::ostringstream oss; diff --git a/openjdkjvmti/ti_redefine.cc b/openjdkjvmti/ti_redefine.cc index 48e2958773..73e37199ed 100644 --- a/openjdkjvmti/ti_redefine.cc +++ b/openjdkjvmti/ti_redefine.cc @@ -61,6 +61,7 @@ #include "jit/jit_code_cache.h" #include "jni/jni_env_ext-inl.h" #include "jvmti_allocator.h" +#include "linear_alloc.h" #include "mirror/class-inl.h" #include "mirror/class_ext.h" #include "mirror/object.h" @@ -68,6 +69,8 @@ #include "non_debuggable_classes.h" #include "object_lock.h" #include "runtime.h" +#include "stack.h" +#include "thread_list.h" #include "ti_breakpoint.h" #include "ti_class_loader.h" #include "transform.h" diff --git a/openjdkjvmti/ti_redefine.h b/openjdkjvmti/ti_redefine.h index 227eacd180..e337491ae3 100644 --- a/openjdkjvmti/ti_redefine.h +++ b/openjdkjvmti/ti_redefine.h @@ -37,34 +37,18 @@ #include <jni.h> #include "art_jvmti.h" -#include "art_method.h" #include "base/array_ref.h" #include "base/globals.h" -#include "base/mem_map.h" -#include "class_linker.h" #include "dex/dex_file.h" -#include "dex/utf.h" -#include "gc_root-inl.h" #include "jni/jni_env_ext-inl.h" #include "jvmti.h" -#include "linear_alloc.h" -#include "mirror/array-inl.h" #include "mirror/array.h" -#include "mirror/class-inl.h" #include "mirror/class.h" -#include "mirror/class_loader-inl.h" -#include "mirror/string-inl.h" -#include "oat_file.h" #include "obj_ptr.h" -#include "scoped_thread_state_change-inl.h" -#include "stack.h" -#include "thread_list.h" -#include "ti_class_definition.h" -#include "transform.h" -#include "utils/dex_cache_arrays_layout-inl.h" namespace openjdkjvmti { +class ArtClassDefinition; class RedefinitionDataHolder; class RedefinitionDataIter; diff --git a/profman/profman.cc b/profman/profman.cc index 661132d94f..096e5dc3bd 100644 --- a/profman/profman.cc +++ b/profman/profman.cc @@ -931,12 +931,12 @@ class ProfMan FINAL { std::vector<ProfileMethodInfo> methods; if (method_str == kClassAllMethods) { ClassAccessor accessor(*dex_file, *dex_file->FindClassDef(class_ref.TypeIndex())); - accessor.VisitMethods([&](const ClassAccessor::Method& method) { + for (const ClassAccessor::Method& method : accessor.GetMethods()) { if (method.GetCodeItemOffset() != 0) { // Add all of the methods that have code to the profile. methods.push_back(ProfileMethodInfo(method.GetReference())); } - }); + } } // TODO: Check return values? profile->AddMethods(methods, static_cast<ProfileCompilationInfo::MethodHotness::Flag>(flags)); diff --git a/runtime/Android.bp b/runtime/Android.bp index b276c81d5a..777a1fc5ee 100644 --- a/runtime/Android.bp +++ b/runtime/Android.bp @@ -574,6 +574,7 @@ art_cc_test { "interpreter/safe_math_test.cc", "interpreter/unstarted_runtime_test.cc", "jdwp/jdwp_options_test.cc", + "jit/profiling_info_test.cc", "jni/java_vm_ext_test.cc", "method_handles_test.cc", "mirror/dex_cache_test.cc", diff --git a/runtime/arch/stub_test.cc b/runtime/arch/stub_test.cc index 78516e3aeb..b0c0e43e35 100644 --- a/runtime/arch/stub_test.cc +++ b/runtime/arch/stub_test.cc @@ -21,6 +21,7 @@ #include "base/callee_save_type.h" #include "base/enums.h" #include "class_linker-inl.h" +#include "class_root.h" #include "common_runtime_test.h" #include "entrypoints/quick/quick_entrypoints_enum.h" #include "imt_conflict_table.h" @@ -2096,7 +2097,7 @@ TEST_F(StubTest, ReadBarrierForRoot) { EXPECT_FALSE(self->IsExceptionPending()); - GcRoot<mirror::Class>& root = mirror::String::java_lang_String_; + GcRoot<mirror::Class> root(GetClassRoot<mirror::String>()); size_t result = Invoke3(reinterpret_cast<size_t>(&root), 0U, 0U, readBarrierForRootSlow, self); EXPECT_FALSE(self->IsExceptionPending()); diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index a2e26866d1..095272394a 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -484,27 +484,10 @@ bool ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b mirror::ObjectArray<mirror::Object>::ClassSize(image_pointer_size_)))); object_array_class->SetComponentType(java_lang_Object.Get()); - // Setup the char (primitive) class to be used for char[]. - Handle<mirror::Class> char_class(hs.NewHandle( - AllocClass(self, java_lang_Class.Get(), - mirror::Class::PrimitiveClassSize(image_pointer_size_)))); - // The primitive char class won't be initialized by - // InitializePrimitiveClass until line 459, but strings (and - // internal char arrays) will be allocated before that and the - // component size, which is computed from the primitive type, needs - // to be set here. - char_class->SetPrimitiveType(Primitive::kPrimChar); - - // Setup the char[] class to be used for String. - Handle<mirror::Class> char_array_class(hs.NewHandle( - AllocClass(self, java_lang_Class.Get(), mirror::Array::ClassSize(image_pointer_size_)))); - char_array_class->SetComponentType(char_class.Get()); - // Setup String. Handle<mirror::Class> java_lang_String(hs.NewHandle( AllocClass(self, java_lang_Class.Get(), mirror::String::ClassSize(image_pointer_size_)))); java_lang_String->SetStringClass(); - mirror::String::SetClass(java_lang_String.Get()); mirror::Class::SetStatus(java_lang_String, ClassStatus::kResolved, self); // Setup java.lang.ref.Reference. @@ -523,7 +506,6 @@ bool ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b SetClassRoot(ClassRoot::kJavaLangObject, java_lang_Object.Get()); SetClassRoot(ClassRoot::kClassArrayClass, class_array_class.Get()); SetClassRoot(ClassRoot::kObjectArrayClass, object_array_class.Get()); - SetClassRoot(ClassRoot::kCharArrayClass, char_array_class.Get()); SetClassRoot(ClassRoot::kJavaLangString, java_lang_String.Get()); SetClassRoot(ClassRoot::kJavaLangRefReference, java_lang_ref_Reference.Get()); @@ -533,6 +515,7 @@ bool ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b // Setup the primitive type classes. SetClassRoot(ClassRoot::kPrimitiveBoolean, CreatePrimitiveClass(self, Primitive::kPrimBoolean)); SetClassRoot(ClassRoot::kPrimitiveByte, CreatePrimitiveClass(self, Primitive::kPrimByte)); + SetClassRoot(ClassRoot::kPrimitiveChar, CreatePrimitiveClass(self, Primitive::kPrimChar)); SetClassRoot(ClassRoot::kPrimitiveShort, CreatePrimitiveClass(self, Primitive::kPrimShort)); SetClassRoot(ClassRoot::kPrimitiveInt, CreatePrimitiveClass(self, Primitive::kPrimInt)); SetClassRoot(ClassRoot::kPrimitiveLong, CreatePrimitiveClass(self, Primitive::kPrimLong)); @@ -543,13 +526,13 @@ bool ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b // 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 AllocDexCache (done in AppendToBootClassPath). + // 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_)))); int_array_class->SetComponentType(GetClassRoot(ClassRoot::kPrimitiveInt, this)); SetClassRoot(ClassRoot::kIntArrayClass, int_array_class.Get()); - // Create long array type for AllocDexCache (done in AppendToBootClassPath). + // Create long array type for native pointer arrays (for example vtables) on 64-bit archs. Handle<mirror::Class> long_array_class(hs.NewHandle( AllocClass(self, java_lang_Class.Get(), mirror::Array::ClassSize(image_pointer_size_)))); long_array_class->SetComponentType(GetClassRoot(ClassRoot::kPrimitiveLong, this)); @@ -604,10 +587,6 @@ bool ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b // now we can use FindSystemClass - // run char class through InitializePrimitiveClass to finish init - InitializePrimitiveClass(char_class.Get(), Primitive::kPrimChar); - SetClassRoot(ClassRoot::kPrimitiveChar, char_class.Get()); // needs descriptor - // Set up GenericJNI entrypoint. That is mainly a hack for common_compiler_test.h so that // we do not need friend classes or a publicly exposed setter. quick_generic_jni_trampoline_ = GetQuickGenericJniStub(); @@ -636,7 +615,7 @@ bool ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b SetClassRoot(ClassRoot::kByteArrayClass, FindSystemClass(self, "[B")); - CheckSystemClass(self, char_array_class, "[C"); + SetClassRoot(ClassRoot::kCharArrayClass, FindSystemClass(self, "[C")); SetClassRoot(ClassRoot::kShortArrayClass, FindSystemClass(self, "[S")); @@ -685,7 +664,7 @@ bool ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b FindSystemClass(self, "Ljava/lang/reflect/Proxy;")); // Create java.lang.reflect.Field.class root. - auto* class_root = FindSystemClass(self, "Ljava/lang/reflect/Field;"); + ObjPtr<mirror::Class> class_root = FindSystemClass(self, "Ljava/lang/reflect/Field;"); CHECK(class_root != nullptr); SetClassRoot(ClassRoot::kJavaLangReflectField, class_root); @@ -759,7 +738,6 @@ bool ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b class_root = FindSystemClass(self, "Ldalvik/system/EmulatedStackFrame;"); CHECK(class_root != nullptr); SetClassRoot(ClassRoot::kDalvikSystemEmulatedStackFrame, class_root); - mirror::EmulatedStackFrame::SetClass(class_root); // java.lang.ref classes need to be specially flagged, but otherwise are normal classes // finish initializing Reference class @@ -790,14 +768,12 @@ bool ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b // Set up java.lang.Throwable, java.lang.ClassNotFoundException, and // java.lang.StackTraceElement as a convenience. SetClassRoot(ClassRoot::kJavaLangThrowable, FindSystemClass(self, "Ljava/lang/Throwable;")); - mirror::Throwable::SetClass(GetClassRoot(ClassRoot::kJavaLangThrowable, this)); SetClassRoot(ClassRoot::kJavaLangClassNotFoundException, FindSystemClass(self, "Ljava/lang/ClassNotFoundException;")); SetClassRoot(ClassRoot::kJavaLangStackTraceElement, FindSystemClass(self, "Ljava/lang/StackTraceElement;")); SetClassRoot(ClassRoot::kJavaLangStackTraceElementArrayClass, FindSystemClass(self, "[Ljava/lang/StackTraceElement;")); - mirror::StackTraceElement::SetClass(GetClassRoot(ClassRoot::kJavaLangStackTraceElement, this)); // Create conflict tables that depend on the class linker. runtime->FixupConflictTables(); @@ -1017,10 +993,6 @@ bool ClassLinker::InitFromBootImage(std::string* error_msg) { spaces[0]->GetImageHeader().GetImageRoot(ImageHeader::kClassRoots))); mirror::Class::SetClassClass(GetClassRoot(ClassRoot::kJavaLangClass, this)); - // Special case of setting up the String class early so that we can test arbitrary objects - // as being Strings or not - mirror::String::SetClass(GetClassRoot<mirror::String>(this)); - ObjPtr<mirror::Class> java_lang_Object = GetClassRoot<mirror::Object>(this); java_lang_Object->SetObjectSize(sizeof(mirror::Object)); // Allocate in non-movable so that it's possible to check if a JNI weak global ref has been @@ -1033,10 +1005,6 @@ bool ClassLinker::InitFromBootImage(std::string* error_msg) { GcRoot<mirror::IfTable>(GetClassRoot(ClassRoot::kObjectArrayClass, this)->GetIfTable()); DCHECK_EQ(array_iftable_.Read(), GetClassRoot(ClassRoot::kBooleanArrayClass, this)->GetIfTable()); // String class root was set above - mirror::Throwable::SetClass(GetClassRoot(ClassRoot::kJavaLangThrowable, this)); - mirror::StackTraceElement::SetClass(GetClassRoot(ClassRoot::kJavaLangStackTraceElement, this)); - mirror::EmulatedStackFrame::SetClass( - GetClassRoot(ClassRoot::kDalvikSystemEmulatedStackFrame, this).Ptr()); mirror::ClassExt::SetClass(GetClassRoot(ClassRoot::kDalvikSystemClassExt, this)); for (gc::space::ImageSpace* image_space : spaces) { @@ -2116,10 +2084,6 @@ void ClassLinker::VisitClassesWithoutClassesLock(ClassVisitor* visitor) { ClassLinker::~ClassLinker() { mirror::Class::ResetClass(); - mirror::StackTraceElement::ResetClass(); - mirror::String::ResetClass(); - mirror::Throwable::ResetClass(); - mirror::EmulatedStackFrame::ResetClass(); Thread* const self = Thread::Current(); for (const ClassLoaderData& data : class_loaders_) { // CHA unloading analysis is not needed. No negative consequences are expected because @@ -3571,20 +3535,13 @@ ClassLinker::DexCacheData ClassLinker::FindDexCacheDataLocked(const DexFile& dex } mirror::Class* ClassLinker::CreatePrimitiveClass(Thread* self, Primitive::Type type) { - ObjPtr<mirror::Class> klass = + ObjPtr<mirror::Class> primitive_class = AllocClass(self, mirror::Class::PrimitiveClassSize(image_pointer_size_)); - if (UNLIKELY(klass == nullptr)) { + if (UNLIKELY(primitive_class == nullptr)) { self->AssertPendingOOMException(); return nullptr; } - return InitializePrimitiveClass(klass, type); -} - -mirror::Class* ClassLinker::InitializePrimitiveClass(ObjPtr<mirror::Class> primitive_class, - Primitive::Type type) { - CHECK(primitive_class != nullptr); // Must hold lock on object when initializing. - Thread* self = Thread::Current(); StackHandleScope<1> hs(self); Handle<mirror::Class> h_class(hs.NewHandle(primitive_class)); ObjectLock<mirror::Class> lock(self, h_class); @@ -3678,8 +3635,6 @@ mirror::Class* ClassLinker::CreateArrayClass(Thread* self, const char* descripto new_class.Assign(GetClassRoot<mirror::ObjectArray<mirror::Object>>(this)); } else if (strcmp(descriptor, "[Ljava/lang/String;") == 0) { new_class.Assign(GetClassRoot<mirror::ObjectArray<mirror::String>>(this)); - } else if (strcmp(descriptor, "[C") == 0) { - new_class.Assign(GetClassRoot<mirror::CharArray>(this)); } else if (strcmp(descriptor, "[I") == 0) { new_class.Assign(GetClassRoot<mirror::IntArray>(this)); } else if (strcmp(descriptor, "[J") == 0) { diff --git a/runtime/class_linker.h b/runtime/class_linker.h index afe5c99990..1f94c43408 100644 --- a/runtime/class_linker.h +++ b/runtime/class_linker.h @@ -793,10 +793,6 @@ class ClassLinker { mirror::Class* CreatePrimitiveClass(Thread* self, Primitive::Type type) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); - mirror::Class* InitializePrimitiveClass(ObjPtr<mirror::Class> primitive_class, - Primitive::Type type) - REQUIRES_SHARED(Locks::mutator_lock_) - REQUIRES(!Roles::uninterruptible_); mirror::Class* CreateArrayClass(Thread* self, const char* descriptor, diff --git a/runtime/dex/dex_file_annotations.cc b/runtime/dex/dex_file_annotations.cc index ffa0a9065a..5cb08dc278 100644 --- a/runtime/dex/dex_file_annotations.cc +++ b/runtime/dex/dex_file_annotations.cc @@ -849,7 +849,8 @@ ObjPtr<mirror::Object> GetAnnotationValue(const ClassData& klass, return annotation_value.value_.GetL(); } -mirror::ObjectArray<mirror::String>* GetSignatureValue(const ClassData& klass, +static ObjPtr<mirror::ObjectArray<mirror::String>> GetSignatureValue( + const ClassData& klass, const DexFile::AnnotationSetItem* annotation_set) REQUIRES_SHARED(Locks::mutator_lock_) { const DexFile& dex_file = klass.GetDexFile(); @@ -860,12 +861,9 @@ mirror::ObjectArray<mirror::String>* GetSignatureValue(const ClassData& klass, if (annotation_item == nullptr) { return nullptr; } - ObjPtr<mirror::Class> string_class = mirror::String::GetJavaLangString(); - Handle<mirror::Class> string_array_class(hs.NewHandle( - Runtime::Current()->GetClassLinker()->FindArrayClass(Thread::Current(), &string_class))); - if (string_array_class == nullptr) { - return nullptr; - } + Handle<mirror::Class> string_array_class = + hs.NewHandle(GetClassRoot<mirror::ObjectArray<mirror::String>>()); + DCHECK(string_array_class != nullptr); ObjPtr<mirror::Object> obj = GetAnnotationValue(klass, annotation_item, "value", string_array_class, DexFile::kDexAnnotationArray); @@ -880,19 +878,16 @@ ObjPtr<mirror::ObjectArray<mirror::Class>> GetThrowsValue( const DexFile::AnnotationSetItem* annotation_set) REQUIRES_SHARED(Locks::mutator_lock_) { const DexFile& dex_file = klass.GetDexFile(); - StackHandleScope<1> hs(Thread::Current()); const DexFile::AnnotationItem* annotation_item = SearchAnnotationSet(dex_file, annotation_set, "Ldalvik/annotation/Throws;", DexFile::kDexVisibilitySystem); if (annotation_item == nullptr) { return nullptr; } - ObjPtr<mirror::Class> class_class = mirror::Class::GetJavaLangClass(); - Handle<mirror::Class> class_array_class(hs.NewHandle( - Runtime::Current()->GetClassLinker()->FindArrayClass(Thread::Current(), &class_class))); - if (class_array_class == nullptr) { - return nullptr; - } + StackHandleScope<1> hs(Thread::Current()); + Handle<mirror::Class> class_array_class = + hs.NewHandle(GetClassRoot<mirror::ObjectArray<mirror::Class>>()); + DCHECK(class_array_class != nullptr); ObjPtr<mirror::Object> obj = GetAnnotationValue(klass, annotation_item, "value", class_array_class, DexFile::kDexAnnotationArray); @@ -1020,7 +1015,7 @@ ObjPtr<mirror::ObjectArray<mirror::Object>> GetAnnotationsForField(ArtField* fie return ProcessAnnotationSet(field_class, annotation_set, DexFile::kDexVisibilityRuntime); } -mirror::ObjectArray<mirror::String>* GetSignatureAnnotationForField(ArtField* field) { +ObjPtr<mirror::ObjectArray<mirror::String>> GetSignatureAnnotationForField(ArtField* field) { const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForField(field); if (annotation_set == nullptr) { return nullptr; @@ -1171,9 +1166,10 @@ ObjPtr<mirror::Object> GetAnnotationForMethodParameter(ArtMethod* method, annotation_class); } -bool GetParametersMetadataForMethod(ArtMethod* method, - MutableHandle<mirror::ObjectArray<mirror::String>>* names, - MutableHandle<mirror::IntArray>* access_flags) { +bool GetParametersMetadataForMethod( + ArtMethod* method, + /*out*/ MutableHandle<mirror::ObjectArray<mirror::String>>* names, + /*out*/ MutableHandle<mirror::IntArray>* access_flags) { const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForMethod(method); if (annotation_set == nullptr) { @@ -1193,12 +1189,10 @@ bool GetParametersMetadataForMethod(ArtMethod* method, StackHandleScope<4> hs(Thread::Current()); // Extract the parameters' names String[]. - ObjPtr<mirror::Class> string_class = mirror::String::GetJavaLangString(); - Handle<mirror::Class> string_array_class(hs.NewHandle( - Runtime::Current()->GetClassLinker()->FindArrayClass(Thread::Current(), &string_class))); - if (UNLIKELY(string_array_class == nullptr)) { - return false; - } + ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); + Handle<mirror::Class> string_array_class = + hs.NewHandle(GetClassRoot<mirror::ObjectArray<mirror::String>>(class_linker)); + DCHECK(string_array_class != nullptr); ClassData data(method); Handle<mirror::Object> names_obj = @@ -1212,10 +1206,8 @@ bool GetParametersMetadataForMethod(ArtMethod* method, } // Extract the parameters' access flags int[]. - Handle<mirror::Class> int_array_class(hs.NewHandle(GetClassRoot<mirror::IntArray>())); - if (UNLIKELY(int_array_class == nullptr)) { - return false; - } + Handle<mirror::Class> int_array_class(hs.NewHandle(GetClassRoot<mirror::IntArray>(class_linker))); + DCHECK(int_array_class != nullptr); Handle<mirror::Object> access_flags_obj = hs.NewHandle(GetAnnotationValue(data, annotation_item, @@ -1226,12 +1218,12 @@ bool GetParametersMetadataForMethod(ArtMethod* method, return false; } - names->Assign(names_obj.Get()->AsObjectArray<mirror::String>()); - access_flags->Assign(access_flags_obj.Get()->AsIntArray()); + names->Assign(names_obj->AsObjectArray<mirror::String>()); + access_flags->Assign(access_flags_obj->AsIntArray()); return true; } -mirror::ObjectArray<mirror::String>* GetSignatureAnnotationForMethod(ArtMethod* method) { +ObjPtr<mirror::ObjectArray<mirror::String>> GetSignatureAnnotationForMethod(ArtMethod* method) { const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForMethod(method); if (annotation_set == nullptr) { return nullptr; @@ -1345,12 +1337,9 @@ ObjPtr<mirror::ObjectArray<mirror::Class>> GetDeclaredClasses(Handle<mirror::Cla return nullptr; } StackHandleScope<1> hs(Thread::Current()); - ObjPtr<mirror::Class> class_class = mirror::Class::GetJavaLangClass(); - Handle<mirror::Class> class_array_class(hs.NewHandle( - Runtime::Current()->GetClassLinker()->FindArrayClass(hs.Self(), &class_class))); - if (class_array_class == nullptr) { - return nullptr; - } + Handle<mirror::Class> class_array_class = + hs.NewHandle(GetClassRoot<mirror::ObjectArray<mirror::Class>>()); + DCHECK(class_array_class != nullptr); ObjPtr<mirror::Object> obj = GetAnnotationValue(data, annotation_item, "value", class_array_class, DexFile::kDexAnnotationArray); @@ -1446,7 +1435,7 @@ ObjPtr<mirror::Object> GetEnclosingMethod(Handle<mirror::Class> klass) { DexFile::kDexAnnotationMethod); } -bool GetInnerClass(Handle<mirror::Class> klass, ObjPtr<mirror::String>* name) { +bool GetInnerClass(Handle<mirror::Class> klass, /*out*/ ObjPtr<mirror::String>* name) { ClassData data(klass); const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForClass(data); if (annotation_set == nullptr) { @@ -1513,7 +1502,8 @@ bool GetInnerClassFlags(Handle<mirror::Class> klass, uint32_t* flags) { return true; } -mirror::ObjectArray<mirror::String>* GetSignatureAnnotationForClass(Handle<mirror::Class> klass) { +ObjPtr<mirror::ObjectArray<mirror::String>> GetSignatureAnnotationForClass( + Handle<mirror::Class> klass) { ClassData data(klass); const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForClass(data); if (annotation_set == nullptr) { diff --git a/runtime/dex/dex_file_annotations.h b/runtime/dex/dex_file_annotations.h index 9645a7febd..bde7891091 100644 --- a/runtime/dex/dex_file_annotations.h +++ b/runtime/dex/dex_file_annotations.h @@ -41,7 +41,7 @@ ObjPtr<mirror::Object> GetAnnotationForField(ArtField* field, REQUIRES_SHARED(Locks::mutator_lock_); ObjPtr<mirror::ObjectArray<mirror::Object>> GetAnnotationsForField(ArtField* field) REQUIRES_SHARED(Locks::mutator_lock_); -mirror::ObjectArray<mirror::String>* GetSignatureAnnotationForField(ArtField* field) +ObjPtr<mirror::ObjectArray<mirror::String>> GetSignatureAnnotationForField(ArtField* field) REQUIRES_SHARED(Locks::mutator_lock_); bool IsFieldAnnotationPresent(ArtField* field, Handle<mirror::Class> annotation_class) REQUIRES_SHARED(Locks::mutator_lock_); @@ -64,11 +64,11 @@ ObjPtr<mirror::Object> GetAnnotationForMethodParameter(ArtMethod* method, uint32_t parameter_idx, Handle<mirror::Class> annotation_class) REQUIRES_SHARED(Locks::mutator_lock_); -bool GetParametersMetadataForMethod(ArtMethod* method, - MutableHandle<mirror::ObjectArray<mirror::String>>* names, - MutableHandle<mirror::IntArray>* access_flags) - REQUIRES_SHARED(Locks::mutator_lock_); -mirror::ObjectArray<mirror::String>* GetSignatureAnnotationForMethod(ArtMethod* method) +bool GetParametersMetadataForMethod( + ArtMethod* method, + /*out*/ MutableHandle<mirror::ObjectArray<mirror::String>>* names, + /*out*/ MutableHandle<mirror::IntArray>* access_flags) REQUIRES_SHARED(Locks::mutator_lock_); +ObjPtr<mirror::ObjectArray<mirror::String>> GetSignatureAnnotationForMethod(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_); // Check whether `method` is annotated with `annotation_class`. // If `lookup_in_resolved_boot_classes` is true, look up any of the @@ -101,12 +101,12 @@ ObjPtr<mirror::Class> GetEnclosingClass(Handle<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_); ObjPtr<mirror::Object> GetEnclosingMethod(Handle<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_); -bool GetInnerClass(Handle<mirror::Class> klass, ObjPtr<mirror::String>* name) +bool GetInnerClass(Handle<mirror::Class> klass, /*out*/ ObjPtr<mirror::String>* name) REQUIRES_SHARED(Locks::mutator_lock_); bool GetInnerClassFlags(Handle<mirror::Class> klass, uint32_t* flags) REQUIRES_SHARED(Locks::mutator_lock_); -mirror::ObjectArray<mirror::String>* GetSignatureAnnotationForClass(Handle<mirror::Class> klass) - REQUIRES_SHARED(Locks::mutator_lock_); +ObjPtr<mirror::ObjectArray<mirror::String>> GetSignatureAnnotationForClass( + Handle<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_); const char* GetSourceDebugExtension(Handle<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_); bool IsClassAnnotationPresent(Handle<mirror::Class> klass, diff --git a/runtime/entrypoints/quick/quick_alloc_entrypoints.cc b/runtime/entrypoints/quick/quick_alloc_entrypoints.cc index ed5885f224..5f7594c68d 100644 --- a/runtime/entrypoints/quick/quick_alloc_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_alloc_entrypoints.cc @@ -25,6 +25,7 @@ #include "mirror/class-inl.h" #include "mirror/object-inl.h" #include "mirror/object_array-inl.h" +#include "mirror/string-inl.h" namespace art { diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h index 37234e1462..0ee780d32d 100644 --- a/runtime/interpreter/interpreter_common.h +++ b/runtime/interpreter/interpreter_common.h @@ -35,6 +35,7 @@ #include "base/macros.h" #include "base/mutex.h" #include "class_linker-inl.h" +#include "class_root.h" #include "common_dex_operations.h" #include "common_throws.h" #include "dex/dex_file-inl.h" @@ -328,7 +329,7 @@ static inline ObjPtr<mirror::String> ResolveString(Thread* self, ShadowFrame& shadow_frame, dex::StringIndex string_idx) REQUIRES_SHARED(Locks::mutator_lock_) { - ObjPtr<mirror::Class> java_lang_string_class = mirror::String::GetJavaLangString(); + ObjPtr<mirror::Class> java_lang_string_class = GetClassRoot<mirror::String>(); if (UNLIKELY(!java_lang_string_class->IsInitialized())) { ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); StackHandleScope<1> hs(self); diff --git a/runtime/interpreter/unstarted_runtime_test.cc b/runtime/interpreter/unstarted_runtime_test.cc index 98fe8b271b..88cfafba47 100644 --- a/runtime/interpreter/unstarted_runtime_test.cc +++ b/runtime/interpreter/unstarted_runtime_test.cc @@ -388,7 +388,7 @@ TEST_F(UnstartedRuntimeTest, StringCharAt) { TEST_F(UnstartedRuntimeTest, StringInit) { Thread* self = Thread::Current(); ScopedObjectAccess soa(self); - ObjPtr<mirror::Class> klass = mirror::String::GetJavaLangString(); + ObjPtr<mirror::Class> klass = GetClassRoot<mirror::String>(); ArtMethod* method = klass->FindConstructor("(Ljava/lang/String;)V", Runtime::Current()->GetClassLinker()->GetImagePointerSize()); @@ -537,7 +537,7 @@ TEST_F(UnstartedRuntimeTest, SystemArrayCopyObjectArrayTest) { tmp, false, object_class.Get(), - mirror::String::GetJavaLangString(), + GetClassRoot<mirror::String>(), hs_src, 1, hs_dst, @@ -551,7 +551,7 @@ TEST_F(UnstartedRuntimeTest, SystemArrayCopyObjectArrayTest) { { StackHandleScope<3> hs_src(self); hs_src.NewHandle(mirror::String::AllocFromModifiedUtf8(self, "1")); - hs_src.NewHandle(mirror::String::GetJavaLangString()); + hs_src.NewHandle(GetClassRoot<mirror::String>()); hs_src.NewHandle(mirror::String::AllocFromModifiedUtf8(self, "3")); StackHandleScope<3> hs_dst(self); @@ -568,7 +568,7 @@ TEST_F(UnstartedRuntimeTest, SystemArrayCopyObjectArrayTest) { tmp, true, object_class.Get(), - mirror::String::GetJavaLangString(), + GetClassRoot<mirror::String>(), hs_src, 0, hs_dst, @@ -1348,7 +1348,7 @@ TEST_F(UnstartedRuntimeTest, ConstructorNewInstance0) { ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); // Get Throwable. - Handle<mirror::Class> throw_class = hs.NewHandle(mirror::Throwable::GetJavaLangThrowable()); + Handle<mirror::Class> throw_class = hs.NewHandle(GetClassRoot<mirror::Throwable>()); ASSERT_TRUE(class_linker->EnsureInitialized(self, throw_class, true, true)); // Get an input object. @@ -1387,8 +1387,8 @@ TEST_F(UnstartedRuntimeTest, ConstructorNewInstance0) { // Should be a new object. ASSERT_NE(result.GetL(), input.Get()); - // Should be a String. - ASSERT_EQ(mirror::Throwable::GetJavaLangThrowable(), result.GetL()->GetClass()); + // Should be of type Throwable. + ASSERT_OBJ_PTR_EQ(GetClassRoot<mirror::Throwable>(), result.GetL()->GetClass()); // Should have the right string. ObjPtr<mirror::String> result_msg = reinterpret_cast<mirror::Throwable*>(result.GetL())->GetDetailMessage(); diff --git a/runtime/jit/profiling_info_test.cc b/runtime/jit/profiling_info_test.cc new file mode 100644 index 0000000000..106a80a568 --- /dev/null +++ b/runtime/jit/profiling_info_test.cc @@ -0,0 +1,329 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <gtest/gtest.h> +#include <stdio.h> + +#include "art_method-inl.h" +#include "base/unix_file/fd_file.h" +#include "class_linker-inl.h" +#include "common_runtime_test.h" +#include "dex/dex_file.h" +#include "dex/dex_file_loader.h" +#include "dex/method_reference.h" +#include "dex/type_reference.h" +#include "handle_scope-inl.h" +#include "linear_alloc.h" +#include "mirror/class-inl.h" +#include "mirror/class_loader.h" +#include "profile/profile_compilation_info.h" +#include "scoped_thread_state_change-inl.h" +#include "ziparchive/zip_writer.h" + +namespace art { + +using Hotness = ProfileCompilationInfo::MethodHotness; + +static constexpr size_t kMaxMethodIds = 65535; + +class ProfileCompilationInfoTest : public CommonRuntimeTest { + public: + void PostRuntimeCreate() OVERRIDE { + allocator_.reset(new ArenaAllocator(Runtime::Current()->GetArenaPool())); + } + + protected: + std::vector<ArtMethod*> GetVirtualMethods(jobject class_loader, + const std::string& clazz) { + ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); + Thread* self = Thread::Current(); + ScopedObjectAccess soa(self); + StackHandleScope<1> hs(self); + Handle<mirror::ClassLoader> h_loader( + hs.NewHandle(self->DecodeJObject(class_loader)->AsClassLoader())); + ObjPtr<mirror::Class> klass = class_linker->FindClass(self, clazz.c_str(), h_loader); + + const auto pointer_size = class_linker->GetImagePointerSize(); + std::vector<ArtMethod*> methods; + for (auto& m : klass->GetVirtualMethods(pointer_size)) { + methods.push_back(&m); + } + return methods; + } + + bool AddMethod(const std::string& dex_location, + uint32_t checksum, + uint16_t method_index, + ProfileCompilationInfo* info) { + return info->AddMethodIndex(Hotness::kFlagHot, + dex_location, + checksum, + method_index, + kMaxMethodIds); + } + + bool AddMethod(const std::string& dex_location, + uint32_t checksum, + uint16_t method_index, + const ProfileCompilationInfo::OfflineProfileMethodInfo& pmi, + ProfileCompilationInfo* info) { + return info->AddMethod( + dex_location, checksum, method_index, kMaxMethodIds, pmi, Hotness::kFlagPostStartup); + } + + bool AddClass(const std::string& dex_location, + uint32_t checksum, + dex::TypeIndex type_index, + ProfileCompilationInfo* info) { + DexCacheResolvedClasses classes(dex_location, dex_location, checksum, kMaxMethodIds); + classes.AddClass(type_index); + return info->AddClasses({classes}); + } + + uint32_t GetFd(const ScratchFile& file) { + return static_cast<uint32_t>(file.GetFd()); + } + + bool SaveProfilingInfo( + const std::string& filename, + const std::vector<ArtMethod*>& methods, + const std::set<DexCacheResolvedClasses>& resolved_classes, + Hotness::Flag flags) { + ProfileCompilationInfo info; + std::vector<ProfileMethodInfo> profile_methods; + ScopedObjectAccess soa(Thread::Current()); + for (ArtMethod* method : methods) { + profile_methods.emplace_back( + MethodReference(method->GetDexFile(), method->GetDexMethodIndex())); + } + if (!info.AddMethods(profile_methods, flags) || !info.AddClasses(resolved_classes)) { + return false; + } + if (info.GetNumberOfMethods() != profile_methods.size()) { + return false; + } + ProfileCompilationInfo file_profile; + if (!file_profile.Load(filename, false)) { + return false; + } + if (!info.MergeWith(file_profile)) { + return false; + } + + return info.Save(filename, nullptr); + } + + // Saves the given art methods to a profile backed by 'filename' and adds + // some fake inline caches to it. The added inline caches are returned in + // the out map `profile_methods_map`. + bool SaveProfilingInfoWithFakeInlineCaches( + const std::string& filename, + const std::vector<ArtMethod*>& methods, + Hotness::Flag flags, + /*out*/ SafeMap<ArtMethod*, ProfileMethodInfo>* profile_methods_map) { + ProfileCompilationInfo info; + std::vector<ProfileMethodInfo> profile_methods; + ScopedObjectAccess soa(Thread::Current()); + for (ArtMethod* method : methods) { + std::vector<ProfileMethodInfo::ProfileInlineCache> caches; + // Monomorphic + for (uint16_t dex_pc = 0; dex_pc < 11; dex_pc++) { + std::vector<TypeReference> classes; + classes.emplace_back(method->GetDexFile(), dex::TypeIndex(0)); + caches.emplace_back(dex_pc, /*is_missing_types*/false, classes); + } + // Polymorphic + for (uint16_t dex_pc = 11; dex_pc < 22; dex_pc++) { + std::vector<TypeReference> classes; + for (uint16_t k = 0; k < InlineCache::kIndividualCacheSize / 2; k++) { + classes.emplace_back(method->GetDexFile(), dex::TypeIndex(k)); + } + caches.emplace_back(dex_pc, /*is_missing_types*/false, classes); + } + // Megamorphic + for (uint16_t dex_pc = 22; dex_pc < 33; dex_pc++) { + std::vector<TypeReference> classes; + for (uint16_t k = 0; k < 2 * InlineCache::kIndividualCacheSize; k++) { + classes.emplace_back(method->GetDexFile(), dex::TypeIndex(k)); + } + caches.emplace_back(dex_pc, /*is_missing_types*/false, classes); + } + // Missing types + for (uint16_t dex_pc = 33; dex_pc < 44; dex_pc++) { + std::vector<TypeReference> classes; + caches.emplace_back(dex_pc, /*is_missing_types*/true, classes); + } + ProfileMethodInfo pmi(MethodReference(method->GetDexFile(), + method->GetDexMethodIndex()), + caches); + profile_methods.push_back(pmi); + profile_methods_map->Put(method, pmi); + } + + if (!info.AddMethods(profile_methods, flags) + || info.GetNumberOfMethods() != profile_methods.size()) { + return false; + } + return info.Save(filename, nullptr); + } + + // Creates an inline cache which will be destructed at the end of the test. + ProfileCompilationInfo::InlineCacheMap* CreateInlineCacheMap() { + used_inline_caches.emplace_back(new ProfileCompilationInfo::InlineCacheMap( + std::less<uint16_t>(), allocator_->Adapter(kArenaAllocProfile))); + return used_inline_caches.back().get(); + } + + ProfileCompilationInfo::OfflineProfileMethodInfo ConvertProfileMethodInfo( + const ProfileMethodInfo& pmi) { + ProfileCompilationInfo::InlineCacheMap* ic_map = CreateInlineCacheMap(); + ProfileCompilationInfo::OfflineProfileMethodInfo offline_pmi(ic_map); + SafeMap<DexFile*, uint8_t> dex_map; // dex files to profile index + for (const auto& inline_cache : pmi.inline_caches) { + ProfileCompilationInfo::DexPcData& dex_pc_data = + ic_map->FindOrAdd( + inline_cache.dex_pc, ProfileCompilationInfo::DexPcData(allocator_.get()))->second; + if (inline_cache.is_missing_types) { + dex_pc_data.SetIsMissingTypes(); + } + for (const auto& class_ref : inline_cache.classes) { + uint8_t dex_profile_index = dex_map.FindOrAdd(const_cast<DexFile*>(class_ref.dex_file), + static_cast<uint8_t>(dex_map.size()))->second; + dex_pc_data.AddClass(dex_profile_index, class_ref.TypeIndex()); + if (dex_profile_index >= offline_pmi.dex_references.size()) { + // This is a new dex. + const std::string& dex_key = ProfileCompilationInfo::GetProfileDexFileKey( + class_ref.dex_file->GetLocation()); + offline_pmi.dex_references.emplace_back(dex_key, + class_ref.dex_file->GetLocationChecksum(), + class_ref.dex_file->NumMethodIds()); + } + } + } + return offline_pmi; + } + + // Cannot sizeof the actual arrays so hard code the values here. + // They should not change anyway. + static constexpr int kProfileMagicSize = 4; + static constexpr int kProfileVersionSize = 4; + + std::unique_ptr<ArenaAllocator> allocator_; + + // Cache of inline caches generated during tests. + // This makes it easier to pass data between different utilities and ensure that + // caches are destructed at the end of the test. + std::vector<std::unique_ptr<ProfileCompilationInfo::InlineCacheMap>> used_inline_caches; +}; + +TEST_F(ProfileCompilationInfoTest, SaveArtMethods) { + ScratchFile profile; + + Thread* self = Thread::Current(); + jobject class_loader; + { + ScopedObjectAccess soa(self); + class_loader = LoadDex("ProfileTestMultiDex"); + } + ASSERT_NE(class_loader, nullptr); + + // Save virtual methods from Main. + std::set<DexCacheResolvedClasses> resolved_classes; + std::vector<ArtMethod*> main_methods = GetVirtualMethods(class_loader, "LMain;"); + ASSERT_TRUE(SaveProfilingInfo( + profile.GetFilename(), main_methods, resolved_classes, Hotness::kFlagPostStartup)); + + // Check that what we saved is in the profile. + ProfileCompilationInfo info1; + ASSERT_TRUE(info1.Load(GetFd(profile))); + ASSERT_EQ(info1.GetNumberOfMethods(), main_methods.size()); + { + ScopedObjectAccess soa(self); + for (ArtMethod* m : main_methods) { + Hotness h = info1.GetMethodHotness(MethodReference(m->GetDexFile(), m->GetDexMethodIndex())); + ASSERT_TRUE(h.IsHot()); + ASSERT_TRUE(h.IsPostStartup()); + } + } + + // Save virtual methods from Second. + std::vector<ArtMethod*> second_methods = GetVirtualMethods(class_loader, "LSecond;"); + ASSERT_TRUE(SaveProfilingInfo( + profile.GetFilename(), second_methods, resolved_classes, Hotness::kFlagStartup)); + + // Check that what we saved is in the profile (methods form Main and Second). + ProfileCompilationInfo info2; + ASSERT_TRUE(profile.GetFile()->ResetOffset()); + ASSERT_TRUE(info2.Load(GetFd(profile))); + ASSERT_EQ(info2.GetNumberOfMethods(), main_methods.size() + second_methods.size()); + { + ScopedObjectAccess soa(self); + for (ArtMethod* m : main_methods) { + Hotness h = info2.GetMethodHotness(MethodReference(m->GetDexFile(), m->GetDexMethodIndex())); + ASSERT_TRUE(h.IsHot()); + ASSERT_TRUE(h.IsPostStartup()); + } + for (ArtMethod* m : second_methods) { + Hotness h = info2.GetMethodHotness(MethodReference(m->GetDexFile(), m->GetDexMethodIndex())); + ASSERT_TRUE(h.IsHot()); + ASSERT_TRUE(h.IsStartup()); + } + } +} + +TEST_F(ProfileCompilationInfoTest, SaveArtMethodsWithInlineCaches) { + ScratchFile profile; + + Thread* self = Thread::Current(); + jobject class_loader; + { + ScopedObjectAccess soa(self); + class_loader = LoadDex("ProfileTestMultiDex"); + } + ASSERT_NE(class_loader, nullptr); + + // Save virtual methods from Main. + std::set<DexCacheResolvedClasses> resolved_classes; + std::vector<ArtMethod*> main_methods = GetVirtualMethods(class_loader, "LMain;"); + + SafeMap<ArtMethod*, ProfileMethodInfo> profile_methods_map; + ASSERT_TRUE(SaveProfilingInfoWithFakeInlineCaches( + profile.GetFilename(), main_methods, Hotness::kFlagStartup, &profile_methods_map)); + + // Check that what we saved is in the profile. + ProfileCompilationInfo info; + ASSERT_TRUE(info.Load(GetFd(profile))); + ASSERT_EQ(info.GetNumberOfMethods(), main_methods.size()); + { + ScopedObjectAccess soa(self); + for (ArtMethod* m : main_methods) { + Hotness h = info.GetMethodHotness(MethodReference(m->GetDexFile(), m->GetDexMethodIndex())); + ASSERT_TRUE(h.IsHot()); + ASSERT_TRUE(h.IsStartup()); + const ProfileMethodInfo& pmi = profile_methods_map.find(m)->second; + std::unique_ptr<ProfileCompilationInfo::OfflineProfileMethodInfo> offline_pmi = + info.GetMethod(m->GetDexFile()->GetLocation(), + m->GetDexFile()->GetLocationChecksum(), + m->GetDexMethodIndex()); + ASSERT_TRUE(offline_pmi != nullptr); + ProfileCompilationInfo::OfflineProfileMethodInfo converted_pmi = + ConvertProfileMethodInfo(pmi); + ASSERT_EQ(converted_pmi, *offline_pmi); + } + } +} + +} // namespace art diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc index ad6b37b86a..cb2708d0cb 100644 --- a/runtime/mirror/class.cc +++ b/runtime/mirror/class.cc @@ -39,6 +39,7 @@ #include "object-refvisitor-inl.h" #include "object_array-inl.h" #include "object_lock.h" +#include "string-inl.h" #include "runtime.h" #include "thread.h" #include "throwable.h" @@ -1460,12 +1461,12 @@ template<VerifyObjectFlags kVerifyFlags> void Class::GetAccessFlagsDCheck() { // circularity issue during loading the names of its members DCHECK(IsIdxLoaded<kVerifyFlags>() || IsRetired<kVerifyFlags>() || IsErroneous<static_cast<VerifyObjectFlags>(kVerifyFlags & ~kVerifyThis)>() || - this == String::GetJavaLangString()) + this == GetClassRoot<String>()) << "IsIdxLoaded=" << IsIdxLoaded<kVerifyFlags>() << " IsRetired=" << IsRetired<kVerifyFlags>() << " IsErroneous=" << IsErroneous<static_cast<VerifyObjectFlags>(kVerifyFlags & ~kVerifyThis)>() - << " IsString=" << (this == String::GetJavaLangString()) + << " IsString=" << (this == GetClassRoot<String>()) << " status= " << GetStatus<kVerifyFlags>() << " descriptor=" << PrettyDescriptor(); } diff --git a/runtime/mirror/emulated_stack_frame.cc b/runtime/mirror/emulated_stack_frame.cc index 527408b3e5..5595102866 100644 --- a/runtime/mirror/emulated_stack_frame.cc +++ b/runtime/mirror/emulated_stack_frame.cc @@ -27,8 +27,6 @@ namespace art { namespace mirror { -GcRoot<mirror::Class> EmulatedStackFrame::static_class_; - // Calculates the size of a stack frame based on the size of its argument // types and return types. static void CalculateFrameAndReferencesSize(ObjPtr<mirror::ObjectArray<mirror::Class>> p_types, @@ -192,7 +190,7 @@ mirror::EmulatedStackFrame* EmulatedStackFrame::CreateFromShadowFrameAndArgs( // Step 5: Construct the EmulatedStackFrame object. Handle<EmulatedStackFrame> sf(hs.NewHandle( - ObjPtr<EmulatedStackFrame>::DownCast(StaticClass()->AllocObject(self)))); + ObjPtr<EmulatedStackFrame>::DownCast(GetClassRoot<EmulatedStackFrame>()->AllocObject(self)))); sf->SetFieldObject<false>(CallsiteTypeOffset(), caller_type.Get()); sf->SetFieldObject<false>(TypeOffset(), callee_type.Get()); sf->SetFieldObject<false>(ReferencesOffset(), references.Get()); @@ -272,20 +270,5 @@ void EmulatedStackFrame::SetReturnValue(Thread* self, const JValue& value) { } } -void EmulatedStackFrame::SetClass(Class* klass) { - CHECK(static_class_.IsNull()) << static_class_.Read() << " " << klass; - CHECK(klass != nullptr); - static_class_ = GcRoot<Class>(klass); -} - -void EmulatedStackFrame::ResetClass() { - CHECK(!static_class_.IsNull()); - static_class_ = GcRoot<Class>(nullptr); -} - -void EmulatedStackFrame::VisitRoots(RootVisitor* visitor) { - static_class_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass)); -} - } // namespace mirror } // namespace art diff --git a/runtime/mirror/emulated_stack_frame.h b/runtime/mirror/emulated_stack_frame.h index 23626f46e0..ec45f57a4d 100644 --- a/runtime/mirror/emulated_stack_frame.h +++ b/runtime/mirror/emulated_stack_frame.h @@ -64,15 +64,7 @@ class MANAGED EmulatedStackFrame : public Object { return GetReferences()->Get(0); } - static void SetClass(Class* klass) REQUIRES_SHARED(Locks::mutator_lock_); - static void ResetClass() REQUIRES_SHARED(Locks::mutator_lock_); - static void VisitRoots(RootVisitor* visitor) REQUIRES_SHARED(Locks::mutator_lock_); - private: - static mirror::Class* StaticClass() REQUIRES_SHARED(Locks::mutator_lock_) { - return static_class_.Read(); - } - mirror::ObjectArray<mirror::Object>* GetReferences() REQUIRES_SHARED(Locks::mutator_lock_) { return GetFieldObject<mirror::ObjectArray<mirror::Object>>( OFFSET_OF_OBJECT_MEMBER(EmulatedStackFrame, references_)); @@ -104,8 +96,6 @@ class MANAGED EmulatedStackFrame : public Object { HeapReference<mirror::ByteArray> stack_frame_; HeapReference<mirror::MethodType> type_; - static GcRoot<mirror::Class> static_class_; // dalvik.system.EmulatedStackFrame.class - friend struct art::EmulatedStackFrameOffsets; // for verifying offset information DISALLOW_IMPLICIT_CONSTRUCTORS(EmulatedStackFrame); }; diff --git a/runtime/mirror/object-inl.h b/runtime/mirror/object-inl.h index c7561f4278..bfebd5d365 100644 --- a/runtime/mirror/object-inl.h +++ b/runtime/mirror/object-inl.h @@ -37,7 +37,7 @@ #include "read_barrier-inl.h" #include "reference.h" #include "runtime.h" -#include "string-inl.h" +#include "string.h" #include "throwable.h" namespace art { diff --git a/runtime/mirror/stack_trace_element.cc b/runtime/mirror/stack_trace_element.cc index bb3242e035..ff353d8939 100644 --- a/runtime/mirror/stack_trace_element.cc +++ b/runtime/mirror/stack_trace_element.cc @@ -18,6 +18,7 @@ #include "class-inl.h" #include "class.h" +#include "class_root.h" #include "gc/accounting/card_table-inl.h" #include "gc_root-inl.h" #include "handle_scope-inl.h" @@ -27,26 +28,13 @@ namespace art { namespace mirror { -GcRoot<Class> StackTraceElement::java_lang_StackTraceElement_; - -void StackTraceElement::SetClass(ObjPtr<Class> java_lang_StackTraceElement) { - CHECK(java_lang_StackTraceElement_.IsNull()); - CHECK(java_lang_StackTraceElement != nullptr); - java_lang_StackTraceElement_ = GcRoot<Class>(java_lang_StackTraceElement); -} - -void StackTraceElement::ResetClass() { - CHECK(!java_lang_StackTraceElement_.IsNull()); - java_lang_StackTraceElement_ = GcRoot<Class>(nullptr); -} - StackTraceElement* StackTraceElement::Alloc(Thread* self, Handle<String> declaring_class, Handle<String> method_name, Handle<String> file_name, int32_t line_number) { ObjPtr<StackTraceElement> trace = - ObjPtr<StackTraceElement>::DownCast(GetStackTraceElement()->AllocObject(self)); + ObjPtr<StackTraceElement>::DownCast(GetClassRoot<StackTraceElement>()->AllocObject(self)); if (LIKELY(trace != nullptr)) { if (Runtime::Current()->IsActiveTransaction()) { trace->Init<true>(declaring_class.Get(), method_name.Get(), file_name.Get(), line_number); @@ -72,10 +60,5 @@ void StackTraceElement::Init(ObjPtr<String> declaring_class, line_number); } -void StackTraceElement::VisitRoots(RootVisitor* visitor) { - java_lang_StackTraceElement_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass)); -} - - } // namespace mirror } // namespace art diff --git a/runtime/mirror/stack_trace_element.h b/runtime/mirror/stack_trace_element.h index 87e8a1f659..f25211c397 100644 --- a/runtime/mirror/stack_trace_element.h +++ b/runtime/mirror/stack_trace_element.h @@ -53,15 +53,6 @@ class MANAGED StackTraceElement FINAL : public Object { int32_t line_number) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); - static void SetClass(ObjPtr<Class> java_lang_StackTraceElement); - static void ResetClass(); - static void VisitRoots(RootVisitor* visitor) - REQUIRES_SHARED(Locks::mutator_lock_); - static Class* GetStackTraceElement() REQUIRES_SHARED(Locks::mutator_lock_) { - DCHECK(!java_lang_StackTraceElement_.IsNull()); - return java_lang_StackTraceElement_.Read(); - } - private: // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses". HeapReference<String> declaring_class_; @@ -76,8 +67,6 @@ class MANAGED StackTraceElement FINAL : public Object { int32_t line_number) REQUIRES_SHARED(Locks::mutator_lock_); - static GcRoot<Class> java_lang_StackTraceElement_; - friend struct art::StackTraceElementOffsets; // for verifying offset information DISALLOW_IMPLICIT_CONSTRUCTORS(StackTraceElement); }; diff --git a/runtime/mirror/string-inl.h b/runtime/mirror/string-inl.h index a60861cc28..8fa2c6cf7f 100644 --- a/runtime/mirror/string-inl.h +++ b/runtime/mirror/string-inl.h @@ -25,6 +25,7 @@ #include "base/globals.h" #include "base/utils.h" #include "class.h" +#include "class_root.h" #include "common_throws.h" #include "dex/utf.h" #include "gc/heap-inl.h" @@ -194,21 +195,6 @@ int32_t String::FastIndexOf(MemoryType* chars, int32_t ch, int32_t start) { return -1; } -template<VerifyObjectFlags kVerifyFlags> -inline size_t String::SizeOf() { - size_t size = sizeof(String); - if (IsCompressed()) { - size += (sizeof(uint8_t) * GetLength<kVerifyFlags>()); - } else { - size += (sizeof(uint16_t) * GetLength<kVerifyFlags>()); - } - // String.equals() intrinsics assume zero-padding up to kObjectAlignment, - // so make sure the zero-padding is actually copied around if GC compaction - // chooses to copy only SizeOf() bytes. - // http://b/23528461 - return RoundUp(size, kObjectAlignment); -} - template <bool kIsInstrumented, typename PreFenceVisitor> inline String* String::Alloc(Thread* self, int32_t utf16_length_with_flag, gc::AllocatorType allocator_type, @@ -226,7 +212,8 @@ inline String* String::Alloc(Thread* self, int32_t utf16_length_with_flag, // http://b/23528461 size_t alloc_size = RoundUp(size, kObjectAlignment); - Class* string_class = GetJavaLangString(); + Runtime* runtime = Runtime::Current(); + ObjPtr<Class> string_class = GetClassRoot<String>(runtime->GetClassLinker()); // Check for overflow and throw OutOfMemoryError if this was an unreasonable request. // Do this by comparing with the maximum length that will _not_ cause an overflow. const size_t overflow_length = (-header_size) / block_size; // Unsigned arithmetic. @@ -242,7 +229,7 @@ inline String* String::Alloc(Thread* self, int32_t utf16_length_with_flag, return nullptr; } - gc::Heap* heap = Runtime::Current()->GetHeap(); + gc::Heap* heap = runtime->GetHeap(); return down_cast<String*>( heap->AllocObjectWithAllocator<kIsInstrumented, true>(self, string_class, alloc_size, allocator_type, pre_fence_visitor)); diff --git a/runtime/mirror/string.cc b/runtime/mirror/string.cc index 6208a962e5..b76ca1968a 100644 --- a/runtime/mirror/string.cc +++ b/runtime/mirror/string.cc @@ -35,9 +35,6 @@ namespace art { namespace mirror { -// TODO: get global references for these -GcRoot<Class> String::java_lang_String_; - int32_t String::FastIndexOf(int32_t ch, int32_t start) { int32_t count = GetLength(); if (start < 0) { @@ -52,18 +49,6 @@ int32_t String::FastIndexOf(int32_t ch, int32_t start) { } } -void String::SetClass(ObjPtr<Class> java_lang_String) { - CHECK(java_lang_String_.IsNull()); - CHECK(java_lang_String != nullptr); - CHECK(java_lang_String->IsStringClass()); - java_lang_String_ = GcRoot<Class>(java_lang_String); -} - -void String::ResetClass() { - CHECK(!java_lang_String_.IsNull()); - java_lang_String_ = GcRoot<Class>(nullptr); -} - int String::ComputeHashCode() { int32_t hash_code = 0; if (IsCompressed()) { @@ -372,10 +357,6 @@ int32_t String::CompareTo(ObjPtr<String> rhs) { return count_diff; } -void String::VisitRoots(RootVisitor* visitor) { - java_lang_String_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass)); -} - CharArray* String::ToCharArray(Thread* self) { StackHandleScope<1> hs(self); Handle<String> string(hs.NewHandle(this)); diff --git a/runtime/mirror/string.h b/runtime/mirror/string.h index c45dc499e5..598175b749 100644 --- a/runtime/mirror/string.h +++ b/runtime/mirror/string.h @@ -17,6 +17,8 @@ #ifndef ART_RUNTIME_MIRROR_STRING_H_ #define ART_RUNTIME_MIRROR_STRING_H_ +#include "base/bit_utils.h" +#include "base/globals.h" #include "gc/allocator_type.h" #include "gc_root-inl.h" #include "class.h" @@ -66,7 +68,19 @@ class MANAGED String FINAL : public Object { } template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> - size_t SizeOf() REQUIRES_SHARED(Locks::mutator_lock_); + size_t SizeOf() REQUIRES_SHARED(Locks::mutator_lock_) { + size_t size = sizeof(String); + if (IsCompressed()) { + size += (sizeof(uint8_t) * GetLength<kVerifyFlags>()); + } else { + size += (sizeof(uint16_t) * GetLength<kVerifyFlags>()); + } + // String.equals() intrinsics assume zero-padding up to kObjectAlignment, + // so make sure the zero-padding is actually copied around if GC compaction + // chooses to copy only SizeOf() bytes. + // http://b/23528461 + return RoundUp(size, kObjectAlignment); + } // Taking out the first/uppermost bit because it is not part of actual length value template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> @@ -214,15 +228,6 @@ class MANAGED String FINAL : public Object { : length; } - static Class* GetJavaLangString() REQUIRES_SHARED(Locks::mutator_lock_) { - DCHECK(!java_lang_String_.IsNull()); - return java_lang_String_.Read(); - } - - static void SetClass(ObjPtr<Class> java_lang_String) REQUIRES_SHARED(Locks::mutator_lock_); - static void ResetClass() REQUIRES_SHARED(Locks::mutator_lock_); - static void VisitRoots(RootVisitor* visitor) REQUIRES_SHARED(Locks::mutator_lock_); - // Returns a human-readable equivalent of 'descriptor'. So "I" would be "int", // "[[I" would be "int[][]", "[Ljava/lang/String;" would be // "java.lang.String[]", and so forth. @@ -267,10 +272,7 @@ class MANAGED String FINAL : public Object { uint8_t value_compressed_[0]; }; - static GcRoot<Class> java_lang_String_; - friend struct art::StringOffsets; // for verifying offset information - ART_FRIEND_TEST(art::StubTest, ReadBarrierForRoot); // For java_lang_String_. DISALLOW_IMPLICIT_CONSTRUCTORS(String); }; diff --git a/runtime/mirror/throwable.cc b/runtime/mirror/throwable.cc index 70069733d1..82e295a616 100644 --- a/runtime/mirror/throwable.cc +++ b/runtime/mirror/throwable.cc @@ -22,6 +22,7 @@ #include "base/enums.h" #include "base/utils.h" #include "class-inl.h" +#include "class_root.h" #include "dex/dex_file-inl.h" #include "gc/accounting/card_table-inl.h" #include "object-inl.h" @@ -36,8 +37,6 @@ namespace mirror { using android::base::StringPrintf; -GcRoot<Class> Throwable::java_lang_Throwable_; - void Throwable::SetDetailMessage(ObjPtr<String> new_detail_message) { if (Runtime::Current()->IsActiveTransaction()) { SetFieldObject<true>(OFFSET_OF_OBJECT_MEMBER(Throwable, detail_message_), new_detail_message); @@ -128,8 +127,7 @@ std::string Throwable::Dump() { } else { ObjPtr<Object> stack_trace = GetStackTrace(); if (stack_trace != nullptr && stack_trace->IsObjectArray()) { - CHECK_EQ(stack_trace->GetClass()->GetComponentType(), - StackTraceElement::GetStackTraceElement()); + CHECK_EQ(stack_trace->GetClass()->GetComponentType(), GetClassRoot<StackTraceElement>()); ObjPtr<ObjectArray<StackTraceElement>> ste_array = ObjPtr<ObjectArray<StackTraceElement>>::DownCast(stack_trace); if (ste_array->GetLength() == 0) { @@ -159,21 +157,6 @@ std::string Throwable::Dump() { return result; } -void Throwable::SetClass(ObjPtr<Class> java_lang_Throwable) { - CHECK(java_lang_Throwable_.IsNull()); - CHECK(java_lang_Throwable != nullptr); - java_lang_Throwable_ = GcRoot<Class>(java_lang_Throwable); -} - -void Throwable::ResetClass() { - CHECK(!java_lang_Throwable_.IsNull()); - java_lang_Throwable_ = GcRoot<Class>(nullptr); -} - -void Throwable::VisitRoots(RootVisitor* visitor) { - java_lang_Throwable_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass)); -} - Object* Throwable::GetStackState() { return GetFieldObjectVolatile<Object>(OFFSET_OF_OBJECT_MEMBER(Throwable, backtrace_)); } diff --git a/runtime/mirror/throwable.h b/runtime/mirror/throwable.h index b901ca2d00..42c612f8b6 100644 --- a/runtime/mirror/throwable.h +++ b/runtime/mirror/throwable.h @@ -46,18 +46,8 @@ class MANAGED Throwable : public Object { bool IsCheckedException() REQUIRES_SHARED(Locks::mutator_lock_); bool IsError() REQUIRES_SHARED(Locks::mutator_lock_); - static Class* GetJavaLangThrowable() REQUIRES_SHARED(Locks::mutator_lock_) { - DCHECK(!java_lang_Throwable_.IsNull()); - return java_lang_Throwable_.Read(); - } - int32_t GetStackDepth() REQUIRES_SHARED(Locks::mutator_lock_); - static void SetClass(ObjPtr<Class> java_lang_Throwable); - static void ResetClass(); - static void VisitRoots(RootVisitor* visitor) - REQUIRES_SHARED(Locks::mutator_lock_); - private: Object* GetStackState() REQUIRES_SHARED(Locks::mutator_lock_); Object* GetStackTrace() REQUIRES_SHARED(Locks::mutator_lock_); @@ -69,8 +59,6 @@ class MANAGED Throwable : public Object { HeapReference<Object> stack_trace_; HeapReference<Object> suppressed_exceptions_; - static GcRoot<Class> java_lang_Throwable_; - friend struct art::ThrowableOffsets; // for verifying offset information DISALLOW_IMPLICIT_CONSTRUCTORS(Throwable); }; diff --git a/runtime/mirror/var_handle_test.cc b/runtime/mirror/var_handle_test.cc index 2c1283225d..cb2d628b5b 100644 --- a/runtime/mirror/var_handle_test.cc +++ b/runtime/mirror/var_handle_test.cc @@ -92,8 +92,7 @@ class VarHandleTest : public CommonRuntimeTest { ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); Handle<Class> var_type = hs.NewHandle(view_array_class->GetComponentType()); Handle<Class> index_type = hs.NewHandle(class_linker->FindPrimitiveClass('I')); - ObjPtr<mirror::Class> byte_class = class_linker->FindPrimitiveClass('B'); - Handle<Class> byte_array_class(hs.NewHandle(class_linker->FindArrayClass(self, &byte_class))); + Handle<Class> byte_array_class(hs.NewHandle(GetClassRoot<mirror::ByteArray>())); InitializeVarHandle(bvh.Get(), var_type, byte_array_class, index_type, access_modes_bit_mask); bvh->SetFieldBoolean<false>(ByteArrayViewVarHandle::NativeByteOrderOffset(), native_byte_order); return bvh.Get(); @@ -234,8 +233,7 @@ static MethodType* MethodTypeOf(const std::string& method_descriptor) { ScopedObjectAccess soa(self); StackHandleScope<3> hs(self); int ptypes_count = static_cast<int>(descriptors.size()) - 1; - ObjPtr<mirror::Class> class_type = mirror::Class::GetJavaLangClass(); - ObjPtr<mirror::Class> array_of_class = class_linker->FindArrayClass(self, &class_type); + ObjPtr<mirror::Class> array_of_class = GetClassRoot<mirror::ObjectArray<mirror::Class>>(); Handle<ObjectArray<Class>> ptypes = hs.NewHandle( ObjectArray<Class>::Alloc(Thread::Current(), array_of_class, ptypes_count)); Handle<mirror::ClassLoader> boot_class_loader = hs.NewHandle<mirror::ClassLoader>(nullptr); @@ -599,10 +597,10 @@ TEST_F(VarHandleTest, ArrayElementVarHandle) { VarHandle::AccessMode::kGetAndBitwiseXorRelease, VarHandle::AccessMode::kGetAndBitwiseXorAcquire); - ObjPtr<mirror::Class> string_class = mirror::String::GetJavaLangString(); - ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); - Handle<Class> string_array_class(hs.NewHandle(class_linker->FindArrayClass(self, &string_class))); - Handle<mirror::ArrayElementVarHandle> vh(hs.NewHandle(CreateArrayElementVarHandle(self, string_array_class, mask))); + Handle<mirror::Class> string_array_class = hs.NewHandle( + GetClassRoot<mirror::ObjectArray<mirror::String>>()); + Handle<mirror::ArrayElementVarHandle> vh( + hs.NewHandle(CreateArrayElementVarHandle(self, string_array_class, mask))); EXPECT_FALSE(vh.IsNull()); // Check access modes @@ -746,11 +744,10 @@ TEST_F(VarHandleTest, ByteArrayViewVarHandle) { VarHandle::AccessMode::kGetAndBitwiseXor, VarHandle::AccessMode::kGetAndBitwiseXorAcquire); - ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); - ObjPtr<mirror::Class> char_class = class_linker->FindPrimitiveClass('C'); - Handle<Class> char_array_class(hs.NewHandle(class_linker->FindArrayClass(self, &char_class))); + Handle<Class> char_array_class(hs.NewHandle(GetClassRoot<mirror::CharArray>())); const bool native_byte_order = true; - Handle<mirror::ByteArrayViewVarHandle> vh(hs.NewHandle(CreateByteArrayViewVarHandle(self, char_array_class, native_byte_order, mask))); + Handle<mirror::ByteArrayViewVarHandle> vh( + hs.NewHandle(CreateByteArrayViewVarHandle(self, char_array_class, native_byte_order, mask))); EXPECT_FALSE(vh.IsNull()); EXPECT_EQ(native_byte_order, vh->GetNativeByteOrder()); @@ -895,11 +892,10 @@ TEST_F(VarHandleTest, ByteBufferViewVarHandle) { VarHandle::AccessMode::kGetAndBitwiseXor, VarHandle::AccessMode::kGetAndBitwiseXorAcquire); - ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); - ObjPtr<mirror::Class> double_class = class_linker->FindPrimitiveClass('D'); - Handle<Class> double_array_class(hs.NewHandle(class_linker->FindArrayClass(self, &double_class))); + Handle<Class> double_array_class(hs.NewHandle(GetClassRoot<mirror::DoubleArray>())); const bool native_byte_order = false; - Handle<mirror::ByteBufferViewVarHandle> vh(hs.NewHandle(CreateByteBufferViewVarHandle(self, double_array_class, native_byte_order, mask))); + Handle<mirror::ByteBufferViewVarHandle> vh(hs.NewHandle( + CreateByteBufferViewVarHandle(self, double_array_class, native_byte_order, mask))); EXPECT_FALSE(vh.IsNull()); EXPECT_EQ(native_byte_order, vh->GetNativeByteOrder()); diff --git a/runtime/native/java_lang_StringFactory.cc b/runtime/native/java_lang_StringFactory.cc index 07e875efcb..3978ca8a36 100644 --- a/runtime/native/java_lang_StringFactory.cc +++ b/runtime/native/java_lang_StringFactory.cc @@ -19,7 +19,7 @@ #include "common_throws.h" #include "jni/jni_internal.h" #include "mirror/object-inl.h" -#include "mirror/string.h" +#include "mirror/string-inl.h" #include "native_util.h" #include "nativehelper/jni_macros.h" #include "nativehelper/scoped_local_ref.h" diff --git a/runtime/native/java_lang_VMClassLoader.cc b/runtime/native/java_lang_VMClassLoader.cc index 0630737d29..b1511c0d88 100644 --- a/runtime/native/java_lang_VMClassLoader.cc +++ b/runtime/native/java_lang_VMClassLoader.cc @@ -20,6 +20,7 @@ #include "class_linker.h" #include "dex/descriptors_names.h" #include "dex/dex_file_loader.h" +#include "dex/utf.h" #include "jni/jni_internal.h" #include "mirror/class_loader.h" #include "mirror/object-inl.h" diff --git a/runtime/oat.h b/runtime/oat.h index 7b8f71a3f3..8069a15661 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: Refactor stackmap encoding. - static constexpr uint8_t kOatVersion[] = { '1', '4', '4', '\0' }; + // Last oat version changed reason: Optimize masks in stack maps. + static constexpr uint8_t kOatVersion[] = { '1', '4', '5', '\0' }; static constexpr const char* kImageLocationKey = "image-location"; static constexpr const char* kDex2OatCmdLineKey = "dex2oat-cmdline"; diff --git a/runtime/quick_exception_handler.cc b/runtime/quick_exception_handler.cc index de613d3b20..26489209b8 100644 --- a/runtime/quick_exception_handler.cc +++ b/runtime/quick_exception_handler.cc @@ -439,7 +439,7 @@ class DeoptimizeStackVisitor FINAL : public StackVisitor { const uint8_t* addr = reinterpret_cast<const uint8_t*>(GetCurrentQuickFrame()) + offset; value = *reinterpret_cast<const uint32_t*>(addr); uint32_t bit = (offset >> 2); - if (bit < code_info.GetNumberOfStackMaskBits() && stack_mask.LoadBit(bit)) { + if (bit < stack_mask.size_in_bits() && stack_mask.LoadBit(bit)) { is_reference = true; } break; diff --git a/runtime/runtime.cc b/runtime/runtime.cc index 630053ac71..6384d01aaf 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -1979,10 +1979,6 @@ void Runtime::VisitConstantRoots(RootVisitor* visitor) { // Visit the classes held as static in mirror classes, these can be visited concurrently and only // need to be visited once per GC since they never change. mirror::Class::VisitRoots(visitor); - mirror::StackTraceElement::VisitRoots(visitor); - mirror::String::VisitRoots(visitor); - mirror::Throwable::VisitRoots(visitor); - mirror::EmulatedStackFrame::VisitRoots(visitor); mirror::ClassExt::VisitRoots(visitor); // Visiting the roots of these ArtMethods is not currently required since all the GcRoots are // null. diff --git a/runtime/stack_map.cc b/runtime/stack_map.cc index 2b7e8dd748..fd0e28d9ac 100644 --- a/runtime/stack_map.cc +++ b/runtime/stack_map.cc @@ -200,7 +200,7 @@ void StackMap::Dump(VariableIndentationOutputStream* vios, << std::dec << ", stack_mask=0b"; BitMemoryRegion stack_mask = code_info.GetStackMaskOf(*this); - for (size_t i = 0, e = code_info.GetNumberOfStackMaskBits(); i < e; ++i) { + for (size_t i = 0, e = stack_mask.size_in_bits(); i < e; ++i) { vios->Stream() << stack_mask.LoadBit(e - i - 1); } vios->Stream() << ")\n"; diff --git a/runtime/stack_map.h b/runtime/stack_map.h index 91cecf0690..1cb9a399f8 100644 --- a/runtime/stack_map.h +++ b/runtime/stack_map.h @@ -799,6 +799,24 @@ class InvokeInfo : public BitTable<3>::Accessor { } }; +// Register masks tend to have many trailing zero bits (caller-saves are usually not encoded), +// therefore it is worth encoding the mask as value+shift. +class RegisterMask : public BitTable<2>::Accessor { + public: + enum Field { + kValue, + kShift, + kCount, + }; + + RegisterMask(const BitTable<kCount>* table, uint32_t row) + : BitTable<kCount>::Accessor(table, row) {} + + ALWAYS_INLINE uint32_t GetMask() const { + return Get<kValue>() << Get<kShift>(); + } +}; + /** * Wrapper around all compiler information collected for a method. * The information is of the form: @@ -833,24 +851,22 @@ class CodeInfo { return DexRegisterLocationCatalog(location_catalog_); } - ALWAYS_INLINE size_t GetNumberOfStackMaskBits() const { - return stack_mask_bits_; - } - ALWAYS_INLINE StackMap GetStackMapAt(size_t index) const { return StackMap(&stack_maps_, index); } BitMemoryRegion GetStackMask(size_t index) const { - return stack_masks_.Subregion(index * stack_mask_bits_, stack_mask_bits_); + return stack_masks_.GetBitMemoryRegion(index); } BitMemoryRegion GetStackMaskOf(const StackMap& stack_map) const { - return GetStackMask(stack_map.GetStackMaskIndex()); + uint32_t index = stack_map.GetStackMaskIndex(); + return (index == StackMap::kNoValue) ? BitMemoryRegion() : GetStackMask(index); } uint32_t GetRegisterMaskOf(const StackMap& stack_map) const { - return register_masks_.Get(stack_map.GetRegisterMaskIndex()); + uint32_t index = stack_map.GetRegisterMaskIndex(); + return (index == StackMap::kNoValue) ? 0 : RegisterMask(®ister_masks_, index).GetMask(); } uint32_t GetNumberOfLocationCatalogEntries() const { @@ -1045,8 +1061,8 @@ class CodeInfo { invoke_infos_.Decode(bit_region, &bit_offset); inline_infos_.Decode(bit_region, &bit_offset); register_masks_.Decode(bit_region, &bit_offset); - stack_mask_bits_ = DecodeVarintBits(bit_region, &bit_offset); - stack_masks_ = bit_region.Subregion(bit_offset, non_header_size * kBitsPerByte - bit_offset); + stack_masks_.Decode(bit_region, &bit_offset); + CHECK_EQ(BitsToBytesRoundUp(bit_offset), non_header_size); } size_t size_; @@ -1056,9 +1072,8 @@ class CodeInfo { BitTable<StackMap::Field::kCount> stack_maps_; BitTable<InvokeInfo::Field::kCount> invoke_infos_; BitTable<InlineInfo::Field::kCount> inline_infos_; - BitTable<1> register_masks_; - uint32_t stack_mask_bits_ = 0; - BitMemoryRegion stack_masks_; + BitTable<RegisterMask::Field::kCount> register_masks_; + BitTable<1> stack_masks_; friend class OatDumper; }; diff --git a/runtime/thread.cc b/runtime/thread.cc index 129bae6d9a..95efc8a42e 100644 --- a/runtime/thread.cc +++ b/runtime/thread.cc @@ -2461,7 +2461,7 @@ class FetchStackTraceVisitor : public StackVisitor { // save frame) ArtMethod* m = GetMethod(); if (skipping_ && !m->IsRuntimeMethod() && - !mirror::Throwable::GetJavaLangThrowable()->IsAssignableFrom(m->GetDeclaringClass())) { + !GetClassRoot<mirror::Throwable>()->IsAssignableFrom(m->GetDeclaringClass())) { skipping_ = false; } if (!skipping_) { @@ -3568,9 +3568,8 @@ class ReferenceMapVisitor : public StackVisitor { T vreg_info(m, code_info, map, visitor_); // Visit stack entries that hold pointers. - const size_t number_of_bits = code_info.GetNumberOfStackMaskBits(); BitMemoryRegion stack_mask = code_info.GetStackMaskOf(map); - for (size_t i = 0; i < number_of_bits; ++i) { + for (size_t i = 0; i < stack_mask.size_in_bits(); ++i) { if (stack_mask.LoadBit(i)) { StackReference<mirror::Object>* ref_addr = vreg_base + i; mirror::Object* ref = ref_addr->AsMirrorPtr(); diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc index 3a49e4d21f..cc71dc5f84 100644 --- a/runtime/verifier/method_verifier.cc +++ b/runtime/verifier/method_verifier.cc @@ -3366,7 +3366,7 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) { } break; } - auto* klass = declaring_class.GetClass(); + ObjPtr<mirror::Class> klass = declaring_class.GetClass(); for (uint32_t i = 0, num_fields = klass->NumInstanceFields(); i < num_fields; ++i) { if (klass->GetInstanceField(i)->IsFinal()) { Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "return-void-no-barrier not expected for " @@ -3529,7 +3529,7 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) { ObjPtr<mirror::Class> klass = linker->ResolveType(handler_type_idx, dex_cache_, class_loader_); if (klass != nullptr) { - if (klass == mirror::Throwable::GetJavaLangThrowable()) { + if (klass == GetClassRoot<mirror::Throwable>()) { has_catch_all_handler = true; } } else { @@ -3667,10 +3667,10 @@ const RegType& MethodVerifier::ResolveClass(dex::TypeIndex class_idx) { UninstantiableError(descriptor); precise = false; } - result = reg_types_.FindClass(klass.Ptr(), precise); + result = reg_types_.FindClass(klass, precise); if (result == nullptr) { const char* descriptor = dex_file_->StringByTypeIdx(class_idx); - result = reg_types_.InsertClass(descriptor, klass.Ptr(), precise); + result = reg_types_.InsertClass(descriptor, klass, precise); } } else { const char* descriptor = dex_file_->StringByTypeIdx(class_idx); @@ -4943,7 +4943,7 @@ const RegType& MethodVerifier::GetDeclaringClass() { const char* descriptor = dex_file_->GetTypeDescriptor(dex_file_->GetTypeId(method_id.class_idx_)); if (method_being_verified_ != nullptr) { - mirror::Class* klass = method_being_verified_->GetDeclaringClass(); + ObjPtr<mirror::Class> klass = method_being_verified_->GetDeclaringClass(); declaring_class_ = &FromClass(descriptor, klass, klass->CannotBeAssignedFromOtherTypes()); } else { declaring_class_ = ®_types_.FromDescriptor(GetClassLoader(), descriptor, false); @@ -5045,7 +5045,7 @@ void MethodVerifier::VisitRoots(RootVisitor* visitor, const RootInfo& root_info) } const RegType& MethodVerifier::FromClass(const char* descriptor, - mirror::Class* klass, + ObjPtr<mirror::Class> klass, bool precise) { DCHECK(klass != nullptr); if (precise && !klass->IsInstantiable() && !klass->IsPrimitive()) { diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h index 531d3dabfa..b2adc62a97 100644 --- a/runtime/verifier/method_verifier.h +++ b/runtime/verifier/method_verifier.h @@ -691,7 +691,7 @@ class MethodVerifier { // non-precise reference will be returned. // Note: we reuse NO_CLASS as this will throw an exception at runtime, when the failing class is // actually touched. - const RegType& FromClass(const char* descriptor, mirror::Class* klass, bool precise) + const RegType& FromClass(const char* descriptor, ObjPtr<mirror::Class> klass, bool precise) REQUIRES_SHARED(Locks::mutator_lock_); ALWAYS_INLINE bool FailOrAbort(bool condition, const char* error_msg, uint32_t work_insn_idx); diff --git a/runtime/verifier/reg_type.cc b/runtime/verifier/reg_type.cc index e7864a28a0..73e516c7bf 100644 --- a/runtime/verifier/reg_type.cc +++ b/runtime/verifier/reg_type.cc @@ -54,17 +54,19 @@ const DoubleHiType* DoubleHiType::instance_ = nullptr; const IntegerType* IntegerType::instance_ = nullptr; const NullType* NullType::instance_ = nullptr; -PrimitiveType::PrimitiveType(mirror::Class* klass, const StringPiece& descriptor, uint16_t cache_id) +PrimitiveType::PrimitiveType(ObjPtr<mirror::Class> klass, + const StringPiece& descriptor, + uint16_t cache_id) : RegType(klass, descriptor, cache_id) { CHECK(klass != nullptr); CHECK(!descriptor.empty()); } -Cat1Type::Cat1Type(mirror::Class* klass, const StringPiece& descriptor, uint16_t cache_id) +Cat1Type::Cat1Type(ObjPtr<mirror::Class> klass, const StringPiece& descriptor, uint16_t cache_id) : PrimitiveType(klass, descriptor, cache_id) { } -Cat2Type::Cat2Type(mirror::Class* klass, const StringPiece& descriptor, uint16_t cache_id) +Cat2Type::Cat2Type(ObjPtr<mirror::Class> klass, const StringPiece& descriptor, uint16_t cache_id) : PrimitiveType(klass, descriptor, cache_id) { } @@ -129,7 +131,7 @@ std::string IntegerType::Dump() const { return "Integer"; } -const DoubleHiType* DoubleHiType::CreateInstance(mirror::Class* klass, +const DoubleHiType* DoubleHiType::CreateInstance(ObjPtr<mirror::Class> klass, const StringPiece& descriptor, uint16_t cache_id) { CHECK(instance_ == nullptr); @@ -144,7 +146,7 @@ void DoubleHiType::Destroy() { } } -const DoubleLoType* DoubleLoType::CreateInstance(mirror::Class* klass, +const DoubleLoType* DoubleLoType::CreateInstance(ObjPtr<mirror::Class> klass, const StringPiece& descriptor, uint16_t cache_id) { CHECK(instance_ == nullptr); @@ -159,14 +161,16 @@ void DoubleLoType::Destroy() { } } -const LongLoType* LongLoType::CreateInstance(mirror::Class* klass, const StringPiece& descriptor, +const LongLoType* LongLoType::CreateInstance(ObjPtr<mirror::Class> klass, + const StringPiece& descriptor, uint16_t cache_id) { CHECK(instance_ == nullptr); instance_ = new LongLoType(klass, descriptor, cache_id); return instance_; } -const LongHiType* LongHiType::CreateInstance(mirror::Class* klass, const StringPiece& descriptor, +const LongHiType* LongHiType::CreateInstance(ObjPtr<mirror::Class> klass, + const StringPiece& descriptor, uint16_t cache_id) { CHECK(instance_ == nullptr); instance_ = new LongHiType(klass, descriptor, cache_id); @@ -187,7 +191,8 @@ void LongLoType::Destroy() { } } -const FloatType* FloatType::CreateInstance(mirror::Class* klass, const StringPiece& descriptor, +const FloatType* FloatType::CreateInstance(ObjPtr<mirror::Class> klass, + const StringPiece& descriptor, uint16_t cache_id) { CHECK(instance_ == nullptr); instance_ = new FloatType(klass, descriptor, cache_id); @@ -201,7 +206,8 @@ void FloatType::Destroy() { } } -const CharType* CharType::CreateInstance(mirror::Class* klass, const StringPiece& descriptor, +const CharType* CharType::CreateInstance(ObjPtr<mirror::Class> klass, + const StringPiece& descriptor, uint16_t cache_id) { CHECK(instance_ == nullptr); instance_ = new CharType(klass, descriptor, cache_id); @@ -215,7 +221,8 @@ void CharType::Destroy() { } } -const ShortType* ShortType::CreateInstance(mirror::Class* klass, const StringPiece& descriptor, +const ShortType* ShortType::CreateInstance(ObjPtr<mirror::Class> klass, + const StringPiece& descriptor, uint16_t cache_id) { CHECK(instance_ == nullptr); instance_ = new ShortType(klass, descriptor, cache_id); @@ -229,7 +236,8 @@ void ShortType::Destroy() { } } -const ByteType* ByteType::CreateInstance(mirror::Class* klass, const StringPiece& descriptor, +const ByteType* ByteType::CreateInstance(ObjPtr<mirror::Class> klass, + const StringPiece& descriptor, uint16_t cache_id) { CHECK(instance_ == nullptr); instance_ = new ByteType(klass, descriptor, cache_id); @@ -243,7 +251,8 @@ void ByteType::Destroy() { } } -const IntegerType* IntegerType::CreateInstance(mirror::Class* klass, const StringPiece& descriptor, +const IntegerType* IntegerType::CreateInstance(ObjPtr<mirror::Class> klass, + const StringPiece& descriptor, uint16_t cache_id) { CHECK(instance_ == nullptr); instance_ = new IntegerType(klass, descriptor, cache_id); @@ -257,7 +266,7 @@ void IntegerType::Destroy() { } } -const ConflictType* ConflictType::CreateInstance(mirror::Class* klass, +const ConflictType* ConflictType::CreateInstance(ObjPtr<mirror::Class> klass, const StringPiece& descriptor, uint16_t cache_id) { CHECK(instance_ == nullptr); @@ -272,8 +281,9 @@ void ConflictType::Destroy() { } } -const BooleanType* BooleanType::CreateInstance(mirror::Class* klass, const StringPiece& descriptor, - uint16_t cache_id) { +const BooleanType* BooleanType::CreateInstance(ObjPtr<mirror::Class> klass, + const StringPiece& descriptor, + uint16_t cache_id) { CHECK(BooleanType::instance_ == nullptr); instance_ = new BooleanType(klass, descriptor, cache_id); return BooleanType::instance_; @@ -290,7 +300,7 @@ std::string UndefinedType::Dump() const REQUIRES_SHARED(Locks::mutator_lock_) { return "Undefined"; } -const UndefinedType* UndefinedType::CreateInstance(mirror::Class* klass, +const UndefinedType* UndefinedType::CreateInstance(ObjPtr<mirror::Class> klass, const StringPiece& descriptor, uint16_t cache_id) { CHECK(instance_ == nullptr); @@ -305,7 +315,8 @@ void UndefinedType::Destroy() { } } -PreciseReferenceType::PreciseReferenceType(mirror::Class* klass, const StringPiece& descriptor, +PreciseReferenceType::PreciseReferenceType(ObjPtr<mirror::Class> klass, + const StringPiece& descriptor, uint16_t cache_id) : RegType(klass, descriptor, cache_id) { // Note: no check for IsInstantiable() here. We may produce this in case an InstantiationError @@ -505,7 +516,7 @@ bool UnresolvedType::IsNonZeroReferenceTypes() const { const RegType& RegType::GetSuperClass(RegTypeCache* cache) const { if (!IsUnresolvedTypes()) { - mirror::Class* super_klass = GetClass()->GetSuperClass(); + ObjPtr<mirror::Class> super_klass = GetClass()->GetSuperClass(); if (super_klass != nullptr) { // A super class of a precise type isn't precise as a precise type indicates the register // holds exactly that type. @@ -543,7 +554,7 @@ bool RegType::IsObjectArrayTypes() const REQUIRES_SHARED(Locks::mutator_lock_) { DCHECK(descriptor_[1] == 'L' || descriptor_[1] == '['); return descriptor_[0] == '['; } else if (HasClass()) { - mirror::Class* type = GetClass(); + ObjPtr<mirror::Class> type = GetClass(); return type->IsArrayClass() && !type->GetComponentType()->IsPrimitive(); } else { return false; @@ -569,7 +580,7 @@ bool RegType::IsArrayTypes() const REQUIRES_SHARED(Locks::mutator_lock_) { bool RegType::IsJavaLangObjectArray() const { if (HasClass()) { - mirror::Class* type = GetClass(); + ObjPtr<mirror::Class> type = GetClass(); return type->IsArrayClass() && type->GetComponentType()->IsObjectClass(); } return false; @@ -712,11 +723,10 @@ const RegType& RegType::Merge(const RegType& incoming_type, // mechanics to continue. return reg_types->FromUnresolvedMerge(*this, incoming_type, verifier); } else { // Two reference types, compute Join - mirror::Class* c1 = GetClass(); - mirror::Class* c2 = incoming_type.GetClass(); - DCHECK(c1 != nullptr && !c1->IsPrimitive()); - DCHECK(c2 != nullptr && !c2->IsPrimitive()); - mirror::Class* join_class = ClassJoin(c1, c2); + // Do not cache the classes as ClassJoin() can suspend and invalidate ObjPtr<>s. + DCHECK(GetClass() != nullptr && !GetClass()->IsPrimitive()); + DCHECK(incoming_type.GetClass() != nullptr && !incoming_type.GetClass()->IsPrimitive()); + ObjPtr<mirror::Class> join_class = ClassJoin(GetClass(), incoming_type.GetClass()); if (UNLIKELY(join_class == nullptr)) { // Internal error joining the classes (e.g., OOME). Report an unresolved reference type. // We cannot report an unresolved merge type, as that will attempt to merge the resolved @@ -731,30 +741,37 @@ const RegType& RegType::Merge(const RegType& incoming_type, // (In that case, it is likely a misconfiguration of dex2oat.) if (!kIsTargetBuild && Runtime::Current()->IsAotCompiler()) { LOG(FATAL) << "Could not create class join of " - << c1->PrettyClass() + << GetClass()->PrettyClass() << " & " - << c2->PrettyClass(); + << incoming_type.GetClass()->PrettyClass(); UNREACHABLE(); } return reg_types->MakeUnresolvedReference(); } - // Record the dependency that both `c1` and `c2` are assignable to `join_class`. - // The `verifier` is null during unit tests. + // Record the dependency that both `GetClass()` and `incoming_type.GetClass()` + // are assignable to `join_class`. The `verifier` is null during unit tests. if (verifier != nullptr) { - VerifierDeps::MaybeRecordAssignability( - verifier->GetDexFile(), join_class, c1, true /* strict */, true /* is_assignable */); - VerifierDeps::MaybeRecordAssignability( - verifier->GetDexFile(), join_class, c2, true /* strict */, true /* is_assignable */); + VerifierDeps::MaybeRecordAssignability(verifier->GetDexFile(), + join_class, + GetClass(), + /* strict */ true, + /* is_assignable */ true); + VerifierDeps::MaybeRecordAssignability(verifier->GetDexFile(), + join_class, + incoming_type.GetClass(), + /* strict */ true, + /* is_assignable */ true); } - if (c1 == join_class && !IsPreciseReference()) { + if (GetClass() == join_class && !IsPreciseReference()) { return *this; - } else if (c2 == join_class && !incoming_type.IsPreciseReference()) { + } else if (incoming_type.GetClass() == join_class && !incoming_type.IsPreciseReference()) { return incoming_type; } else { std::string temp; - return reg_types->FromClass(join_class->GetDescriptor(&temp), join_class, false); + const char* descriptor = join_class->GetDescriptor(&temp); + return reg_types->FromClass(descriptor, join_class, /* precise */ false); } } } else { @@ -763,7 +780,7 @@ const RegType& RegType::Merge(const RegType& incoming_type, } // See comment in reg_type.h -mirror::Class* RegType::ClassJoin(mirror::Class* s, mirror::Class* t) { +ObjPtr<mirror::Class> RegType::ClassJoin(ObjPtr<mirror::Class> s, ObjPtr<mirror::Class> t) { DCHECK(!s->IsPrimitive()) << s->PrettyClass(); DCHECK(!t->IsPrimitive()) << t->PrettyClass(); if (s == t) { @@ -773,12 +790,12 @@ mirror::Class* RegType::ClassJoin(mirror::Class* s, mirror::Class* t) { } else if (t->IsAssignableFrom(s)) { return t; } else if (s->IsArrayClass() && t->IsArrayClass()) { - mirror::Class* s_ct = s->GetComponentType(); - mirror::Class* t_ct = t->GetComponentType(); + ObjPtr<mirror::Class> s_ct = s->GetComponentType(); + ObjPtr<mirror::Class> t_ct = t->GetComponentType(); if (s_ct->IsPrimitive() || t_ct->IsPrimitive()) { // Given the types aren't the same, if either array is of primitive types then the only // common parent is java.lang.Object - mirror::Class* result = s->GetSuperClass(); // short-cut to java.lang.Object + ObjPtr<mirror::Class> result = s->GetSuperClass(); // short-cut to java.lang.Object DCHECK(result->IsObjectClass()); return result; } @@ -788,8 +805,9 @@ mirror::Class* RegType::ClassJoin(mirror::Class* s, mirror::Class* t) { self->AssertPendingException(); return nullptr; } - ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); - mirror::Class* array_class = class_linker->FindArrayClass(self, &common_elem); + // Note: The following lookup invalidates existing ObjPtr<>s. + ObjPtr<mirror::Class> array_class = + Runtime::Current()->GetClassLinker()->FindArrayClass(self, &common_elem); if (UNLIKELY(array_class == nullptr)) { self->AssertPendingException(); return nullptr; @@ -971,7 +989,7 @@ bool RegType::CanAssignArray(const RegType& src, return cmp1.CanAssignArray(cmp2, reg_types, class_loader, verifier, soft_error); } -const NullType* NullType::CreateInstance(mirror::Class* klass, +const NullType* NullType::CreateInstance(ObjPtr<mirror::Class> klass, const StringPiece& descriptor, uint16_t cache_id) { CHECK(instance_ == nullptr); diff --git a/runtime/verifier/reg_type.h b/runtime/verifier/reg_type.h index 3e994074a1..29da376091 100644 --- a/runtime/verifier/reg_type.h +++ b/runtime/verifier/reg_type.h @@ -191,7 +191,7 @@ class RegType { !IsUnresolvedSuperClass())); return descriptor_; } - mirror::Class* GetClass() const REQUIRES_SHARED(Locks::mutator_lock_) { + ObjPtr<mirror::Class> GetClass() const REQUIRES_SHARED(Locks::mutator_lock_) { DCHECK(!IsUnresolvedReference()); DCHECK(!klass_.IsNull()) << Dump(); DCHECK(HasClass()); @@ -318,7 +318,7 @@ class RegType { } protected: - RegType(mirror::Class* klass, + RegType(ObjPtr<mirror::Class> klass, const StringPiece& descriptor, uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_) : descriptor_(descriptor), @@ -365,7 +365,7 @@ class RegType { * * [1] Java bytecode verification: algorithms and formalizations, Xavier Leroy */ - static mirror::Class* ClassJoin(mirror::Class* s, mirror::Class* t) + static ObjPtr<mirror::Class> ClassJoin(ObjPtr<mirror::Class> s, ObjPtr<mirror::Class> t) REQUIRES_SHARED(Locks::mutator_lock_); static bool AssignableFrom(const RegType& lhs, @@ -388,7 +388,7 @@ class ConflictType FINAL : public RegType { static const ConflictType* GetInstance() PURE; // Create the singleton instance. - static const ConflictType* CreateInstance(mirror::Class* klass, + static const ConflictType* CreateInstance(ObjPtr<mirror::Class> klass, const StringPiece& descriptor, uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_); @@ -401,7 +401,8 @@ class ConflictType FINAL : public RegType { } private: - ConflictType(mirror::Class* klass, const StringPiece& descriptor, + ConflictType(ObjPtr<mirror::Class> klass, + const StringPiece& descriptor, uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_) : RegType(klass, descriptor, cache_id) { CheckConstructorInvariants(this); @@ -423,7 +424,7 @@ class UndefinedType FINAL : public RegType { static const UndefinedType* GetInstance() PURE; // Create the singleton instance. - static const UndefinedType* CreateInstance(mirror::Class* klass, + static const UndefinedType* CreateInstance(ObjPtr<mirror::Class> klass, const StringPiece& descriptor, uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_); @@ -436,7 +437,8 @@ class UndefinedType FINAL : public RegType { } private: - UndefinedType(mirror::Class* klass, const StringPiece& descriptor, + UndefinedType(ObjPtr<mirror::Class> klass, + const StringPiece& descriptor, uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_) : RegType(klass, descriptor, cache_id) { CheckConstructorInvariants(this); @@ -447,7 +449,8 @@ class UndefinedType FINAL : public RegType { class PrimitiveType : public RegType { public: - PrimitiveType(mirror::Class* klass, const StringPiece& descriptor, + PrimitiveType(ObjPtr<mirror::Class> klass, + const StringPiece& descriptor, uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_); bool HasClassVirtual() const OVERRIDE { return true; } @@ -455,7 +458,7 @@ class PrimitiveType : public RegType { class Cat1Type : public PrimitiveType { public: - Cat1Type(mirror::Class* klass, const StringPiece& descriptor, + Cat1Type(ObjPtr<mirror::Class> klass, const StringPiece& descriptor, uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_); }; @@ -463,7 +466,7 @@ class IntegerType FINAL : public Cat1Type { public: bool IsInteger() const OVERRIDE { return true; } std::string Dump() const OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_); - static const IntegerType* CreateInstance(mirror::Class* klass, + static const IntegerType* CreateInstance(ObjPtr<mirror::Class> klass, const StringPiece& descriptor, uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_); @@ -475,7 +478,8 @@ class IntegerType FINAL : public Cat1Type { } private: - IntegerType(mirror::Class* klass, const StringPiece& descriptor, + IntegerType(ObjPtr<mirror::Class> klass, + const StringPiece& descriptor, uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_) : Cat1Type(klass, descriptor, cache_id) { CheckConstructorInvariants(this); @@ -487,7 +491,7 @@ class BooleanType FINAL : public Cat1Type { public: bool IsBoolean() const OVERRIDE { return true; } std::string Dump() const OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_); - static const BooleanType* CreateInstance(mirror::Class* klass, + static const BooleanType* CreateInstance(ObjPtr<mirror::Class> klass, const StringPiece& descriptor, uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_); @@ -499,7 +503,8 @@ class BooleanType FINAL : public Cat1Type { } private: - BooleanType(mirror::Class* klass, const StringPiece& descriptor, + BooleanType(ObjPtr<mirror::Class> klass, + const StringPiece& descriptor, uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_) : Cat1Type(klass, descriptor, cache_id) { CheckConstructorInvariants(this); @@ -512,7 +517,7 @@ class ByteType FINAL : public Cat1Type { public: bool IsByte() const OVERRIDE { return true; } std::string Dump() const OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_); - static const ByteType* CreateInstance(mirror::Class* klass, + static const ByteType* CreateInstance(ObjPtr<mirror::Class> klass, const StringPiece& descriptor, uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_); @@ -524,7 +529,8 @@ class ByteType FINAL : public Cat1Type { } private: - ByteType(mirror::Class* klass, const StringPiece& descriptor, + ByteType(ObjPtr<mirror::Class> klass, + const StringPiece& descriptor, uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_) : Cat1Type(klass, descriptor, cache_id) { CheckConstructorInvariants(this); @@ -536,7 +542,7 @@ class ShortType FINAL : public Cat1Type { public: bool IsShort() const OVERRIDE { return true; } std::string Dump() const OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_); - static const ShortType* CreateInstance(mirror::Class* klass, + static const ShortType* CreateInstance(ObjPtr<mirror::Class> klass, const StringPiece& descriptor, uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_); @@ -548,7 +554,7 @@ class ShortType FINAL : public Cat1Type { } private: - ShortType(mirror::Class* klass, const StringPiece& descriptor, + ShortType(ObjPtr<mirror::Class> klass, const StringPiece& descriptor, uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_) : Cat1Type(klass, descriptor, cache_id) { CheckConstructorInvariants(this); @@ -560,7 +566,7 @@ class CharType FINAL : public Cat1Type { public: bool IsChar() const OVERRIDE { return true; } std::string Dump() const OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_); - static const CharType* CreateInstance(mirror::Class* klass, + static const CharType* CreateInstance(ObjPtr<mirror::Class> klass, const StringPiece& descriptor, uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_); @@ -572,7 +578,8 @@ class CharType FINAL : public Cat1Type { } private: - CharType(mirror::Class* klass, const StringPiece& descriptor, + CharType(ObjPtr<mirror::Class> klass, + const StringPiece& descriptor, uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_) : Cat1Type(klass, descriptor, cache_id) { CheckConstructorInvariants(this); @@ -584,7 +591,7 @@ class FloatType FINAL : public Cat1Type { public: bool IsFloat() const OVERRIDE { return true; } std::string Dump() const OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_); - static const FloatType* CreateInstance(mirror::Class* klass, + static const FloatType* CreateInstance(ObjPtr<mirror::Class> klass, const StringPiece& descriptor, uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_); @@ -596,7 +603,8 @@ class FloatType FINAL : public Cat1Type { } private: - FloatType(mirror::Class* klass, const StringPiece& descriptor, + FloatType(ObjPtr<mirror::Class> klass, + const StringPiece& descriptor, uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_) : Cat1Type(klass, descriptor, cache_id) { CheckConstructorInvariants(this); @@ -606,7 +614,8 @@ class FloatType FINAL : public Cat1Type { class Cat2Type : public PrimitiveType { public: - Cat2Type(mirror::Class* klass, const StringPiece& descriptor, + Cat2Type(ObjPtr<mirror::Class> klass, + const StringPiece& descriptor, uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_); }; @@ -615,7 +624,7 @@ class LongLoType FINAL : public Cat2Type { std::string Dump() const OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_); bool IsLongLo() const OVERRIDE { return true; } bool IsLong() const OVERRIDE { return true; } - static const LongLoType* CreateInstance(mirror::Class* klass, + static const LongLoType* CreateInstance(ObjPtr<mirror::Class> klass, const StringPiece& descriptor, uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_); @@ -627,7 +636,8 @@ class LongLoType FINAL : public Cat2Type { } private: - LongLoType(mirror::Class* klass, const StringPiece& descriptor, + LongLoType(ObjPtr<mirror::Class> klass, + const StringPiece& descriptor, uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_) : Cat2Type(klass, descriptor, cache_id) { CheckConstructorInvariants(this); @@ -639,7 +649,7 @@ class LongHiType FINAL : public Cat2Type { public: std::string Dump() const OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_); bool IsLongHi() const OVERRIDE { return true; } - static const LongHiType* CreateInstance(mirror::Class* klass, + static const LongHiType* CreateInstance(ObjPtr<mirror::Class> klass, const StringPiece& descriptor, uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_); @@ -651,7 +661,8 @@ class LongHiType FINAL : public Cat2Type { } private: - LongHiType(mirror::Class* klass, const StringPiece& descriptor, + LongHiType(ObjPtr<mirror::Class> klass, + const StringPiece& descriptor, uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_) : Cat2Type(klass, descriptor, cache_id) { CheckConstructorInvariants(this); @@ -664,7 +675,7 @@ class DoubleLoType FINAL : public Cat2Type { std::string Dump() const OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_); bool IsDoubleLo() const OVERRIDE { return true; } bool IsDouble() const OVERRIDE { return true; } - static const DoubleLoType* CreateInstance(mirror::Class* klass, + static const DoubleLoType* CreateInstance(ObjPtr<mirror::Class> klass, const StringPiece& descriptor, uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_); @@ -676,7 +687,8 @@ class DoubleLoType FINAL : public Cat2Type { } private: - DoubleLoType(mirror::Class* klass, const StringPiece& descriptor, + DoubleLoType(ObjPtr<mirror::Class> klass, + const StringPiece& descriptor, uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_) : Cat2Type(klass, descriptor, cache_id) { CheckConstructorInvariants(this); @@ -688,9 +700,9 @@ class DoubleHiType FINAL : public Cat2Type { public: std::string Dump() const OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_); virtual bool IsDoubleHi() const OVERRIDE { return true; } - static const DoubleHiType* CreateInstance(mirror::Class* klass, - const StringPiece& descriptor, - uint16_t cache_id) + static const DoubleHiType* CreateInstance(ObjPtr<mirror::Class> klass, + const StringPiece& descriptor, + uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_); static const DoubleHiType* GetInstance() PURE; static void Destroy(); @@ -700,7 +712,8 @@ class DoubleHiType FINAL : public Cat2Type { } private: - DoubleHiType(mirror::Class* klass, const StringPiece& descriptor, + DoubleHiType(ObjPtr<mirror::Class> klass, + const StringPiece& descriptor, uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_) : Cat2Type(klass, descriptor, cache_id) { CheckConstructorInvariants(this); @@ -872,7 +885,7 @@ class NullType FINAL : public RegType { static const NullType* GetInstance() PURE; // Create the singleton instance. - static const NullType* CreateInstance(mirror::Class* klass, + static const NullType* CreateInstance(ObjPtr<mirror::Class> klass, const StringPiece& descriptor, uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_); @@ -892,7 +905,7 @@ class NullType FINAL : public RegType { } private: - NullType(mirror::Class* klass, const StringPiece& descriptor, uint16_t cache_id) + NullType(ObjPtr<mirror::Class> klass, const StringPiece& descriptor, uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_) : RegType(klass, descriptor, cache_id) { CheckConstructorInvariants(this); @@ -906,8 +919,10 @@ class NullType FINAL : public RegType { // instructions and must be passed to a constructor. class UninitializedType : public RegType { public: - UninitializedType(mirror::Class* klass, const StringPiece& descriptor, - uint32_t allocation_pc, uint16_t cache_id) + UninitializedType(ObjPtr<mirror::Class> klass, + const StringPiece& descriptor, + uint32_t allocation_pc, + uint16_t cache_id) : RegType(klass, descriptor, cache_id), allocation_pc_(allocation_pc) {} bool IsUninitializedTypes() const OVERRIDE; @@ -929,9 +944,10 @@ class UninitializedType : public RegType { // Similar to ReferenceType but not yet having been passed to a constructor. class UninitializedReferenceType FINAL : public UninitializedType { public: - UninitializedReferenceType(mirror::Class* klass, + UninitializedReferenceType(ObjPtr<mirror::Class> klass, const StringPiece& descriptor, - uint32_t allocation_pc, uint16_t cache_id) + uint32_t allocation_pc, + uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_) : UninitializedType(klass, descriptor, allocation_pc, cache_id) { CheckConstructorInvariants(this); @@ -969,7 +985,7 @@ class UnresolvedUninitializedRefType FINAL : public UninitializedType { // of a constructor. class UninitializedThisReferenceType FINAL : public UninitializedType { public: - UninitializedThisReferenceType(mirror::Class* klass, + UninitializedThisReferenceType(ObjPtr<mirror::Class> klass, const StringPiece& descriptor, uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_) @@ -1010,7 +1026,8 @@ class UnresolvedUninitializedThisRefType FINAL : public UninitializedType { // sub-class. class ReferenceType FINAL : public RegType { public: - ReferenceType(mirror::Class* klass, const StringPiece& descriptor, + ReferenceType(ObjPtr<mirror::Class> klass, + const StringPiece& descriptor, uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_) : RegType(klass, descriptor, cache_id) { CheckConstructorInvariants(this); @@ -1034,7 +1051,8 @@ class ReferenceType FINAL : public RegType { // type. class PreciseReferenceType FINAL : public RegType { public: - PreciseReferenceType(mirror::Class* klass, const StringPiece& descriptor, + PreciseReferenceType(ObjPtr<mirror::Class> klass, + const StringPiece& descriptor, uint16_t cache_id) REQUIRES_SHARED(Locks::mutator_lock_); diff --git a/runtime/verifier/reg_type_cache-inl.h b/runtime/verifier/reg_type_cache-inl.h index 43c0ab9598..9f87adfa31 100644 --- a/runtime/verifier/reg_type_cache-inl.h +++ b/runtime/verifier/reg_type_cache-inl.h @@ -124,36 +124,42 @@ inline const ImpreciseConstType& RegTypeCache::PosShortConstant() { } inline const PreciseReferenceType& RegTypeCache::JavaLangClass() { - const RegType* result = &FromClass("Ljava/lang/Class;", mirror::Class::GetJavaLangClass(), true); + const RegType* result = &FromClass("Ljava/lang/Class;", + GetClassRoot<mirror::Class>(), + /* precise */ true); DCHECK(result->IsPreciseReference()); return *down_cast<const PreciseReferenceType*>(result); } inline const PreciseReferenceType& RegTypeCache::JavaLangString() { // String is final and therefore always precise. - const RegType* result = &FromClass("Ljava/lang/String;", mirror::String::GetJavaLangString(), - true); + const RegType* result = &FromClass("Ljava/lang/String;", + GetClassRoot<mirror::String>(), + /* precise */ true); DCHECK(result->IsPreciseReference()); return *down_cast<const PreciseReferenceType*>(result); } inline const PreciseReferenceType& RegTypeCache::JavaLangInvokeMethodHandle() { const RegType* result = &FromClass("Ljava/lang/invoke/MethodHandle;", - GetClassRoot<mirror::MethodHandle>().Ptr(), true); + GetClassRoot<mirror::MethodHandle>(), + /* precise */ true); DCHECK(result->IsPreciseReference()); return *down_cast<const PreciseReferenceType*>(result); } inline const PreciseReferenceType& RegTypeCache::JavaLangInvokeMethodType() { const RegType* result = &FromClass("Ljava/lang/invoke/MethodType;", - GetClassRoot<mirror::MethodType>().Ptr(), true); + GetClassRoot<mirror::MethodType>(), + /* precise */ true); DCHECK(result->IsPreciseReference()); return *down_cast<const PreciseReferenceType*>(result); } inline const RegType& RegTypeCache::JavaLangThrowable(bool precise) { const RegType* result = &FromClass("Ljava/lang/Throwable;", - mirror::Throwable::GetJavaLangThrowable(), precise); + GetClassRoot<mirror::Throwable>(), + precise); if (precise) { DCHECK(result->IsPreciseReference()); return *down_cast<const PreciseReferenceType*>(result); @@ -164,8 +170,7 @@ inline const RegType& RegTypeCache::JavaLangThrowable(bool precise) { } inline const RegType& RegTypeCache::JavaLangObject(bool precise) { - const RegType* result = &FromClass("Ljava/lang/Object;", - mirror::Class::GetJavaLangClass()->GetSuperClass(), precise); + const RegType* result = &FromClass("Ljava/lang/Object;", GetClassRoot<mirror::Object>(), precise); if (precise) { DCHECK(result->IsPreciseReference()); return *down_cast<const PreciseReferenceType*>(result); @@ -180,7 +185,7 @@ inline RegTypeType& RegTypeCache::AddEntry(RegTypeType* new_entry) { DCHECK(new_entry != nullptr); entries_.push_back(new_entry); if (new_entry->HasClass()) { - mirror::Class* klass = new_entry->GetClass(); + ObjPtr<mirror::Class> klass = new_entry->GetClass(); DCHECK(!klass->IsPrimitive()); klass_entries_.push_back(std::make_pair(GcRoot<mirror::Class>(klass), new_entry)); } diff --git a/runtime/verifier/reg_type_cache.cc b/runtime/verifier/reg_type_cache.cc index 87fc60bd23..f1f3488a3c 100644 --- a/runtime/verifier/reg_type_cache.cc +++ b/runtime/verifier/reg_type_cache.cc @@ -77,7 +77,7 @@ void RegTypeCache::FillPrimitiveAndSmallConstantTypes() { DCHECK_EQ(entries_.size(), primitive_count_); } -const RegType& RegTypeCache::FromDescriptor(mirror::ClassLoader* loader, +const RegType& RegTypeCache::FromDescriptor(ObjPtr<mirror::ClassLoader> loader, const char* descriptor, bool precise) { DCHECK(RegTypeCache::primitive_initialized_); @@ -149,14 +149,15 @@ bool RegTypeCache::MatchDescriptor(size_t idx, const StringPiece& descriptor, bo return true; } -mirror::Class* RegTypeCache::ResolveClass(const char* descriptor, mirror::ClassLoader* loader) { +ObjPtr<mirror::Class> RegTypeCache::ResolveClass(const char* descriptor, + ObjPtr<mirror::ClassLoader> loader) { // Class was not found, must create new type. // Try resolving class ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); Thread* self = Thread::Current(); StackHandleScope<1> hs(self); Handle<mirror::ClassLoader> class_loader(hs.NewHandle(loader)); - mirror::Class* klass = nullptr; + ObjPtr<mirror::Class> klass = nullptr; if (can_load_classes_) { klass = class_linker->FindClass(self, descriptor, class_loader); } else { @@ -175,7 +176,7 @@ StringPiece RegTypeCache::AddString(const StringPiece& string_piece) { return StringPiece(ptr, string_piece.length()); } -const RegType& RegTypeCache::From(mirror::ClassLoader* loader, +const RegType& RegTypeCache::From(ObjPtr<mirror::ClassLoader> loader, const char* descriptor, bool precise) { StringPiece sp_descriptor(descriptor); @@ -188,7 +189,7 @@ const RegType& RegTypeCache::From(mirror::ClassLoader* loader, } // Class not found in the cache, will create a new type for that. // Try resolving class. - mirror::Class* klass = ResolveClass(descriptor, loader); + ObjPtr<mirror::Class> klass = ResolveClass(descriptor, loader); if (klass != nullptr) { // Class resolved, first look for the class in the list of entries // Class was not found, must create new type. @@ -234,7 +235,7 @@ const RegType& RegTypeCache::MakeUnresolvedReference() { return AddEntry(new (&allocator_) UnresolvedReferenceType(AddString("a"), entries_.size())); } -const RegType* RegTypeCache::FindClass(mirror::Class* klass, bool precise) const { +const RegType* RegTypeCache::FindClass(ObjPtr<mirror::Class> klass, bool precise) const { DCHECK(klass != nullptr); if (klass->IsPrimitive()) { // Note: precise isn't used for primitive classes. A char is assignable to an int. All @@ -242,7 +243,7 @@ const RegType* RegTypeCache::FindClass(mirror::Class* klass, bool precise) const return &RegTypeFromPrimitiveType(klass->GetPrimitiveType()); } for (auto& pair : klass_entries_) { - mirror::Class* const reg_klass = pair.first.Read(); + ObjPtr<mirror::Class> const reg_klass = pair.first.Read(); if (reg_klass == klass) { const RegType* reg_type = pair.second; if (MatchingPrecisionForClass(reg_type, precise)) { @@ -254,7 +255,7 @@ const RegType* RegTypeCache::FindClass(mirror::Class* klass, bool precise) const } const RegType* RegTypeCache::InsertClass(const StringPiece& descriptor, - mirror::Class* klass, + ObjPtr<mirror::Class> klass, bool precise) { // No reference to the class was found, create new reference. DCHECK(FindClass(klass, precise) == nullptr); @@ -265,7 +266,9 @@ const RegType* RegTypeCache::InsertClass(const StringPiece& descriptor, return &AddEntry(reg_type); } -const RegType& RegTypeCache::FromClass(const char* descriptor, mirror::Class* klass, bool precise) { +const RegType& RegTypeCache::FromClass(const char* descriptor, + ObjPtr<mirror::Class> klass, + bool precise) { DCHECK(klass != nullptr); const RegType* reg_type = FindClass(klass, precise); if (reg_type == nullptr) { @@ -342,7 +345,7 @@ void RegTypeCache::CreatePrimitiveAndSmallConstantTypes() { // code cannot leak to other users. auto create_primitive_type_instance = [&](auto type) REQUIRES_SHARED(Locks::mutator_lock_) { using Type = typename decltype(type)::type; - mirror::Class* klass = nullptr; + ObjPtr<mirror::Class> klass = nullptr; // Try loading the class from linker. DCHECK(type.descriptor != nullptr); if (strlen(type.descriptor) > 0) { @@ -500,7 +503,7 @@ const UninitializedType& RegTypeCache::Uninitialized(const RegType& type, uint32 allocation_pc, entries_.size()); } else { - mirror::Class* klass = type.GetClass(); + ObjPtr<mirror::Class> klass = type.GetClass(); for (size_t i = primitive_count_; i < entries_.size(); i++) { const RegType* cur_entry = entries_[i]; if (cur_entry->IsUninitializedReference() && @@ -532,7 +535,7 @@ const RegType& RegTypeCache::FromUninitialized(const RegType& uninit_type) { } entry = new (&allocator_) UnresolvedReferenceType(descriptor, entries_.size()); } else { - mirror::Class* klass = uninit_type.GetClass(); + ObjPtr<mirror::Class> klass = uninit_type.GetClass(); if (uninit_type.IsUninitializedThisReference() && !klass->IsFinal()) { // For uninitialized "this reference" look for reference types that are not precise. for (size_t i = primitive_count_; i < entries_.size(); i++) { @@ -583,7 +586,7 @@ const UninitializedType& RegTypeCache::UninitializedThisArgument(const RegType& } entry = new (&allocator_) UnresolvedUninitializedThisRefType(descriptor, entries_.size()); } else { - mirror::Class* klass = type.GetClass(); + ObjPtr<mirror::Class> klass = type.GetClass(); for (size_t i = primitive_count_; i < entries_.size(); i++) { const RegType* cur_entry = entries_[i]; if (cur_entry->IsUninitializedThisReference() && cur_entry->GetClass() == klass) { @@ -647,7 +650,8 @@ const ConstantType& RegTypeCache::FromCat2ConstHi(int32_t value, bool precise) { return AddEntry(entry); } -const RegType& RegTypeCache::GetComponentType(const RegType& array, mirror::ClassLoader* loader) { +const RegType& RegTypeCache::GetComponentType(const RegType& array, + ObjPtr<mirror::ClassLoader> loader) { if (!array.IsArrayTypes()) { return Conflict(); } else if (array.IsUnresolvedTypes()) { @@ -655,7 +659,7 @@ const RegType& RegTypeCache::GetComponentType(const RegType& array, mirror::Clas const std::string descriptor(array.GetDescriptor().as_string()); return FromDescriptor(loader, descriptor.c_str() + 1, false); } else { - mirror::Class* klass = array.GetClass()->GetComponentType(); + ObjPtr<mirror::Class> klass = array.GetClass()->GetComponentType(); std::string temp; const char* descriptor = klass->GetDescriptor(&temp); if (klass->IsErroneous()) { diff --git a/runtime/verifier/reg_type_cache.h b/runtime/verifier/reg_type_cache.h index b32dc115a7..d668222901 100644 --- a/runtime/verifier/reg_type_cache.h +++ b/runtime/verifier/reg_type_cache.h @@ -74,16 +74,18 @@ class RegTypeCache { } static void ShutDown(); const art::verifier::RegType& GetFromId(uint16_t id) const; - const RegType& From(mirror::ClassLoader* loader, const char* descriptor, bool precise) + const RegType& From(ObjPtr<mirror::ClassLoader> loader, const char* descriptor, bool precise) REQUIRES_SHARED(Locks::mutator_lock_); // Find a RegType, returns null if not found. - const RegType* FindClass(mirror::Class* klass, bool precise) const + const RegType* FindClass(ObjPtr<mirror::Class> klass, bool precise) const REQUIRES_SHARED(Locks::mutator_lock_); // Insert a new class with a specified descriptor, must not already be in the cache. - const RegType* InsertClass(const StringPiece& descriptor, mirror::Class* klass, bool precise) + const RegType* InsertClass(const StringPiece& descriptor, + ObjPtr<mirror::Class> klass, + bool precise) REQUIRES_SHARED(Locks::mutator_lock_); // Get or insert a reg type for a description, klass, and precision. - const RegType& FromClass(const char* descriptor, mirror::Class* klass, bool precise) + const RegType& FromClass(const char* descriptor, ObjPtr<mirror::Class> klass, bool precise) REQUIRES_SHARED(Locks::mutator_lock_); const ConstantType& FromCat1Const(int32_t value, bool precise) REQUIRES_SHARED(Locks::mutator_lock_); @@ -91,7 +93,9 @@ class RegTypeCache { REQUIRES_SHARED(Locks::mutator_lock_); const ConstantType& FromCat2ConstHi(int32_t value, bool precise) REQUIRES_SHARED(Locks::mutator_lock_); - const RegType& FromDescriptor(mirror::ClassLoader* loader, const char* descriptor, bool precise) + const RegType& FromDescriptor(ObjPtr<mirror::ClassLoader> loader, + const char* descriptor, + bool precise) REQUIRES_SHARED(Locks::mutator_lock_); const RegType& FromUnresolvedMerge(const RegType& left, const RegType& right, @@ -146,7 +150,7 @@ class RegTypeCache { const ImpreciseConstType& IntConstant() REQUIRES_SHARED(Locks::mutator_lock_); const ImpreciseConstType& PosByteConstant() REQUIRES_SHARED(Locks::mutator_lock_); const ImpreciseConstType& PosShortConstant() REQUIRES_SHARED(Locks::mutator_lock_); - const RegType& GetComponentType(const RegType& array, mirror::ClassLoader* loader) + const RegType& GetComponentType(const RegType& array, ObjPtr<mirror::ClassLoader> loader) REQUIRES_SHARED(Locks::mutator_lock_); void Dump(std::ostream& os) REQUIRES_SHARED(Locks::mutator_lock_); const RegType& RegTypeFromPrimitiveType(Primitive::Type) const; @@ -158,7 +162,7 @@ class RegTypeCache { private: void FillPrimitiveAndSmallConstantTypes() REQUIRES_SHARED(Locks::mutator_lock_); - mirror::Class* ResolveClass(const char* descriptor, mirror::ClassLoader* loader) + ObjPtr<mirror::Class> ResolveClass(const char* descriptor, ObjPtr<mirror::ClassLoader> loader) REQUIRES_SHARED(Locks::mutator_lock_); bool MatchDescriptor(size_t idx, const StringPiece& descriptor, bool precise) REQUIRES_SHARED(Locks::mutator_lock_); diff --git a/runtime/verifier/verifier_deps.cc b/runtime/verifier/verifier_deps.cc index fe839f7312..500cc37af4 100644 --- a/runtime/verifier/verifier_deps.cc +++ b/runtime/verifier/verifier_deps.cc @@ -77,8 +77,8 @@ const VerifierDeps::DexFileDeps* VerifierDeps::GetDexFileDeps(const DexFile& dex static constexpr uint32_t kAccVdexAccessFlags = kAccPublic | kAccPrivate | kAccProtected | kAccStatic | kAccInterface; -template <typename T> -uint16_t VerifierDeps::GetAccessFlags(T* element) { +template <typename Ptr> +uint16_t VerifierDeps::GetAccessFlags(Ptr element) { static_assert(kAccJavaFlagsMask == 0xFFFF, "Unexpected value of a constant"); if (element == nullptr) { return VerifierDeps::kUnresolvedMarker; @@ -277,7 +277,7 @@ bool VerifierDeps::IsInClassPath(ObjPtr<mirror::Class> klass) const { void VerifierDeps::AddClassResolution(const DexFile& dex_file, dex::TypeIndex type_idx, - mirror::Class* klass) { + ObjPtr<mirror::Class> klass) { DexFileDeps* dex_deps = GetDexFileDeps(dex_file); if (dex_deps == nullptr) { // This invocation is from verification of a dex file which is not being compiled. @@ -336,12 +336,13 @@ void VerifierDeps::AddMethodResolution(const DexFile& dex_file, dex_deps->methods_.insert(method_tuple); } -mirror::Class* VerifierDeps::FindOneClassPathBoundaryForInterface(mirror::Class* destination, - mirror::Class* source) const { +ObjPtr<mirror::Class> VerifierDeps::FindOneClassPathBoundaryForInterface( + ObjPtr<mirror::Class> destination, + ObjPtr<mirror::Class> source) const { DCHECK(destination->IsInterface()); DCHECK(IsInClassPath(destination)); Thread* thread = Thread::Current(); - mirror::Class* current = source; + ObjPtr<mirror::Class> current = source; // Record the classes that are at the boundary between the compiled DEX files and // the classpath. We will check those classes later to find one class that inherits // `destination`. @@ -367,7 +368,7 @@ mirror::Class* VerifierDeps::FindOneClassPathBoundaryForInterface(mirror::Class* int32_t iftable_count = source->GetIfTableCount(); ObjPtr<mirror::IfTable> iftable = source->GetIfTable(); for (int32_t i = 0; i < iftable_count; ++i) { - mirror::Class* itf = iftable->GetInterface(i); + ObjPtr<mirror::Class> itf = iftable->GetInterface(i); if (!IsInClassPath(itf)) { for (size_t j = 0; j < itf->NumDirectInterfaces(); ++j) { ObjPtr<mirror::Class> direct = mirror::Class::GetDirectInterface(thread, itf, j); @@ -391,8 +392,8 @@ mirror::Class* VerifierDeps::FindOneClassPathBoundaryForInterface(mirror::Class* } void VerifierDeps::AddAssignability(const DexFile& dex_file, - mirror::Class* destination, - mirror::Class* source, + ObjPtr<mirror::Class> destination, + ObjPtr<mirror::Class> source, bool is_strict, bool is_assignable) { // Test that the method is only called on reference types. @@ -429,8 +430,8 @@ void VerifierDeps::AddAssignability(const DexFile& dex_file, // Both types are arrays. Break down to component types and add recursively. // This helps filter out destinations from compiled DEX files (see below) // and deduplicate entries with the same canonical component type. - mirror::Class* destination_component = destination->GetComponentType(); - mirror::Class* source_component = source->GetComponentType(); + ObjPtr<mirror::Class> destination_component = destination->GetComponentType(); + ObjPtr<mirror::Class> source_component = source->GetComponentType(); // Only perform the optimization if both types are resolved which guarantees // that they linked successfully, as required at the top of this method. @@ -511,7 +512,7 @@ void VerifierDeps::MaybeRecordVerificationStatus(const DexFile& dex_file, void VerifierDeps::MaybeRecordClassResolution(const DexFile& dex_file, dex::TypeIndex type_idx, - mirror::Class* klass) { + ObjPtr<mirror::Class> klass) { VerifierDeps* thread_deps = GetThreadLocalVerifierDeps(); if (thread_deps != nullptr) { thread_deps->AddClassResolution(dex_file, type_idx, klass); @@ -537,8 +538,8 @@ void VerifierDeps::MaybeRecordMethodResolution(const DexFile& dex_file, } void VerifierDeps::MaybeRecordAssignability(const DexFile& dex_file, - mirror::Class* destination, - mirror::Class* source, + ObjPtr<mirror::Class> destination, + ObjPtr<mirror::Class> source, bool is_strict, bool is_assignable) { VerifierDeps* thread_deps = GetThreadLocalVerifierDeps(); @@ -858,12 +859,12 @@ bool VerifierDeps::ValidateDependencies(Handle<mirror::ClassLoader> class_loader // TODO: share that helper with other parts of the compiler that have // the same lookup pattern. -static mirror::Class* FindClassAndClearException(ClassLinker* class_linker, - Thread* self, - const char* name, - Handle<mirror::ClassLoader> class_loader) +static ObjPtr<mirror::Class> FindClassAndClearException(ClassLinker* class_linker, + Thread* self, + const char* name, + Handle<mirror::ClassLoader> class_loader) REQUIRES_SHARED(Locks::mutator_lock_) { - mirror::Class* result = class_linker->FindClass(self, name, class_loader); + ObjPtr<mirror::Class> result = class_linker->FindClass(self, name, class_loader); if (result == nullptr) { DCHECK(self->IsExceptionPending()); self->ClearException(); @@ -971,7 +972,7 @@ bool VerifierDeps::VerifyFields(Handle<mirror::ClassLoader> class_loader, std::string expected_decl_klass = entry.IsResolved() ? GetStringFromId(dex_file, entry.GetDeclaringClassIndex()) : dex_file.StringByTypeIdx(field_id.class_idx_); - mirror::Class* cls = FindClassAndClearException( + ObjPtr<mirror::Class> cls = FindClassAndClearException( class_linker, self, expected_decl_klass.c_str(), class_loader); if (cls == nullptr) { LOG(INFO) << "VerifierDeps: Could not resolve class " << expected_decl_klass; @@ -1034,7 +1035,7 @@ bool VerifierDeps::VerifyMethods(Handle<mirror::ClassLoader> class_loader, ? GetStringFromId(dex_file, entry.GetDeclaringClassIndex()) : dex_file.StringByTypeIdx(method_id.class_idx_); - mirror::Class* cls = FindClassAndClearException( + ObjPtr<mirror::Class> cls = FindClassAndClearException( class_linker, self, expected_decl_klass.c_str(), class_loader); if (cls == nullptr) { LOG(INFO) << "VerifierDeps: Could not resolve class " << expected_decl_klass; diff --git a/runtime/verifier/verifier_deps.h b/runtime/verifier/verifier_deps.h index 94441da7e2..0146b17020 100644 --- a/runtime/verifier/verifier_deps.h +++ b/runtime/verifier/verifier_deps.h @@ -75,7 +75,7 @@ class VerifierDeps { // If `klass` is null, the class is assumed unresolved. static void MaybeRecordClassResolution(const DexFile& dex_file, dex::TypeIndex type_idx, - mirror::Class* klass) + ObjPtr<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Locks::verifier_deps_lock_); @@ -99,8 +99,8 @@ class VerifierDeps { // to `destination` as defined by RegType::AssignableFrom. `dex_file` is the // owner of the method for which MethodVerifier performed the assignability test. static void MaybeRecordAssignability(const DexFile& dex_file, - mirror::Class* destination, - mirror::Class* source, + ObjPtr<mirror::Class> destination, + ObjPtr<mirror::Class> source, bool is_strict, bool is_assignable) REQUIRES_SHARED(Locks::mutator_lock_) @@ -218,8 +218,8 @@ class VerifierDeps { // Finds the class in the classpath that makes `source` inherit` from `destination`. // Returns null if a class defined in the compiled DEX files, and assignable to // `source`, direclty inherits from `destination`. - mirror::Class* FindOneClassPathBoundaryForInterface(mirror::Class* destination, - mirror::Class* source) const + ObjPtr<mirror::Class> FindOneClassPathBoundaryForInterface(ObjPtr<mirror::Class> destination, + ObjPtr<mirror::Class> source) const REQUIRES_SHARED(Locks::mutator_lock_); // Returns the index of `str`. If it is defined in `dex_file_`, this is the dex @@ -234,8 +234,8 @@ class VerifierDeps { // Returns the bytecode access flags of `element` (bottom 16 bits), or // `kUnresolvedMarker` if `element` is null. - template <typename T> - static uint16_t GetAccessFlags(T* element) + template <typename Ptr> + static uint16_t GetAccessFlags(Ptr element) REQUIRES_SHARED(Locks::mutator_lock_); // Returns a string ID of the descriptor of the declaring class of `element`, @@ -256,7 +256,7 @@ class VerifierDeps { void AddClassResolution(const DexFile& dex_file, dex::TypeIndex type_idx, - mirror::Class* klass) + ObjPtr<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Locks::verifier_deps_lock_); @@ -273,8 +273,8 @@ class VerifierDeps { REQUIRES(!Locks::verifier_deps_lock_); void AddAssignability(const DexFile& dex_file, - mirror::Class* destination, - mirror::Class* source, + ObjPtr<mirror::Class> destination, + ObjPtr<mirror::Class> source, bool is_strict, bool is_assignable) REQUIRES_SHARED(Locks::mutator_lock_); diff --git a/test/166-bad-interface-super/build b/test/166-bad-interface-super/build index d85147f17b..bba6184e16 100644 --- a/test/166-bad-interface-super/build +++ b/test/166-bad-interface-super/build @@ -14,7 +14,14 @@ # See the License for the specific language governing permissions and # limitations under the License. -# See b/65168732 -export USE_D8=false +# Use the jasmin sources for JVM, otherwise the smali sources. +extra_arg="--no-jasmin" -./default-build "$@" +for arg in "$@"; do + if [[ "$arg" == "--jvm" ]]; then + extra_arg="--no-smali" + break + fi +done + +./default-build "$@" "$extra_arg" diff --git a/test/476-checker-ctor-fence-redun-elim/build b/test/166-bad-interface-super/smali/BadSuper1.smali index 10ffcc537d..6233403897 100644 --- a/test/476-checker-ctor-fence-redun-elim/build +++ b/test/166-bad-interface-super/smali/BadSuper1.smali @@ -1,6 +1,4 @@ -#!/bin/bash -# -# Copyright 2017 The Android Open Source Project +# Copyright (C) 2018 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. @@ -14,7 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -# See b/65168732 -export USE_D8=false - -./default-build "$@" +.class public interface LBadSuper1; +.super LBaseInterface; +.source "BadSuper1.j" diff --git a/test/450-checker-types/build b/test/166-bad-interface-super/smali/BadSuper2.smali index 10ffcc537d..8e410cf1b4 100755..100644 --- a/test/450-checker-types/build +++ b/test/166-bad-interface-super/smali/BadSuper2.smali @@ -1,6 +1,4 @@ -#!/bin/bash -# -# Copyright 2017 The Android Open Source Project +# Copyright (C) 2018 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. @@ -14,7 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -# See b/65168732 -export USE_D8=false - -./default-build "$@" +.class public interface LBadSuper2; +.super LBaseClass; +.source "BadSuper2.j" diff --git a/test/dexdump/run-all-tests b/test/dexdump/run-all-tests index c9976cd090..e555a44e5d 100755 --- a/test/dexdump/run-all-tests +++ b/test/dexdump/run-all-tests @@ -37,51 +37,73 @@ prog="${progdir}"/`basename "${prog}"` tmpdir=/tmp/test-$$ mkdir ${tmpdir} -# Set up dexdump binary and flags to test. -DEXD="${ANDROID_HOST_OUT}/bin/dexdump2" -DEXDFLAGS1="-adfh" -DEXDFLAGS2="-e -l xml" +# Set up tools and commands to run +DEXDUMP="${ANDROID_HOST_OUT}/bin/dexdump2" +DEXLIST="${ANDROID_HOST_OUT}/bin/dexlist" -# Set up dexlist binary and flags to test. -DEXL="${ANDROID_HOST_OUT}/bin/dexlist" -DEXLFLAGS="" +declare -A SUFFIX_COMMAND_MAP +SUFFIX_COMMAND_MAP[txt]="${DEXDUMP} -adfh" +SUFFIX_COMMAND_MAP[xml]="${DEXDUMP} -e -l xml" +SUFFIX_COMMAND_MAP[lst]="${DEXLIST}" + +# Parse command-line options +UPDATE="no" +USAGE="no" +while [ $# -ne 0 ]; do + case "$1" in + --update) + UPDATE="yes" + ;; + *) + echo "Unknown option $1" 1>&2 + USAGE="yes" + ;; + esac + shift +done + +if [ "${USAGE}" = "yes" ]; then + cat 1>&2 <<USAGE_END +Usage: + ${prog##*/} [--update] +Options: + --update Update reference outputs +USAGE_END + exit 1 +fi + +if [ "${UPDATE}" = "yes" ]; then + for dex in *.dex; do + for suffix in ${!SUFFIX_COMMAND_MAP[@]}; do + new_output=${dex%%.*}.${suffix} + ${SUFFIX_COMMAND_MAP[${suffix}]} ${dex} > ${new_output} + if [ $? -ne 0 ]; then + echo "Failed running ${SUFFIX_COMMAND_MAP[${suffix}]} ${dex} > ${new_output}" 2>&1 + exit 1 + fi + done + done + exit 0 +fi # Run the tests. passed=0 failed=0 -for i in *.dex; do - echo $i - basenm=`basename "${i}" .dex` - txtfile=${basenm}.txt - xmlfile=${basenm}.xml - lstfile=${basenm}.lst - gentxtfile=${tmpdir}/${txtfile} - genxmlfile=${tmpdir}/${xmlfile} - genlstfile=${tmpdir}/${lstfile} - ${DEXD} ${DEXDFLAGS1} ${i} > ${gentxtfile} - cmp ${txtfile} ${gentxtfile} - if [ "$?" = "0" ]; then - ((passed += 1)) - else - ((failed += 1)) - echo failed: ${i} - fi - ${DEXD} ${DEXDFLAGS2} ${i} > ${genxmlfile} - cmp ${xmlfile} ${genxmlfile} - if [ "$?" = "0" ]; then - ((passed += 1)) - else - ((failed += 1)) - echo failed: ${i} - fi - ${DEXL} ${DEXLFLAGS} ${i} > ${genlstfile} - cmp ${lstfile} ${genlstfile} +for dex in *.dex; do + echo ${dex} + for suffix in ${!SUFFIX_COMMAND_MAP[@]}; do + expected_output=${dex%%.*}.${suffix} + actual_output=${tmpdir}/${expected_output} + cmd="${SUFFIX_COMMAND_MAP[${suffix}]} ${dex}" + ${cmd} > ${actual_output} + cmp ${expected_output} ${actual_output} if [ "$?" = "0" ]; then ((passed += 1)) else ((failed += 1)) - echo failed: ${i} + echo failed: ${cmd} fi + done done # Report results. diff --git a/test/etc/default-build b/test/etc/default-build index d0ebe80e68..9dbc73c6b4 100755 --- a/test/etc/default-build +++ b/test/etc/default-build @@ -169,6 +169,9 @@ while true; do elif [ "x$1" = "x--no-smali" ]; then HAS_SMALI=false shift + elif [ "x$1" = "x--no-jasmin" ]; then + HAS_JASMIN=false + shift elif [ "x$1" = "x--experimental" ]; then shift # We have a specific experimental configuration so don't use the default. diff --git a/tools/cleanup-buildbot-device.sh b/tools/cleanup-buildbot-device.sh index 2144b02c2f..ca5219aa25 100755 --- a/tools/cleanup-buildbot-device.sh +++ b/tools/cleanup-buildbot-device.sh @@ -40,7 +40,7 @@ if [[ -n "$ART_TEST_CHROOT" ]]; then # # TODO: Reorder ART Buildbot steps so that "device cleanup" happens # before "setup device" and remove this special case. - adb shell test -f "$ART_TEST_CHROOT/system" \ + adb shell test -d "$ART_TEST_CHROOT/system" \ "&&" find "$ART_TEST_CHROOT/system" \ ! -path "$ART_TEST_CHROOT/system/etc/selinux/plat_property_contexts" \ ! -type d \ diff --git a/tools/dexanalyze/dexanalyze_experiments.cc b/tools/dexanalyze/dexanalyze_experiments.cc index 82cb0d28ab..0f20a99f05 100644 --- a/tools/dexanalyze/dexanalyze_experiments.cc +++ b/tools/dexanalyze/dexanalyze_experiments.cc @@ -130,7 +130,7 @@ void CountDexIndices::ProcessDexFile(const DexFile& dex_file) { for (ClassAccessor accessor : dex_file.GetClasses()) { std::set<size_t> unique_method_ids; std::set<size_t> unique_string_ids; - accessor.VisitMethods([&](const ClassAccessor::Method& method) { + for (const ClassAccessor::Method& method : accessor.GetMethods()) { dex_code_bytes_ += method.GetInstructions().InsnsSizeInBytes(); unique_code_items.insert(method.GetCodeItemOffset()); for (const DexInstructionPcPair& inst : method.GetInstructions()) { @@ -188,7 +188,7 @@ void CountDexIndices::ProcessDexFile(const DexFile& dex_file) { break; } } - }); + } total_unique_method_idx_ += unique_method_ids.size(); total_unique_string_ids_ += unique_string_ids.size(); } diff --git a/tools/run-jdwp-tests.sh b/tools/run-jdwp-tests.sh index eebc09278a..0796432f68 100755 --- a/tools/run-jdwp-tests.sh +++ b/tools/run-jdwp-tests.sh @@ -36,10 +36,9 @@ if [ -z "$ANDROID_HOST_OUT" ] ; then ANDROID_HOST_OUT=${OUT_DIR-$ANDROID_BUILD_TOP/out}/host/linux-x86 fi -android_root="/system" -if [ -n "$ART_TEST_ANDROID_ROOT" ]; then - android_root="$ART_TEST_ANDROID_ROOT" -fi +# "Root" (actually "system") directory on device (in the case of +# target testing). +android_root=${ART_TEST_ANDROID_ROOT:-/system} java_lib_location="${ANDROID_HOST_OUT}/../common/obj/JAVA_LIBRARIES" make_target_name="apache-harmony-jdwp-tests-hostdex" @@ -48,6 +47,7 @@ vm_args="" art="$android_root/bin/art" art_debugee="sh $android_root/bin/art" args=$@ +chroot_option= debuggee_args="-Xcompiler-option --debuggable" device_dir="--device-dir=/data/local/tmp" # We use the art script on target to ensure the runner and the debuggee share the same @@ -68,8 +68,6 @@ test="org.apache.harmony.jpda.tests.share.AllTests" mode="target" # Use JIT compiling by default. use_jit=true -# Don't use chroot by default. -use_chroot=false variant_cmdline_parameter="--variant=X32" dump_command="/bin/true" # Timeout of JDWP test in ms. @@ -112,15 +110,6 @@ while true; do # We don't care about jit with the RI use_jit=false shift - elif [[ "$1" == "--chroot" ]]; then - use_chroot=true - # Adjust settings for chroot environment. - art="/system/bin/art" - art_debugee="sh /system/bin/art" - vm_command="--vm-command=$art" - device_dir="--device-dir=/tmp" - # Shift the "--chroot" flag and its argument. - shift 2 elif [[ $1 == --test-timeout-ms ]]; then # Remove the --test-timeout-ms from the arguments. args=${args/$1} @@ -202,10 +191,17 @@ while true; do fi done -if $use_chroot && [[ $mode == "host" ]]; then - # Chroot-based testing is not supported on host. - echo "Cannot use --chroot with --mode=host" - exit 1 +if [[ $mode == "target" ]]; then + # Honor environment variable ART_TEST_CHROOT. + if [[ -n "$ART_TEST_CHROOT" ]]; then + # Set Vogar's `--chroot` option. + chroot_option="--chroot $ART_TEST_CHROOT" + # Adjust settings for chroot environment. + art="/system/bin/art" + art_debugee="sh /system/bin/art" + vm_command="--vm-command=$art" + device_dir="--device-dir=/tmp" + fi fi if [[ $has_gdb = "yes" ]]; then @@ -341,6 +337,7 @@ vogar $vm_command \ $vm_args \ --verbose \ $args \ + $chroot_option \ $device_dir \ $image_compiler_option \ --timeout 800 \ diff --git a/tools/run-libcore-tests.sh b/tools/run-libcore-tests.sh index 3537c1b861..aff009abb6 100755 --- a/tools/run-libcore-tests.sh +++ b/tools/run-libcore-tests.sh @@ -28,10 +28,9 @@ else JAVA_LIBRARIES=${ANDROID_PRODUCT_OUT}/../../common/obj/JAVA_LIBRARIES fi -android_root="/system" -if [ -n "$ART_TEST_ANDROID_ROOT" ]; then - android_root="$ART_TEST_ANDROID_ROOT" -fi +# "Root" (actually "system") directory on device (in the case of +# target testing). +android_root=${ART_TEST_ANDROID_ROOT:-/system} function classes_jar_path { local var="$1" @@ -106,8 +105,6 @@ debug=false # Don't use device mode by default. device_mode=false -# Don't use chroot by default. -use_chroot=false while true; do if [[ "$1" == "--mode=device" ]]; then @@ -135,10 +132,6 @@ while true; do elif [[ "$1" == "-Xgc:gcstress" ]]; then gcstress=true shift - elif [[ "$1" == "--chroot" ]]; then - use_chroot=true - # Shift the "--chroot" flag and its argument. - shift 2 elif [[ "$1" == "" ]]; then break else @@ -147,20 +140,17 @@ while true; do done if $device_mode; then - if $use_chroot; then + # Honor environment variable ART_TEST_CHROOT. + if [[ -n "$ART_TEST_CHROOT" ]]; then + # Set Vogar's `--chroot` option. + vogar_args="$vogar_args --chroot $ART_TEST_CHROOT" vogar_args="$vogar_args --device-dir=/tmp" - vogar_args="$vogar_args --vm-command=/system/bin/art" else + # When not using a chroot on device, set Vogar's work directory to + # /data/local/tmp. vogar_args="$vogar_args --device-dir=/data/local/tmp" - vogar_args="$vogar_args --vm-command=$android_root/bin/art" - fi -else - # Host mode. - if $use_chroot; then - # Chroot-based testing is not supported on host. - echo "Cannot use --chroot with --mode=host" - exit 1 fi + vogar_args="$vogar_args --vm-command=$android_root/bin/art" fi # Increase the timeout, as vogar cannot set individual test |