diff options
author | 2017-09-23 16:11:06 -0700 | |
---|---|---|
committer | 2017-09-27 11:51:53 -0700 | |
commit | 1d2d4ff8570bb88d9d2d4633706fd7f6fb18d75e (patch) | |
tree | cbe67e8e9214828656314117121e8ce906a762ab | |
parent | e5b35ed787fbfb388d162361310bae5b0e7682a7 (diff) |
Add DexInstructionIterator and use it a few places
Motivation:
Want to start abstracting away dex specific functionality to enable
CompactDex. Adding an iterator will enable CompactDex iteration to
work differently than normal dex iteration.
Will eventually replace CodeItemIterator.
Bug: 63756964
Test: test-art-host
Change-Id: I90e67c1a994b7698aaac0523a82816b0a003fbdc
-rw-r--r-- | compiler/dex/dex_to_dex_compiler.cc | 4 | ||||
-rw-r--r-- | compiler/dex/inline_method_analyser.cc | 46 | ||||
-rw-r--r-- | compiler/dex/verified_method.cc | 17 | ||||
-rw-r--r-- | compiler/driver/compiler_driver.cc | 31 | ||||
-rw-r--r-- | compiler/optimizing/code_generator.cc | 12 | ||||
-rw-r--r-- | compiler/optimizing/instruction_builder.cc | 13 | ||||
-rw-r--r-- | dexlayout/dex_ir.cc | 13 | ||||
-rw-r--r-- | dexlayout/dex_ir.h | 5 | ||||
-rw-r--r-- | dexlayout/dexlayout.cc | 13 | ||||
-rw-r--r-- | oatdump/oatdump.cc | 28 | ||||
-rw-r--r-- | runtime/dex_file.h | 11 | ||||
-rw-r--r-- | runtime/dex_instruction_iterator.h | 107 | ||||
-rw-r--r-- | runtime/dex_instruction_test.cc | 7 | ||||
-rw-r--r-- | runtime/entrypoints/quick/quick_trampoline_entrypoints.cc | 6 | ||||
-rw-r--r-- | runtime/interpreter/unstarted_runtime_test.cc | 12 | ||||
-rw-r--r-- | runtime/jit/profiling_info.cc | 15 | ||||
-rw-r--r-- | runtime/verifier/method_verifier.cc | 89 |
17 files changed, 252 insertions, 177 deletions
diff --git a/compiler/dex/dex_to_dex_compiler.cc b/compiler/dex/dex_to_dex_compiler.cc index e49f83f943..7581962a86 100644 --- a/compiler/dex/dex_to_dex_compiler.cc +++ b/compiler/dex/dex_to_dex_compiler.cc @@ -374,8 +374,8 @@ CompiledMethod* ArtCompileDEX( // Dex pc is not serialized, only used for checking the instructions. Since we access the // array based on the index of the quickened instruction, the indexes must line up perfectly. // The reader side uses the NeedsIndexForInstruction function too. - const Instruction* inst = Instruction::At(code_item->insns_ + info.dex_pc); - CHECK(QuickenInfoTable::NeedsIndexForInstruction(inst)) << inst->Opcode(); + const Instruction& inst = code_item->InstructionAt(info.dex_pc); + CHECK(QuickenInfoTable::NeedsIndexForInstruction(&inst)) << inst.Opcode(); // Add the index. quicken_data.push_back(static_cast<uint8_t>(info.dex_member_index >> 0)); quicken_data.push_back(static_cast<uint8_t>(info.dex_member_index >> 8)); diff --git a/compiler/dex/inline_method_analyser.cc b/compiler/dex/inline_method_analyser.cc index c8e3d5edd8..925863ef0e 100644 --- a/compiler/dex/inline_method_analyser.cc +++ b/compiler/dex/inline_method_analyser.cc @@ -64,14 +64,14 @@ class Matcher { private: explicit Matcher(const DexFile::CodeItem* code_item) : code_item_(code_item), - instruction_(Instruction::At(code_item->insns_)), + instruction_(code_item->Instructions().begin()), pos_(0u), mark_(0u) { } static bool DoMatch(const DexFile::CodeItem* code_item, MatchFn* const* pattern, size_t size); const DexFile::CodeItem* const code_item_; - const Instruction* instruction_; + DexInstructionIterator instruction_; size_t pos_; size_t mark_; }; @@ -93,7 +93,7 @@ bool Matcher::Required(Matcher* matcher) { return false; } matcher->pos_ += 1u; - matcher->instruction_ = matcher->instruction_->Next(); + ++matcher->instruction_; return true; } @@ -105,7 +105,7 @@ bool Matcher::Repeated(Matcher* matcher) { return true; } matcher->pos_ = matcher->mark_; - matcher->instruction_ = matcher->instruction_->Next(); + ++matcher->instruction_; return true; } @@ -301,26 +301,27 @@ bool DoAnalyseConstructor(const DexFile::CodeItem* code_item, // Verify the invoke, prevent a few odd cases and collect IPUTs. uint16_t this_vreg = code_item->registers_size_ - code_item->ins_size_; uint16_t zero_vreg_mask = 0u; - for (const Instruction* instruction = Instruction::At(code_item->insns_); - instruction->Opcode() != Instruction::RETURN_VOID; - instruction = instruction->Next()) { - if (instruction->Opcode() == Instruction::INVOKE_DIRECT) { - ArtMethod* target_method = GetTargetConstructor(method, instruction); + + for (const Instruction& instruction : code_item->Instructions()) { + if (instruction.Opcode() == Instruction::RETURN_VOID) { + break; + } else if (instruction.Opcode() == Instruction::INVOKE_DIRECT) { + ArtMethod* target_method = GetTargetConstructor(method, &instruction); if (target_method == nullptr) { return false; } // We allow forwarding constructors only if they pass more arguments // to prevent infinite recursion. if (target_method->GetDeclaringClass() == method->GetDeclaringClass() && - instruction->VRegA_35c() <= code_item->ins_size_) { + instruction.VRegA_35c() <= code_item->ins_size_) { return false; } - size_t forwarded = CountForwardedConstructorArguments(code_item, instruction, zero_vreg_mask); + size_t forwarded = CountForwardedConstructorArguments(code_item, &instruction, zero_vreg_mask); if (forwarded == static_cast<size_t>(-1)) { return false; } if (target_method->GetDeclaringClass()->IsObjectClass()) { - DCHECK_EQ(Instruction::At(target_method->GetCodeItem()->insns_)->Opcode(), + DCHECK_EQ(target_method->GetCodeItem()->Instructions().begin()->Opcode(), Instruction::RETURN_VOID); } else { const DexFile::CodeItem* target_code_item = target_method->GetCodeItem(); @@ -345,15 +346,15 @@ bool DoAnalyseConstructor(const DexFile::CodeItem* code_item, return false; } } - } else if (IsInstructionDirectConst(instruction->Opcode())) { - zero_vreg_mask |= GetZeroVRegMask(instruction); + } else if (IsInstructionDirectConst(instruction.Opcode())) { + zero_vreg_mask |= GetZeroVRegMask(&instruction); if ((zero_vreg_mask & (1u << this_vreg)) != 0u) { return false; // Overwriting `this` is unsupported. } } else { - DCHECK(IsInstructionIPut(instruction->Opcode())); - DCHECK_EQ(instruction->VRegB_22c(), this_vreg); - if (!RecordConstructorIPut(method, instruction, this_vreg, zero_vreg_mask, iputs)) { + DCHECK(IsInstructionIPut(instruction.Opcode())); + DCHECK_EQ(instruction.VRegB_22c(), this_vreg); + if (!RecordConstructorIPut(method, &instruction, this_vreg, zero_vreg_mask, iputs)) { return false; } } @@ -447,8 +448,7 @@ bool InlineMethodAnalyser::AnalyseMethodCode(const DexFile::CodeItem* code_item, // We currently support only plain return or 2-instruction methods. DCHECK_NE(code_item->insns_size_in_code_units_, 0u); - const Instruction* instruction = Instruction::At(code_item->insns_); - Instruction::Code opcode = instruction->Opcode(); + Instruction::Code opcode = code_item->Instructions().begin()->Opcode(); switch (opcode) { case Instruction::RETURN_VOID: @@ -519,7 +519,7 @@ bool InlineMethodAnalyser::IsSyntheticAccessor(MethodReference ref) { bool InlineMethodAnalyser::AnalyseReturnMethod(const DexFile::CodeItem* code_item, InlineMethod* result) { - const Instruction* return_instruction = Instruction::At(code_item->insns_); + DexInstructionIterator return_instruction = code_item->Instructions().begin(); Instruction::Code return_opcode = return_instruction->Opcode(); uint32_t reg = return_instruction->VRegA_11x(); uint32_t arg_start = code_item->registers_size_ - code_item->ins_size_; @@ -541,7 +541,7 @@ bool InlineMethodAnalyser::AnalyseReturnMethod(const DexFile::CodeItem* code_ite bool InlineMethodAnalyser::AnalyseConstMethod(const DexFile::CodeItem* code_item, InlineMethod* result) { - const Instruction* instruction = Instruction::At(code_item->insns_); + DexInstructionIterator instruction = code_item->Instructions().begin(); const Instruction* return_instruction = instruction->Next(); Instruction::Code return_opcode = return_instruction->Opcode(); if (return_opcode != Instruction::RETURN && @@ -575,7 +575,7 @@ bool InlineMethodAnalyser::AnalyseIGetMethod(const DexFile::CodeItem* code_item, bool is_static, ArtMethod* method, InlineMethod* result) { - const Instruction* instruction = Instruction::At(code_item->insns_); + DexInstructionIterator instruction = code_item->Instructions().begin(); Instruction::Code opcode = instruction->Opcode(); DCHECK(IsInstructionIGet(opcode)); @@ -639,7 +639,7 @@ bool InlineMethodAnalyser::AnalyseIPutMethod(const DexFile::CodeItem* code_item, bool is_static, ArtMethod* method, InlineMethod* result) { - const Instruction* instruction = Instruction::At(code_item->insns_); + DexInstructionIterator instruction = code_item->Instructions().begin(); Instruction::Code opcode = instruction->Opcode(); DCHECK(IsInstructionIPut(opcode)); diff --git a/compiler/dex/verified_method.cc b/compiler/dex/verified_method.cc index e46dc597fa..9c5b63232e 100644 --- a/compiler/dex/verified_method.cc +++ b/compiler/dex/verified_method.cc @@ -64,24 +64,21 @@ void VerifiedMethod::GenerateSafeCastSet(verifier::MethodVerifier* method_verifi if (method_verifier->HasFailures()) { return; } - const DexFile::CodeItem* code_item = method_verifier->CodeItem(); - const Instruction* inst = Instruction::At(code_item->insns_); - const Instruction* end = Instruction::At(code_item->insns_ + - code_item->insns_size_in_code_units_); - - for (; inst < end; inst = inst->Next()) { - Instruction::Code code = inst->Opcode(); + IterationRange<DexInstructionIterator> instructions = method_verifier->CodeItem()->Instructions(); + for (auto it = instructions.begin(); it != instructions.end(); ++it) { + const Instruction& inst = *it; + const Instruction::Code code = inst.Opcode(); if (code == Instruction::CHECK_CAST) { - uint32_t dex_pc = inst->GetDexPc(code_item->insns_); + const uint32_t dex_pc = it.GetDexPC(instructions.begin()); if (!method_verifier->GetInstructionFlags(dex_pc).IsVisited()) { // Do not attempt to quicken this instruction, it's unreachable anyway. continue; } const verifier::RegisterLine* line = method_verifier->GetRegLine(dex_pc); const verifier::RegType& reg_type(line->GetRegisterType(method_verifier, - inst->VRegA_21c())); + inst.VRegA_21c())); const verifier::RegType& cast_type = - method_verifier->ResolveCheckedClass(dex::TypeIndex(inst->VRegB_21c())); + method_verifier->ResolveCheckedClass(dex::TypeIndex(inst.VRegB_21c())); // Pass null for the method verifier to not record the VerifierDeps dependency // if the types are not assignable. if (cast_type.IsStrictlyAssignableFrom(reg_type, /* method_verifier */ nullptr)) { diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index 03d8ef5915..7573367788 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -762,18 +762,14 @@ static void ResolveConstStrings(Handle<mirror::DexCache> dex_cache, return; } - const uint16_t* code_ptr = code_item->insns_; - const uint16_t* code_end = code_item->insns_ + code_item->insns_size_in_code_units_; ClassLinker* const class_linker = Runtime::Current()->GetClassLinker(); - - while (code_ptr < code_end) { - const Instruction* inst = Instruction::At(code_ptr); - switch (inst->Opcode()) { + for (const Instruction& inst : code_item->Instructions()) { + switch (inst.Opcode()) { case Instruction::CONST_STRING: case Instruction::CONST_STRING_JUMBO: { - dex::StringIndex string_index((inst->Opcode() == Instruction::CONST_STRING) - ? inst->VRegB_21c() - : inst->VRegB_31c()); + dex::StringIndex string_index((inst.Opcode() == Instruction::CONST_STRING) + ? inst.VRegB_21c() + : inst.VRegB_31c()); mirror::String* string = class_linker->ResolveString(dex_file, string_index, dex_cache); CHECK(string != nullptr) << "Could not allocate a string when forcing determinism"; break; @@ -782,8 +778,6 @@ static void ResolveConstStrings(Handle<mirror::DexCache> dex_cache, default: break; } - - code_ptr += inst->SizeInCodeUnits(); } } @@ -2439,21 +2433,16 @@ class InitializeClassVisitor : public CompilationVisitor { if (clinit != nullptr) { const DexFile::CodeItem* code_item = clinit->GetCodeItem(); DCHECK(code_item != nullptr); - const Instruction* inst = Instruction::At(code_item->insns_); - - const uint32_t insns_size = code_item->insns_size_in_code_units_; - for (uint32_t dex_pc = 0; dex_pc < insns_size;) { - if (inst->Opcode() == Instruction::CONST_STRING) { + for (const Instruction& inst : code_item->Instructions()) { + if (inst.Opcode() == Instruction::CONST_STRING) { ObjPtr<mirror::String> s = class_linker->ResolveString( - *dex_file, dex::StringIndex(inst->VRegB_21c()), h_dex_cache); + *dex_file, dex::StringIndex(inst.VRegB_21c()), h_dex_cache); CHECK(s != nullptr); - } else if (inst->Opcode() == Instruction::CONST_STRING_JUMBO) { + } else if (inst.Opcode() == Instruction::CONST_STRING_JUMBO) { ObjPtr<mirror::String> s = class_linker->ResolveString( - *dex_file, dex::StringIndex(inst->VRegB_31c()), h_dex_cache); + *dex_file, dex::StringIndex(inst.VRegB_31c()), h_dex_cache); CHECK(s != nullptr); } - dex_pc += inst->SizeInCodeUnits(); - inst = inst->Next(); } } } diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc index b8e4f326c8..3cb37926af 100644 --- a/compiler/optimizing/code_generator.cc +++ b/compiler/optimizing/code_generator.cc @@ -722,12 +722,10 @@ static void CheckLoopEntriesCanBeUsedForOsr(const HGraph& graph, } } ArenaVector<size_t> covered(loop_headers.size(), 0, graph.GetArena()->Adapter(kArenaAllocMisc)); - const uint16_t* code_ptr = code_item.insns_; - const uint16_t* code_end = code_item.insns_ + code_item.insns_size_in_code_units_; - - size_t dex_pc = 0; - while (code_ptr < code_end) { - const Instruction& instruction = *Instruction::At(code_ptr); + IterationRange<DexInstructionIterator> instructions = code_item.Instructions(); + for (auto it = instructions.begin(); it != instructions.end(); ++it) { + const uint32_t dex_pc = it.GetDexPC(instructions.begin()); + const Instruction& instruction = *it; if (instruction.IsBranch()) { uint32_t target = dex_pc + instruction.GetTargetOffset(); CheckCovers(target, graph, code_info, loop_headers, &covered); @@ -743,8 +741,6 @@ static void CheckLoopEntriesCanBeUsedForOsr(const HGraph& graph, CheckCovers(target, graph, code_info, loop_headers, &covered); } } - dex_pc += instruction.SizeInCodeUnits(); - code_ptr += instruction.SizeInCodeUnits(); } for (size_t i = 0; i < covered.size(); ++i) { diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc index e832b10b79..6ad8036870 100644 --- a/compiler/optimizing/instruction_builder.cc +++ b/compiler/optimizing/instruction_builder.cc @@ -368,17 +368,16 @@ void HInstructionBuilder::FindNativeDebugInfoLocations(ArenaBitVector* locations }; dex_file_->DecodeDebugPositionInfo(&code_item_, Callback::Position, locations); // Instruction-specific tweaks. - const Instruction* const begin = Instruction::At(code_item_.insns_); - const Instruction* const end = begin->RelativeAt(code_item_.insns_size_in_code_units_); - for (const Instruction* inst = begin; inst < end; inst = inst->Next()) { - switch (inst->Opcode()) { + IterationRange<DexInstructionIterator> instructions = code_item_.Instructions(); + for (const Instruction& inst : instructions) { + switch (inst.Opcode()) { case Instruction::MOVE_EXCEPTION: { // Stop in native debugger after the exception has been moved. // The compiler also expects the move at the start of basic block so // we do not want to interfere by inserting native-debug-info before it. - locations->ClearBit(inst->GetDexPc(code_item_.insns_)); - const Instruction* next = inst->Next(); - if (next < end) { + locations->ClearBit(inst.GetDexPc(code_item_.insns_)); + const Instruction* next = inst.Next(); + if (DexInstructionIterator(next) != instructions.end()) { locations->SetBit(next->GetDexPc(code_item_.insns_)); } break; diff --git a/dexlayout/dex_ir.cc b/dexlayout/dex_ir.cc index 5913832f96..0c944cee2c 100644 --- a/dexlayout/dex_ir.cc +++ b/dexlayout/dex_ir.cc @@ -185,21 +185,14 @@ static bool GetIdsFromByteCode(Collections& collections, std::vector<MethodId*>* method_ids, std::vector<FieldId*>* field_ids) { bool has_id = false; - // Iterate over all instructions. - const uint16_t* insns = code->Insns(); - for (uint32_t insn_idx = 0; insn_idx < code->InsnsSize();) { - const Instruction* instruction = Instruction::At(&insns[insn_idx]); - const uint32_t insn_width = instruction->SizeInCodeUnits(); - if (insn_width == 0) { - break; - } + for (const Instruction& instruction : code->Instructions()) { + CHECK_GT(instruction.SizeInCodeUnits(), 0u); has_id |= GetIdFromInstruction(collections, - instruction, + &instruction, type_ids, string_ids, method_ids, field_ids); - insn_idx += insn_width; } // for return has_id; } diff --git a/dexlayout/dex_ir.h b/dexlayout/dex_ir.h index 362c08b918..5dcc87dd2e 100644 --- a/dexlayout/dex_ir.h +++ b/dexlayout/dex_ir.h @@ -947,6 +947,11 @@ class CodeItem : public Item { void Accept(AbstractDispatcher* dispatch) { dispatch->Dispatch(this); } + IterationRange<DexInstructionIterator> Instructions() const { + return MakeIterationRange(DexInstructionIterator(Insns()), + DexInstructionIterator(Insns() + InsnsSize())); + } + private: uint16_t registers_size_; uint16_t ins_size_; diff --git a/dexlayout/dexlayout.cc b/dexlayout/dexlayout.cc index 92a1366778..095c960bc0 100644 --- a/dexlayout/dexlayout.cc +++ b/dexlayout/dexlayout.cc @@ -1079,16 +1079,15 @@ void DexLayout::DumpBytecodes(uint32_t idx, const dex_ir::CodeItem* code, uint32 code_offset, code_offset, dot.c_str(), name, type_descriptor.c_str()); // Iterate over all instructions. - const uint16_t* insns = code->Insns(); - for (uint32_t insn_idx = 0; insn_idx < code->InsnsSize();) { - const Instruction* instruction = Instruction::At(&insns[insn_idx]); - const uint32_t insn_width = instruction->SizeInCodeUnits(); + IterationRange<DexInstructionIterator> instructions = code->Instructions(); + for (auto inst = instructions.begin(); inst != instructions.end(); ++inst) { + const uint32_t dex_pc = inst.GetDexPC(instructions.begin()); + const uint32_t insn_width = inst->SizeInCodeUnits(); if (insn_width == 0) { - fprintf(stderr, "GLITCH: zero-width instruction at idx=0x%04x\n", insn_idx); + fprintf(stderr, "GLITCH: zero-width instruction at idx=0x%04x\n", dex_pc); break; } - DumpInstruction(code, code_offset, insn_idx, insn_width, instruction); - insn_idx += insn_width; + DumpInstruction(code, code_offset, dex_pc, insn_width, &*inst); } // for } diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc index be78136f4e..bcf007b87a 100644 --- a/oatdump/oatdump.cc +++ b/oatdump/oatdump.cc @@ -905,26 +905,23 @@ class OatDumper { if (code_item == nullptr) { return; } - const size_t code_item_size = code_item->insns_size_in_code_units_; - const uint16_t* code_ptr = code_item->insns_; - const uint16_t* code_end = code_item->insns_ + code_item_size; + const uint16_t* code_ptr = code_item->insns_; // If we inserted a new dex code item pointer, add to total code bytes. if (dex_code_item_ptrs_.insert(code_ptr).second) { - dex_code_bytes_ += code_item_size * sizeof(code_ptr[0]); + dex_code_bytes_ += code_item->insns_size_in_code_units_ * sizeof(code_ptr[0]); } - while (code_ptr < code_end) { - const Instruction* inst = Instruction::At(code_ptr); - switch (inst->Opcode()) { + for (const Instruction& inst : code_item->Instructions()) { + switch (inst.Opcode()) { case Instruction::CONST_STRING: { - const dex::StringIndex string_index(inst->VRegB_21c()); + const dex::StringIndex string_index(inst.VRegB_21c()); unique_string_ids_from_code_.insert(StringReference(&dex_file, string_index)); ++num_string_ids_from_code_; break; } case Instruction::CONST_STRING_JUMBO: { - const dex::StringIndex string_index(inst->VRegB_31c()); + const dex::StringIndex string_index(inst.VRegB_31c()); unique_string_ids_from_code_.insert(StringReference(&dex_file, string_index)); ++num_string_ids_from_code_; break; @@ -932,8 +929,6 @@ class OatDumper { default: break; } - - code_ptr += inst->SizeInCodeUnits(); } } @@ -1520,12 +1515,11 @@ class OatDumper { void DumpDexCode(std::ostream& os, const DexFile& dex_file, const DexFile::CodeItem* code_item) { if (code_item != nullptr) { - size_t i = 0; - while (i < code_item->insns_size_in_code_units_) { - const Instruction* instruction = Instruction::At(&code_item->insns_[i]); - os << StringPrintf("0x%04zx: ", i) << instruction->DumpHexLE(5) - << StringPrintf("\t| %s\n", instruction->DumpString(&dex_file).c_str()); - i += instruction->SizeInCodeUnits(); + IterationRange<DexInstructionIterator> instructions = code_item->Instructions(); + for (auto it = instructions.begin(); it != instructions.end(); ++it) { + const size_t dex_pc = it.GetDexPC(instructions.begin()); + os << StringPrintf("0x%04zx: ", dex_pc) << it->DumpHexLE(5) + << StringPrintf("\t| %s\n", it->DumpString(&dex_file).c_str()); } } } diff --git a/runtime/dex_file.h b/runtime/dex_file.h index 480742775b..ac91d52a45 100644 --- a/runtime/dex_file.h +++ b/runtime/dex_file.h @@ -21,9 +21,11 @@ #include <string> #include <vector> +#include "base/iteration_range.h" #include "base/logging.h" #include "base/value_object.h" #include "dex_file_types.h" +#include "dex_instruction_iterator.h" #include "globals.h" #include "jni.h" #include "modifiers.h" @@ -293,6 +295,15 @@ class DexFile { // Raw code_item. struct CodeItem { + IterationRange<DexInstructionIterator> Instructions() const { + return { DexInstructionIterator(insns_), + DexInstructionIterator(insns_ + insns_size_in_code_units_)}; + } + + const Instruction& InstructionAt(uint32_t dex_pc) const { + return *Instruction::At(insns_ + dex_pc); + } + 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 diff --git a/runtime/dex_instruction_iterator.h b/runtime/dex_instruction_iterator.h new file mode 100644 index 0000000000..6585875df4 --- /dev/null +++ b/runtime/dex_instruction_iterator.h @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_RUNTIME_DEX_INSTRUCTION_ITERATOR_H_ +#define ART_RUNTIME_DEX_INSTRUCTION_ITERATOR_H_ + +#include <iterator> + +#include "dex_instruction.h" +#include "base/logging.h" + +namespace art { + +class DexInstructionIterator : public std::iterator<std::forward_iterator_tag, Instruction> { + public: + using Type = std::iterator<std::forward_iterator_tag, Instruction>::value_type; + using difference_type = typename std::iterator<std::forward_iterator_tag, Type>::difference_type; + + DexInstructionIterator() = default; + DexInstructionIterator(const DexInstructionIterator&) = default; + DexInstructionIterator(DexInstructionIterator&&) = default; + DexInstructionIterator& operator=(const DexInstructionIterator&) = default; + DexInstructionIterator& operator=(DexInstructionIterator&&) = default; + + explicit DexInstructionIterator(const Type* inst) : inst_(inst) {} + explicit DexInstructionIterator(const uint16_t* inst) : inst_(Type::At(inst)) {} + + ALWAYS_INLINE bool operator==(const DexInstructionIterator& other) const { + return inst_ == other.inst_ || inst_ == nullptr || other.inst_ == nullptr; + } + + // Value after modification. + DexInstructionIterator& operator++() { + inst_ = inst_->Next(); + return *this; + } + + // Value before modification. + DexInstructionIterator operator++(int) { + DexInstructionIterator temp = *this; + ++*this; + return temp; + } + + const Type& operator*() const { + return *inst_; + } + + const Type* operator->() const { + return &**this; + } + + // Return the dex pc for an iterator compared to the code item begin. + uint32_t GetDexPC(const DexInstructionIterator& code_item_begin) { + return reinterpret_cast<const uint16_t*>(inst_) - + reinterpret_cast<const uint16_t*>(code_item_begin.inst_); + } + + const Type* Inst() const { + return inst_; + } + + private: + const Type* inst_ = nullptr; +}; + +static inline bool operator!=(const DexInstructionIterator& lhs, + const DexInstructionIterator& rhs) { + return !(lhs == rhs); +} + +static inline bool operator<(const DexInstructionIterator& lhs, + const DexInstructionIterator& rhs) { + return lhs.Inst() < rhs.Inst(); +} + +static inline bool operator>(const DexInstructionIterator& lhs, + const DexInstructionIterator& rhs) { + return rhs < lhs; +} + +static inline bool operator<=(const DexInstructionIterator& lhs, + const DexInstructionIterator& rhs) { + return !(rhs < lhs); +} + +static inline bool operator>=(const DexInstructionIterator& lhs, + const DexInstructionIterator& rhs) { + return !(lhs < rhs); +} + +} // namespace art + +#endif // ART_RUNTIME_DEX_INSTRUCTION_ITERATOR_H_ diff --git a/runtime/dex_instruction_test.cc b/runtime/dex_instruction_test.cc index 3f7ac57cef..48ed027882 100644 --- a/runtime/dex_instruction_test.cc +++ b/runtime/dex_instruction_test.cc @@ -15,6 +15,7 @@ */ #include "dex_instruction-inl.h" +#include "dex_instruction_iterator.h" #include "gtest/gtest.h" namespace art { @@ -73,7 +74,7 @@ TEST(Instruction, PropertiesOf45cc) { Build45cc(4u /* num_vregs */, 16u /* method_idx */, 32u /* proto_idx */, 0xcafe /* arg_regs */, instruction); - const Instruction* ins = Instruction::At(instruction); + DexInstructionIterator ins(instruction); ASSERT_EQ(4u, ins->SizeInCodeUnits()); ASSERT_TRUE(ins->HasVRegA()); @@ -108,7 +109,7 @@ TEST(Instruction, PropertiesOf4rcc) { Build4rcc(4u /* num_vregs */, 16u /* method_idx */, 32u /* proto_idx */, 0xcafe /* arg_regs */, instruction); - const Instruction* ins = Instruction::At(instruction); + DexInstructionIterator ins(instruction); ASSERT_EQ(4u, ins->SizeInCodeUnits()); ASSERT_TRUE(ins->HasVRegA()); @@ -154,7 +155,7 @@ static std::string DumpInst35c(Instruction::Code code, std::vector<uint16_t> args) { uint16_t inst[6] = {}; Build35c(inst, code, method_idx, args); - return Instruction::At(inst)->DumpString(nullptr); + return DexInstructionIterator(inst)->DumpString(nullptr); } TEST(Instruction, DumpString) { diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc index 211381ccbe..eef277398c 100644 --- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc @@ -1119,7 +1119,7 @@ extern "C" const void* artQuickResolutionTrampoline( const DexFile::CodeItem* code; code = caller->GetCodeItem(); CHECK_LT(dex_pc, code->insns_size_in_code_units_); - const Instruction* instr = Instruction::At(&code->insns_[dex_pc]); + const Instruction* instr = &code->InstructionAt(dex_pc); Instruction::Code instr_code = instr->Opcode(); bool is_range; switch (instr_code) { @@ -2484,7 +2484,7 @@ extern "C" TwoWordReturn artInvokeInterfaceTrampoline(ArtMethod* interface_metho 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 = Instruction::At(&code_item->insns_[dex_pc]); + const Instruction* instr = &code_item->InstructionAt(dex_pc); Instruction::Code instr_code = instr->Opcode(); DCHECK(instr_code == Instruction::INVOKE_INTERFACE || instr_code == Instruction::INVOKE_INTERFACE_RANGE) @@ -2600,7 +2600,7 @@ extern "C" uintptr_t artInvokePolymorphic( ArtMethod* caller_method = QuickArgumentVisitor::GetCallingMethod(sp); uint32_t dex_pc = QuickArgumentVisitor::GetCallingDexPc(sp); const DexFile::CodeItem* code = caller_method->GetCodeItem(); - const Instruction* inst = Instruction::At(&code->insns_[dex_pc]); + const Instruction* inst = &code->InstructionAt(dex_pc); DCHECK(inst->Opcode() == Instruction::INVOKE_POLYMORPHIC || inst->Opcode() == Instruction::INVOKE_POLYMORPHIC_RANGE); const DexFile* dex_file = caller_method->GetDexFile(); diff --git a/runtime/interpreter/unstarted_runtime_test.cc b/runtime/interpreter/unstarted_runtime_test.cc index 71ab01e0fc..fb378251ad 100644 --- a/runtime/interpreter/unstarted_runtime_test.cc +++ b/runtime/interpreter/unstarted_runtime_test.cc @@ -393,7 +393,7 @@ TEST_F(UnstartedRuntimeTest, StringInit) { // create instruction data for invoke-direct {v0, v1} of method with fake index uint16_t inst_data[3] = { 0x2070, 0x0000, 0x0010 }; - const Instruction* inst = Instruction::At(inst_data); + DexInstructionIterator inst(inst_data); JValue result; ShadowFrame* shadow_frame = ShadowFrame::CreateDeoptimizedFrame(10, nullptr, method, 0); @@ -403,7 +403,7 @@ TEST_F(UnstartedRuntimeTest, StringInit) { shadow_frame->SetVRegReference(0, reference_empty_string); shadow_frame->SetVRegReference(1, string_arg); - interpreter::DoCall<false, false>(method, self, *shadow_frame, inst, inst_data[0], &result); + interpreter::DoCall<false, false>(method, self, *shadow_frame, &*inst, inst_data[0], &result); mirror::String* string_result = reinterpret_cast<mirror::String*>(result.GetL()); EXPECT_EQ(string_arg->GetLength(), string_result->GetLength()); @@ -1027,12 +1027,12 @@ TEST_F(UnstartedRuntimeTest, FloatConversion) { // create instruction data for invoke-direct {v0, v1} of method with fake index uint16_t inst_data[3] = { 0x2070, 0x0000, 0x0010 }; - const Instruction* inst = Instruction::At(inst_data); + DexInstructionIterator inst(inst_data); JValue result; ShadowFrame* shadow_frame = ShadowFrame::CreateDeoptimizedFrame(10, nullptr, method, 0); shadow_frame->SetVRegDouble(0, 1.23); - interpreter::DoCall<false, false>(method, self, *shadow_frame, inst, inst_data[0], &result); + interpreter::DoCall<false, false>(method, self, *shadow_frame, &*inst, inst_data[0], &result); ObjPtr<mirror::String> string_result = reinterpret_cast<mirror::String*>(result.GetL()); ASSERT_TRUE(string_result != nullptr); @@ -1187,12 +1187,12 @@ class UnstartedClassForNameTest : public UnstartedRuntimeTest { // create instruction data for invoke-direct {v0} of method with fake index uint16_t inst_data[3] = { 0x1070, 0x0000, 0x0010 }; - const Instruction* inst = Instruction::At(inst_data); + DexInstructionIterator inst(inst_data); interpreter::DoCall<false, false>(boot_cp_init, self, *shadow_frame, - inst, + &*inst, inst_data[0], &result); CHECK(!self->IsExceptionPending()); diff --git a/runtime/jit/profiling_info.cc b/runtime/jit/profiling_info.cc index 1bd095a88e..ad013244c3 100644 --- a/runtime/jit/profiling_info.cc +++ b/runtime/jit/profiling_info.cc @@ -43,15 +43,12 @@ bool ProfilingInfo::Create(Thread* self, ArtMethod* method, bool retry_allocatio // instructions we are interested in profiling. DCHECK(!method->IsNative()); - const DexFile::CodeItem& code_item = *method->GetCodeItem(); - const uint16_t* code_ptr = code_item.insns_; - const uint16_t* code_end = code_item.insns_ + code_item.insns_size_in_code_units_; - - uint32_t dex_pc = 0; std::vector<uint32_t> entries; - while (code_ptr < code_end) { - const Instruction& instruction = *Instruction::At(code_ptr); - switch (instruction.Opcode()) { + + IterationRange<DexInstructionIterator> instructions = method->GetCodeItem()->Instructions(); + for (auto inst = instructions.begin(); inst != instructions.end(); ++inst) { + const uint32_t dex_pc = inst.GetDexPC(instructions.begin()); + switch (inst->Opcode()) { case Instruction::INVOKE_VIRTUAL: case Instruction::INVOKE_VIRTUAL_RANGE: case Instruction::INVOKE_VIRTUAL_QUICK: @@ -64,8 +61,6 @@ bool ProfilingInfo::Create(Thread* self, ArtMethod* method, bool retry_allocatio default: break; } - dex_pc += instruction.SizeInCodeUnits(); - code_ptr += instruction.SizeInCodeUnits(); } // We always create a `ProfilingInfo` object, even if there is no instruction we are diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc index e4ad55dda1..b789ac6b8d 100644 --- a/runtime/verifier/method_verifier.cc +++ b/runtime/verifier/method_verifier.cc @@ -616,18 +616,11 @@ void MethodVerifier::FindLocksAtDexPc(ArtMethod* m, uint32_t dex_pc, } static bool HasMonitorEnterInstructions(const DexFile::CodeItem* const code_item) { - const Instruction* inst = Instruction::At(code_item->insns_); - - uint32_t insns_size = code_item->insns_size_in_code_units_; - for (uint32_t dex_pc = 0; dex_pc < insns_size;) { - if (inst->Opcode() == Instruction::MONITOR_ENTER) { + for (const Instruction& inst : code_item->Instructions()) { + if (inst.Opcode() == Instruction::MONITOR_ENTER) { return true; } - - dex_pc += inst->SizeInCodeUnits(); - inst = inst->Next(); } - return false; } @@ -683,7 +676,7 @@ ArtField* MethodVerifier::FindAccessedFieldAtDexPc(uint32_t dex_pc) { if (register_line == nullptr) { return nullptr; } - const Instruction* inst = Instruction::At(code_item_->insns_ + dex_pc); + const Instruction* inst = &code_item_->InstructionAt(dex_pc); return GetQuickFieldAccess(inst, register_line); } @@ -723,7 +716,7 @@ ArtMethod* MethodVerifier::FindInvokedMethodAtDexPc(uint32_t dex_pc) { if (register_line == nullptr) { return nullptr; } - const Instruction* inst = Instruction::At(code_item_->insns_ + dex_pc); + const Instruction* inst = &code_item_->InstructionAt(dex_pc); const bool is_range = (inst->Opcode() == Instruction::INVOKE_VIRTUAL_RANGE_QUICK); return GetQuickInvokedMethod(inst, register_line, is_range, false); } @@ -929,9 +922,8 @@ std::ostream& MethodVerifier::Fail(VerifyError error) { // Note: this can fail before we touch any instruction, for the signature of a method. So // add a check. if (work_insn_idx_ < dex::kDexNoIndex) { - const uint16_t* insns = code_item_->insns_ + work_insn_idx_; - const Instruction* inst = Instruction::At(insns); - int opcode_flags = Instruction::FlagsOf(inst->Opcode()); + const Instruction& inst = code_item_->InstructionAt(work_insn_idx_); + int opcode_flags = Instruction::FlagsOf(inst.Opcode()); if ((opcode_flags & Instruction::kThrow) == 0 && CurrentInsnFlags()->IsInTry()) { saved_line_->CopyFromLine(work_line_.get()); @@ -990,14 +982,12 @@ void MethodVerifier::AppendToLastFailMessage(const std::string& append) { } bool MethodVerifier::ComputeWidthsAndCountOps() { - const uint16_t* insns = code_item_->insns_; - size_t insns_size = code_item_->insns_size_in_code_units_; - const Instruction* inst = Instruction::At(insns); size_t new_instance_count = 0; size_t monitor_enter_count = 0; - size_t dex_pc = 0; - while (dex_pc < insns_size) { + IterationRange<DexInstructionIterator> instructions = code_item_->Instructions(); + DexInstructionIterator inst = instructions.begin(); + for ( ; inst < instructions.end(); ++inst) { Instruction::Code opcode = inst->Opcode(); switch (opcode) { case Instruction::APUT_OBJECT: @@ -1019,15 +1009,14 @@ bool MethodVerifier::ComputeWidthsAndCountOps() { default: break; } - size_t inst_size = inst->SizeInCodeUnits(); - GetInstructionFlags(dex_pc).SetIsOpcode(); - dex_pc += inst_size; - inst = inst->RelativeAt(inst_size); + GetInstructionFlags(inst.GetDexPC(instructions.begin())).SetIsOpcode(); } - if (dex_pc != insns_size) { + if (inst != instructions.end()) { + const size_t insns_size = code_item_->insns_size_in_code_units_; Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "code did not end where expected (" - << dex_pc << " vs. " << insns_size << ")"; + << inst.GetDexPC(instructions.begin()) << " vs. " + << insns_size << ")"; return false; } @@ -1105,15 +1094,13 @@ bool MethodVerifier::ScanTryCatchBlocks() { template <bool kAllowRuntimeOnlyInstructions> bool MethodVerifier::VerifyInstructions() { - const Instruction* inst = Instruction::At(code_item_->insns_); - /* Flag the start of the method as a branch target, and a GC point due to stack overflow errors */ GetInstructionFlags(0).SetBranchTarget(); GetInstructionFlags(0).SetCompileTimeInfoPoint(); - - uint32_t insns_size = code_item_->insns_size_in_code_units_; - for (uint32_t dex_pc = 0; dex_pc < insns_size;) { - if (!VerifyInstruction<kAllowRuntimeOnlyInstructions>(inst, dex_pc)) { + IterationRange<DexInstructionIterator> instructions = code_item_->Instructions(); + for (auto inst = instructions.begin(); inst != instructions.end(); ++inst) { + const uint32_t dex_pc = inst.GetDexPC(instructions.begin()); + if (!VerifyInstruction<kAllowRuntimeOnlyInstructions>(&*inst, dex_pc)) { DCHECK_NE(failures_.size(), 0U); return false; } @@ -1134,8 +1121,6 @@ bool MethodVerifier::VerifyInstructions() { } else if (inst->IsReturn()) { GetInstructionFlags(dex_pc).SetCompileTimeInfoPointAndReturn(); } - dex_pc += inst->SizeInCodeUnits(); - inst = inst->Next(); } return true; } @@ -1671,9 +1656,10 @@ void MethodVerifier::Dump(VariableIndentationOutputStream* vios) { } vios->Stream() << "Dumping instructions and register lines:\n"; ScopedIndentation indent1(vios); - const Instruction* inst = Instruction::At(code_item_->insns_); - for (size_t dex_pc = 0; dex_pc < code_item_->insns_size_in_code_units_; - dex_pc += inst->SizeInCodeUnits(), inst = inst->Next()) { + + IterationRange<DexInstructionIterator> instructions = code_item_->Instructions(); + for (auto inst = instructions.begin(); inst != instructions.end(); ++inst) { + const size_t dex_pc = inst.GetDexPC(instructions.begin()); RegisterLine* reg_line = reg_table_.GetLine(dex_pc); if (reg_line != nullptr) { vios->Stream() << reg_line->Dump(this) << "\n"; @@ -1938,9 +1924,10 @@ bool MethodVerifier::CodeFlowVerifyMethod() { * we are almost certainly going to have some dead code. */ int dead_start = -1; - uint32_t insn_idx = 0; - for (; insn_idx < insns_size; - insn_idx += Instruction::At(code_item_->insns_ + insn_idx)->SizeInCodeUnits()) { + + IterationRange<DexInstructionIterator> instructions = code_item_->Instructions(); + for (auto inst = instructions.begin(); inst != instructions.end(); ++inst) { + const uint32_t insn_idx = inst.GetDexPC(instructions.begin()); /* * Switch-statement data doesn't get "visited" by scanner. It * may or may not be preceded by a padding NOP (for alignment). @@ -1956,8 +1943,9 @@ bool MethodVerifier::CodeFlowVerifyMethod() { } if (!GetInstructionFlags(insn_idx).IsVisited()) { - if (dead_start < 0) + if (dead_start < 0) { dead_start = insn_idx; + } } else if (dead_start >= 0) { LogVerifyInfo() << "dead code " << reinterpret_cast<void*>(dead_start) << "-" << reinterpret_cast<void*>(insn_idx - 1); @@ -1965,8 +1953,9 @@ bool MethodVerifier::CodeFlowVerifyMethod() { } } if (dead_start >= 0) { - LogVerifyInfo() << "dead code " << reinterpret_cast<void*>(dead_start) - << "-" << reinterpret_cast<void*>(insn_idx - 1); + LogVerifyInfo() + << "dead code " << reinterpret_cast<void*>(dead_start) + << "-" << reinterpret_cast<void*>(instructions.end().GetDexPC(instructions.begin())); } // To dump the state of the verify after a method, do something like: // if (dex_file_->PrettyMethod(dex_method_idx_) == @@ -2340,17 +2329,17 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) { while (0 != prev_idx && !GetInstructionFlags(prev_idx).IsOpcode()) { prev_idx--; } - const Instruction* prev_inst = Instruction::At(code_item_->insns_ + prev_idx); - switch (prev_inst->Opcode()) { + const Instruction& prev_inst = code_item_->InstructionAt(prev_idx); + switch (prev_inst.Opcode()) { case Instruction::MOVE_OBJECT: case Instruction::MOVE_OBJECT_16: case Instruction::MOVE_OBJECT_FROM16: - if (prev_inst->VRegB() == inst->VRegA_11x()) { + if (prev_inst.VRegB() == inst->VRegA_11x()) { // Redo the copy. This won't change the register types, but update the lock status // for the aliased register. work_line_->CopyRegister1(this, - prev_inst->VRegA(), - prev_inst->VRegB(), + prev_inst.VRegA(), + prev_inst.VRegB(), kTypeCategoryRef); } break; @@ -2648,7 +2637,7 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) { break; } - const Instruction* instance_of_inst = Instruction::At(code_item_->insns_ + instance_of_idx); + const Instruction* instance_of_inst = &code_item_->InstructionAt(instance_of_idx); /* Check for peep-hole pattern of: * ...; @@ -2710,7 +2699,7 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) { work_insn_idx_)) { break; } - const Instruction* move_inst = Instruction::At(code_item_->insns_ + move_idx); + const Instruction* move_inst = &code_item_->InstructionAt(move_idx); switch (move_inst->Opcode()) { case Instruction::MOVE_OBJECT: if (move_inst->VRegA_12x() == instance_of_inst->VRegB_22c()) { @@ -3648,7 +3637,7 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) { * and this change should not be used in those cases. */ if ((opcode_flags & Instruction::kContinue) != 0) { - DCHECK_EQ(Instruction::At(code_item_->insns_ + work_insn_idx_), inst); + DCHECK_EQ(&code_item_->InstructionAt(work_insn_idx_), inst); uint32_t next_insn_idx = work_insn_idx_ + inst->SizeInCodeUnits(); if (next_insn_idx >= code_item_->insns_size_in_code_units_) { Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Execution can walk off end of code area"; |