diff options
author | 2017-12-15 11:19:33 -0800 | |
---|---|---|
committer | 2017-12-22 09:41:17 -0800 | |
commit | 808c7a57bb913b13c22884f57cdacd59bf1fdb3f (patch) | |
tree | d7f0d7cabaac5a7646c25bae584a82a9aa279cc0 | |
parent | 64bae9fb677aa0e2406d13ea9f8ebaa92e16f978 (diff) |
Make CodeItem fields private
Make code item fields private and use accessors. Added a hand full of
friend classes to reduce the size of the change.
Changed default to be nullable and removed CreateNullable.
CreateNullable was a bad API since it defaulted to the unsafe, may
add a CreateNonNullable if it's important for performance.
Motivation:
Have a different layout for code items in cdex.
Bug: 63756964
Test: test-art-host-gtest
Test: test/testrunner/testrunner.py --host
Test: art/tools/run-jdwp-tests.sh '--mode=host' '--variant=X32' --debug
Change-Id: I42bc7435e20358682075cb6de52713b595f95bf9
58 files changed, 486 insertions, 477 deletions
diff --git a/compiler/compiler.cc b/compiler/compiler.cc index bb614ae7b2..47f44ff3bc 100644 --- a/compiler/compiler.cc +++ b/compiler/compiler.cc @@ -19,6 +19,7 @@ #include <android-base/logging.h> #include "base/macros.h" +#include "code_item_accessors-inl.h" #include "driver/compiler_driver.h" #include "optimizing/optimizing_compiler.h" #include "utils.h" @@ -46,15 +47,16 @@ bool Compiler::IsPathologicalCase(const DexFile::CodeItem& code_item, * Dalvik uses 16-bit uints for instruction and register counts. We'll limit to a quarter * of that, which also guarantees we cannot overflow our 16-bit internal Quick SSA name space. */ - if (code_item.insns_size_in_code_units_ >= UINT16_MAX / 4) { + CodeItemDataAccessor accessor(&dex_file, &code_item); + if (accessor.InsnsSizeInCodeUnits() >= UINT16_MAX / 4) { LOG(INFO) << "Method exceeds compiler instruction limit: " - << code_item.insns_size_in_code_units_ + << accessor.InsnsSizeInCodeUnits() << " in " << dex_file.PrettyMethod(method_idx); return true; } - if (code_item.registers_size_ >= UINT16_MAX / 4) { + if (accessor.RegistersSize() >= UINT16_MAX / 4) { LOG(INFO) << "Method exceeds compiler virtual register limit: " - << code_item.registers_size_ << " in " << dex_file.PrettyMethod(method_idx); + << accessor.RegistersSize() << " in " << dex_file.PrettyMethod(method_idx); return true; } return false; diff --git a/compiler/debug/elf_debug_info_writer.h b/compiler/debug/elf_debug_info_writer.h index 107ed488cd..0e11e32987 100644 --- a/compiler/debug/elf_debug_info_writer.h +++ b/compiler/debug/elf_debug_info_writer.h @@ -260,14 +260,10 @@ class ElfCompilationUnitWriter { // Write local variables. LocalInfos local_infos; - if (dex->DecodeDebugLocalInfo(accessor.RegistersSize(), - accessor.InsSize(), - accessor.InsnsSizeInCodeUnits(), - accessor.DebugInfoOffset(), - is_static, - mi->dex_method_index, - LocalInfoCallback, - &local_infos)) { + if (accessor.DecodeDebugLocalInfo(is_static, + mi->dex_method_index, + LocalInfoCallback, + &local_infos)) { for (const DexFile::LocalInfo& var : local_infos) { if (var.reg_ < accessor.RegistersSize() - accessor.InsSize()) { info_.StartTag(DW_TAG_variable); diff --git a/compiler/debug/elf_debug_loc_writer.h b/compiler/debug/elf_debug_loc_writer.h index 1d609af4e6..34c2919a21 100644 --- a/compiler/debug/elf_debug_loc_writer.h +++ b/compiler/debug/elf_debug_loc_writer.h @@ -149,11 +149,12 @@ static std::vector<VariableLocation> GetVariableLocations( DCHECK_LT(stack_map_index, dex_register_maps.size()); DexRegisterMap dex_register_map = dex_register_maps[stack_map_index]; DCHECK(dex_register_map.IsValid()); + CodeItemDataAccessor accessor(method_info->dex_file, method_info->code_item); reg_lo = dex_register_map.GetDexRegisterLocation( - vreg, method_info->code_item->registers_size_, code_info, encoding); + vreg, accessor.RegistersSize(), code_info, encoding); if (is64bitValue) { reg_hi = dex_register_map.GetDexRegisterLocation( - vreg + 1, method_info->code_item->registers_size_, code_info, encoding); + vreg + 1, accessor.RegistersSize(), code_info, encoding); } // Add location entry for this address range. diff --git a/compiler/dex/inline_method_analyser.cc b/compiler/dex/inline_method_analyser.cc index b409eb2dbb..80677b934b 100644 --- a/compiler/dex/inline_method_analyser.cc +++ b/compiler/dex/inline_method_analyser.cc @@ -141,8 +141,11 @@ bool Matcher::DoMatch(const CodeItemDataAccessor* code_item, MatchFn* const* pat ArtMethod* GetTargetConstructor(ArtMethod* method, const Instruction* invoke_direct) REQUIRES_SHARED(Locks::mutator_lock_) { DCHECK_EQ(invoke_direct->Opcode(), Instruction::INVOKE_DIRECT); - DCHECK_EQ(invoke_direct->VRegC_35c(), - method->GetCodeItem()->registers_size_ - method->GetCodeItem()->ins_size_); + if (kIsDebugBuild) { + CodeItemDataAccessor accessor(method); + DCHECK_EQ(invoke_direct->VRegC_35c(), + accessor.RegistersSize() - accessor.InsSize()); + } uint32_t method_index = invoke_direct->VRegB_35c(); ArtMethod* target_method = Runtime::Current()->GetClassLinker()->LookupResolvedMethod( method_index, method->GetDexCache(), method->GetClassLoader()); @@ -323,7 +326,7 @@ bool DoAnalyseConstructor(const CodeItemDataAccessor* code_item, if (target_method->GetDeclaringClass()->IsObjectClass()) { DCHECK_EQ(CodeItemDataAccessor(target_method).begin()->Opcode(), Instruction::RETURN_VOID); } else { - CodeItemDataAccessor target_code_item = CodeItemDataAccessor::CreateNullable(target_method); + CodeItemDataAccessor target_code_item(target_method); if (!target_code_item.HasCodeItem()) { return false; // Native constructor? } @@ -427,7 +430,7 @@ static_assert(InlineMethodAnalyser::IGetVariant(Instruction::IGET_SHORT) == InlineMethodAnalyser::IPutVariant(Instruction::IPUT_SHORT), "iget/iput_short variant"); bool InlineMethodAnalyser::AnalyseMethodCode(ArtMethod* method, InlineMethod* result) { - CodeItemDataAccessor code_item = CodeItemDataAccessor::CreateNullable(method); + CodeItemDataAccessor code_item(method); if (!code_item.HasCodeItem()) { // Native or abstract. return false; diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index 0631c0f12c..68f963e3ab 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -949,14 +949,14 @@ class ResolveCatchBlockExceptionsClassVisitor : public ClassVisitor { ArtMethod* method, std::set<std::pair<dex::TypeIndex, const DexFile*>>* exceptions_to_resolve) REQUIRES_SHARED(Locks::mutator_lock_) { - const DexFile::CodeItem* code_item = method->GetCodeItem(); - if (code_item == nullptr) { + if (method->GetCodeItem() == nullptr) { return; // native or abstract method } - if (code_item->tries_size_ == 0) { + CodeItemDataAccessor accessor(method); + if (accessor.TriesSize() == 0) { return; // nothing to process } - const uint8_t* encoded_catch_handler_list = DexFile::GetCatchHandlerData(*code_item, 0); + const uint8_t* encoded_catch_handler_list = accessor.GetCatchHandlerData(); size_t num_encoded_catch_handlers = DecodeUnsignedLeb128(&encoded_catch_handler_list); for (size_t i = 0; i < num_encoded_catch_handlers; i++) { int32_t encoded_catch_handler_size = DecodeSignedLeb128(&encoded_catch_handler_list); diff --git a/compiler/exception_test.cc b/compiler/exception_test.cc index 897b50bdac..4dbef0d799 100644 --- a/compiler/exception_test.cc +++ b/compiler/exception_test.cc @@ -20,6 +20,7 @@ #include "base/callee_save_type.h" #include "base/enums.h" #include "class_linker.h" +#include "code_item_accessors-inl.h" #include "common_runtime_test.h" #include "dex_file-inl.h" #include "dex_file.h" @@ -129,11 +130,12 @@ class ExceptionTest : public CommonRuntimeTest { TEST_F(ExceptionTest, FindCatchHandler) { ScopedObjectAccess soa(Thread::Current()); const DexFile::CodeItem* code_item = dex_->GetCodeItem(method_f_->GetCodeItemOffset()); + CodeItemDataAccessor accessor(dex_, code_item); ASSERT_TRUE(code_item != nullptr); - ASSERT_EQ(2u, code_item->tries_size_); - ASSERT_NE(0u, code_item->insns_size_in_code_units_); + ASSERT_EQ(2u, accessor.TriesSize()); + ASSERT_NE(0u, accessor.InsnsSizeInCodeUnits()); const DexFile::TryItem *t0, *t1; t0 = dex_->GetTryItems(*code_item, 0); diff --git a/compiler/optimizing/block_builder.cc b/compiler/optimizing/block_builder.cc index 58f591bd1e..c505efafe2 100644 --- a/compiler/optimizing/block_builder.cc +++ b/compiler/optimizing/block_builder.cc @@ -18,10 +18,31 @@ #include "base/logging.h" // FOR VLOG. #include "bytecode_utils.h" +#include "code_item_accessors-inl.h" #include "quicken_info.h" namespace art { +HBasicBlockBuilder::HBasicBlockBuilder(HGraph* graph, + const DexFile* const dex_file, + const CodeItemDebugInfoAccessor& accessor, + ScopedArenaAllocator* local_allocator) + : allocator_(graph->GetAllocator()), + graph_(graph), + dex_file_(dex_file), + code_item_accessor_(accessor), + local_allocator_(local_allocator), + branch_targets_(code_item_accessor_.HasCodeItem() + ? code_item_accessor_.InsnsSizeInCodeUnits() + : /* fake dex_pc=0 for intrinsic graph */ 1u, + nullptr, + local_allocator->Adapter(kArenaAllocGraphBuilder)), + throwing_blocks_(kDefaultNumberOfThrowingBlocks, + local_allocator->Adapter(kArenaAllocGraphBuilder)), + number_of_branches_(0u), + quicken_index_for_dex_pc_(std::less<uint32_t>(), + local_allocator->Adapter(kArenaAllocGraphBuilder)) {} + HBasicBlock* HBasicBlockBuilder::MaybeCreateBlockAt(uint32_t dex_pc) { return MaybeCreateBlockAt(dex_pc, dex_pc); } @@ -41,20 +62,19 @@ bool HBasicBlockBuilder::CreateBranchTargets() { // Create the first block for the dex instructions, single successor of the entry block. MaybeCreateBlockAt(0u); - if (code_item_->tries_size_ != 0) { + if (code_item_accessor_.TriesSize() != 0) { // Create branch targets at the start/end of the TryItem range. These are // places where the program might fall through into/out of the a block and // where TryBoundary instructions will be inserted later. Other edges which // enter/exit the try blocks are a result of branches/switches. - for (size_t idx = 0; idx < code_item_->tries_size_; ++idx) { - const DexFile::TryItem* try_item = DexFile::GetTryItems(*code_item_, idx); - uint32_t dex_pc_start = try_item->start_addr_; - uint32_t dex_pc_end = dex_pc_start + try_item->insn_count_; + for (const DexFile::TryItem& try_item : code_item_accessor_.TryItems()) { + uint32_t dex_pc_start = try_item.start_addr_; + uint32_t dex_pc_end = dex_pc_start + try_item.insn_count_; MaybeCreateBlockAt(dex_pc_start); - if (dex_pc_end < code_item_->insns_size_in_code_units_) { + if (dex_pc_end < code_item_accessor_.InsnsSizeInCodeUnits()) { // TODO: Do not create block if the last instruction cannot fall through. MaybeCreateBlockAt(dex_pc_end); - } else if (dex_pc_end == code_item_->insns_size_in_code_units_) { + } else if (dex_pc_end == code_item_accessor_.InsnsSizeInCodeUnits()) { // The TryItem spans until the very end of the CodeItem and therefore // cannot have any code afterwards. } else { @@ -65,7 +85,7 @@ bool HBasicBlockBuilder::CreateBranchTargets() { } // Create branch targets for exception handlers. - const uint8_t* handlers_ptr = DexFile::GetCatchHandlerData(*code_item_, 0); + const uint8_t* handlers_ptr = code_item_accessor_.GetCatchHandlerData(); uint32_t handlers_size = DecodeUnsignedLeb128(&handlers_ptr); for (uint32_t idx = 0; idx < handlers_size; ++idx) { CatchHandlerIterator iterator(handlers_ptr); @@ -78,8 +98,7 @@ bool HBasicBlockBuilder::CreateBranchTargets() { // Iterate over all instructions and find branching instructions. Create blocks for // the locations these instructions branch to. - IterationRange<DexInstructionIterator> instructions = code_item_->Instructions(); - for (const DexInstructionPcPair& pair : instructions) { + for (const DexInstructionPcPair& pair : code_item_accessor_) { const uint32_t dex_pc = pair.DexPc(); const Instruction& instruction = pair.Inst(); @@ -109,7 +128,7 @@ bool HBasicBlockBuilder::CreateBranchTargets() { if (instruction.CanFlowThrough()) { DexInstructionIterator next(std::next(DexInstructionIterator(pair))); - if (next == instructions.end()) { + if (next == code_item_accessor_.end()) { // In the normal case we should never hit this but someone can artificially forge a dex // file to fall-through out the method code. In this case we bail out compilation. VLOG(compiler) << "Not compiled: Fall-through beyond the CodeItem"; @@ -130,7 +149,7 @@ void HBasicBlockBuilder::ConnectBasicBlocks() { bool is_throwing_block = false; // Calculate the qucikening index here instead of CreateBranchTargets since it's easier to // calculate in dex_pc order. - for (const DexInstructionPcPair& pair : code_item_->Instructions()) { + for (const DexInstructionPcPair& pair : code_item_accessor_) { const uint32_t dex_pc = pair.DexPc(); const Instruction& instruction = pair.Inst(); @@ -213,10 +232,12 @@ static const DexFile::TryItem* GetTryItem( // successors matches the order in which runtime exception delivery searches // for a handler. static void LinkToCatchBlocks(HTryBoundary* try_boundary, - const DexFile::CodeItem& code_item, + const CodeItemDataAccessor& accessor, const DexFile::TryItem* try_item, const ScopedArenaSafeMap<uint32_t, HBasicBlock*>& catch_blocks) { - for (CatchHandlerIterator it(code_item, *try_item); it.HasNext(); it.Next()) { + for (CatchHandlerIterator it(accessor.GetCatchHandlerData(try_item->handler_off_)); + it.HasNext(); + it.Next()) { try_boundary->AddExceptionHandler(catch_blocks.Get(it.GetHandlerAddress())); } } @@ -232,7 +253,7 @@ bool HBasicBlockBuilder::MightHaveLiveNormalPredecessors(HBasicBlock* catch_bloc } } - const Instruction& first = code_item_->InstructionAt(catch_block->GetDexPc()); + const Instruction& first = code_item_accessor_.InstructionAt(catch_block->GetDexPc()); if (first.Opcode() == Instruction::MOVE_EXCEPTION) { // Verifier guarantees that if a catch block begins with MOVE_EXCEPTION then // it has no live normal predecessors. @@ -250,7 +271,7 @@ bool HBasicBlockBuilder::MightHaveLiveNormalPredecessors(HBasicBlock* catch_bloc } void HBasicBlockBuilder::InsertTryBoundaryBlocks() { - if (code_item_->tries_size_ == 0) { + if (code_item_accessor_.TriesSize() == 0) { return; } @@ -272,12 +293,10 @@ void HBasicBlockBuilder::InsertTryBoundaryBlocks() { // loop for synchronized blocks. if (ContainsElement(throwing_blocks_, block)) { // Try to find a TryItem covering the block. - const int32_t try_item_idx = DexFile::FindTryItem(DexFile::GetTryItems(*code_item_, 0u), - code_item_->tries_size_, - block->GetDexPc()); - if (try_item_idx != -1) { + const DexFile::TryItem* try_item = code_item_accessor_.FindTryItem(block->GetDexPc()); + if (try_item != nullptr) { // Block throwing and in a TryItem. Store the try block information. - try_block_info.Put(block->GetBlockId(), DexFile::GetTryItems(*code_item_, try_item_idx)); + try_block_info.Put(block->GetBlockId(), try_item); } } } @@ -288,7 +307,7 @@ void HBasicBlockBuilder::InsertTryBoundaryBlocks() { // Iterate over catch blocks, create artifical landing pads if necessary to // simplify the CFG, and set metadata. - const uint8_t* handlers_ptr = DexFile::GetCatchHandlerData(*code_item_, 0); + const uint8_t* handlers_ptr = code_item_accessor_.GetCatchHandlerData(); uint32_t handlers_size = DecodeUnsignedLeb128(&handlers_ptr); for (uint32_t idx = 0; idx < handlers_size; ++idx) { CatchHandlerIterator iterator(handlers_ptr); @@ -336,7 +355,7 @@ void HBasicBlockBuilder::InsertTryBoundaryBlocks() { HTryBoundary* try_entry = new (allocator_) HTryBoundary( HTryBoundary::BoundaryKind::kEntry, try_block->GetDexPc()); try_block->CreateImmediateDominator()->AddInstruction(try_entry); - LinkToCatchBlocks(try_entry, *code_item_, try_item, catch_blocks); + LinkToCatchBlocks(try_entry, code_item_accessor_, try_item, catch_blocks); break; } } @@ -364,13 +383,13 @@ void HBasicBlockBuilder::InsertTryBoundaryBlocks() { HTryBoundary* try_exit = new (allocator_) HTryBoundary(HTryBoundary::BoundaryKind::kExit, successor->GetDexPc()); graph_->SplitEdge(try_block, successor)->AddInstruction(try_exit); - LinkToCatchBlocks(try_exit, *code_item_, try_item, catch_blocks); + LinkToCatchBlocks(try_exit, code_item_accessor_, try_item, catch_blocks); } } } bool HBasicBlockBuilder::Build() { - DCHECK(code_item_ != nullptr); + DCHECK(code_item_accessor_.HasCodeItem()); DCHECK(graph_->GetBlocks().empty()); graph_->SetEntryBlock(new (allocator_) HBasicBlock(graph_, kNoDexPc)); @@ -388,7 +407,7 @@ bool HBasicBlockBuilder::Build() { } void HBasicBlockBuilder::BuildIntrinsic() { - DCHECK(code_item_ == nullptr); + DCHECK(!code_item_accessor_.HasCodeItem()); DCHECK(graph_->GetBlocks().empty()); // Create blocks. diff --git a/compiler/optimizing/block_builder.h b/compiler/optimizing/block_builder.h index 7d0f56db34..e68b95c46f 100644 --- a/compiler/optimizing/block_builder.h +++ b/compiler/optimizing/block_builder.h @@ -19,6 +19,7 @@ #include "base/scoped_arena_allocator.h" #include "base/scoped_arena_containers.h" +#include "code_item_accessors.h" #include "dex_file.h" #include "nodes.h" @@ -28,22 +29,8 @@ class HBasicBlockBuilder : public ValueObject { public: HBasicBlockBuilder(HGraph* graph, const DexFile* const dex_file, - const DexFile::CodeItem* code_item, - ScopedArenaAllocator* local_allocator) - : allocator_(graph->GetAllocator()), - graph_(graph), - dex_file_(dex_file), - code_item_(code_item), - local_allocator_(local_allocator), - branch_targets_(code_item != nullptr ? code_item->insns_size_in_code_units_ - : /* fake dex_pc=0 for intrinsic graph */ 1u, - nullptr, - local_allocator->Adapter(kArenaAllocGraphBuilder)), - throwing_blocks_(kDefaultNumberOfThrowingBlocks, - local_allocator->Adapter(kArenaAllocGraphBuilder)), - number_of_branches_(0u), - quicken_index_for_dex_pc_(std::less<uint32_t>(), - local_allocator->Adapter(kArenaAllocGraphBuilder)) {} + const CodeItemDebugInfoAccessor& accessor, + ScopedArenaAllocator* local_allocator); // Creates basic blocks in `graph_` at branch target dex_pc positions of the // `code_item_`. Blocks are connected but left unpopulated with instructions. @@ -83,7 +70,7 @@ class HBasicBlockBuilder : public ValueObject { HGraph* const graph_; const DexFile* const dex_file_; - const DexFile::CodeItem* const code_item_; // null for intrinsic graph. + CodeItemDataAccessor code_item_accessor_; // null code item for intrinsic graph. ScopedArenaAllocator* const local_allocator_; ScopedArenaVector<HBasicBlock*> branch_targets_; diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc index d73ef1f3a1..af537dd653 100644 --- a/compiler/optimizing/builder.cc +++ b/compiler/optimizing/builder.cc @@ -37,7 +37,7 @@ namespace art { HGraphBuilder::HGraphBuilder(HGraph* graph, - const DexFile::CodeItem* code_item, + const CodeItemDebugInfoAccessor& accessor, const DexCompilationUnit* dex_compilation_unit, const DexCompilationUnit* outer_compilation_unit, CompilerDriver* driver, @@ -47,7 +47,7 @@ HGraphBuilder::HGraphBuilder(HGraph* graph, VariableSizedHandleScope* handles) : graph_(graph), dex_file_(&graph->GetDexFile()), - code_item_(code_item), + code_item_accessor_(accessor), dex_compilation_unit_(dex_compilation_unit), outer_compilation_unit_(outer_compilation_unit), compiler_driver_(driver), @@ -57,6 +57,23 @@ HGraphBuilder::HGraphBuilder(HGraph* graph, handles_(handles), return_type_(DataType::FromShorty(dex_compilation_unit_->GetShorty()[0])) {} +HGraphBuilder::HGraphBuilder(HGraph* graph, + const DexCompilationUnit* dex_compilation_unit, + const CodeItemDebugInfoAccessor& accessor, + VariableSizedHandleScope* handles, + DataType::Type return_type) + : graph_(graph), + dex_file_(&graph->GetDexFile()), + code_item_accessor_(accessor), + dex_compilation_unit_(dex_compilation_unit), + outer_compilation_unit_(nullptr), + compiler_driver_(nullptr), + code_generator_(nullptr), + compilation_stats_(nullptr), + interpreter_metadata_(nullptr), + handles_(handles), + return_type_(return_type) {} + bool HGraphBuilder::SkipCompilation(size_t number_of_branches) { if (compiler_driver_ == nullptr) { // Note that the compiler driver is null when unit testing. @@ -69,20 +86,20 @@ bool HGraphBuilder::SkipCompilation(size_t number_of_branches) { return false; } - if (compiler_options.IsHugeMethod(code_item_->insns_size_in_code_units_)) { + const uint32_t code_units = code_item_accessor_.InsnsSizeInCodeUnits(); + if (compiler_options.IsHugeMethod(code_units)) { VLOG(compiler) << "Skip compilation of huge method " << dex_file_->PrettyMethod(dex_compilation_unit_->GetDexMethodIndex()) - << ": " << code_item_->insns_size_in_code_units_ << " code units"; + << ": " << code_units << " code units"; MaybeRecordStat(compilation_stats_, MethodCompilationStat::kNotCompiledHugeMethod); return true; } // If it's large and contains no branches, it's likely to be machine generated initialization. - if (compiler_options.IsLargeMethod(code_item_->insns_size_in_code_units_) - && (number_of_branches == 0)) { + if (compiler_options.IsLargeMethod(code_units) && (number_of_branches == 0)) { VLOG(compiler) << "Skip compilation of large method with no branch " << dex_file_->PrettyMethod(dex_compilation_unit_->GetDexMethodIndex()) - << ": " << code_item_->insns_size_in_code_units_ << " code units"; + << ": " << code_units << " code units"; MaybeRecordStat(compilation_stats_, MethodCompilationStat::kNotCompiledLargeMethodNoBranches); return true; } @@ -91,17 +108,17 @@ bool HGraphBuilder::SkipCompilation(size_t number_of_branches) { } GraphAnalysisResult HGraphBuilder::BuildGraph() { - DCHECK(code_item_ != nullptr); + DCHECK(code_item_accessor_.HasCodeItem()); DCHECK(graph_->GetBlocks().empty()); - graph_->SetNumberOfVRegs(code_item_->registers_size_); - graph_->SetNumberOfInVRegs(code_item_->ins_size_); - graph_->SetMaximumNumberOfOutVRegs(code_item_->outs_size_); - graph_->SetHasTryCatch(code_item_->tries_size_ != 0); + graph_->SetNumberOfVRegs(code_item_accessor_.RegistersSize()); + graph_->SetNumberOfInVRegs(code_item_accessor_.InsSize()); + graph_->SetMaximumNumberOfOutVRegs(code_item_accessor_.OutsSize()); + graph_->SetHasTryCatch(code_item_accessor_.TriesSize() != 0); // Use ScopedArenaAllocator for all local allocations. ScopedArenaAllocator local_allocator(graph_->GetArenaStack()); - HBasicBlockBuilder block_builder(graph_, dex_file_, code_item_, &local_allocator); + HBasicBlockBuilder block_builder(graph_, dex_file_, code_item_accessor_, &local_allocator); SsaBuilder ssa_builder(graph_, dex_compilation_unit_->GetClassLoader(), dex_compilation_unit_->GetDexCache(), @@ -111,7 +128,7 @@ GraphAnalysisResult HGraphBuilder::BuildGraph() { &block_builder, &ssa_builder, dex_file_, - code_item_, + code_item_accessor_, return_type_, dex_compilation_unit_, outer_compilation_unit_, @@ -150,7 +167,7 @@ GraphAnalysisResult HGraphBuilder::BuildGraph() { } void HGraphBuilder::BuildIntrinsicGraph(ArtMethod* method) { - DCHECK(code_item_ == nullptr); + DCHECK(!code_item_accessor_.HasCodeItem()); DCHECK(graph_->GetBlocks().empty()); // Determine the number of arguments and associated vregs. @@ -170,7 +187,10 @@ void HGraphBuilder::BuildIntrinsicGraph(ArtMethod* method) { // Use ScopedArenaAllocator for all local allocations. ScopedArenaAllocator local_allocator(graph_->GetArenaStack()); - HBasicBlockBuilder block_builder(graph_, dex_file_, /* code_item */ nullptr, &local_allocator); + HBasicBlockBuilder block_builder(graph_, + dex_file_, + CodeItemDebugInfoAccessor(), + &local_allocator); SsaBuilder ssa_builder(graph_, dex_compilation_unit_->GetClassLoader(), dex_compilation_unit_->GetDexCache(), @@ -180,7 +200,7 @@ void HGraphBuilder::BuildIntrinsicGraph(ArtMethod* method) { &block_builder, &ssa_builder, dex_file_, - /* code_item */ nullptr, + CodeItemDebugInfoAccessor(), return_type_, dex_compilation_unit_, outer_compilation_unit_, diff --git a/compiler/optimizing/builder.h b/compiler/optimizing/builder.h index 0bb3a051f7..c40e0b4e6a 100644 --- a/compiler/optimizing/builder.h +++ b/compiler/optimizing/builder.h @@ -18,6 +18,7 @@ #define ART_COMPILER_OPTIMIZING_BUILDER_H_ #include "base/arena_object.h" +#include "code_item_accessors.h" #include "dex_file-inl.h" #include "dex_file.h" #include "driver/compiler_driver.h" @@ -33,7 +34,7 @@ class OptimizingCompilerStats; class HGraphBuilder : public ValueObject { public: HGraphBuilder(HGraph* graph, - const DexFile::CodeItem* code_item, + const CodeItemDebugInfoAccessor& accessor, const DexCompilationUnit* dex_compilation_unit, const DexCompilationUnit* outer_compilation_unit, CompilerDriver* driver, @@ -45,20 +46,9 @@ class HGraphBuilder : public ValueObject { // Only for unit testing. HGraphBuilder(HGraph* graph, const DexCompilationUnit* dex_compilation_unit, - const DexFile::CodeItem& code_item, + const CodeItemDebugInfoAccessor& accessor, VariableSizedHandleScope* handles, - DataType::Type return_type = DataType::Type::kInt32) - : graph_(graph), - dex_file_(&graph->GetDexFile()), - code_item_(&code_item), - dex_compilation_unit_(dex_compilation_unit), - outer_compilation_unit_(nullptr), - compiler_driver_(nullptr), - code_generator_(nullptr), - compilation_stats_(nullptr), - interpreter_metadata_(nullptr), - handles_(handles), - return_type_(return_type) {} + DataType::Type return_type = DataType::Type::kInt32); GraphAnalysisResult BuildGraph(); void BuildIntrinsicGraph(ArtMethod* method); @@ -70,7 +60,7 @@ class HGraphBuilder : public ValueObject { HGraph* const graph_; const DexFile* const dex_file_; - const DexFile::CodeItem* const code_item_; // null for intrinsic graph. + const CodeItemDebugInfoAccessor code_item_accessor_; // null for intrinsic graph. // The compilation unit of the current method being compiled. Note that // it can be an inlined method. diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc index 8750910fe1..7a66d807cf 100644 --- a/compiler/optimizing/inliner.cc +++ b/compiler/optimizing/inliner.cc @@ -1381,26 +1381,26 @@ bool HInliner::TryBuildAndInline(HInvoke* invoke_instruction, bool same_dex_file = IsSameDexFile(*outer_compilation_unit_.GetDexFile(), *method->GetDexFile()); - const DexFile::CodeItem* code_item = method->GetCodeItem(); + CodeItemDataAccessor accessor(method); - if (code_item == nullptr) { + if (!accessor.HasCodeItem()) { LOG_FAIL_NO_STAT() << "Method " << method->PrettyMethod() << " is not inlined because it is native"; return false; } size_t inline_max_code_units = compiler_driver_->GetCompilerOptions().GetInlineMaxCodeUnits(); - if (code_item->insns_size_in_code_units_ > inline_max_code_units) { + if (accessor.InsnsSizeInCodeUnits() > inline_max_code_units) { LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedCodeItem) << "Method " << method->PrettyMethod() << " is not inlined because its code item is too big: " - << code_item->insns_size_in_code_units_ + << accessor.InsnsSizeInCodeUnits() << " > " << inline_max_code_units; return false; } - if (code_item->tries_size_ != 0) { + if (accessor.TriesSize() != 0) { LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedTryCatch) << "Method " << method->PrettyMethod() << " is not inlined because of try block"; return false; @@ -1660,6 +1660,7 @@ bool HInliner::TryBuildAndInlineHelper(HInvoke* invoke_instruction, const DexFile::CodeItem* code_item = resolved_method->GetCodeItem(); const DexFile& callee_dex_file = *resolved_method->GetDexFile(); uint32_t method_index = resolved_method->GetDexMethodIndex(); + CodeItemDebugInfoAccessor code_item_accessor(&callee_dex_file, code_item); ClassLinker* class_linker = caller_compilation_unit_.GetClassLinker(); Handle<mirror::DexCache> dex_cache = NewHandleIfDifferent(resolved_method->GetDexCache(), caller_compilation_unit_.GetDexCache(), @@ -1714,7 +1715,7 @@ bool HInliner::TryBuildAndInlineHelper(HInvoke* invoke_instruction, } } HGraphBuilder builder(callee_graph, - code_item, + code_item_accessor, &dex_compilation_unit, &outer_compilation_unit_, compiler_driver_, @@ -1967,6 +1968,7 @@ void HInliner::RunOptimizations(HGraph* callee_graph, return; } + CodeItemDataAccessor accessor(&callee_graph->GetDexFile(), code_item); HInliner inliner(callee_graph, outermost_graph_, codegen_, @@ -1975,7 +1977,7 @@ void HInliner::RunOptimizations(HGraph* callee_graph, compiler_driver_, handles_, inline_stats_, - total_number_of_dex_registers_ + code_item->registers_size_, + total_number_of_dex_registers_ + accessor.RegistersSize(), total_number_of_instructions_ + number_of_instructions, this, depth_ + 1); diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc index e36d91fb05..3f5923fa3f 100644 --- a/compiler/optimizing/instruction_builder.cc +++ b/compiler/optimizing/instruction_builder.cc @@ -39,6 +39,44 @@ namespace art { +HInstructionBuilder::HInstructionBuilder(HGraph* graph, + HBasicBlockBuilder* block_builder, + SsaBuilder* ssa_builder, + const DexFile* dex_file, + const CodeItemDebugInfoAccessor& accessor, + DataType::Type return_type, + const DexCompilationUnit* dex_compilation_unit, + const DexCompilationUnit* outer_compilation_unit, + CompilerDriver* compiler_driver, + CodeGenerator* code_generator, + const uint8_t* interpreter_metadata, + OptimizingCompilerStats* compiler_stats, + VariableSizedHandleScope* handles, + ScopedArenaAllocator* local_allocator) + : allocator_(graph->GetAllocator()), + graph_(graph), + handles_(handles), + dex_file_(dex_file), + code_item_accessor_(accessor), + return_type_(return_type), + block_builder_(block_builder), + ssa_builder_(ssa_builder), + compiler_driver_(compiler_driver), + code_generator_(code_generator), + dex_compilation_unit_(dex_compilation_unit), + outer_compilation_unit_(outer_compilation_unit), + quicken_info_(interpreter_metadata), + compilation_stats_(compiler_stats), + local_allocator_(local_allocator), + locals_for_(local_allocator->Adapter(kArenaAllocGraphBuilder)), + current_block_(nullptr), + current_locals_(nullptr), + latest_result_(nullptr), + current_this_parameter_(nullptr), + loop_headers_(local_allocator->Adapter(kArenaAllocGraphBuilder)) { + loop_headers_.reserve(kDefaultNumberOfLoops); +} + HBasicBlock* HInstructionBuilder::FindBlockStartingAt(uint32_t dex_pc) const { return block_builder_->GetBlockAt(dex_pc); } @@ -273,7 +311,7 @@ static bool IsBlockPopulated(HBasicBlock* block) { } bool HInstructionBuilder::Build() { - DCHECK(code_item_ != nullptr); + DCHECK(code_item_accessor_.HasCodeItem()); locals_for_.resize( graph_->GetBlocks().size(), ScopedArenaVector<HInstruction*>(local_allocator_->Adapter(kArenaAllocGraphBuilder))); @@ -323,7 +361,7 @@ bool HInstructionBuilder::Build() { quicken_index = block_builder_->GetQuickenIndex(block_dex_pc); } - for (const DexInstructionPcPair& pair : code_item_->Instructions(block_dex_pc)) { + for (const DexInstructionPcPair& pair : code_item_accessor_.InstructionsFrom(block_dex_pc)) { if (current_block_ == nullptr) { // The previous instruction ended this block. break; @@ -367,7 +405,7 @@ bool HInstructionBuilder::Build() { } void HInstructionBuilder::BuildIntrinsic(ArtMethod* method) { - DCHECK(code_item_ == nullptr); + DCHECK(!code_item_accessor_.HasCodeItem()); DCHECK(method->IsIntrinsic()); locals_for_.resize( @@ -442,15 +480,16 @@ ArenaBitVector* HInstructionBuilder::FindNativeDebugInfoLocations() { return false; } }; - CodeItemDebugInfoAccessor accessor(dex_file_, code_item_); ArenaBitVector* locations = ArenaBitVector::Create(local_allocator_, - accessor.InsnsSizeInCodeUnits(), + code_item_accessor_.InsnsSizeInCodeUnits(), /* expandable */ false, kArenaAllocGraphBuilder); locations->ClearAllBits(); - dex_file_->DecodeDebugPositionInfo(accessor.DebugInfoOffset(), Callback::Position, locations); + dex_file_->DecodeDebugPositionInfo(code_item_accessor_.DebugInfoOffset(), + Callback::Position, + locations); // Instruction-specific tweaks. - for (const DexInstructionPcPair& inst : accessor) { + for (const DexInstructionPcPair& inst : code_item_accessor_) { switch (inst->Opcode()) { case Instruction::MOVE_EXCEPTION: { // Stop in native debugger after the exception has been moved. @@ -459,7 +498,7 @@ ArenaBitVector* HInstructionBuilder::FindNativeDebugInfoLocations() { locations->ClearBit(inst.DexPc()); DexInstructionIterator next = std::next(DexInstructionIterator(inst)); DCHECK(next.DexPc() != inst.DexPc()); - if (next != accessor.end()) { + if (next != code_item_accessor_.end()) { locations->SetBit(next.DexPc()); } break; @@ -1706,7 +1745,8 @@ void HInstructionBuilder::BuildFillArrayData(const Instruction& instruction, uin int32_t payload_offset = instruction.VRegB_31t() + dex_pc; const Instruction::ArrayDataPayload* payload = - reinterpret_cast<const Instruction::ArrayDataPayload*>(code_item_->insns_ + payload_offset); + reinterpret_cast<const Instruction::ArrayDataPayload*>( + code_item_accessor_.Insns() + payload_offset); const uint8_t* data = payload->data; uint32_t element_count = payload->element_count; diff --git a/compiler/optimizing/instruction_builder.h b/compiler/optimizing/instruction_builder.h index 0500d40cd3..b4e30516ab 100644 --- a/compiler/optimizing/instruction_builder.h +++ b/compiler/optimizing/instruction_builder.h @@ -19,6 +19,7 @@ #include "base/scoped_arena_allocator.h" #include "base/scoped_arena_containers.h" +#include "code_item_accessors.h" #include "data_type.h" #include "dex_file.h" #include "dex_file_types.h" @@ -50,7 +51,7 @@ class HInstructionBuilder : public ValueObject { HBasicBlockBuilder* block_builder, SsaBuilder* ssa_builder, const DexFile* dex_file, - const DexFile::CodeItem* code_item, + const CodeItemDebugInfoAccessor& accessor, DataType::Type return_type, const DexCompilationUnit* dex_compilation_unit, const DexCompilationUnit* outer_compilation_unit, @@ -59,30 +60,7 @@ class HInstructionBuilder : public ValueObject { const uint8_t* interpreter_metadata, OptimizingCompilerStats* compiler_stats, VariableSizedHandleScope* handles, - ScopedArenaAllocator* local_allocator) - : allocator_(graph->GetAllocator()), - graph_(graph), - handles_(handles), - dex_file_(dex_file), - code_item_(code_item), - return_type_(return_type), - block_builder_(block_builder), - ssa_builder_(ssa_builder), - compiler_driver_(compiler_driver), - code_generator_(code_generator), - dex_compilation_unit_(dex_compilation_unit), - outer_compilation_unit_(outer_compilation_unit), - quicken_info_(interpreter_metadata), - compilation_stats_(compiler_stats), - local_allocator_(local_allocator), - locals_for_(local_allocator->Adapter(kArenaAllocGraphBuilder)), - current_block_(nullptr), - current_locals_(nullptr), - latest_result_(nullptr), - current_this_parameter_(nullptr), - loop_headers_(local_allocator->Adapter(kArenaAllocGraphBuilder)) { - loop_headers_.reserve(kDefaultNumberOfLoops); - } + ScopedArenaAllocator* local_allocator); bool Build(); void BuildIntrinsic(ArtMethod* method); @@ -329,7 +307,7 @@ class HInstructionBuilder : public ValueObject { // The dex file where the method being compiled is, and the bytecode data. const DexFile* const dex_file_; - const DexFile::CodeItem* const code_item_; // null for intrinsic graph. + const CodeItemDebugInfoAccessor code_item_accessor_; // null for intrinsic graph. // The return type of the method being compiled. const DataType::Type return_type_; diff --git a/compiler/optimizing/optimization.cc b/compiler/optimizing/optimization.cc index 7149d93d07..d8ac696d1e 100644 --- a/compiler/optimizing/optimization.cc +++ b/compiler/optimizing/optimization.cc @@ -35,6 +35,7 @@ #include "bounds_check_elimination.h" #include "cha_guard_optimization.h" +#include "code_item_accessors-inl.h" #include "code_sinking.h" #include "constant_folding.h" #include "constructor_fence_redundancy_elimination.h" @@ -241,7 +242,8 @@ ArenaVector<HOptimization*> ConstructOptimizations( opt = new (allocator) HDeadCodeElimination(graph, stats, name); break; case OptimizationPass::kInliner: { - size_t number_of_dex_registers = dex_compilation_unit.GetCodeItem()->registers_size_; + CodeItemDataAccessor accessor(dex_compilation_unit.GetDexFile(), + dex_compilation_unit.GetCodeItem()); opt = new (allocator) HInliner(graph, // outer_graph graph, // outermost_graph codegen, @@ -250,7 +252,7 @@ ArenaVector<HOptimization*> ConstructOptimizations( driver, handles, stats, - number_of_dex_registers, + accessor.RegistersSize(), /* total_number_of_instructions */ 0, /* parent */ nullptr, /* depth */ 0, diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc index 24b1a123ee..9d04dd8343 100644 --- a/compiler/optimizing/optimizing_compiler.cc +++ b/compiler/optimizing/optimizing_compiler.cc @@ -766,11 +766,13 @@ CodeGenerator* OptimizingCompiler::TryCompile(ArenaAllocator* allocator, static constexpr size_t kSpaceFilterOptimizingThreshold = 128; const CompilerOptions& compiler_options = compiler_driver->GetCompilerOptions(); if ((compiler_options.GetCompilerFilter() == CompilerFilter::kSpace) - && (code_item->insns_size_in_code_units_ > kSpaceFilterOptimizingThreshold)) { + && (CodeItemInstructionAccessor(&dex_file, code_item).InsnsSizeInCodeUnits() > + kSpaceFilterOptimizingThreshold)) { MaybeRecordStat(compilation_stats_.get(), MethodCompilationStat::kNotCompiledSpaceFilter); return nullptr; } + CodeItemDebugInfoAccessor code_item_accessor(&dex_file, code_item); HGraph* graph = new (allocator) HGraph( allocator, arena_stack, @@ -814,7 +816,7 @@ CodeGenerator* OptimizingCompiler::TryCompile(ArenaAllocator* allocator, VLOG(compiler) << "Building " << pass_observer.GetMethodName(); PassScope scope(HGraphBuilder::kBuilderPassName, &pass_observer); HGraphBuilder builder(graph, - code_item, + code_item_accessor, &dex_compilation_unit, &dex_compilation_unit, compiler_driver, @@ -932,7 +934,7 @@ CodeGenerator* OptimizingCompiler::TryCompileIntrinsic( VLOG(compiler) << "Building intrinsic graph " << pass_observer.GetMethodName(); PassScope scope(HGraphBuilder::kBuilderPassName, &pass_observer); HGraphBuilder builder(graph, - /* code_item */ nullptr, + CodeItemDebugInfoAccessor(), // Null code item. &dex_compilation_unit, &dex_compilation_unit, compiler_driver, diff --git a/compiler/optimizing/optimizing_unit_test.h b/compiler/optimizing/optimizing_unit_test.h index 158c252f45..7d05262b10 100644 --- a/compiler/optimizing/optimizing_unit_test.h +++ b/compiler/optimizing/optimizing_unit_test.h @@ -19,6 +19,7 @@ #include "base/scoped_arena_allocator.h" #include "builder.h" +#include "code_item_accessors-inl.h" #include "common_compiler_test.h" #include "dex_file.h" #include "dex_instruction.h" @@ -145,7 +146,8 @@ class OptimizingUnitTest : public CommonCompilerTest { /* access_flags */ 0u, /* verified_method */ nullptr, handles_->NewHandle<mirror::DexCache>(nullptr)); - HGraphBuilder builder(graph, dex_compilation_unit, *code_item, handles_.get(), return_type); + CodeItemDebugInfoAccessor accessor(&graph->GetDexFile(), code_item); + HGraphBuilder builder(graph, dex_compilation_unit, accessor, handles_.get(), return_type); bool graph_built = (builder.BuildGraph() == kAnalysisSuccess); return graph_built ? graph : nullptr; } diff --git a/dexdump/dexdump.cc b/dexdump/dexdump.cc index f64c89a5b0..730d4b97a0 100644 --- a/dexdump/dexdump.cc +++ b/dexdump/dexdump.cc @@ -735,7 +735,7 @@ static void dumpInterface(const DexFile* pDexFile, const DexFile::TypeItem& pTyp * Dumps the catches table associated with the code. */ static void dumpCatches(const DexFile* pDexFile, const DexFile::CodeItem* pCode) { - const u4 triesSize = pCode->tries_size_; + const u4 triesSize = CodeItemDataAccessor(pDexFile, pCode).TriesSize(); // No catch table. if (triesSize == 0) { diff --git a/dexdump/dexdump_cfg.cc b/dexdump/dexdump_cfg.cc index 23ecf93447..dd57a11758 100644 --- a/dexdump/dexdump_cfg.cc +++ b/dexdump/dexdump_cfg.cc @@ -25,6 +25,7 @@ #include <set> #include <sstream> +#include "code_item_accessors-no_art-inl.h" #include "dex_file-inl.h" #include "dex_instruction-inl.h" @@ -37,17 +38,17 @@ static void dumpMethodCFGImpl(const DexFile* dex_file, os << "digraph {\n"; os << " # /* " << dex_file->PrettyMethod(dex_method_idx, true) << " */\n"; + CodeItemInstructionAccessor accessor(dex_file, code_item); + std::set<uint32_t> dex_pc_is_branch_target; { // Go and populate. - const Instruction* inst = Instruction::At(code_item->insns_); - for (uint32_t dex_pc = 0; - dex_pc < code_item->insns_size_in_code_units_; - dex_pc += inst->SizeInCodeUnits(), inst = inst->Next()) { + for (const DexInstructionPcPair& pair : accessor) { + const Instruction* inst = &pair.Inst(); if (inst->IsBranch()) { - dex_pc_is_branch_target.insert(dex_pc + inst->GetTargetOffset()); + dex_pc_is_branch_target.insert(pair.DexPc() + inst->GetTargetOffset()); } else if (inst->IsSwitch()) { - const uint16_t* insns = code_item->insns_ + dex_pc; + const uint16_t* insns = reinterpret_cast<const uint16_t*>(inst); int32_t switch_offset = insns[1] | (static_cast<int32_t>(insns[2]) << 16); const uint16_t* switch_insns = insns + switch_offset; uint32_t switch_count = switch_insns[1]; @@ -63,7 +64,7 @@ static void dumpMethodCFGImpl(const DexFile* dex_file, int32_t offset = static_cast<int32_t>(switch_insns[targets_offset + targ * 2]) | static_cast<int32_t>(switch_insns[targets_offset + targ * 2 + 1] << 16); - dex_pc_is_branch_target.insert(dex_pc + offset); + dex_pc_is_branch_target.insert(pair.DexPc() + offset); } } } @@ -74,12 +75,10 @@ static void dumpMethodCFGImpl(const DexFile* dex_file, std::map<uint32_t, uint32_t> dex_pc_to_incl_id; // This has entries for all dex pcs. { - const Instruction* inst = Instruction::At(code_item->insns_); bool first_in_block = true; bool force_new_block = false; - for (uint32_t dex_pc = 0; - dex_pc < code_item->insns_size_in_code_units_; - dex_pc += inst->SizeInCodeUnits(), inst = inst->Next()) { + for (const DexInstructionPcPair& pair : accessor) { + const uint32_t dex_pc = pair.DexPc(); if (dex_pc == 0 || (dex_pc_is_branch_target.find(dex_pc) != dex_pc_is_branch_target.end()) || force_new_block) { @@ -108,7 +107,7 @@ static void dumpMethodCFGImpl(const DexFile* dex_file, // Dump the instruction. Need to escape '"', '<', '>', '{' and '}'. os << "<" << "p" << dex_pc << ">"; os << " 0x" << std::hex << dex_pc << std::dec << ": "; - std::string inst_str = inst->DumpString(dex_file); + std::string inst_str = pair.Inst().DumpString(dex_file); size_t cur_start = 0; // It's OK to start at zero, instruction dumps don't start with chars // we need to escape. while (cur_start != std::string::npos) { @@ -137,7 +136,7 @@ static void dumpMethodCFGImpl(const DexFile* dex_file, // Force a new block for some fall-throughs and some instructions that terminate the "local" // control flow. - force_new_block = inst->IsSwitch() || inst->IsBasicBlockEnd(); + force_new_block = pair.Inst().IsSwitch() || pair.Inst().IsBasicBlockEnd(); } // Close last node. if (dex_pc_to_node_id.size() > 0) { @@ -162,10 +161,9 @@ static void dumpMethodCFGImpl(const DexFile* dex_file, uint32_t last_node_id = std::numeric_limits<uint32_t>::max(); uint32_t old_dex_pc = 0; uint32_t block_start_dex_pc = std::numeric_limits<uint32_t>::max(); - const Instruction* inst = Instruction::At(code_item->insns_); - for (uint32_t dex_pc = 0; - dex_pc < code_item->insns_size_in_code_units_; - old_dex_pc = dex_pc, dex_pc += inst->SizeInCodeUnits(), inst = inst->Next()) { + for (const DexInstructionPcPair& pair : accessor) { + const Instruction* inst = &pair.Inst(); + const uint32_t dex_pc = pair.DexPc(); { auto it = dex_pc_to_node_id.find(dex_pc); if (it != dex_pc_to_node_id.end()) { @@ -222,7 +220,7 @@ static void dumpMethodCFGImpl(const DexFile* dex_file, } } else if (inst->IsSwitch()) { // TODO: Iterate through all switch targets. - const uint16_t* insns = code_item->insns_ + dex_pc; + const uint16_t* insns = reinterpret_cast<const uint16_t*>(inst); /* make sure the start of the switch is in range */ int32_t switch_offset = insns[1] | (static_cast<int32_t>(insns[2]) << 16); /* offset to switch table is a relative branch-style offset */ @@ -272,6 +270,7 @@ static void dumpMethodCFGImpl(const DexFile* dex_file, // No fall-through. last_node_id = std::numeric_limits<uint32_t>::max(); } + old_dex_pc = pair.DexPc(); } // Finish up the last block, if it had common exceptions. if (!exception_targets.empty()) { @@ -293,7 +292,7 @@ static void dumpMethodCFGImpl(const DexFile* dex_file, // TODO // Exception edges. If this is not the first instruction in the block for (uint32_t dex_pc : blocks_with_detailed_exceptions) { - const Instruction* inst = Instruction::At(&code_item->insns_[dex_pc]); + const Instruction* inst = &accessor.InstructionAt(dex_pc); uint32_t this_node_id = dex_pc_to_incl_id.find(dex_pc)->second; while (true) { CatchHandlerIterator catch_it(*code_item, dex_pc); @@ -322,7 +321,7 @@ static void dumpMethodCFGImpl(const DexFile* dex_file, // Loop update. Have a break-out if the next instruction is a branch target and thus in // another block. dex_pc += inst->SizeInCodeUnits(); - if (dex_pc >= code_item->insns_size_in_code_units_) { + if (dex_pc >= accessor.InsnsSizeInCodeUnits()) { break; } if (dex_pc_to_node_id.find(dex_pc) != dex_pc_to_node_id.end()) { diff --git a/dexlayout/dex_ir.cc b/dexlayout/dex_ir.cc index 90df2d7bb9..a163bd96c0 100644 --- a/dexlayout/dex_ir.cc +++ b/dexlayout/dex_ir.cc @@ -21,6 +21,8 @@ */ #include "dex_ir.h" + +#include "code_item_accessors-inl.h" #include "dex_instruction-inl.h" #include "dex_ir_builder.h" @@ -564,13 +566,14 @@ ParameterAnnotation* Collections::GenerateParameterAnnotation( CodeItem* Collections::CreateCodeItem(const DexFile& dex_file, const DexFile::CodeItem& disk_code_item, uint32_t offset) { - uint16_t registers_size = disk_code_item.registers_size_; - uint16_t ins_size = disk_code_item.ins_size_; - uint16_t outs_size = disk_code_item.outs_size_; - uint32_t tries_size = disk_code_item.tries_size_; + CodeItemDebugInfoAccessor accessor(&dex_file, &disk_code_item); + const uint16_t registers_size = accessor.RegistersSize(); + const uint16_t ins_size = accessor.InsSize(); + const uint16_t outs_size = accessor.OutsSize(); + const uint32_t tries_size = accessor.TriesSize(); // TODO: Calculate the size of the debug info. - uint32_t debug_info_offset = dex_file.GetDebugInfoOffset(&disk_code_item); + const uint32_t debug_info_offset = accessor.DebugInfoOffset(); const uint8_t* debug_info_stream = dex_file.GetDebugInfoStream(debug_info_offset); DebugInfoItem* debug_info = nullptr; if (debug_info_stream != nullptr) { @@ -584,20 +587,19 @@ CodeItem* Collections::CreateCodeItem(const DexFile& dex_file, } } - uint32_t insns_size = disk_code_item.insns_size_in_code_units_; + uint32_t insns_size = accessor.InsnsSizeInCodeUnits(); uint16_t* insns = new uint16_t[insns_size]; - memcpy(insns, disk_code_item.insns_, insns_size * sizeof(uint16_t)); + memcpy(insns, accessor.Insns(), insns_size * sizeof(uint16_t)); TryItemVector* tries = nullptr; CatchHandlerVector* handler_list = nullptr; if (tries_size > 0) { tries = new TryItemVector(); handler_list = new CatchHandlerVector(); - for (uint32_t i = 0; i < tries_size; ++i) { - const DexFile::TryItem* disk_try_item = dex_file.GetTryItems(disk_code_item, i); - uint32_t start_addr = disk_try_item->start_addr_; - uint16_t insn_count = disk_try_item->insn_count_; - uint16_t handler_off = disk_try_item->handler_off_; + for (const DexFile::TryItem& disk_try_item : accessor.TryItems()) { + uint32_t start_addr = disk_try_item.start_addr_; + uint16_t insn_count = disk_try_item.insn_count_; + uint16_t handler_off = disk_try_item.handler_off_; const CatchHandler* handlers = nullptr; for (std::unique_ptr<const CatchHandler>& existing_handlers : *handler_list) { if (handler_off == existing_handlers->GetListOffset()) { @@ -608,7 +610,7 @@ CodeItem* Collections::CreateCodeItem(const DexFile& dex_file, if (handlers == nullptr) { bool catch_all = false; TypeAddrPairVector* addr_pairs = new TypeAddrPairVector(); - for (CatchHandlerIterator it(disk_code_item, *disk_try_item); it.HasNext(); it.Next()) { + for (CatchHandlerIterator it(disk_code_item, disk_try_item); it.HasNext(); it.Next()) { const dex::TypeIndex type_index = it.GetHandlerTypeIndex(); const TypeId* type_id = GetTypeIdOrNullPtr(type_index.index_); catch_all |= type_id == nullptr; @@ -622,7 +624,7 @@ CodeItem* Collections::CreateCodeItem(const DexFile& dex_file, tries->push_back(std::unique_ptr<const TryItem>(try_item)); } // Manually walk catch handlers list and add any missing handlers unreferenced by try items. - const uint8_t* handlers_base = DexFile::GetCatchHandlerData(disk_code_item, 0); + const uint8_t* handlers_base = accessor.GetCatchHandlerData(); const uint8_t* handlers_data = handlers_base; uint32_t handlers_size = DecodeUnsignedLeb128(&handlers_data); while (handlers_size > handler_list->size()) { diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc index 1a1d8cc76e..b2e19a89d6 100644 --- a/oatdump/oatdump.cc +++ b/oatdump/oatdump.cc @@ -1261,8 +1261,7 @@ class OatDumper { bool* addr_found) { bool success = true; - CodeItemDataAccessor code_item_accessor(CodeItemDataAccessor::CreateNullable(&dex_file, - code_item)); + CodeItemDataAccessor code_item_accessor(&dex_file, code_item); // TODO: Support regex std::string method_name = dex_file.GetMethodName(dex_file.GetMethodId(dex_method_idx)); diff --git a/openjdkjvmti/ti_breakpoint.cc b/openjdkjvmti/ti_breakpoint.cc index 8e5b56e9bf..7634fa312f 100644 --- a/openjdkjvmti/ti_breakpoint.cc +++ b/openjdkjvmti/ti_breakpoint.cc @@ -98,7 +98,7 @@ jvmtiError BreakpointUtil::SetBreakpoint(jvmtiEnv* jenv, jmethodID method, jloca art::ScopedObjectAccess soa(art::Thread::Current()); art::ArtMethod* art_method = art::jni::DecodeArtMethod(method)->GetCanonicalMethod(); if (location < 0 || static_cast<uint32_t>(location) >= - art_method->GetCodeItem()->insns_size_in_code_units_) { + art_method->DexInstructions().InsnsSizeInCodeUnits()) { return ERR(INVALID_LOCATION); } DeoptManager::Get()->AddMethodBreakpoint(art_method); diff --git a/openjdkjvmti/ti_method.cc b/openjdkjvmti/ti_method.cc index 4444853427..947ba7911f 100644 --- a/openjdkjvmti/ti_method.cc +++ b/openjdkjvmti/ti_method.cc @@ -123,19 +123,19 @@ jvmtiError MethodUtil::GetBytecodes(jvmtiEnv* env, } art::ScopedObjectAccess soa(art::Thread::Current()); - const art::DexFile::CodeItem* code_item = art_method->GetCodeItem(); - if (code_item == nullptr) { + art::CodeItemInstructionAccessor accessor(art_method); + if (!accessor.HasCodeItem()) { *size_ptr = 0; *bytecode_ptr = nullptr; return OK; } // 2 bytes per instruction for dex code. - *size_ptr = code_item->insns_size_in_code_units_ * 2; + *size_ptr = accessor.InsnsSizeInCodeUnits() * 2; jvmtiError err = env->Allocate(*size_ptr, bytecode_ptr); if (err != OK) { return err; } - memcpy(*bytecode_ptr, code_item->insns_, *size_ptr); + memcpy(*bytecode_ptr, accessor.Insns(), *size_ptr); return OK; } @@ -168,7 +168,7 @@ jvmtiError MethodUtil::GetArgumentsSize(jvmtiEnv* env ATTRIBUTE_UNUSED, } DCHECK_NE(art_method->GetCodeItemOffset(), 0u); - *size_ptr = art_method->GetCodeItem()->ins_size_; + *size_ptr = art::CodeItemDataAccessor(art_method).InsSize(); return ERR(NONE); } @@ -266,14 +266,10 @@ jvmtiError MethodUtil::GetLocalVariableTable(jvmtiEnv* env, }; LocalVariableContext context(env); - if (!dex_file->DecodeDebugLocalInfo(accessor.RegistersSize(), - accessor.InsSize(), - accessor.InsnsSizeInCodeUnits(), - accessor.DebugInfoOffset(), - art_method->IsStatic(), - art_method->GetDexMethodIndex(), - LocalVariableContext::Callback, - &context)) { + if (!accessor.DecodeDebugLocalInfo(art_method->IsStatic(), + art_method->GetDexMethodIndex(), + LocalVariableContext::Callback, + &context)) { // Something went wrong with decoding the debug information. It might as well not be there. return ERR(ABSENT_INFORMATION); } else { @@ -305,7 +301,7 @@ jvmtiError MethodUtil::GetMaxLocals(jvmtiEnv* env ATTRIBUTE_UNUSED, } DCHECK_NE(art_method->GetCodeItemOffset(), 0u); - *max_ptr = art_method->GetCodeItem()->registers_size_; + *max_ptr = art::CodeItemDataAccessor(art_method).RegistersSize(); return ERR(NONE); } @@ -420,7 +416,7 @@ jvmtiError MethodUtil::GetMethodLocation(jvmtiEnv* env ATTRIBUTE_UNUSED, DCHECK_NE(art_method->GetCodeItemOffset(), 0u); *start_location_ptr = 0; - *end_location_ptr = art_method->GetCodeItem()->insns_size_in_code_units_ - 1; + *end_location_ptr = art_method->DexInstructions().InsnsSizeInCodeUnits() - 1; return ERR(NONE); } @@ -571,7 +567,7 @@ class CommonLocalVariableClosure : public art::Closure { // TODO It might be useful to fake up support for get at least on proxy frames. result_ = ERR(OPAQUE_FRAME); return; - } else if (method->GetCodeItem()->registers_size_ <= slot_) { + } else if (art::CodeItemDataAccessor(method).RegistersSize() <= slot_) { result_ = ERR(INVALID_SLOT); return; } diff --git a/openjdkjvmti/ti_stack.cc b/openjdkjvmti/ti_stack.cc index b43eaa0286..17b4243377 100644 --- a/openjdkjvmti/ti_stack.cc +++ b/openjdkjvmti/ti_stack.cc @@ -44,6 +44,7 @@ #include "base/bit_utils.h" #include "base/enums.h" #include "base/mutex.h" +#include "code_item_accessors-inl.h" #include "dex_file.h" #include "dex_file_annotations.h" #include "dex_file_types.h" @@ -1044,7 +1045,7 @@ jvmtiError StackUtil::NotifyFramePop(jvmtiEnv* env, jthread thread, jint depth) if (shadow_frame == nullptr) { needs_instrument = true; const size_t frame_id = visitor.GetFrameId(); - const uint16_t num_regs = method->GetCodeItem()->registers_size_; + const uint16_t num_regs = art::CodeItemDataAccessor(method).RegistersSize(); shadow_frame = target->FindOrCreateDebuggerShadowFrame(frame_id, num_regs, method, diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h index 869394c388..c6c4f4ae41 100644 --- a/runtime/art_method-inl.h +++ b/runtime/art_method-inl.h @@ -459,16 +459,8 @@ inline void ArtMethod::UpdateEntrypoints(const Visitor& visitor, PointerSize poi } } -inline IterationRange<DexInstructionIterator> ArtMethod::DexInstructions() { - CodeItemInstructionAccessor accessor(this); - return { accessor.begin(), - accessor.end() }; -} - -inline IterationRange<DexInstructionIterator> ArtMethod::NullableDexInstructions() { - CodeItemInstructionAccessor accessor(CodeItemInstructionAccessor::CreateNullable(this)); - return { accessor.begin(), - accessor.end() }; +inline CodeItemInstructionAccessor ArtMethod::DexInstructions() { + return CodeItemInstructionAccessor(this); } } // namespace art diff --git a/runtime/art_method.cc b/runtime/art_method.cc index 9005120eb0..7ddaa7edc3 100644 --- a/runtime/art_method.cc +++ b/runtime/art_method.cc @@ -297,9 +297,8 @@ uint32_t ArtMethod::FindCatchBlock(Handle<mirror::Class> exception_type, } } if (found_dex_pc != dex::kDexNoIndex) { - const Instruction* first_catch_instr = - Instruction::At(&code_item->insns_[found_dex_pc]); - *has_no_move_exception = (first_catch_instr->Opcode() != Instruction::MOVE_EXCEPTION); + const Instruction& first_catch_instr = DexInstructions().InstructionAt(found_dex_pc); + *has_no_move_exception = (first_catch_instr.Opcode() != Instruction::MOVE_EXCEPTION); } // Put the exception back. if (exception != nullptr) { diff --git a/runtime/art_method.h b/runtime/art_method.h index f433223ebf..ab90a10f5a 100644 --- a/runtime/art_method.h +++ b/runtime/art_method.h @@ -27,6 +27,7 @@ #include "base/iteration_range.h" #include "base/macros.h" #include "base/runtime_debug.h" +#include "code_item_accessors.h" #include "dex_file.h" #include "dex_instruction_iterator.h" #include "gc_root.h" @@ -716,13 +717,9 @@ class ArtMethod FINAL { "ptr_sized_fields_.entry_point_from_quick_compiled_code_"); } - // Returns the dex instructions of the code item for the art method. Must not be called on null - // code items. - ALWAYS_INLINE IterationRange<DexInstructionIterator> DexInstructions() - REQUIRES_SHARED(Locks::mutator_lock_); - - // Handles a null code item by returning iterators that have a null address. - ALWAYS_INLINE IterationRange<DexInstructionIterator> NullableDexInstructions() + // Returns the dex instructions of the code item for the art method. Returns an empty array for + // the null code item case. + ALWAYS_INLINE CodeItemInstructionAccessor DexInstructions() REQUIRES_SHARED(Locks::mutator_lock_); protected: diff --git a/runtime/check_reference_map_visitor.h b/runtime/check_reference_map_visitor.h index d9e89159f5..c4a613a942 100644 --- a/runtime/check_reference_map_visitor.h +++ b/runtime/check_reference_map_visitor.h @@ -18,6 +18,7 @@ #define ART_RUNTIME_CHECK_REFERENCE_MAP_VISITOR_H_ #include "art_method-inl.h" +#include "code_item_accessors-inl.h" #include "dex_file_types.h" #include "oat_quick_method_header.h" #include "scoped_thread_state_change-inl.h" @@ -66,14 +67,15 @@ class CheckReferenceMapVisitor : public StackVisitor { CodeInfo code_info = GetCurrentOatQuickMethodHeader()->GetOptimizedCodeInfo(); CodeInfoEncoding encoding = code_info.ExtractEncoding(); StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset, encoding); - uint16_t number_of_dex_registers = m->GetCodeItem()->registers_size_; + CodeItemDataAccessor accessor(m); + uint16_t number_of_dex_registers = accessor.RegistersSize(); DexRegisterMap dex_register_map = code_info.GetDexRegisterMapOf(stack_map, encoding, number_of_dex_registers); uint32_t register_mask = code_info.GetRegisterMaskOf(encoding, stack_map); BitMemoryRegion stack_mask = code_info.GetStackMaskOf(encoding, stack_map); for (int i = 0; i < number_of_references; ++i) { int reg = registers[i]; - CHECK(reg < m->GetCodeItem()->registers_size_); + CHECK_LT(reg, accessor.RegistersSize()); DexRegisterLocation location = dex_register_map.GetDexRegisterLocation( reg, number_of_dex_registers, code_info, encoding); switch (location.GetKind()) { diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 55fa6328f5..45b761893f 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -4317,15 +4317,14 @@ void ClassLinker::ResolveClassExceptionHandlerTypes(Handle<mirror::Class> klass) void ClassLinker::ResolveMethodExceptionHandlerTypes(ArtMethod* method) { // similar to DexVerifier::ScanTryCatchBlocks and dex2oat's ResolveExceptionsForMethod. - const DexFile::CodeItem* code_item = - method->GetDexFile()->GetCodeItem(method->GetCodeItemOffset()); - if (code_item == nullptr) { + CodeItemDataAccessor accessor(method); + if (!accessor.HasCodeItem()) { return; // native or abstract method } - if (code_item->tries_size_ == 0) { + if (accessor.TriesSize() == 0) { return; // nothing to process } - const uint8_t* handlers_ptr = DexFile::GetCatchHandlerData(*code_item, 0); + const uint8_t* handlers_ptr = accessor.GetCatchHandlerData(0); uint32_t handlers_size = DecodeUnsignedLeb128(&handlers_ptr); for (uint32_t idx = 0; idx < handlers_size; idx++) { CatchHandlerIterator iterator(handlers_ptr); diff --git a/runtime/code_item_accessors-inl.h b/runtime/code_item_accessors-inl.h index 1ba3c55f77..f63ea6990f 100644 --- a/runtime/code_item_accessors-inl.h +++ b/runtime/code_item_accessors-inl.h @@ -30,27 +30,9 @@ namespace art { inline CodeItemInstructionAccessor::CodeItemInstructionAccessor(ArtMethod* method) : CodeItemInstructionAccessor(method->GetDexFile(), method->GetCodeItem()) {} -inline CodeItemInstructionAccessor CodeItemInstructionAccessor::CreateNullable( - ArtMethod* method) { - DCHECK(method != nullptr); - CodeItemInstructionAccessor ret; - const DexFile::CodeItem* code_item = method->GetCodeItem(); - if (code_item != nullptr) { - ret.Init(method->GetDexFile(), code_item); - } else { - DCHECK(!ret.HasCodeItem()) << "Should be null initialized"; - } - return ret; -} - inline CodeItemDataAccessor::CodeItemDataAccessor(ArtMethod* method) : CodeItemDataAccessor(method->GetDexFile(), method->GetCodeItem()) {} -inline CodeItemDataAccessor CodeItemDataAccessor::CreateNullable(ArtMethod* method) { - DCHECK(method != nullptr); - return CreateNullable(method->GetDexFile(), method->GetCodeItem()); -} - inline CodeItemDebugInfoAccessor::CodeItemDebugInfoAccessor(ArtMethod* method) : CodeItemDebugInfoAccessor(method->GetDexFile(), method->GetCodeItem()) {} @@ -59,7 +41,7 @@ inline CodeItemDebugInfoAccessor::CodeItemDebugInfoAccessor(const DexFile* dex_f if (code_item == nullptr) { return; } - Init(dex_file, code_item, OatFile::GetDebugInfoOffset(*dex_file, code_item)); + Init(dex_file, code_item, OatFile::GetDebugInfoOffset(*dex_file, code_item->debug_info_off_)); } } // namespace art diff --git a/runtime/code_item_accessors-no_art-inl.h b/runtime/code_item_accessors-no_art-inl.h index 96321b54f5..ebdd78bd74 100644 --- a/runtime/code_item_accessors-no_art-inl.h +++ b/runtime/code_item_accessors-no_art-inl.h @@ -24,7 +24,6 @@ #include "standard_dex_file.h" // The no ART version is used by binaries that don't include the whole runtime. - namespace art { inline void CodeItemInstructionAccessor::Init(const CompactDexFile::CodeItem& code_item) { @@ -39,13 +38,14 @@ inline void CodeItemInstructionAccessor::Init(const StandardDexFile::CodeItem& c inline void CodeItemInstructionAccessor::Init(const DexFile* dex_file, const DexFile::CodeItem* code_item) { - DCHECK(dex_file != nullptr); - DCHECK(code_item != nullptr); - if (dex_file->IsCompactDexFile()) { - Init(down_cast<const CompactDexFile::CodeItem&>(*code_item)); - } else { - DCHECK(dex_file->IsStandardDexFile()); - Init(down_cast<const StandardDexFile::CodeItem&>(*code_item)); + if (code_item != nullptr) { + DCHECK(dex_file != nullptr); + if (dex_file->IsCompactDexFile()) { + Init(down_cast<const CompactDexFile::CodeItem&>(*code_item)); + } else { + DCHECK(dex_file->IsStandardDexFile()); + Init(down_cast<const StandardDexFile::CodeItem&>(*code_item)); + } } } @@ -63,6 +63,14 @@ inline DexInstructionIterator CodeItemInstructionAccessor::end() const { return DexInstructionIterator(insns_, insns_size_in_code_units_); } +inline IterationRange<DexInstructionIterator> CodeItemInstructionAccessor::InstructionsFrom( + uint32_t start_dex_pc) const { + DCHECK_LT(start_dex_pc, InsnsSizeInCodeUnits()); + return { + DexInstructionIterator(insns_, start_dex_pc), + DexInstructionIterator(insns_, insns_size_in_code_units_) }; +} + inline void CodeItemDataAccessor::Init(const CompactDexFile::CodeItem& code_item) { CodeItemInstructionAccessor::Init(code_item); registers_size_ = code_item.registers_size_; @@ -81,13 +89,14 @@ inline void CodeItemDataAccessor::Init(const StandardDexFile::CodeItem& code_ite inline void CodeItemDataAccessor::Init(const DexFile* dex_file, const DexFile::CodeItem* code_item) { - DCHECK(dex_file != nullptr); - DCHECK(code_item != nullptr); - if (dex_file->IsCompactDexFile()) { - CodeItemDataAccessor::Init(down_cast<const CompactDexFile::CodeItem&>(*code_item)); - } else { - DCHECK(dex_file->IsStandardDexFile()); - CodeItemDataAccessor::Init(down_cast<const StandardDexFile::CodeItem&>(*code_item)); + if (code_item != nullptr) { + DCHECK(dex_file != nullptr); + if (dex_file->IsCompactDexFile()) { + CodeItemDataAccessor::Init(down_cast<const CompactDexFile::CodeItem&>(*code_item)); + } else { + DCHECK(dex_file->IsStandardDexFile()); + CodeItemDataAccessor::Init(down_cast<const StandardDexFile::CodeItem&>(*code_item)); + } } } @@ -96,18 +105,6 @@ inline CodeItemDataAccessor::CodeItemDataAccessor(const DexFile* dex_file, Init(dex_file, code_item); } -inline CodeItemDataAccessor CodeItemDataAccessor::CreateNullable( - const DexFile* dex_file, - const DexFile::CodeItem* code_item) { - CodeItemDataAccessor ret; - if (code_item != nullptr) { - ret.Init(dex_file, code_item); - } else { - DCHECK(!ret.HasCodeItem()) << "Should be null initialized"; - } - return ret; -} - inline IterationRange<const DexFile::TryItem*> CodeItemDataAccessor::TryItems() const { const DexFile::TryItem* try_items = DexFile::GetTryItems(end(), 0u); return { @@ -163,7 +160,6 @@ inline bool CodeItemDebugInfoAccessor::DecodeDebugLocalInfo(bool is_static, context); } - } // namespace art #endif // ART_RUNTIME_CODE_ITEM_ACCESSORS_NO_ART_INL_H_ diff --git a/runtime/code_item_accessors.h b/runtime/code_item_accessors.h index 9f40114438..4cbe7a1ba0 100644 --- a/runtime/code_item_accessors.h +++ b/runtime/code_item_accessors.h @@ -42,6 +42,8 @@ class CodeItemInstructionAccessor { ALWAYS_INLINE DexInstructionIterator end() const; + IterationRange<DexInstructionIterator> InstructionsFrom(uint32_t start_dex_pc) const; + uint32_t InsnsSizeInCodeUnits() const { return insns_size_in_code_units_; } @@ -52,6 +54,7 @@ class CodeItemInstructionAccessor { // Return the instruction for a dex pc. const Instruction& InstructionAt(uint32_t dex_pc) const { + DCHECK_LT(dex_pc, InsnsSizeInCodeUnits()); return *Instruction::At(insns_ + dex_pc); } @@ -60,10 +63,6 @@ class CodeItemInstructionAccessor { return Insns() != nullptr; } - // CreateNullable allows ArtMethods that have a null code item. - ALWAYS_INLINE static CodeItemInstructionAccessor CreateNullable(ArtMethod* method) - REQUIRES_SHARED(Locks::mutator_lock_); - protected: CodeItemInstructionAccessor() = default; @@ -109,14 +108,6 @@ class CodeItemDataAccessor : public CodeItemInstructionAccessor { const DexFile::TryItem* FindTryItem(uint32_t try_dex_pc) const; - // CreateNullable allows ArtMethods that have a null code item. - ALWAYS_INLINE static CodeItemDataAccessor CreateNullable(ArtMethod* method) - REQUIRES_SHARED(Locks::mutator_lock_); - - ALWAYS_INLINE static CodeItemDataAccessor CreateNullable( - const DexFile* dex_file, - const DexFile::CodeItem* code_item); - protected: CodeItemDataAccessor() = default; diff --git a/runtime/common_dex_operations.h b/runtime/common_dex_operations.h index 267735fe95..89887022e0 100644 --- a/runtime/common_dex_operations.h +++ b/runtime/common_dex_operations.h @@ -23,6 +23,7 @@ #include "base/macros.h" #include "base/mutex.h" #include "class_linker.h" +#include "code_item_accessors.h" #include "handle_scope-inl.h" #include "instrumentation.h" #include "interpreter/shadow_frame.h" @@ -52,7 +53,7 @@ namespace interpreter { } // namespace interpreter inline void PerformCall(Thread* self, - const DexFile::CodeItem* code_item, + const CodeItemDataAccessor& accessor, ArtMethod* caller_method, const size_t first_dest_reg, ShadowFrame* callee_frame, @@ -61,13 +62,13 @@ inline void PerformCall(Thread* self, REQUIRES_SHARED(Locks::mutator_lock_) { if (LIKELY(Runtime::Current()->IsStarted())) { if (use_interpreter_entrypoint) { - interpreter::ArtInterpreterToInterpreterBridge(self, code_item, callee_frame, result); + interpreter::ArtInterpreterToInterpreterBridge(self, accessor, callee_frame, result); } else { interpreter::ArtInterpreterToCompiledCodeBridge( self, caller_method, callee_frame, first_dest_reg, result); } } else { - interpreter::UnstartedRuntime::Invoke(self, code_item, callee_frame, result, first_dest_reg); + interpreter::UnstartedRuntime::Invoke(self, accessor, callee_frame, result, first_dest_reg); } } diff --git a/runtime/common_throws.cc b/runtime/common_throws.cc index 575d18e26a..707885c88d 100644 --- a/runtime/common_throws.cc +++ b/runtime/common_throws.cc @@ -551,43 +551,43 @@ static bool IsValidImplicitCheck(uintptr_t addr, const Instruction& instr) void ThrowNullPointerExceptionFromDexPC(bool check_address, uintptr_t addr) { uint32_t throw_dex_pc; ArtMethod* method = Thread::Current()->GetCurrentMethod(&throw_dex_pc); - const DexFile::CodeItem* code = method->GetCodeItem(); - CHECK_LT(throw_dex_pc, code->insns_size_in_code_units_); - const Instruction* instr = Instruction::At(&code->insns_[throw_dex_pc]); - if (check_address && !IsValidImplicitCheck(addr, *instr)) { + CodeItemInstructionAccessor accessor(method); + CHECK_LT(throw_dex_pc, accessor.InsnsSizeInCodeUnits()); + const Instruction& instr = accessor.InstructionAt(throw_dex_pc); + if (check_address && !IsValidImplicitCheck(addr, instr)) { const DexFile* dex_file = method->GetDeclaringClass()->GetDexCache()->GetDexFile(); LOG(FATAL) << "Invalid address for an implicit NullPointerException check: " << "0x" << std::hex << addr << std::dec << ", at " - << instr->DumpString(dex_file) + << instr.DumpString(dex_file) << " in " << method->PrettyMethod(); } - switch (instr->Opcode()) { + switch (instr.Opcode()) { case Instruction::INVOKE_DIRECT: - ThrowNullPointerExceptionForMethodAccess(instr->VRegB_35c(), kDirect); + ThrowNullPointerExceptionForMethodAccess(instr.VRegB_35c(), kDirect); break; case Instruction::INVOKE_DIRECT_RANGE: - ThrowNullPointerExceptionForMethodAccess(instr->VRegB_3rc(), kDirect); + ThrowNullPointerExceptionForMethodAccess(instr.VRegB_3rc(), kDirect); break; case Instruction::INVOKE_VIRTUAL: - ThrowNullPointerExceptionForMethodAccess(instr->VRegB_35c(), kVirtual); + ThrowNullPointerExceptionForMethodAccess(instr.VRegB_35c(), kVirtual); break; case Instruction::INVOKE_VIRTUAL_RANGE: - ThrowNullPointerExceptionForMethodAccess(instr->VRegB_3rc(), kVirtual); + ThrowNullPointerExceptionForMethodAccess(instr.VRegB_3rc(), kVirtual); break; case Instruction::INVOKE_INTERFACE: - ThrowNullPointerExceptionForMethodAccess(instr->VRegB_35c(), kInterface); + ThrowNullPointerExceptionForMethodAccess(instr.VRegB_35c(), kInterface); break; case Instruction::INVOKE_INTERFACE_RANGE: - ThrowNullPointerExceptionForMethodAccess(instr->VRegB_3rc(), kInterface); + ThrowNullPointerExceptionForMethodAccess(instr.VRegB_3rc(), kInterface); break; case Instruction::INVOKE_POLYMORPHIC: - ThrowNullPointerExceptionForMethodAccess(instr->VRegB_45cc(), kVirtual); + ThrowNullPointerExceptionForMethodAccess(instr.VRegB_45cc(), kVirtual); break; case Instruction::INVOKE_POLYMORPHIC_RANGE: - ThrowNullPointerExceptionForMethodAccess(instr->VRegB_4rcc(), kVirtual); + ThrowNullPointerExceptionForMethodAccess(instr.VRegB_4rcc(), kVirtual); break; case Instruction::INVOKE_VIRTUAL_QUICK: case Instruction::INVOKE_VIRTUAL_RANGE_QUICK: { @@ -612,7 +612,7 @@ void ThrowNullPointerExceptionFromDexPC(bool check_address, uintptr_t addr) { case Instruction::IGET_CHAR: case Instruction::IGET_SHORT: { ArtField* field = - Runtime::Current()->GetClassLinker()->ResolveField(instr->VRegC_22c(), method, false); + Runtime::Current()->GetClassLinker()->ResolveField(instr.VRegC_22c(), method, false); ThrowNullPointerExceptionForFieldAccess(field, true /* read */); break; } @@ -644,7 +644,7 @@ void ThrowNullPointerExceptionFromDexPC(bool check_address, uintptr_t addr) { case Instruction::IPUT_CHAR: case Instruction::IPUT_SHORT: { ArtField* field = - Runtime::Current()->GetClassLinker()->ResolveField(instr->VRegC_22c(), method, false); + Runtime::Current()->GetClassLinker()->ResolveField(instr.VRegC_22c(), method, false); ThrowNullPointerExceptionForFieldAccess(field, false /* write */); break; } @@ -707,7 +707,7 @@ void ThrowNullPointerExceptionFromDexPC(bool check_address, uintptr_t addr) { const DexFile* dex_file = method->GetDeclaringClass()->GetDexCache()->GetDexFile(); LOG(FATAL) << "NullPointerException at an unexpected instruction: " - << instr->DumpString(dex_file) + << instr.DumpString(dex_file) << " in " << method->PrettyMethod(); break; diff --git a/runtime/debugger.cc b/runtime/debugger.cc index c85c2336b0..2be00f5f5b 100644 --- a/runtime/debugger.cc +++ b/runtime/debugger.cc @@ -278,11 +278,8 @@ class DebugInstrumentationListener FINAL : public instrumentation::Instrumentati } private: - static bool IsReturn(ArtMethod* method, uint32_t dex_pc) - REQUIRES_SHARED(Locks::mutator_lock_) { - const DexFile::CodeItem* code_item = method->GetCodeItem(); - const Instruction* instruction = Instruction::At(&code_item->insns_[dex_pc]); - return instruction->IsReturn(); + static bool IsReturn(ArtMethod* method, uint32_t dex_pc) REQUIRES_SHARED(Locks::mutator_lock_) { + return method->DexInstructions().InstructionAt(dex_pc).IsReturn(); } static bool IsListeningToDexPcMoved() REQUIRES_SHARED(Locks::mutator_lock_) { @@ -1535,15 +1532,15 @@ static uint32_t MangleAccessFlags(uint32_t accessFlags) { */ static uint16_t MangleSlot(uint16_t slot, ArtMethod* m) REQUIRES_SHARED(Locks::mutator_lock_) { - const DexFile::CodeItem* code_item = m->GetCodeItem(); - if (code_item == nullptr) { + CodeItemDataAccessor accessor(m); + if (!accessor.HasCodeItem()) { // We should not get here for a method without code (native, proxy or abstract). Log it and // return the slot as is since all registers are arguments. LOG(WARNING) << "Trying to mangle slot for method without code " << m->PrettyMethod(); return slot; } - uint16_t ins_size = code_item->ins_size_; - uint16_t locals_size = code_item->registers_size_ - ins_size; + uint16_t ins_size = accessor.InsSize(); + uint16_t locals_size = accessor.RegistersSize() - ins_size; if (slot >= locals_size) { return slot - locals_size; } else { @@ -1566,8 +1563,8 @@ static size_t GetMethodNumArgRegistersIncludingThis(ArtMethod* method) */ static uint16_t DemangleSlot(uint16_t slot, ArtMethod* m, JDWP::JdwpError* error) REQUIRES_SHARED(Locks::mutator_lock_) { - const DexFile::CodeItem* code_item = m->GetCodeItem(); - if (code_item == nullptr) { + CodeItemDataAccessor accessor(m); + if (!accessor.HasCodeItem()) { // We should not get here for a method without code (native, proxy or abstract). Log it and // return the slot as is since all registers are arguments. LOG(WARNING) << "Trying to demangle slot for method without code " @@ -1578,9 +1575,9 @@ static uint16_t DemangleSlot(uint16_t slot, ArtMethod* m, JDWP::JdwpError* error return slot; } } else { - if (slot < code_item->registers_size_) { - uint16_t ins_size = code_item->ins_size_; - uint16_t locals_size = code_item->registers_size_ - ins_size; + if (slot < accessor.RegistersSize()) { + uint16_t ins_size = accessor.InsSize(); + uint16_t locals_size = accessor.RegistersSize() - ins_size; *error = JDWP::ERR_NONE; return (slot < ins_size) ? slot + locals_size : slot - ins_size; } @@ -1793,9 +1790,9 @@ JDWP::JdwpError Dbg::GetBytecodes(JDWP::RefTypeId, JDWP::MethodId method_id, if (m == nullptr) { return JDWP::ERR_INVALID_METHODID; } - const DexFile::CodeItem* code_item = m->GetCodeItem(); - size_t byte_count = code_item->insns_size_in_code_units_ * 2; - const uint8_t* begin = reinterpret_cast<const uint8_t*>(code_item->insns_); + CodeItemDataAccessor accessor(m); + size_t byte_count = accessor.InsnsSizeInCodeUnits() * 2; + const uint8_t* begin = reinterpret_cast<const uint8_t*>(accessor.Insns()); const uint8_t* end = begin + byte_count; for (const uint8_t* p = begin; p != end; ++p) { bytecodes->push_back(*p); @@ -2978,9 +2975,8 @@ void Dbg::PostLocationEvent(ArtMethod* m, int dex_pc, mirror::Object* this_objec Handle<mirror::Throwable> pending_exception(hs.NewHandle(self->GetException())); self->ClearException(); if (kIsDebugBuild && pending_exception != nullptr) { - const DexFile::CodeItem* code_item = location.method->GetCodeItem(); - const Instruction* instr = Instruction::At(&code_item->insns_[location.dex_pc]); - CHECK_EQ(Instruction::MOVE_EXCEPTION, instr->Opcode()); + const Instruction& instr = location.method->DexInstructions().InstructionAt(location.dex_pc); + CHECK_EQ(Instruction::MOVE_EXCEPTION, instr.Opcode()); } gJdwpState->PostLocationEvent(&location, this_object, event_flags, return_value); diff --git a/runtime/dex_file.h b/runtime/dex_file.h index 76110f2e5d..f3a88f766c 100644 --- a/runtime/dex_file.h +++ b/runtime/dex_file.h @@ -320,6 +320,7 @@ class DexFile { debug_info_off_ = new_offset; } + private: uint16_t registers_size_; // the number of registers used by this code // (locals + parameters) uint16_t ins_size_; // the number of words of incoming arguments to the method @@ -340,6 +341,14 @@ class DexFile { uint16_t insns_[1]; // actual array of bytecode. private: + ART_FRIEND_TEST(CodeItemAccessorsTest, TestDexInstructionsAccessor); + friend class CatchHandlerIterator; + friend class CodeItemDataAccessor; + friend class CodeItemDebugInfoAccessor; + friend class CodeItemInstructionAccessor; + friend class DexFile; // TODO: Remove this one when it's cleaned up. + friend class DexFileVerifier; + friend class VdexFile; // TODO: Remove this one when it's cleaned up. DISALLOW_COPY_AND_ASSIGN(CodeItem); }; diff --git a/runtime/dex_file_test.cc b/runtime/dex_file_test.cc index 69055041e5..87eec571f1 100644 --- a/runtime/dex_file_test.cc +++ b/runtime/dex_file_test.cc @@ -22,6 +22,7 @@ #include "base/stl_util.h" #include "base/unix_file/fd_file.h" +#include "code_item_accessors-inl.h" #include "common_runtime_test.h" #include "dex_file-inl.h" #include "dex_file_loader.h" @@ -730,15 +731,8 @@ TEST_F(DexFileTest, OpenDexDebugInfoLocalNullType) { kRawDexDebugInfoLocalNullType, tmp.GetFilename().c_str(), 0xf25f2b38U, true); const DexFile::ClassDef& class_def = raw->GetClassDef(0); const DexFile::CodeItem* code_item = raw->GetCodeItem(raw->FindCodeItemOffset(class_def, 1)); - uint32_t debug_info_offset = raw->GetDebugInfoOffset(code_item); - ASSERT_TRUE(raw->DecodeDebugLocalInfo(code_item->registers_size_, - code_item->ins_size_, - code_item->insns_size_in_code_units_, - debug_info_offset, - true, - 1, - Callback, - nullptr)); + CodeItemDebugInfoAccessor accessor(raw.get(), code_item); + ASSERT_TRUE(accessor.DecodeDebugLocalInfo(true, 1, Callback, nullptr)); } } // namespace art diff --git a/runtime/dex_file_tracking_registrar.cc b/runtime/dex_file_tracking_registrar.cc index 4de43760d4..c157ddc790 100644 --- a/runtime/dex_file_tracking_registrar.cc +++ b/runtime/dex_file_tracking_registrar.cc @@ -30,6 +30,7 @@ #endif #include "base/memory_tool.h" +#include "code_item_accessors-inl.h" #include "dex_file-inl.h" namespace art { @@ -184,9 +185,12 @@ void DexFileTrackingRegistrar::SetAllCodeItemStartRegistration(bool should_poiso if (code_item != nullptr) { const void* code_item_begin = reinterpret_cast<const void*>(code_item); size_t code_item_start = reinterpret_cast<size_t>(code_item); - size_t code_item_start_end = reinterpret_cast<size_t>(&code_item->insns_[1]); + CodeItemInstructionAccessor accessor(dex_file_, code_item); + size_t code_item_start_end = reinterpret_cast<size_t>(accessor.Insns()); size_t code_item_start_size = code_item_start_end - code_item_start; - range_values_.push_back(std::make_tuple(code_item_begin, code_item_start_size, should_poison)); + range_values_.push_back(std::make_tuple(code_item_begin, + code_item_start_size, + should_poison)); } cdit.Next(); } @@ -204,9 +208,10 @@ void DexFileTrackingRegistrar::SetAllInsnsRegistration(bool should_poison) { while (cdit.HasNextMethod()) { const DexFile::CodeItem* code_item = cdit.GetMethodCodeItem(); if (code_item != nullptr) { - const void* insns_begin = reinterpret_cast<const void*>(&code_item->insns_); + CodeItemInstructionAccessor accessor(dex_file_, code_item); + const void* insns_begin = reinterpret_cast<const void*>(accessor.Insns()); // Member insns_size_in_code_units_ is in 2-byte units - size_t insns_size = code_item->insns_size_in_code_units_ * 2; + size_t insns_size = accessor.InsnsSizeInCodeUnits() * 2; range_values_.push_back(std::make_tuple(insns_begin, insns_size, should_poison)); } cdit.Next(); diff --git a/runtime/entrypoints/quick/quick_fillarray_entrypoints.cc b/runtime/entrypoints/quick/quick_fillarray_entrypoints.cc index d4bc1c76b1..d22f180c7a 100644 --- a/runtime/entrypoints/quick/quick_fillarray_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_fillarray_entrypoints.cc @@ -28,7 +28,7 @@ extern "C" int artHandleFillArrayDataFromCode(uint32_t payload_offset, mirror::A ArtMethod* method, Thread* self) REQUIRES_SHARED(Locks::mutator_lock_) { ScopedQuickEntrypointChecks sqec(self); - const uint16_t* const insns = method->GetCodeItem()->insns_; + const uint16_t* const insns = method->DexInstructions().Insns(); const Instruction::ArrayDataPayload* payload = reinterpret_cast<const Instruction::ArrayDataPayload*>(insns + payload_offset); bool success = FillArrayData(array, payload); diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc index ca5b79921c..a4d14ecf7e 100644 --- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc @@ -784,8 +784,8 @@ extern "C" uint64_t artQuickToInterpreterBridge(ArtMethod* method, Thread* self, DCHECK(!method->IsNative()) << method->PrettyMethod(); uint32_t shorty_len = 0; ArtMethod* non_proxy_method = method->GetInterfaceMethodIfProxy(kRuntimePointerSize); - const DexFile::CodeItem* code_item = non_proxy_method->GetCodeItem(); - DCHECK(code_item != nullptr) << method->PrettyMethod(); + DCHECK(non_proxy_method->GetCodeItem() != nullptr) << method->PrettyMethod(); + CodeItemDataAccessor accessor(non_proxy_method); const char* shorty = non_proxy_method->GetShorty(&shorty_len); JValue result; @@ -795,12 +795,12 @@ extern "C" uint64_t artQuickToInterpreterBridge(ArtMethod* method, Thread* self, } else { const char* old_cause = self->StartAssertNoThreadSuspension( "Building interpreter shadow frame"); - uint16_t num_regs = code_item->registers_size_; + uint16_t num_regs = accessor.RegistersSize(); // No last shadow coming from quick. ShadowFrameAllocaUniquePtr shadow_frame_unique_ptr = CREATE_SHADOW_FRAME(num_regs, /* link */ nullptr, method, /* dex pc */ 0); ShadowFrame* shadow_frame = shadow_frame_unique_ptr.get(); - size_t first_arg_reg = code_item->registers_size_ - code_item->ins_size_; + size_t first_arg_reg = accessor.RegistersSize() - accessor.InsSize(); BuildQuickShadowFrameVisitor shadow_frame_builder(sp, method->IsStatic(), shorty, shorty_len, shadow_frame, first_arg_reg); shadow_frame_builder.VisitArguments(); @@ -823,7 +823,7 @@ extern "C" uint64_t artQuickToInterpreterBridge(ArtMethod* method, Thread* self, } } - result = interpreter::EnterInterpreterFromEntryPoint(self, code_item, shadow_frame); + result = interpreter::EnterInterpreterFromEntryPoint(self, accessor, shadow_frame); } // Pop transition. @@ -1121,10 +1121,9 @@ extern "C" const void* artQuickResolutionTrampoline( // code. if (!found_stack_map || kIsDebugBuild) { uint32_t dex_pc = QuickArgumentVisitor::GetCallingDexPc(sp); - const DexFile::CodeItem* code; - code = caller->GetCodeItem(); - CHECK_LT(dex_pc, code->insns_size_in_code_units_); - const Instruction& instr = code->InstructionAt(dex_pc); + CodeItemInstructionAccessor accessor(caller); + CHECK_LT(dex_pc, accessor.InsnsSizeInCodeUnits()); + const Instruction& instr = accessor.InstructionAt(dex_pc); Instruction::Code instr_code = instr.Opcode(); bool is_range; switch (instr_code) { @@ -2450,9 +2449,7 @@ extern "C" TwoWordReturn artInvokeInterfaceTrampoline(ArtMethod* interface_metho // Fetch the dex_method_idx of the target interface method from the caller. uint32_t dex_method_idx; uint32_t dex_pc = QuickArgumentVisitor::GetCallingDexPc(sp); - const DexFile::CodeItem* code_item = caller_method->GetCodeItem(); - DCHECK_LT(dex_pc, code_item->insns_size_in_code_units_); - const Instruction& instr = code_item->InstructionAt(dex_pc); + const Instruction& instr = caller_method->DexInstructions().InstructionAt(dex_pc); Instruction::Code instr_code = instr.Opcode(); DCHECK(instr_code == Instruction::INVOKE_INTERFACE || instr_code == Instruction::INVOKE_INTERFACE_RANGE) diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc index 49f202182d..a4ee21d4aa 100644 --- a/runtime/instrumentation.cc +++ b/runtime/instrumentation.cc @@ -1246,18 +1246,17 @@ struct RuntimeMethodShortyVisitor : public StackVisitor { shorty = m->GetInterfaceMethodIfProxy(kRuntimePointerSize)->GetShorty()[0]; return false; } - const DexFile::CodeItem* code_item = m->GetCodeItem(); - const Instruction* instr = Instruction::At(&code_item->insns_[GetDexPc()]); - if (instr->IsInvoke()) { + const Instruction& instr = m->DexInstructions().InstructionAt(GetDexPc()); + if (instr.IsInvoke()) { const DexFile* dex_file = m->GetDexFile(); - if (interpreter::IsStringInit(dex_file, instr->VRegB())) { + if (interpreter::IsStringInit(dex_file, instr.VRegB())) { // Invoking string init constructor is turned into invoking // StringFactory.newStringFromChars() which returns a string. shorty = 'L'; return false; } // A regular invoke, use callee's shorty. - uint32_t method_idx = instr->VRegB(); + uint32_t method_idx = instr.VRegB(); shorty = dex_file->GetMethodShorty(method_idx)[0]; } // Stop stack walking since we've seen a Java frame. diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc index 01b7d4e457..9b81819da2 100644 --- a/runtime/interpreter/interpreter.cc +++ b/runtime/interpreter/interpreter.cc @@ -240,7 +240,7 @@ static constexpr InterpreterImplKind kInterpreterImplKind = kMterpImplKind; static inline JValue Execute( Thread* self, - const DexFile::CodeItem* code_item, + const CodeItemDataAccessor& accessor, ShadowFrame& shadow_frame, JValue result_register, bool stay_in_interpreter = false) REQUIRES_SHARED(Locks::mutator_lock_) { @@ -254,11 +254,13 @@ static inline JValue Execute( ArtMethod *method = shadow_frame.GetMethod(); if (UNLIKELY(instrumentation->HasMethodEntryListeners())) { - instrumentation->MethodEnterEvent(self, shadow_frame.GetThisObject(code_item->ins_size_), - method, 0); + instrumentation->MethodEnterEvent(self, + shadow_frame.GetThisObject(accessor.InsSize()), + method, + 0); if (UNLIKELY(self->IsExceptionPending())) { instrumentation->MethodUnwindEvent(self, - shadow_frame.GetThisObject(code_item->ins_size_), + shadow_frame.GetThisObject(accessor.InsSize()), method, 0); return JValue(); @@ -277,7 +279,7 @@ static inline JValue Execute( // Calculate the offset of the first input reg. The input registers are in the high regs. // It's ok to access the code item here since JIT code will have been touched by the // interpreter and compiler already. - uint16_t arg_offset = code_item->registers_size_ - code_item->ins_size_; + uint16_t arg_offset = accessor.RegistersSize() - accessor.InsSize(); ArtInterpreterToCompiledCodeBridge(self, nullptr, &shadow_frame, arg_offset, &result); // Push the shadow frame back as the caller will expect it. self->PushShadowFrame(&shadow_frame); @@ -302,27 +304,27 @@ static inline JValue Execute( if (kInterpreterImplKind == kMterpImplKind) { if (transaction_active) { // No Mterp variant - just use the switch interpreter. - return ExecuteSwitchImpl<false, true>(self, code_item, shadow_frame, result_register, + return ExecuteSwitchImpl<false, true>(self, accessor, shadow_frame, result_register, false); } else if (UNLIKELY(!Runtime::Current()->IsStarted())) { - return ExecuteSwitchImpl<false, false>(self, code_item, shadow_frame, result_register, + return ExecuteSwitchImpl<false, false>(self, accessor, shadow_frame, result_register, false); } else { while (true) { // Mterp does not support all instrumentation/debugging. if (MterpShouldSwitchInterpreters() != 0) { - return ExecuteSwitchImpl<false, false>(self, code_item, shadow_frame, result_register, + return ExecuteSwitchImpl<false, false>(self, accessor, shadow_frame, result_register, false); } bool returned = ExecuteMterpImpl(self, - code_item->insns_, + accessor.Insns(), &shadow_frame, &result_register); if (returned) { return result_register; } else { // Mterp didn't like that instruction. Single-step it with the reference interpreter. - result_register = ExecuteSwitchImpl<false, false>(self, code_item, shadow_frame, + result_register = ExecuteSwitchImpl<false, false>(self, accessor, shadow_frame, result_register, true); if (shadow_frame.GetDexPC() == dex::kDexNoIndex) { // Single-stepped a return or an exception not handled locally. Return to caller. @@ -334,10 +336,10 @@ static inline JValue Execute( } else { DCHECK_EQ(kInterpreterImplKind, kSwitchImplKind); if (transaction_active) { - return ExecuteSwitchImpl<false, true>(self, code_item, shadow_frame, result_register, + return ExecuteSwitchImpl<false, true>(self, accessor, shadow_frame, result_register, false); } else { - return ExecuteSwitchImpl<false, false>(self, code_item, shadow_frame, result_register, + return ExecuteSwitchImpl<false, false>(self, accessor, shadow_frame, result_register, false); } } @@ -346,19 +348,19 @@ static inline JValue Execute( if (kInterpreterImplKind == kMterpImplKind) { // No access check variants for Mterp. Just use the switch version. if (transaction_active) { - return ExecuteSwitchImpl<true, true>(self, code_item, shadow_frame, result_register, + return ExecuteSwitchImpl<true, true>(self, accessor, shadow_frame, result_register, false); } else { - return ExecuteSwitchImpl<true, false>(self, code_item, shadow_frame, result_register, + return ExecuteSwitchImpl<true, false>(self, accessor, shadow_frame, result_register, false); } } else { DCHECK_EQ(kInterpreterImplKind, kSwitchImplKind); if (transaction_active) { - return ExecuteSwitchImpl<true, true>(self, code_item, shadow_frame, result_register, + return ExecuteSwitchImpl<true, true>(self, accessor, shadow_frame, result_register, false); } else { - return ExecuteSwitchImpl<true, false>(self, code_item, shadow_frame, result_register, + return ExecuteSwitchImpl<true, false>(self, accessor, shadow_frame, result_register, false); } } @@ -387,12 +389,12 @@ void EnterInterpreterFromInvoke(Thread* self, } const char* old_cause = self->StartAssertNoThreadSuspension("EnterInterpreterFromInvoke"); - const DexFile::CodeItem* code_item = method->GetCodeItem(); + CodeItemDataAccessor accessor(method); uint16_t num_regs; uint16_t num_ins; - if (code_item != nullptr) { - num_regs = code_item->registers_size_; - num_ins = code_item->ins_size_; + if (accessor.HasCodeItem()) { + num_regs = accessor.RegistersSize(); + num_ins = accessor.InsSize(); } else if (!method->IsInvokable()) { self->EndAssertNoThreadSuspension(old_cause); method->ThrowInvocationTimeError(); @@ -454,7 +456,7 @@ void EnterInterpreterFromInvoke(Thread* self, } } if (LIKELY(!method->IsNative())) { - JValue r = Execute(self, code_item, *shadow_frame, JValue(), stay_in_interpreter); + JValue r = Execute(self, accessor, *shadow_frame, JValue(), stay_in_interpreter); if (result != nullptr) { *result = r; } @@ -497,7 +499,7 @@ void EnterInterpreterFromDeoptimize(Thread* self, DCHECK(!shadow_frame->GetMethod()->MustCountLocks()); self->SetTopOfShadowStack(shadow_frame); - const DexFile::CodeItem* code_item = shadow_frame->GetMethod()->GetCodeItem(); + CodeItemDataAccessor accessor(shadow_frame->GetMethod()); const uint32_t dex_pc = shadow_frame->GetDexPC(); uint32_t new_dex_pc = dex_pc; if (UNLIKELY(self->IsExceptionPending())) { @@ -510,7 +512,7 @@ void EnterInterpreterFromDeoptimize(Thread* self, self, *shadow_frame, instrumentation) ? shadow_frame->GetDexPC() : dex::kDexNoIndex; } else if (!from_code) { // Deoptimization is not called from code directly. - const Instruction* instr = Instruction::At(&code_item->insns_[dex_pc]); + const Instruction* instr = &accessor.InstructionAt(dex_pc); if (deopt_method_type == DeoptimizationMethodType::kKeepDexPc) { DCHECK(first); // Need to re-execute the dex instruction. @@ -566,7 +568,7 @@ void EnterInterpreterFromDeoptimize(Thread* self, } if (new_dex_pc != dex::kDexNoIndex) { shadow_frame->SetDexPC(new_dex_pc); - value = Execute(self, code_item, *shadow_frame, value); + value = Execute(self, accessor, *shadow_frame, value); } ShadowFrame* old_frame = shadow_frame; shadow_frame = shadow_frame->GetLink(); @@ -580,7 +582,7 @@ void EnterInterpreterFromDeoptimize(Thread* self, ret_val->SetJ(value.GetJ()); } -JValue EnterInterpreterFromEntryPoint(Thread* self, const DexFile::CodeItem* code_item, +JValue EnterInterpreterFromEntryPoint(Thread* self, const CodeItemDataAccessor& accessor, ShadowFrame* shadow_frame) { DCHECK_EQ(self, Thread::Current()); bool implicit_check = !Runtime::Current()->ExplicitStackOverflowChecks(); @@ -593,11 +595,11 @@ JValue EnterInterpreterFromEntryPoint(Thread* self, const DexFile::CodeItem* cod if (jit != nullptr) { jit->NotifyCompiledCodeToInterpreterTransition(self, shadow_frame->GetMethod()); } - return Execute(self, code_item, *shadow_frame, JValue()); + return Execute(self, accessor, *shadow_frame, JValue()); } void ArtInterpreterToInterpreterBridge(Thread* self, - const DexFile::CodeItem* code_item, + const CodeItemDataAccessor& accessor, ShadowFrame* shadow_frame, JValue* result) { bool implicit_check = !Runtime::Current()->ExplicitStackOverflowChecks(); @@ -626,7 +628,7 @@ void ArtInterpreterToInterpreterBridge(Thread* self, } if (LIKELY(!shadow_frame->GetMethod()->IsNative())) { - result->SetJ(Execute(self, code_item, *shadow_frame, JValue()).GetJ()); + result->SetJ(Execute(self, accessor, *shadow_frame, JValue()).GetJ()); } else { // We don't expect to be asked to interpret native code (which is entered via a JNI compiler // generated stub) except during testing and image writing. diff --git a/runtime/interpreter/interpreter.h b/runtime/interpreter/interpreter.h index df8568edcd..f9d7774d5b 100644 --- a/runtime/interpreter/interpreter.h +++ b/runtime/interpreter/interpreter.h @@ -27,6 +27,7 @@ class Object; } // namespace mirror class ArtMethod; +class CodeItemDataAccessor; union JValue; class ShadowFrame; class Thread; @@ -52,12 +53,15 @@ extern void EnterInterpreterFromDeoptimize(Thread* self, DeoptimizationMethodType method_type) REQUIRES_SHARED(Locks::mutator_lock_); -extern JValue EnterInterpreterFromEntryPoint(Thread* self, const DexFile::CodeItem* code_item, +extern JValue EnterInterpreterFromEntryPoint(Thread* self, + const CodeItemDataAccessor& accessor, ShadowFrame* shadow_frame) REQUIRES_SHARED(Locks::mutator_lock_); -void ArtInterpreterToInterpreterBridge(Thread* self, const DexFile::CodeItem* code_item, - ShadowFrame* shadow_frame, JValue* result) +void ArtInterpreterToInterpreterBridge(Thread* self, + const CodeItemDataAccessor& accessor, + ShadowFrame* shadow_frame, + JValue* result) REQUIRES_SHARED(Locks::mutator_lock_); // One-time sanity check. diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc index 122d1a816b..deed16b974 100644 --- a/runtime/interpreter/interpreter_common.cc +++ b/runtime/interpreter/interpreter_common.cc @@ -1320,7 +1320,7 @@ static inline bool DoCallCommon(ArtMethod* called_method, } // Compute method information. - const DexFile::CodeItem* code_item = called_method->GetCodeItem(); + CodeItemDataAccessor accessor(called_method); // Number of registers for the callee's call frame. uint16_t num_regs; // Test whether to use the interpreter or compiler entrypoint, and save that result to pass to @@ -1334,7 +1334,7 @@ static inline bool DoCallCommon(ArtMethod* called_method, ClassLinker::ShouldUseInterpreterEntrypoint( called_method, called_method->GetEntryPointFromQuickCompiledCode()); - if (LIKELY(code_item != nullptr)) { + if (LIKELY(accessor.HasCodeItem())) { // When transitioning to compiled code, space only needs to be reserved for the input registers. // The rest of the frame gets discarded. This also prevents accessing the called method's code // item, saving memory by keeping code items of compiled code untouched. @@ -1342,8 +1342,8 @@ static inline bool DoCallCommon(ArtMethod* called_method, DCHECK(!Runtime::Current()->IsAotCompiler()) << "Compiler should use interpreter entrypoint"; num_regs = number_of_inputs; } else { - num_regs = code_item->registers_size_; - DCHECK_EQ(string_init ? number_of_inputs - 1 : number_of_inputs, code_item->ins_size_); + num_regs = accessor.RegistersSize(); + DCHECK_EQ(string_init ? number_of_inputs - 1 : number_of_inputs, accessor.InsSize()); } } else { DCHECK(called_method->IsNative() || called_method->IsProxyMethod()); @@ -1367,7 +1367,7 @@ static inline bool DoCallCommon(ArtMethod* called_method, DCHECK_GT(num_regs, 0u); // As the method is an instance method, there should be at least 1. // The new StringFactory call is static and has one fewer argument. - if (code_item == nullptr) { + if (!accessor.HasCodeItem()) { DCHECK(called_method->IsNative() || called_method->IsProxyMethod()); num_regs--; } // else ... don't need to change num_regs since it comes up from the string_init's code item @@ -1499,7 +1499,7 @@ static inline bool DoCallCommon(ArtMethod* called_method, } PerformCall(self, - code_item, + accessor, shadow_frame.GetMethod(), first_dest_reg, new_shadow_frame, diff --git a/runtime/interpreter/interpreter_switch_impl.cc b/runtime/interpreter/interpreter_switch_impl.cc index 094f08664e..81c1e1deeb 100644 --- a/runtime/interpreter/interpreter_switch_impl.cc +++ b/runtime/interpreter/interpreter_switch_impl.cc @@ -67,7 +67,7 @@ namespace interpreter { { \ if (UNLIKELY(instrumentation->HasDexPcListeners()) && \ UNLIKELY(!DoDexPcMoveEvent(self, \ - code_item, \ + accessor, \ shadow_frame, \ dex_pc, \ instrumentation, \ @@ -125,7 +125,7 @@ namespace interpreter { // jvmti-agents while handling breakpoint or single step events. We had to move this into its own // function because it was making ExecuteSwitchImpl have too large a stack. NO_INLINE static bool DoDexPcMoveEvent(Thread* self, - const DexFile::CodeItem* code_item, + const CodeItemDataAccessor& accessor, const ShadowFrame& shadow_frame, uint32_t dex_pc, const instrumentation::Instrumentation* instrumentation, @@ -139,7 +139,7 @@ NO_INLINE static bool DoDexPcMoveEvent(Thread* self, hs.NewHandleWrapper(LIKELY(save_ref == nullptr) ? &null_obj : save_ref->GetGCRoot())); self->ClearException(); instrumentation->DexPcMovedEvent(self, - shadow_frame.GetThisObject(code_item->ins_size_), + shadow_frame.GetThisObject(accessor.InsSize()), shadow_frame.GetMethod(), dex_pc); if (UNLIKELY(self->IsExceptionPending())) { @@ -188,7 +188,7 @@ NO_INLINE static bool SendMethodExitEvents(Thread* self, } template<bool do_access_check, bool transaction_active> -JValue ExecuteSwitchImpl(Thread* self, const DexFile::CodeItem* code_item, +JValue ExecuteSwitchImpl(Thread* self, const CodeItemDataAccessor& accessor, ShadowFrame& shadow_frame, JValue result_register, bool interpret_one_instruction) { constexpr bool do_assignability_check = do_access_check; @@ -200,10 +200,10 @@ JValue ExecuteSwitchImpl(Thread* self, const DexFile::CodeItem* code_item, uint32_t dex_pc = shadow_frame.GetDexPC(); const auto* const instrumentation = Runtime::Current()->GetInstrumentation(); - const uint16_t* const insns = code_item->insns_; + ArtMethod* method = shadow_frame.GetMethod(); + const uint16_t* const insns = accessor.Insns(); const Instruction* inst = Instruction::At(insns + dex_pc); uint16_t inst_data; - ArtMethod* method = shadow_frame.GetMethod(); jit::Jit* jit = Runtime::Current()->GetJit(); do { @@ -303,7 +303,7 @@ JValue ExecuteSwitchImpl(Thread* self, const DexFile::CodeItem* code_item, !SendMethodExitEvents(self, instrumentation, shadow_frame, - shadow_frame.GetThisObject(code_item->ins_size_), + shadow_frame.GetThisObject(accessor.InsSize()), shadow_frame.GetMethod(), inst->GetDexPc(insns), result))) { @@ -325,7 +325,7 @@ JValue ExecuteSwitchImpl(Thread* self, const DexFile::CodeItem* code_item, !SendMethodExitEvents(self, instrumentation, shadow_frame, - shadow_frame.GetThisObject(code_item->ins_size_), + shadow_frame.GetThisObject(accessor.InsSize()), shadow_frame.GetMethod(), inst->GetDexPc(insns), result))) { @@ -348,7 +348,7 @@ JValue ExecuteSwitchImpl(Thread* self, const DexFile::CodeItem* code_item, !SendMethodExitEvents(self, instrumentation, shadow_frame, - shadow_frame.GetThisObject(code_item->ins_size_), + shadow_frame.GetThisObject(accessor.InsSize()), shadow_frame.GetMethod(), inst->GetDexPc(insns), result))) { @@ -370,7 +370,7 @@ JValue ExecuteSwitchImpl(Thread* self, const DexFile::CodeItem* code_item, !SendMethodExitEvents(self, instrumentation, shadow_frame, - shadow_frame.GetThisObject(code_item->ins_size_), + shadow_frame.GetThisObject(accessor.InsSize()), shadow_frame.GetMethod(), inst->GetDexPc(insns), result))) { @@ -412,7 +412,7 @@ JValue ExecuteSwitchImpl(Thread* self, const DexFile::CodeItem* code_item, !SendMethodExitEvents(self, instrumentation, shadow_frame, - shadow_frame.GetThisObject(code_item->ins_size_), + shadow_frame.GetThisObject(accessor.InsSize()), shadow_frame.GetMethod(), inst->GetDexPc(insns), result))) { @@ -2484,19 +2484,19 @@ JValue ExecuteSwitchImpl(Thread* self, const DexFile::CodeItem* code_item, // Explicit definitions of ExecuteSwitchImpl. template HOT_ATTR -JValue ExecuteSwitchImpl<true, false>(Thread* self, const DexFile::CodeItem* code_item, +JValue ExecuteSwitchImpl<true, false>(Thread* self, const CodeItemDataAccessor& accessor, ShadowFrame& shadow_frame, JValue result_register, bool interpret_one_instruction); template HOT_ATTR -JValue ExecuteSwitchImpl<false, false>(Thread* self, const DexFile::CodeItem* code_item, +JValue ExecuteSwitchImpl<false, false>(Thread* self, const CodeItemDataAccessor& accessor, ShadowFrame& shadow_frame, JValue result_register, bool interpret_one_instruction); template -JValue ExecuteSwitchImpl<true, true>(Thread* self, const DexFile::CodeItem* code_item, +JValue ExecuteSwitchImpl<true, true>(Thread* self, const CodeItemDataAccessor& accessor, ShadowFrame& shadow_frame, JValue result_register, bool interpret_one_instruction); template -JValue ExecuteSwitchImpl<false, true>(Thread* self, const DexFile::CodeItem* code_item, +JValue ExecuteSwitchImpl<false, true>(Thread* self, const CodeItemDataAccessor& accessor, ShadowFrame& shadow_frame, JValue result_register, bool interpret_one_instruction); diff --git a/runtime/interpreter/interpreter_switch_impl.h b/runtime/interpreter/interpreter_switch_impl.h index 267df2e219..aa0f854bb7 100644 --- a/runtime/interpreter/interpreter_switch_impl.h +++ b/runtime/interpreter/interpreter_switch_impl.h @@ -25,6 +25,7 @@ namespace art { +class CodeItemDataAccessor; class ShadowFrame; class Thread; @@ -32,7 +33,7 @@ namespace interpreter { template<bool do_access_check, bool transaction_active> JValue ExecuteSwitchImpl(Thread* self, - const DexFile::CodeItem* code_item, + const CodeItemDataAccessor& accessor, ShadowFrame& shadow_frame, JValue result_register, bool interpret_one_instruction) REQUIRES_SHARED(Locks::mutator_lock_); diff --git a/runtime/interpreter/shadow_frame.cc b/runtime/interpreter/shadow_frame.cc index ab154cf767..fe7e3e0a9b 100644 --- a/runtime/interpreter/shadow_frame.cc +++ b/runtime/interpreter/shadow_frame.cc @@ -27,9 +27,9 @@ mirror::Object* ShadowFrame::GetThisObject() const { } else if (m->IsNative()) { return GetVRegReference(0); } else { - const DexFile::CodeItem* code_item = m->GetCodeItem(); - CHECK(code_item != nullptr) << ArtMethod::PrettyMethod(m); - uint16_t reg = code_item->registers_size_ - code_item->ins_size_; + CHECK(m->GetCodeItem() != nullptr) << ArtMethod::PrettyMethod(m); + CodeItemDataAccessor accessor(m); + uint16_t reg = accessor.RegistersSize() - accessor.InsSize(); return GetVRegReference(reg); } } diff --git a/runtime/interpreter/unstarted_runtime.cc b/runtime/interpreter/unstarted_runtime.cc index dece830f1a..d1436fa9cf 100644 --- a/runtime/interpreter/unstarted_runtime.cc +++ b/runtime/interpreter/unstarted_runtime.cc @@ -1910,7 +1910,7 @@ void UnstartedRuntime::Initialize() { tables_initialized_ = true; } -void UnstartedRuntime::Invoke(Thread* self, const DexFile::CodeItem* code_item, +void UnstartedRuntime::Invoke(Thread* self, const CodeItemDataAccessor& accessor, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset) { // In a runtime that's not started we intercept certain methods to avoid complicated dependency // problems in core libraries. @@ -1930,7 +1930,7 @@ void UnstartedRuntime::Invoke(Thread* self, const DexFile::CodeItem* code_item, self->PopShadowFrame(); } else { // Not special, continue with regular interpreter execution. - ArtInterpreterToInterpreterBridge(self, code_item, shadow_frame, result); + ArtInterpreterToInterpreterBridge(self, accessor, shadow_frame, result); } } diff --git a/runtime/interpreter/unstarted_runtime.h b/runtime/interpreter/unstarted_runtime.h index bc9ead8360..2e86dea1a9 100644 --- a/runtime/interpreter/unstarted_runtime.h +++ b/runtime/interpreter/unstarted_runtime.h @@ -25,6 +25,7 @@ namespace art { class ArtMethod; +class CodeItemDataAccessor; class Thread; class ShadowFrame; @@ -48,7 +49,7 @@ class UnstartedRuntime { static void Initialize(); static void Invoke(Thread* self, - const DexFile::CodeItem* code_item, + const CodeItemDataAccessor& accessor, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset) diff --git a/runtime/jit/jit.cc b/runtime/jit/jit.cc index 278bc57412..12bf79d7ca 100644 --- a/runtime/jit/jit.cc +++ b/runtime/jit/jit.cc @@ -467,7 +467,8 @@ bool Jit::MaybeDoOnStackReplacement(Thread* thread, // Fetch some data before looking up for an OSR method. We don't want thread // suspension once we hold an OSR method, as the JIT code cache could delete the OSR // method while we are being suspended. - const size_t number_of_vregs = method->GetCodeItem()->registers_size_; + CodeItemDataAccessor accessor(method); + const size_t number_of_vregs = accessor.RegistersSize(); const char* shorty = method->GetShorty(); std::string method_name(VLOG_IS_ON(jit) ? method->PrettyMethod() : ""); void** memory = nullptr; diff --git a/runtime/method_handles.cc b/runtime/method_handles.cc index 8eb31c1ef8..88f30a8900 100644 --- a/runtime/method_handles.cc +++ b/runtime/method_handles.cc @@ -408,7 +408,7 @@ static inline bool MethodHandleInvokeMethod(ArtMethod* called_method, const InstructionOperands* const operands, JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) { // Compute method information. - const DexFile::CodeItem* code_item = called_method->GetCodeItem(); + CodeItemDataAccessor accessor(called_method); // Number of registers for the callee's call frame. Note that for non-exact // invokes, we always derive this information from the callee method. We @@ -419,10 +419,10 @@ static inline bool MethodHandleInvokeMethod(ArtMethod* called_method, uint16_t num_regs; size_t num_input_regs; size_t first_dest_reg; - if (LIKELY(code_item != nullptr)) { - num_regs = code_item->registers_size_; - first_dest_reg = num_regs - code_item->ins_size_; - num_input_regs = code_item->ins_size_; + if (LIKELY(accessor.HasCodeItem())) { + num_regs = accessor.RegistersSize(); + first_dest_reg = num_regs - accessor.InsSize(); + num_input_regs = accessor.InsSize(); // Parameter registers go at the end of the shadow frame. DCHECK_NE(first_dest_reg, (size_t)-1); } else { @@ -496,7 +496,7 @@ static inline bool MethodHandleInvokeMethod(ArtMethod* called_method, bool use_interpreter_entrypoint = ClassLinker::ShouldUseInterpreterEntrypoint( called_method, called_method->GetEntryPointFromQuickCompiledCode()); PerformCall(self, - code_item, + accessor, shadow_frame.GetMethod(), first_dest_reg, new_shadow_frame, @@ -550,10 +550,9 @@ static inline bool MethodHandleInvokeTransform(ArtMethod* called_method, // - One for the only method argument (an EmulatedStackFrame). static constexpr size_t kNumRegsForTransform = 2; - const DexFile::CodeItem* code_item = called_method->GetCodeItem(); - DCHECK(code_item != nullptr); - DCHECK_EQ(kNumRegsForTransform, code_item->registers_size_); - DCHECK_EQ(kNumRegsForTransform, code_item->ins_size_); + CodeItemDataAccessor accessor(called_method); + DCHECK_EQ(kNumRegsForTransform, accessor.RegistersSize()); + DCHECK_EQ(kNumRegsForTransform, accessor.InsSize()); ShadowFrameAllocaUniquePtr shadow_frame_unique_ptr = CREATE_SHADOW_FRAME(kNumRegsForTransform, &shadow_frame, called_method, /* dex pc */ 0); @@ -589,7 +588,7 @@ static inline bool MethodHandleInvokeTransform(ArtMethod* called_method, bool use_interpreter_entrypoint = ClassLinker::ShouldUseInterpreterEntrypoint( called_method, called_method->GetEntryPointFromQuickCompiledCode()); PerformCall(self, - code_item, + accessor, shadow_frame.GetMethod(), 0 /* first destination register */, new_shadow_frame, @@ -1035,14 +1034,14 @@ static inline bool MethodHandleInvokeExactInternal( } // Compute method information. - const DexFile::CodeItem* code_item = called_method->GetCodeItem(); + CodeItemDataAccessor accessor(called_method); uint16_t num_regs; size_t num_input_regs; size_t first_dest_reg; - if (LIKELY(code_item != nullptr)) { - num_regs = code_item->registers_size_; - first_dest_reg = num_regs - code_item->ins_size_; - num_input_regs = code_item->ins_size_; + if (LIKELY(accessor.HasCodeItem())) { + num_regs = accessor.RegistersSize(); + first_dest_reg = num_regs - accessor.InsSize(); + num_input_regs = accessor.InsSize(); // Parameter registers go at the end of the shadow frame. DCHECK_NE(first_dest_reg, (size_t)-1); } else { @@ -1066,7 +1065,7 @@ static inline bool MethodHandleInvokeExactInternal( bool use_interpreter_entrypoint = ClassLinker::ShouldUseInterpreterEntrypoint( called_method, called_method->GetEntryPointFromQuickCompiledCode()); PerformCall(self, - code_item, + accessor, shadow_frame.GetMethod(), first_dest_reg, new_shadow_frame, diff --git a/runtime/monitor.cc b/runtime/monitor.cc index cfef9c7d96..542692fe46 100644 --- a/runtime/monitor.cc +++ b/runtime/monitor.cc @@ -1377,9 +1377,9 @@ void Monitor::VisitLocks(StackVisitor* stack_visitor, void (*callback)(mirror::O } // Is there any reason to believe there's any synchronization in this method? - const DexFile::CodeItem* code_item = m->GetCodeItem(); - CHECK(code_item != nullptr) << m->PrettyMethod(); - if (code_item->tries_size_ == 0) { + CHECK(m->GetCodeItem() != nullptr) << m->PrettyMethod(); + CodeItemDataAccessor accessor(m); + if (accessor.TriesSize() == 0) { return; // No "tries" implies no synchronization, so no held locks to report. } @@ -1399,11 +1399,10 @@ void Monitor::VisitLocks(StackVisitor* stack_visitor, void (*callback)(mirror::O for (verifier::MethodVerifier::DexLockInfo& dex_lock_info : monitor_enter_dex_pcs) { // As a debug check, check that dex PC corresponds to a monitor-enter. if (kIsDebugBuild) { - const Instruction* monitor_enter_instruction = - Instruction::At(&code_item->insns_[dex_lock_info.dex_pc]); - CHECK_EQ(monitor_enter_instruction->Opcode(), Instruction::MONITOR_ENTER) + const Instruction& monitor_enter_instruction = accessor.InstructionAt(dex_lock_info.dex_pc); + CHECK_EQ(monitor_enter_instruction.Opcode(), Instruction::MONITOR_ENTER) << "expected monitor-enter @" << dex_lock_info.dex_pc << "; was " - << reinterpret_cast<const void*>(monitor_enter_instruction); + << reinterpret_cast<const void*>(&monitor_enter_instruction); } // Iterate through the set of dex registers, as the compiler may not have held all of them diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc index 32f8df7010..f437db281d 100644 --- a/runtime/oat_file.cc +++ b/runtime/oat_file.cc @@ -1500,14 +1500,10 @@ ArrayRef<GcRoot<mirror::Object>> OatFile::GetBssGcRoots() const { } } -uint32_t OatFile::GetDebugInfoOffset(const DexFile& dex_file, - const DexFile::CodeItem* code_item) { - if (code_item == nullptr) { - return 0; - } - const uint32_t debug_info_off = code_item->debug_info_off_; +uint32_t OatFile::GetDebugInfoOffset(const DexFile& dex_file, uint32_t debug_info_off) { // Note that although the specification says that 0 should be used if there // is no debug information, some applications incorrectly use 0xFFFFFFFF. + // The following check also handles debug_info_off == 0. if (debug_info_off < dex_file.Size() || debug_info_off == 0xFFFFFFFF) { return debug_info_off; } diff --git a/runtime/oat_file.h b/runtime/oat_file.h index 36a4d7b8fc..1fb17a46f8 100644 --- a/runtime/oat_file.h +++ b/runtime/oat_file.h @@ -114,9 +114,9 @@ class OatFile { const char* abs_dex_location, std::string* error_msg); - // Return the debug info offset of the code item `item` located in `dex_file`. - static uint32_t GetDebugInfoOffset(const DexFile& dex_file, - const DexFile::CodeItem* item); + // Return the actual debug info offset for an offset that might be actually pointing to + // dequickening info. The returned debug info offset is the one originally in the the dex file. + static uint32_t GetDebugInfoOffset(const DexFile& dex_file, uint32_t debug_info_off); virtual ~OatFile(); diff --git a/runtime/quick_exception_handler.cc b/runtime/quick_exception_handler.cc index a7771abc26..06b94c30d2 100644 --- a/runtime/quick_exception_handler.cc +++ b/runtime/quick_exception_handler.cc @@ -222,7 +222,8 @@ void QuickExceptionHandler::SetCatchEnvironmentForOptimizedHandler(StackVisitor* self_->DumpStack(LOG_STREAM(INFO) << "Setting catch phis: "); } - const size_t number_of_vregs = handler_method_->GetCodeItem()->registers_size_; + CodeItemDataAccessor accessor(handler_method_); + const size_t number_of_vregs = accessor.RegistersSize(); CodeInfo code_info = handler_method_header_->GetOptimizedCodeInfo(); CodeInfoEncoding encoding = code_info.ExtractEncoding(); @@ -359,7 +360,8 @@ class DeoptimizeStackVisitor FINAL : public StackVisitor { const size_t frame_id = GetFrameId(); ShadowFrame* new_frame = GetThread()->FindDebuggerShadowFrame(frame_id); const bool* updated_vregs; - const size_t num_regs = method->GetCodeItem()->registers_size_; + CodeItemDataAccessor accessor(method); + const size_t num_regs = accessor.RegistersSize(); if (new_frame == nullptr) { new_frame = ShadowFrame::CreateDeoptimizedFrame(num_regs, nullptr, method, GetDexPc()); updated_vregs = nullptr; @@ -406,7 +408,8 @@ class DeoptimizeStackVisitor FINAL : public StackVisitor { uintptr_t native_pc_offset = method_header->NativeQuickPcOffset(GetCurrentQuickFramePc()); CodeInfoEncoding encoding = code_info.ExtractEncoding(); StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset, encoding); - const size_t number_of_vregs = m->GetCodeItem()->registers_size_; + CodeItemDataAccessor accessor(m); + const size_t number_of_vregs = accessor.RegistersSize(); uint32_t register_mask = code_info.GetRegisterMaskOf(encoding, stack_map); BitMemoryRegion stack_mask = code_info.GetStackMaskOf(encoding, stack_map); DexRegisterMap vreg_map = IsInInlinedFrame() diff --git a/runtime/stack.cc b/runtime/stack.cc index 5ad1f7c9c5..bbea48b441 100644 --- a/runtime/stack.cc +++ b/runtime/stack.cc @@ -154,13 +154,13 @@ mirror::Object* StackVisitor::GetThisObject() const { return cur_shadow_frame_->GetVRegReference(0); } } else { - const DexFile::CodeItem* code_item = m->GetCodeItem(); - if (code_item == nullptr) { + CodeItemDataAccessor accessor(m); + if (!accessor.HasCodeItem()) { UNIMPLEMENTED(ERROR) << "Failed to determine this object of abstract or proxy method: " << ArtMethod::PrettyMethod(m); return nullptr; } else { - uint16_t reg = code_item->registers_size_ - code_item->ins_size_; + uint16_t reg = accessor.RegistersSize() - accessor.InsSize(); uint32_t value = 0; bool success = GetVReg(m, reg, kReferenceVReg, &value); // We currently always guarantee the `this` object is live throughout the method. @@ -223,11 +223,11 @@ bool StackVisitor::GetVReg(ArtMethod* m, uint16_t vreg, VRegKind kind, uint32_t* bool StackVisitor::GetVRegFromOptimizedCode(ArtMethod* m, uint16_t vreg, VRegKind kind, uint32_t* val) const { DCHECK_EQ(m, GetMethod()); - const DexFile::CodeItem* code_item = m->GetCodeItem(); - DCHECK(code_item != nullptr) << m->PrettyMethod(); // Can't be null or how would we compile - // its instructions? - uint16_t number_of_dex_registers = code_item->registers_size_; - DCHECK_LT(vreg, code_item->registers_size_); + // Can't be null or how would we compile its instructions? + DCHECK(m->GetCodeItem() != nullptr) << m->PrettyMethod(); + CodeItemDataAccessor accessor(m); + uint16_t number_of_dex_registers = accessor.RegistersSize(); + DCHECK_LT(vreg, number_of_dex_registers); const OatQuickMethodHeader* method_header = GetCurrentOatQuickMethodHeader(); CodeInfo code_info = method_header->GetOptimizedCodeInfo(); CodeInfoEncoding encoding = code_info.ExtractEncoding(); @@ -395,8 +395,8 @@ bool StackVisitor::SetVReg(ArtMethod* m, uint16_t vreg, uint32_t new_value, VRegKind kind) { - const DexFile::CodeItem* code_item = m->GetCodeItem(); - if (code_item == nullptr) { + CodeItemDataAccessor accessor(m); + if (!accessor.HasCodeItem()) { return false; } ShadowFrame* shadow_frame = GetCurrentShadowFrame(); @@ -404,7 +404,7 @@ bool StackVisitor::SetVReg(ArtMethod* m, // This is a compiled frame: we must prepare and update a shadow frame that will // be executed by the interpreter after deoptimization of the stack. const size_t frame_id = GetFrameId(); - const uint16_t num_regs = code_item->registers_size_; + const uint16_t num_regs = accessor.RegistersSize(); shadow_frame = thread_->FindOrCreateDebuggerShadowFrame(frame_id, num_regs, m, GetDexPc()); CHECK(shadow_frame != nullptr); // Remember the vreg has been set for debugging and must not be overwritten by the @@ -432,15 +432,15 @@ bool StackVisitor::SetVRegPair(ArtMethod* m, LOG(FATAL) << "Expected long or double: kind_lo=" << kind_lo << ", kind_hi=" << kind_hi; UNREACHABLE(); } - const DexFile::CodeItem* code_item = m->GetCodeItem(); - if (code_item == nullptr) { + CodeItemDataAccessor accessor(m); + if (!accessor.HasCodeItem()) { return false; } ShadowFrame* shadow_frame = GetCurrentShadowFrame(); if (shadow_frame == nullptr) { // This is a compiled frame: we must prepare for deoptimization (see SetVRegFromDebugger). const size_t frame_id = GetFrameId(); - const uint16_t num_regs = code_item->registers_size_; + const uint16_t num_regs = accessor.RegistersSize(); shadow_frame = thread_->FindOrCreateDebuggerShadowFrame(frame_id, num_regs, m, GetDexPc()); CHECK(shadow_frame != nullptr); // Remember the vreg pair has been set for debugging and must not be overwritten by the diff --git a/runtime/thread.cc b/runtime/thread.cc index b86e56b531..6babd75d48 100644 --- a/runtime/thread.cc +++ b/runtime/thread.cc @@ -3425,7 +3425,7 @@ class ReferenceMapVisitor : public StackVisitor { const CodeInfoEncoding& _encoding, const StackMap& map, RootVisitor& _visitor) - : number_of_dex_registers(method->GetCodeItem()->registers_size_), + : number_of_dex_registers(CodeItemDataAccessor(method).RegistersSize()), code_info(_code_info), encoding(_encoding), dex_register_map(code_info.GetDexRegisterMapOf(map, diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc index 4ff49edb90..be6915f04b 100644 --- a/runtime/verifier/method_verifier.cc +++ b/runtime/verifier/method_verifier.cc @@ -350,13 +350,13 @@ FailureKind MethodVerifier::VerifyClass(Thread* self, } } -static bool IsLargeMethod(const DexFile::CodeItem* const code_item) { - if (code_item == nullptr) { +static bool IsLargeMethod(const CodeItemDataAccessor& accessor) { + if (!accessor.HasCodeItem()) { return false; } - uint16_t registers_size = code_item->registers_size_; - uint32_t insns_size = code_item->insns_size_in_code_units_; + uint16_t registers_size = accessor.RegistersSize(); + uint32_t insns_size = accessor.InsnsSizeInCodeUnits(); return registers_size * insns_size > 4*1024*1024; } @@ -494,7 +494,7 @@ MethodVerifier::FailureData MethodVerifier::VerifyMethod(Thread* self, if (duration_ns > MsToNs(100)) { LOG(WARNING) << "Verification of " << dex_file->PrettyMethod(method_idx) << " took " << PrettyDuration(duration_ns) - << (IsLargeMethod(code_item) ? " (large method)" : ""); + << (IsLargeMethod(verifier.CodeItem()) ? " (large method)" : ""); } } result.types = verifier.encountered_failure_types_; @@ -567,7 +567,7 @@ MethodVerifier::MethodVerifier(Thread* self, dex_cache_(dex_cache), class_loader_(class_loader), class_def_(class_def), - code_item_accessor_(CodeItemDataAccessor::CreateNullable(dex_file, code_item)), + code_item_accessor_(dex_file, code_item), declaring_class_(nullptr), interesting_dex_pc_(-1), monitor_enter_dex_pcs_(nullptr), diff --git a/test/466-get-live-vreg/get_live_vreg_jni.cc b/test/466-get-live-vreg/get_live_vreg_jni.cc index 6cea673b41..24792f1eed 100644 --- a/test/466-get-live-vreg/get_live_vreg_jni.cc +++ b/test/466-get-live-vreg/get_live_vreg_jni.cc @@ -16,6 +16,7 @@ #include "arch/context.h" #include "art_method-inl.h" +#include "code_item_accessors-inl.h" #include "jni.h" #include "oat_quick_method_header.h" #include "scoped_thread_state_change-inl.h" @@ -41,7 +42,7 @@ class TestVisitor : public StackVisitor { CHECK(GetVReg(m, 0, kIntVReg, &value)); CHECK_EQ(value, 42u); } else if (m_name.compare("$opt$noinline$testIntervalHole") == 0) { - uint32_t number_of_dex_registers = m->GetCodeItem()->registers_size_; + uint32_t number_of_dex_registers = CodeItemDataAccessor(m).RegistersSize(); uint32_t dex_register_of_first_parameter = number_of_dex_registers - 2; found_method_ = true; uint32_t value = 0; |