diff options
27 files changed, 610 insertions, 763 deletions
diff --git a/compiler/Android.mk b/compiler/Android.mk index 274678ad67..021392c8e1 100644 --- a/compiler/Android.mk +++ b/compiler/Android.mk @@ -61,7 +61,6 @@ LIBART_COMPILER_SRC_FILES := \ dex/mir_optimization.cc \ dex/bb_optimizations.cc \ dex/pass_driver_me.cc \ - dex/bit_vector_block_iterator.cc \ dex/frontend.cc \ dex/mir_graph.cc \ dex/mir_analysis.cc \ diff --git a/compiler/dex/bb_optimizations.cc b/compiler/dex/bb_optimizations.cc index 1852f805f4..8b5eba0f67 100644 --- a/compiler/dex/bb_optimizations.cc +++ b/compiler/dex/bb_optimizations.cc @@ -38,6 +38,13 @@ bool CodeLayout::Worker(const PassDataHolder* data) const { /* * SSATransformation pass implementation start. */ +void SSATransformation::Start(const PassDataHolder* data) const { + DCHECK(data != nullptr); + CompilationUnit* cUnit = down_cast<const PassMEDataHolder*>(data)->c_unit; + DCHECK(cUnit != nullptr); + cUnit->mir_graph->SSATransformationStart(); +} + bool SSATransformation::Worker(const PassDataHolder* data) const { DCHECK(data != nullptr); const PassMEDataHolder* pass_me_data_holder = down_cast<const PassMEDataHolder*>(data); @@ -54,10 +61,7 @@ void SSATransformation::End(const PassDataHolder* data) const { DCHECK(data != nullptr); CompilationUnit* cUnit = down_cast<const PassMEDataHolder*>(data)->c_unit; DCHECK(cUnit != nullptr); - // Verify the dataflow information after the pass. - if (cUnit->enable_debug & (1 << kDebugVerifyDataflow)) { - cUnit->mir_graph->VerifyDataflow(); - } + cUnit->mir_graph->SSATransformationEnd(); } /* diff --git a/compiler/dex/bb_optimizations.h b/compiler/dex/bb_optimizations.h index 43dcdf4504..3a529f2096 100644 --- a/compiler/dex/bb_optimizations.h +++ b/compiler/dex/bb_optimizations.h @@ -143,12 +143,7 @@ class SSATransformation : public PassME { bool Worker(const PassDataHolder* data) const; - void Start(const PassDataHolder* data) const { - DCHECK(data != nullptr); - CompilationUnit* cUnit = down_cast<const PassMEDataHolder*>(data)->c_unit; - DCHECK(cUnit != nullptr); - cUnit->mir_graph->InitializeSSATransformation(); - } + void Start(const PassDataHolder* data) const; void End(const PassDataHolder* data) const; }; diff --git a/compiler/dex/bit_vector_block_iterator.cc b/compiler/dex/bit_vector_block_iterator.cc deleted file mode 100644 index 32d7d71ede..0000000000 --- a/compiler/dex/bit_vector_block_iterator.cc +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "bit_vector_block_iterator.h" -#include "mir_graph.h" - -namespace art { - -BasicBlock* BitVectorBlockIterator::Next() { - int idx = internal_iterator_.Next(); - - if (idx == -1) { - return nullptr; - } - - return mir_graph_->GetBasicBlock(idx); -} - -} // namespace art diff --git a/compiler/dex/bit_vector_block_iterator.h b/compiler/dex/bit_vector_block_iterator.h deleted file mode 100644 index 0f1c2b6756..0000000000 --- a/compiler/dex/bit_vector_block_iterator.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ART_COMPILER_DEX_BIT_VECTOR_BLOCK_ITERATOR_H_ -#define ART_COMPILER_DEX_BIT_VECTOR_BLOCK_ITERATOR_H_ - -#include "base/bit_vector.h" -#include "compiler_enums.h" -#include "utils/arena_bit_vector.h" -#include "utils/arena_allocator.h" -#include "compiler_ir.h" - -namespace art { - -class MIRGraph; - -/** - * @class BasicBlockIterator - * @brief Helper class to get the BasicBlocks when iterating through the ArenaBitVector. - */ -class BitVectorBlockIterator { - public: - explicit BitVectorBlockIterator(BitVector* bv, MIRGraph* mir_graph) - : mir_graph_(mir_graph), - internal_iterator_(bv) {} - - explicit BitVectorBlockIterator(BitVector* bv, CompilationUnit* c_unit) - : mir_graph_(c_unit->mir_graph.get()), - internal_iterator_(bv) {} - - BasicBlock* Next(); - - void* operator new(size_t size, ArenaAllocator* arena) { - return arena->Alloc(size, kArenaAllocGrowableArray); - }; - void operator delete(void* p) {} // Nop. - - private: - MIRGraph* const mir_graph_; - BitVector::Iterator internal_iterator_; -}; - -} // namespace art - -#endif // ART_COMPILER_DEX_BIT_VECTOR_BLOCK_ITERATOR_H_ diff --git a/compiler/dex/frontend.cc b/compiler/dex/frontend.cc index 63e38317f9..9bad736c8d 100644 --- a/compiler/dex/frontend.cc +++ b/compiler/dex/frontend.cc @@ -879,8 +879,9 @@ static CompiledMethod* CompileMethod(CompilerDriver& driver, (1 << kPromoteCompilerTemps)); } - if (cu.instruction_set == kArm64) { + if (cu.instruction_set == kArm64 || cu.instruction_set == kX86_64) { // TODO(Arm64): enable optimizations once backend is mature enough. + // TODO(X86_64): enable optimizations once backend is mature enough. cu.disable_opt = ~(uint32_t)0; cu.enable_debug |= (1 << kDebugCodegenDump); } diff --git a/compiler/dex/mir_graph.cc b/compiler/dex/mir_graph.cc index c34a9f5638..1300071c86 100644 --- a/compiler/dex/mir_graph.cc +++ b/compiler/dex/mir_graph.cc @@ -80,7 +80,6 @@ MIRGraph::MIRGraph(CompilationUnit* cu, ArenaAllocator* arena) topological_order_(nullptr), i_dom_list_(NULL), def_block_matrix_(NULL), - temp_dalvik_register_v_(NULL), temp_scoped_alloc_(), temp_insn_data_(nullptr), temp_bit_vector_size_(0u), @@ -1318,7 +1317,13 @@ void MIRGraph::InitializeMethodUses() { } } -void MIRGraph::InitializeSSATransformation() { +void MIRGraph::SSATransformationStart() { + DCHECK(temp_scoped_alloc_.get() == nullptr); + temp_scoped_alloc_.reset(ScopedArenaAllocator::Create(&cu_->arena_stack)); + temp_bit_vector_size_ = cu_->num_dalvik_registers; + temp_bit_vector_ = new (temp_scoped_alloc_.get()) ArenaBitVector( + temp_scoped_alloc_.get(), temp_bit_vector_size_, false, kBitMapRegisterV); + /* Compute the DFS order */ ComputeDFSOrders(); @@ -1339,6 +1344,18 @@ void MIRGraph::InitializeSSATransformation() { DoDFSPreOrderSSARename(GetEntryBlock()); } +void MIRGraph::SSATransformationEnd() { + // Verify the dataflow information after the pass. + if (cu_->enable_debug & (1 << kDebugVerifyDataflow)) { + VerifyDataflow(); + } + + temp_bit_vector_size_ = 0u; + temp_bit_vector_ = nullptr; + DCHECK(temp_scoped_alloc_.get() != nullptr); + temp_scoped_alloc_.reset(); +} + void MIRGraph::ComputeTopologicalSortOrder() { std::queue<BasicBlock *> q; std::map<int, int> visited_cnt_values; @@ -1590,4 +1607,57 @@ uint32_t SSARepresentation::GetStartUseIndex(Instruction::Code opcode) { return res; } +/** + * @brief Given a decoded instruction, it checks whether the instruction + * sets a constant and if it does, more information is provided about the + * constant being set. + * @param ptr_value pointer to a 64-bit holder for the constant. + * @param wide Updated by function whether a wide constant is being set by bytecode. + * @return Returns false if the decoded instruction does not represent a constant bytecode. + */ +bool MIR::DecodedInstruction::GetConstant(int64_t* ptr_value, bool* wide) const { + bool sets_const = true; + int64_t value = vB; + + DCHECK(ptr_value != nullptr); + DCHECK(wide != nullptr); + + switch (opcode) { + case Instruction::CONST_4: + case Instruction::CONST_16: + case Instruction::CONST: + *wide = false; + value <<= 32; // In order to get the sign extend. + value >>= 32; + break; + case Instruction::CONST_HIGH16: + *wide = false; + value <<= 48; // In order to get the sign extend. + value >>= 32; + break; + case Instruction::CONST_WIDE_16: + case Instruction::CONST_WIDE_32: + *wide = true; + value <<= 32; // In order to get the sign extend. + value >>= 32; + break; + case Instruction::CONST_WIDE: + *wide = true; + value = vB_wide; + break; + case Instruction::CONST_WIDE_HIGH16: + *wide = true; + value <<= 48; // In order to get the sign extend. + break; + default: + sets_const = false; + break; + } + + if (sets_const) { + *ptr_value = value; + } + + return sets_const; +} } // namespace art diff --git a/compiler/dex/mir_graph.h b/compiler/dex/mir_graph.h index 3a00a434b8..a849bc1883 100644 --- a/compiler/dex/mir_graph.h +++ b/compiler/dex/mir_graph.h @@ -266,6 +266,56 @@ struct MIR { explicit DecodedInstruction():vA(0), vB(0), vB_wide(0), vC(0), opcode(Instruction::NOP) { } + + /* + * Given a decoded instruction representing a const bytecode, it updates + * the out arguments with proper values as dictated by the constant bytecode. + */ + bool GetConstant(int64_t* ptr_value, bool* wide) const; + + bool IsStore() const { + return ((Instruction::FlagsOf(opcode) & Instruction::kStore) == Instruction::kStore); + } + + bool IsLoad() const { + return ((Instruction::FlagsOf(opcode) & Instruction::kLoad) == Instruction::kLoad); + } + + bool IsConditionalBranch() const { + return (Instruction::FlagsOf(opcode) == (Instruction::kContinue | Instruction::kBranch)); + } + + /** + * @brief Is the register C component of the decoded instruction a constant? + */ + bool IsCFieldOrConstant() const { + return ((Instruction::FlagsOf(opcode) & Instruction::kRegCFieldOrConstant) == Instruction::kRegCFieldOrConstant); + } + + /** + * @brief Is the register C component of the decoded instruction a constant? + */ + bool IsBFieldOrConstant() const { + return ((Instruction::FlagsOf(opcode) & Instruction::kRegBFieldOrConstant) == Instruction::kRegBFieldOrConstant); + } + + bool IsCast() const { + return ((Instruction::FlagsOf(opcode) & Instruction::kCast) == Instruction::kCast); + } + + /** + * @brief Does the instruction clobber memory? + * @details Clobber means that the instruction changes the memory not in a punctual way. + * Therefore any supposition on memory aliasing or memory contents should be disregarded + * when crossing such an instruction. + */ + bool Clobbers() const { + return ((Instruction::FlagsOf(opcode) & Instruction::kClobber) == Instruction::kClobber); + } + + bool IsLinear() const { + return (Instruction::FlagsOf(opcode) & (Instruction::kAdd | Instruction::kSubtract)) != 0; + } } dalvikInsn; NarrowDexOffset offset; // Offset of the instruction in code units. @@ -890,7 +940,7 @@ class MIRGraph { /** * @brief Perform the initial preparation for the SSA Transformation. */ - void InitializeSSATransformation(); + void SSATransformationStart(); /** * @brief Insert a the operands for the Phi nodes. @@ -900,6 +950,11 @@ class MIRGraph { bool InsertPhiNodeOperands(BasicBlock* bb); /** + * @brief Perform the cleanup after the SSA Transformation. + */ + void SSATransformationEnd(); + + /** * @brief Perform constant propagation on a BasicBlock. * @param bb the considered BasicBlock. */ @@ -1012,7 +1067,6 @@ class MIRGraph { GrowableArray<BasicBlockId>* topological_order_; int* i_dom_list_; ArenaBitVector** def_block_matrix_; // num_dalvik_register x num_blocks. - ArenaBitVector* temp_dalvik_register_v_; std::unique_ptr<ScopedArenaAllocator> temp_scoped_alloc_; uint16_t* temp_insn_data_; uint32_t temp_bit_vector_size_; diff --git a/compiler/dex/pass_driver.cc b/compiler/dex/pass_driver.cc deleted file mode 100644 index ca936cd41a..0000000000 --- a/compiler/dex/pass_driver.cc +++ /dev/null @@ -1,265 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <dlfcn.h> - -#include "base/logging.h" -#include "base/macros.h" -#include "bb_optimizations.h" -#include "compiler_internals.h" -#include "dataflow_iterator.h" -#include "dataflow_iterator-inl.h" -#include "pass.h" -#include "pass_driver.h" - -namespace art { - -namespace { // anonymous namespace - -/** - * @brief Helper function to create a single instance of a given Pass and can be shared across - * the threads. - */ -template <typename PassType> -const Pass* GetPassInstance() { - static const PassType pass; - return &pass; -} - -void DoWalkBasicBlocks(CompilationUnit* c_unit, const Pass* pass, DataflowIterator* iterator) { - // Paranoid: Check the iterator before walking the BasicBlocks. - DCHECK(iterator != nullptr); - - bool change = false; - for (BasicBlock *bb = iterator->Next(change); bb != 0; bb = iterator->Next(change)) { - change = pass->WalkBasicBlocks(c_unit, bb); - } -} - -template <typename Iterator> -inline void DoWalkBasicBlocks(CompilationUnit* c_unit, const Pass* pass) { - Iterator iterator(c_unit->mir_graph.get()); - DoWalkBasicBlocks(c_unit, pass, &iterator); -} - -} // anonymous namespace - -PassDriver::PassDriver(CompilationUnit* cu, bool create_default_passes) - : cu_(cu), dump_cfg_folder_("/sdcard/") { - DCHECK(cu != nullptr); - - // If need be, create the default passes. - if (create_default_passes) { - CreatePasses(); - } -} - -PassDriver::~PassDriver() { -} - -void PassDriver::InsertPass(const Pass* new_pass) { - DCHECK(new_pass != nullptr); - DCHECK(new_pass->GetName() != nullptr && new_pass->GetName()[0] != 0); - - // It is an error to override an existing pass. - DCHECK(GetPass(new_pass->GetName()) == nullptr) - << "Pass name " << new_pass->GetName() << " already used."; - - // Now add to the list. - pass_list_.push_back(new_pass); -} - -/* - * Create the pass list. These passes are immutable and are shared across the threads. - * - * Advantage is that there will be no race conditions here. - * Disadvantage is the passes can't change their internal states depending on CompilationUnit: - * - This is not yet an issue: no current pass would require it. - */ -static const Pass* const gPasses[] = { - GetPassInstance<CacheFieldLoweringInfo>(), - GetPassInstance<CacheMethodLoweringInfo>(), - GetPassInstance<CallInlining>(), - GetPassInstance<CodeLayout>(), - GetPassInstance<SSATransformation>(), - GetPassInstance<ConstantPropagation>(), - GetPassInstance<InitRegLocations>(), - GetPassInstance<MethodUseCount>(), - GetPassInstance<NullCheckEliminationAndTypeInference>(), - GetPassInstance<ClassInitCheckElimination>(), - GetPassInstance<BBCombine>(), - GetPassInstance<BBOptimizations>(), -}; - -// The default pass list is used by CreatePasses to initialize pass_list_. -static std::vector<const Pass*> gDefaultPassList(gPasses, gPasses + arraysize(gPasses)); - -void PassDriver::CreateDefaultPassList(const std::string& disable_passes) { - // Insert each pass from gPasses into gDefaultPassList. - gDefaultPassList.clear(); - gDefaultPassList.reserve(arraysize(gPasses)); - for (const Pass* pass : gPasses) { - // Check if we should disable this pass. - if (disable_passes.find(pass->GetName()) != std::string::npos) { - LOG(INFO) << "Skipping " << pass->GetName(); - } else { - gDefaultPassList.push_back(pass); - } - } -} - -void PassDriver::CreatePasses() { - // Insert each pass into the list via the InsertPass method. - pass_list_.reserve(gDefaultPassList.size()); - for (const Pass* pass : gDefaultPassList) { - InsertPass(pass); - } -} - -void PassDriver::HandlePassFlag(CompilationUnit* c_unit, const Pass* pass) { - // Unused parameters for the moment. - UNUSED(c_unit); - UNUSED(pass); -} - -void PassDriver::DispatchPass(CompilationUnit* c_unit, const Pass* curPass) { - VLOG(compiler) << "Dispatching " << curPass->GetName(); - - DataFlowAnalysisMode mode = curPass->GetTraversal(); - - switch (mode) { - case kPreOrderDFSTraversal: - DoWalkBasicBlocks<PreOrderDfsIterator>(c_unit, curPass); - break; - case kRepeatingPreOrderDFSTraversal: - DoWalkBasicBlocks<RepeatingPreOrderDfsIterator>(c_unit, curPass); - break; - case kRepeatingPostOrderDFSTraversal: - DoWalkBasicBlocks<RepeatingPostOrderDfsIterator>(c_unit, curPass); - break; - case kReversePostOrderDFSTraversal: - DoWalkBasicBlocks<ReversePostOrderDfsIterator>(c_unit, curPass); - break; - case kRepeatingReversePostOrderDFSTraversal: - DoWalkBasicBlocks<RepeatingReversePostOrderDfsIterator>(c_unit, curPass); - break; - case kPostOrderDOMTraversal: - DoWalkBasicBlocks<PostOrderDOMIterator>(c_unit, curPass); - break; - case kAllNodes: - DoWalkBasicBlocks<AllNodesIterator>(c_unit, curPass); - break; - case kTopologicalSortTraversal: - DoWalkBasicBlocks<TopologicalSortIterator>(c_unit, curPass); - break; - case kRepeatingTopologicalSortTraversal: - DoWalkBasicBlocks<RepeatingTopologicalSortIterator>(c_unit, curPass); - break; - case kNoNodes: - break; - default: - LOG(FATAL) << "Iterator mode not handled in dispatcher: " << mode; - break; - } -} - -void PassDriver::ApplyPass(CompilationUnit* c_unit, const Pass* curPass) { - curPass->Start(c_unit); - DispatchPass(c_unit, curPass); - curPass->End(c_unit); -} - -bool PassDriver::RunPass(CompilationUnit* c_unit, const Pass* pass, bool time_split) { - // Paranoid: c_unit and pass cannot be nullptr, and the pass should have a name. - DCHECK(c_unit != nullptr); - DCHECK(pass != nullptr); - DCHECK(pass->GetName() != nullptr && pass->GetName()[0] != 0); - - // Do we perform a time split - if (time_split) { - c_unit->NewTimingSplit(pass->GetName()); - } - - // Check the pass gate first. - bool should_apply_pass = pass->Gate(c_unit); - - if (should_apply_pass) { - // Applying the pass: first start, doWork, and end calls. - ApplyPass(c_unit, pass); - - // Clean up if need be. - HandlePassFlag(c_unit, pass); - - // Do we want to log it? - if ((c_unit->enable_debug& (1 << kDebugDumpCFG)) != 0) { - // Do we have a pass folder? - const char* passFolder = pass->GetDumpCFGFolder(); - DCHECK(passFolder != nullptr); - - if (passFolder[0] != 0) { - // Create directory prefix. - std::string prefix = GetDumpCFGFolder(); - prefix += passFolder; - prefix += "/"; - - c_unit->mir_graph->DumpCFG(prefix.c_str(), false); - } - } - } - - // If the pass gate passed, we can declare success. - return should_apply_pass; -} - -bool PassDriver::RunPass(CompilationUnit* c_unit, const char* pass_name) { - // Paranoid: c_unit cannot be nullptr and we need a pass name. - DCHECK(c_unit != nullptr); - DCHECK(pass_name != nullptr && pass_name[0] != 0); - - const Pass* cur_pass = GetPass(pass_name); - - if (cur_pass != nullptr) { - return RunPass(c_unit, cur_pass); - } - - // Return false, we did not find the pass. - return false; -} - -void PassDriver::Launch() { - for (const Pass* cur_pass : pass_list_) { - RunPass(cu_, cur_pass, true); - } -} - -void PassDriver::PrintPassNames() { - LOG(INFO) << "Loop Passes are:"; - - for (const Pass* cur_pass : gPasses) { - LOG(INFO) << "\t-" << cur_pass->GetName(); - } -} - -const Pass* PassDriver::GetPass(const char* name) const { - for (const Pass* cur_pass : pass_list_) { - if (strcmp(name, cur_pass->GetName()) == 0) { - return cur_pass; - } - } - return nullptr; -} - -} // namespace art diff --git a/compiler/dex/quick/gen_invoke.cc b/compiler/dex/quick/gen_invoke.cc index 721b3452b7..5ec1ca9d63 100644 --- a/compiler/dex/quick/gen_invoke.cc +++ b/compiler/dex/quick/gen_invoke.cc @@ -1659,9 +1659,13 @@ void Mir2Lir::GenInvoke(CallInfo* info) { return; } DCHECK(cu_->compiler_driver->GetMethodInlinerMap() != nullptr); - if (cu_->compiler_driver->GetMethodInlinerMap()->GetMethodInliner(cu_->dex_file) - ->GenIntrinsic(this, info)) { - return; + // TODO: Enable instrinsics for x86_64 + // Temporary disable intrinsics for x86_64. We will enable them later step by step. + if (cu_->instruction_set != kX86_64) { + if (cu_->compiler_driver->GetMethodInlinerMap()->GetMethodInliner(cu_->dex_file) + ->GenIntrinsic(this, info)) { + return; + } } GenInvokeNoInline(info); } diff --git a/compiler/dex/ssa_transformation.cc b/compiler/dex/ssa_transformation.cc index 865311b084..6f47b8f8d1 100644 --- a/compiler/dex/ssa_transformation.cc +++ b/compiler/dex/ssa_transformation.cc @@ -14,7 +14,6 @@ * limitations under the License. */ -#include "bit_vector_block_iterator.h" #include "compiler_internals.h" #include "dataflow_iterator-inl.h" @@ -127,12 +126,7 @@ bool MIRGraph::FillDefBlockMatrix(BasicBlock* bb) { return false; } - ArenaBitVector::Iterator iterator(bb->data_flow_info->def_v); - while (true) { - int idx = iterator.Next(); - if (idx == -1) { - break; - } + for (uint32_t idx : bb->data_flow_info->def_v->Indexes()) { /* Block bb defines register idx */ def_block_matrix_[idx]->SetBit(bb->id); } @@ -182,22 +176,22 @@ void MIRGraph::ComputeDomPostOrderTraversal(BasicBlock* bb) { dom_post_order_traversal_->Reset(); } ClearAllVisitedFlags(); - std::vector<std::pair<BasicBlock*, ArenaBitVector::Iterator*>> work_stack; + std::vector<std::pair<BasicBlock*, ArenaBitVector::IndexIterator>> work_stack; bb->visited = true; - work_stack.push_back(std::make_pair(bb, bb->i_dominated->GetIterator())); + work_stack.push_back(std::make_pair(bb, bb->i_dominated->Indexes().begin())); while (!work_stack.empty()) { - const std::pair<BasicBlock*, ArenaBitVector::Iterator*>& curr = work_stack.back(); - BasicBlock* curr_bb = curr.first; - ArenaBitVector::Iterator* curr_idom_iter = curr.second; - int bb_idx = curr_idom_iter->Next(); - while ((bb_idx != -1) && (NeedsVisit(GetBasicBlock(bb_idx)) == NULL)) { - bb_idx = curr_idom_iter->Next(); + std::pair<BasicBlock*, ArenaBitVector::IndexIterator>* curr = &work_stack.back(); + BasicBlock* curr_bb = curr->first; + ArenaBitVector::IndexIterator* curr_idom_iter = &curr->second; + while (!curr_idom_iter->Done() && (NeedsVisit(GetBasicBlock(**curr_idom_iter)) == nullptr)) { + ++*curr_idom_iter; } - if (bb_idx != -1) { - BasicBlock* new_bb = GetBasicBlock(bb_idx); + // NOTE: work_stack.push_back()/pop_back() invalidate curr and curr_idom_iter. + if (!curr_idom_iter->Done()) { + BasicBlock* new_bb = GetBasicBlock(**curr_idom_iter); + ++*curr_idom_iter; new_bb->visited = true; - work_stack.push_back( - std::make_pair(new_bb, new_bb->i_dominated->GetIterator())); + work_stack.push_back(std::make_pair(new_bb, new_bb->i_dominated->Indexes().begin())); } else { // no successor/next if (curr_bb->id != NullBasicBlockId) { @@ -249,11 +243,10 @@ bool MIRGraph::ComputeDominanceFrontier(BasicBlock* bb) { } /* Calculate DF_up */ - BitVectorBlockIterator it(bb->i_dominated, cu_); - for (BasicBlock *dominated_bb = it.Next(); dominated_bb != nullptr; dominated_bb = it.Next()) { - BitVectorBlockIterator inner_it(dominated_bb->dom_frontier, cu_); - for (BasicBlock *df_up_block = inner_it.Next(); df_up_block != nullptr; - df_up_block = inner_it.Next()) { + for (uint32_t dominated_idx : bb->i_dominated->Indexes()) { + BasicBlock *dominated_bb = GetBasicBlock(dominated_idx); + for (uint32_t df_up_block_idx : dominated_bb->dom_frontier->Indexes()) { + BasicBlock *df_up_block = GetBasicBlock(df_up_block_idx); CheckForDominanceFrontier(bb, df_up_block); } } @@ -449,7 +442,8 @@ void MIRGraph::ComputeSuccLineIn(ArenaBitVector* dest, const ArenaBitVector* src * insert a phi node if the variable is live-in to the block. */ bool MIRGraph::ComputeBlockLiveIns(BasicBlock* bb) { - ArenaBitVector* temp_dalvik_register_v = temp_dalvik_register_v_; + DCHECK_EQ(temp_bit_vector_size_, cu_->num_dalvik_registers); + ArenaBitVector* temp_dalvik_register_v = temp_bit_vector_; if (bb->data_flow_info == NULL) { return false; @@ -487,15 +481,10 @@ bool MIRGraph::ComputeBlockLiveIns(BasicBlock* bb) { /* Insert phi nodes to for each variable to the dominance frontiers */ void MIRGraph::InsertPhiNodes() { int dalvik_reg; - ArenaBitVector* phi_blocks = - new (arena_) ArenaBitVector(arena_, GetNumBlocks(), false, kBitMapPhi); - ArenaBitVector* tmp_blocks = - new (arena_) ArenaBitVector(arena_, GetNumBlocks(), false, kBitMapTmpBlocks); - ArenaBitVector* input_blocks = - new (arena_) ArenaBitVector(arena_, GetNumBlocks(), false, kBitMapInputBlocks); - - temp_dalvik_register_v_ = - new (arena_) ArenaBitVector(arena_, cu_->num_dalvik_registers, false, kBitMapRegisterV); + ArenaBitVector* phi_blocks = new (temp_scoped_alloc_.get()) ArenaBitVector( + temp_scoped_alloc_.get(), GetNumBlocks(), false, kBitMapPhi); + ArenaBitVector* input_blocks = new (temp_scoped_alloc_.get()) ArenaBitVector( + temp_scoped_alloc_.get(), GetNumBlocks(), false, kBitMapInputBlocks); RepeatingPostOrderDfsIterator iter(this); bool change = false; @@ -505,53 +494,23 @@ void MIRGraph::InsertPhiNodes() { /* Iterate through each Dalvik register */ for (dalvik_reg = cu_->num_dalvik_registers - 1; dalvik_reg >= 0; dalvik_reg--) { - bool change; - input_blocks->Copy(def_block_matrix_[dalvik_reg]); phi_blocks->ClearAllBits(); - - /* Calculate the phi blocks for each Dalvik register */ do { - change = false; - tmp_blocks->ClearAllBits(); - ArenaBitVector::Iterator iterator(input_blocks); - - while (true) { - int idx = iterator.Next(); - if (idx == -1) { - break; - } + // TUNING: When we repeat this, we could skip indexes from the previous pass. + for (uint32_t idx : input_blocks->Indexes()) { BasicBlock* def_bb = GetBasicBlock(idx); - - /* Merge the dominance frontier to tmp_blocks */ - // TUNING: hot call to Union(). - if (def_bb->dom_frontier != NULL) { - tmp_blocks->Union(def_bb->dom_frontier); + if (def_bb->dom_frontier != nullptr) { + phi_blocks->Union(def_bb->dom_frontier); } } - if (!phi_blocks->Equal(tmp_blocks)) { - change = true; - phi_blocks->Copy(tmp_blocks); - - /* - * Iterate through the original blocks plus the new ones in - * the dominance frontier. - */ - input_blocks->Copy(phi_blocks); - input_blocks->Union(def_block_matrix_[dalvik_reg]); - } - } while (change); + } while (input_blocks->Union(phi_blocks)); /* * Insert a phi node for dalvik_reg in the phi_blocks if the Dalvik * register is in the live-in set. */ - ArenaBitVector::Iterator iterator(phi_blocks); - while (true) { - int idx = iterator.Next(); - if (idx == -1) { - break; - } + for (uint32_t idx : phi_blocks->Indexes()) { BasicBlock* phi_bb = GetBasicBlock(idx); /* Variable will be clobbered before being used - no need for phi */ if (!phi_bb->data_flow_info->live_in_v->IsBitSet(dalvik_reg)) { diff --git a/compiler/optimizing/parallel_move_resolver.h b/compiler/optimizing/parallel_move_resolver.h index f652db1095..ff20cb0bc6 100644 --- a/compiler/optimizing/parallel_move_resolver.h +++ b/compiler/optimizing/parallel_move_resolver.h @@ -33,6 +33,7 @@ class MoveOperands; class ParallelMoveResolver : public ValueObject { public: explicit ParallelMoveResolver(ArenaAllocator* allocator) : moves_(allocator, 32) {} + virtual ~ParallelMoveResolver() {} // Resolve a set of parallel moves, emitting assembler instructions. void EmitNativeCode(HParallelMove* parallel_move); diff --git a/compiler/optimizing/ssa_liveness_analysis.cc b/compiler/optimizing/ssa_liveness_analysis.cc index 0f16ad2ae8..938c5ecb5a 100644 --- a/compiler/optimizing/ssa_liveness_analysis.cc +++ b/compiler/optimizing/ssa_liveness_analysis.cc @@ -174,28 +174,6 @@ void SsaLivenessAnalysis::ComputeLiveness() { ComputeLiveInAndLiveOutSets(); } -class InstructionBitVectorIterator : public ValueObject { - public: - InstructionBitVectorIterator(const BitVector& vector, - const GrowableArray<HInstruction*>& instructions) - : instructions_(instructions), - iterator_(BitVector::Iterator(&vector)), - current_bit_index_(iterator_.Next()) {} - - bool Done() const { return current_bit_index_ == -1; } - HInstruction* Current() const { return instructions_.Get(current_bit_index_); } - void Advance() { - current_bit_index_ = iterator_.Next(); - } - - private: - const GrowableArray<HInstruction*> instructions_; - BitVector::Iterator iterator_; - int32_t current_bit_index_; - - DISALLOW_COPY_AND_ASSIGN(InstructionBitVectorIterator); -}; - void SsaLivenessAnalysis::ComputeLiveRanges() { // Do a post order visit, adding inputs of instructions live in the block where // that instruction is defined, and killing instructions that are being visited. @@ -218,10 +196,9 @@ void SsaLivenessAnalysis::ComputeLiveRanges() { } // Add a range that covers this block to all instructions live_in because of successors. - for (InstructionBitVectorIterator it(*live_in, instructions_from_ssa_index_); - !it.Done(); - it.Advance()) { - it.Current()->GetLiveInterval()->AddRange(block->GetLifetimeStart(), block->GetLifetimeEnd()); + for (uint32_t idx : live_in->Indexes()) { + HInstruction* current = instructions_from_ssa_index_.Get(idx); + current->GetLiveInterval()->AddRange(block->GetLifetimeStart(), block->GetLifetimeEnd()); } for (HBackwardInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) { @@ -268,11 +245,10 @@ void SsaLivenessAnalysis::ComputeLiveRanges() { HBasicBlock* back_edge = block->GetLoopInformation()->GetBackEdges().Get(0); // For all live_in instructions at the loop header, we need to create a range // that covers the full loop. - for (InstructionBitVectorIterator it(*live_in, instructions_from_ssa_index_); - !it.Done(); - it.Advance()) { - it.Current()->GetLiveInterval()->AddLoopRange(block->GetLifetimeStart(), - back_edge->GetLifetimeEnd()); + for (uint32_t idx : live_in->Indexes()) { + HInstruction* current = instructions_from_ssa_index_.Get(idx); + current->GetLiveInterval()->AddLoopRange(block->GetLifetimeStart(), + back_edge->GetLifetimeEnd()); } } } diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc index d38f37f0f3..5dee1af9dc 100644 --- a/oatdump/oatdump.cc +++ b/oatdump/oatdump.cc @@ -430,7 +430,7 @@ class OatDumper { auto class_loader(hs.NewHandle<mirror::ClassLoader>(nullptr)); verifier::MethodVerifier verifier(&dex_file, &dex_cache, &class_loader, &class_def, code_item, dex_method_idx, nullptr, method_access_flags, - true, true); + true, true, true); verifier.Verify(); DumpCode(indent2_os, &verifier, oat_method, code_item); } else { diff --git a/runtime/base/bit_vector.cc b/runtime/base/bit_vector.cc index a3e2b15232..0053389b47 100644 --- a/runtime/base/bit_vector.cc +++ b/runtime/base/bit_vector.cc @@ -45,10 +45,11 @@ BitVector::BitVector(uint32_t start_bits, storage_size_(storage_size), storage_(storage), number_of_bits_(start_bits) { - DCHECK_EQ(sizeof(*storage_), 4U); // Assuming 32-bit units. + COMPILE_ASSERT(sizeof(*storage_) == kWordBytes, check_word_bytes); + COMPILE_ASSERT(sizeof(*storage_) * 8u == kWordBits, check_word_bits); if (storage_ == nullptr) { storage_size_ = BitsToWords(start_bits); - storage_ = static_cast<uint32_t*>(allocator_->Alloc(storage_size_ * sizeof(*storage_))); + storage_ = static_cast<uint32_t*>(allocator_->Alloc(storage_size_ * kWordBytes)); } } @@ -61,7 +62,7 @@ BitVector::~BitVector() { */ bool BitVector::IsBitSet(uint32_t num) const { // If the index is over the size: - if (num >= storage_size_ * sizeof(*storage_) * 8) { + if (num >= storage_size_ * kWordBits) { // Whether it is expandable or not, this bit does not exist: thus it is not set. return false; } @@ -71,7 +72,7 @@ bool BitVector::IsBitSet(uint32_t num) const { // Mark all bits bit as "clear". void BitVector::ClearAllBits() { - memset(storage_, 0, storage_size_ * sizeof(*storage_)); + memset(storage_, 0, storage_size_ * kWordBytes); } // Mark the specified bit as "set". @@ -80,17 +81,17 @@ void BitVector::ClearAllBits() { * not using it badly or change resize mechanism. */ void BitVector::SetBit(uint32_t num) { - if (num >= storage_size_ * sizeof(*storage_) * 8) { + if (num >= storage_size_ * kWordBits) { DCHECK(expandable_) << "Attempted to expand a non-expandable bitmap to position " << num; /* Round up to word boundaries for "num+1" bits */ uint32_t new_size = BitsToWords(num + 1); DCHECK_GT(new_size, storage_size_); uint32_t *new_storage = - static_cast<uint32_t*>(allocator_->Alloc(new_size * sizeof(*storage_))); - memcpy(new_storage, storage_, storage_size_ * sizeof(*storage_)); + static_cast<uint32_t*>(allocator_->Alloc(new_size * kWordBytes)); + memcpy(new_storage, storage_, storage_size_ * kWordBytes); // Zero out the new storage words. - memset(&new_storage[storage_size_], 0, (new_size - storage_size_) * sizeof(*storage_)); + memset(&new_storage[storage_size_], 0, (new_size - storage_size_) * kWordBytes); // TOTO: collect stats on space wasted because of resize. storage_ = new_storage; storage_size_ = new_size; @@ -103,7 +104,7 @@ void BitVector::SetBit(uint32_t num) { // Mark the specified bit as "unset". void BitVector::ClearBit(uint32_t num) { // If the index is over the size, we don't have to do anything, it is cleared. - if (num < storage_size_ * sizeof(*storage_) * 8) { + if (num < storage_size_ * kWordBits) { // Otherwise, go ahead and clear it. storage_[num >> 5] &= ~check_masks[num & 0x1f]; } @@ -132,7 +133,7 @@ bool BitVector::SameBitsSet(const BitVector *src) { // - Therefore, min_size goes up to at least that, we are thus comparing at least what we need to, but not less. // ie. we are comparing all storage cells that could have difference, if both vectors have cells above our_highest_index, // they are automatically at 0. - return (memcmp(storage_, src->GetRawStorage(), our_highest_index * sizeof(*storage_)) == 0); + return (memcmp(storage_, src->GetRawStorage(), our_highest_index * kWordBytes) == 0); } // Intersect with another bit vector. @@ -180,7 +181,7 @@ bool BitVector::Union(const BitVector* src) { SetBit(highest_bit); // Paranoid: storage size should be big enough to hold this bit now. - DCHECK_LT(static_cast<uint32_t> (highest_bit), storage_size_ * sizeof(*(storage_)) * 8); + DCHECK_LT(static_cast<uint32_t> (highest_bit), storage_size_ * kWordBits); } for (uint32_t idx = 0; idx < src_size; idx++) { @@ -215,7 +216,7 @@ bool BitVector::UnionIfNotIn(const BitVector* union_with, const BitVector* not_i SetBit(highest_bit); // Paranoid: storage size should be big enough to hold this bit now. - DCHECK_LT(static_cast<uint32_t> (highest_bit), storage_size_ * sizeof(*(storage_)) * 8); + DCHECK_LT(static_cast<uint32_t> (highest_bit), storage_size_ * kWordBits); } uint32_t not_in_size = not_in->GetStorageSize(); @@ -268,14 +269,10 @@ uint32_t BitVector::NumSetBits() const { // Count the number of bits that are set in range [0, end). uint32_t BitVector::NumSetBits(uint32_t end) const { - DCHECK_LE(end, storage_size_ * sizeof(*storage_) * 8); + DCHECK_LE(end, storage_size_ * kWordBits); return NumSetBits(storage_, end); } -BitVector::Iterator* BitVector::GetIterator() const { - return new (allocator_) Iterator(this); -} - /* * Mark specified number of bits as "set". Cannot set all bits like ClearAll * since there might be unused bits - setting those to one will confuse the @@ -329,7 +326,7 @@ int BitVector::GetHighestBitSet() const { } // Return cnt + how many storage units still remain * the number of bits per unit. - int res = cnt + (idx * (sizeof(*storage_) * 8)); + int res = cnt + (idx * kWordBits); return res; } } @@ -369,14 +366,14 @@ void BitVector::Copy(const BitVector *src) { SetBit(highest_bit); // Now set until highest bit's storage. - uint32_t size = 1 + (highest_bit / (sizeof(*storage_) * 8)); - memcpy(storage_, src->GetRawStorage(), sizeof(*storage_) * size); + uint32_t size = 1 + (highest_bit / kWordBits); + memcpy(storage_, src->GetRawStorage(), kWordBytes * size); // Set upper bits to 0. uint32_t left = storage_size_ - size; if (left > 0) { - memset(storage_ + size, 0, sizeof(*storage_) * left); + memset(storage_ + size, 0, kWordBytes * left); } } @@ -401,14 +398,12 @@ uint32_t BitVector::NumSetBits(const uint32_t* storage, uint32_t end) { void BitVector::Dump(std::ostream& os, const char *prefix) const { std::ostringstream buffer; - DumpHelper(buffer, prefix); + DumpHelper(prefix, buffer); os << buffer.str() << std::endl; } -void BitVector::DumpDot(FILE* file, const char* prefix, bool last_entry) const { - std::ostringstream buffer; - Dump(buffer, prefix); +void BitVector::DumpDotHelper(bool last_entry, FILE* file, std::ostringstream& buffer) const { // Now print it to the file. fprintf(file, " {%s}", buffer.str().c_str()); @@ -421,7 +416,32 @@ void BitVector::DumpDot(FILE* file, const char* prefix, bool last_entry) const { fprintf(file, "\\\n"); } -void BitVector::DumpHelper(std::ostringstream& buffer, const char* prefix) const { +void BitVector::DumpDot(FILE* file, const char* prefix, bool last_entry) const { + std::ostringstream buffer; + DumpHelper(prefix, buffer); + DumpDotHelper(last_entry, file, buffer); +} + +void BitVector::DumpIndicesDot(FILE* file, const char* prefix, bool last_entry) const { + std::ostringstream buffer; + DumpIndicesHelper(prefix, buffer); + DumpDotHelper(last_entry, file, buffer); +} + +void BitVector::DumpIndicesHelper(const char* prefix, std::ostringstream& buffer) const { + // Initialize it. + if (prefix != nullptr) { + buffer << prefix; + } + + for (size_t i = 0; i < number_of_bits_; i++) { + if (IsBitSet(i)) { + buffer << i << " "; + } + } +} + +void BitVector::DumpHelper(const char* prefix, std::ostringstream& buffer) const { // Initialize it. if (prefix != nullptr) { buffer << prefix; diff --git a/runtime/base/bit_vector.h b/runtime/base/bit_vector.h index 2a6839619a..8f9afff47d 100644 --- a/runtime/base/bit_vector.h +++ b/runtime/base/bit_vector.h @@ -32,59 +32,115 @@ namespace art { */ class BitVector { public: - class Iterator { + class IndexContainer; + + /** + * @brief Convenient iterator across the indexes of the BitVector's set bits. + * + * @details IndexIterator is a Forward iterator (C++11: 24.2.5) from the lowest + * to the highest index of the BitVector's set bits. Instances can be retrieved + * only through BitVector::Indexes() which returns an IndexContainer wrapper + * object with begin() and end() suitable for range-based loops: + * for (uint32_t idx : bit_vector.Indexes()) { + * // Use idx. + * } + */ + class IndexIterator + : std::iterator<std::forward_iterator_tag, uint32_t, ptrdiff_t, void, uint32_t> { public: - explicit Iterator(const BitVector* bit_vector) - : p_bits_(bit_vector), - bit_storage_(bit_vector->GetRawStorage()), - bit_index_(0), - bit_size_(p_bits_->storage_size_ * sizeof(uint32_t) * 8) {} - - // Return the position of the next set bit. -1 means end-of-element reached. - int32_t Next() { - // Did anything obviously change since we started? - DCHECK_EQ(bit_size_, p_bits_->GetStorageSize() * sizeof(uint32_t) * 8); - DCHECK_EQ(bit_storage_, p_bits_->GetRawStorage()); - - if (UNLIKELY(bit_index_ >= bit_size_)) { - return -1; - } + bool operator==(const IndexIterator& other) const { + DCHECK(bit_storage_ == other.bit_storage_); + DCHECK_EQ(storage_size_, other.storage_size_); + return bit_index_ == other.bit_index_; + } - uint32_t word_index = bit_index_ / 32; - uint32_t word = bit_storage_[word_index]; - // Mask out any bits in the first word we've already considered. - word >>= bit_index_ & 0x1f; - if (word == 0) { - bit_index_ &= ~0x1f; - do { - word_index++; - if (UNLIKELY((word_index * 32) >= bit_size_)) { - bit_index_ = bit_size_; - return -1; - } - word = bit_storage_[word_index]; - bit_index_ += 32; - } while (word == 0); - } - bit_index_ += CTZ(word) + 1; - return bit_index_ - 1; + bool operator!=(const IndexIterator& other) const { + return !(*this == other); + } + + int operator*() const { + DCHECK_LT(bit_index_, BitSize()); + return bit_index_; + } + + IndexIterator& operator++() { + DCHECK_LT(bit_index_, BitSize()); + bit_index_ = FindIndex(bit_index_ + 1u); + return *this; } - static void* operator new(size_t size, Allocator* allocator) { - return allocator->Alloc(sizeof(BitVector::Iterator)); - }; - static void operator delete(void* p) { - Iterator* it = reinterpret_cast<Iterator*>(p); - it->p_bits_->allocator_->Free(p); + IndexIterator operator++(int) { + IndexIterator result(*this); + ++*this; + return result; + } + + // Helper function to check for end without comparing with bit_vector.Indexes().end(). + bool Done() const { + return bit_index_ == BitSize(); } private: - const BitVector* const p_bits_; + struct begin_tag { }; + struct end_tag { }; + + IndexIterator(const BitVector* bit_vector, begin_tag) + : bit_storage_(bit_vector->GetRawStorage()), + storage_size_(bit_vector->storage_size_), + bit_index_(FindIndex(0u)) { } + + IndexIterator(const BitVector* bit_vector, end_tag) + : bit_storage_(bit_vector->GetRawStorage()), + storage_size_(bit_vector->storage_size_), + bit_index_(BitSize()) { } + + uint32_t BitSize() const { + return storage_size_ * kWordBits; + } + + uint32_t FindIndex(uint32_t start_index) const { + DCHECK_LE(start_index, BitSize()); + uint32_t word_index = start_index / kWordBits; + if (UNLIKELY(word_index == storage_size_)) { + return start_index; + } + uint32_t word = bit_storage_[word_index]; + // Mask out any bits in the first word we've already considered. + word &= static_cast<uint32_t>(-1) << (start_index & 0x1f); + while (word == 0u) { + ++word_index; + if (UNLIKELY(word_index == storage_size_)) { + return BitSize(); + } + word = bit_storage_[word_index]; + } + return word_index * 32u + CTZ(word); + } + const uint32_t* const bit_storage_; + const uint32_t storage_size_; // Size of vector in words. uint32_t bit_index_; // Current index (size in bits). - const uint32_t bit_size_; // Size of vector in bits. - friend class BitVector; + friend class BitVector::IndexContainer; + }; + + /** + * @brief BitVector wrapper class for iteration across indexes of set bits. + */ + class IndexContainer { + public: + explicit IndexContainer(const BitVector* bit_vector) : bit_vector_(bit_vector) { } + + IndexIterator begin() const { + return IndexIterator(bit_vector_, IndexIterator::begin_tag()); + } + + IndexIterator end() const { + return IndexIterator(bit_vector_, IndexIterator::end_tag()); + } + + private: + const BitVector* const bit_vector_; }; BitVector(uint32_t start_bits, @@ -127,14 +183,16 @@ class BitVector { // Number of bits set in range [0, end). uint32_t NumSetBits(uint32_t end) const; - Iterator* GetIterator() const; + IndexContainer Indexes() const { + return IndexContainer(this); + } uint32_t GetStorageSize() const { return storage_size_; } bool IsExpandable() const { return expandable_; } uint32_t GetRawStorageWord(size_t idx) const { return storage_[idx]; } uint32_t* GetRawStorage() { return storage_; } const uint32_t* GetRawStorage() const { return storage_; } - size_t GetSizeOf() const { return storage_size_ * sizeof(uint32_t); } + size_t GetSizeOf() const { return storage_size_ * kWordBytes; } /** * @return the highest bit set, -1 if none are set @@ -149,12 +207,42 @@ class BitVector { bool EnsureSizeAndClear(unsigned int num); void Dump(std::ostream& os, const char* prefix) const; + + /** + * @brief last_entry is this the last entry for the dot dumping + * @details if not, a "|" is appended to the dump. + */ void DumpDot(FILE* file, const char* prefix, bool last_entry = false) const; + /** + * @brief last_entry is this the last entry for the dot dumping + * @details if not, a "|" is appended to the dump. + */ + void DumpIndicesDot(FILE* file, const char* prefix, bool last_entry = false) const; + protected: - void DumpHelper(std::ostringstream& buffer, const char* prefix) const; + /** + * @brief Dump the bitvector into buffer in a 00101..01 format. + * @param buffer the ostringstream used to dump the bitvector into. + */ + void DumpHelper(const char* prefix, std::ostringstream& buffer) const; + + /** + * @brief Dump the bitvector in a 1 2 5 8 format, where the numbers are the bit set. + * @param buffer the ostringstream used to dump the bitvector into. + */ + void DumpIndicesHelper(const char* prefix, std::ostringstream& buffer) const; + + /** + * @brief Wrapper to perform the bitvector dumping with the .dot format. + * @param buffer the ostringstream used to dump the bitvector into. + */ + void DumpDotHelper(bool last_entry, FILE* file, std::ostringstream& buffer) const; private: + static constexpr uint32_t kWordBytes = sizeof(uint32_t); + static constexpr uint32_t kWordBits = kWordBytes * 8; + Allocator* const allocator_; const bool expandable_; // expand bitmap if we run out? uint32_t storage_size_; // current size, in 32-bit words. diff --git a/runtime/base/bit_vector_test.cc b/runtime/base/bit_vector_test.cc index 0f866a4442..1403f50c04 100644 --- a/runtime/base/bit_vector_test.cc +++ b/runtime/base/bit_vector_test.cc @@ -38,11 +38,8 @@ TEST(BitVector, Test) { EXPECT_EQ(0U, bv.GetRawStorageWord(0)); EXPECT_EQ(0U, *bv.GetRawStorage()); - BitVector::Iterator empty_iterator(&bv); - EXPECT_EQ(-1, empty_iterator.Next()); - - std::unique_ptr<BitVector::Iterator> empty_iterator_on_heap(bv.GetIterator()); - EXPECT_EQ(-1, empty_iterator_on_heap->Next()); + EXPECT_TRUE(bv.Indexes().begin().Done()); + EXPECT_TRUE(bv.Indexes().begin() == bv.Indexes().end()); bv.SetBit(0); bv.SetBit(kBits - 1); @@ -57,10 +54,14 @@ TEST(BitVector, Test) { EXPECT_EQ(0x80000001U, bv.GetRawStorageWord(0)); EXPECT_EQ(0x80000001U, *bv.GetRawStorage()); - BitVector::Iterator iterator(&bv); - EXPECT_EQ(0, iterator.Next()); - EXPECT_EQ(static_cast<int>(kBits - 1), iterator.Next()); - EXPECT_EQ(-1, iterator.Next()); + BitVector::IndexIterator iterator = bv.Indexes().begin(); + EXPECT_TRUE(iterator != bv.Indexes().end()); + EXPECT_EQ(0, *iterator); + ++iterator; + EXPECT_TRUE(iterator != bv.Indexes().end()); + EXPECT_EQ(static_cast<int>(kBits - 1), *iterator); + ++iterator; + EXPECT_TRUE(iterator == bv.Indexes().end()); } TEST(BitVector, NoopAllocator) { diff --git a/runtime/base/mutex-inl.h b/runtime/base/mutex-inl.h index 6c415e77e3..a9472f7504 100644 --- a/runtime/base/mutex-inl.h +++ b/runtime/base/mutex-inl.h @@ -146,7 +146,7 @@ static inline void CheckUnattachedThread(LockLevel level) NO_THREAD_SAFETY_ANALY // Ignore logging which may or may not have set up thread data structures. level == kLoggingLock || // Avoid recursive death. - level == kAbortLock); + level == kAbortLock) << level; } } diff --git a/runtime/debugger.cc b/runtime/debugger.cc index 8c8a3556da..984f28723c 100644 --- a/runtime/debugger.cc +++ b/runtime/debugger.cc @@ -2881,7 +2881,7 @@ static bool IsMethodPossiblyInlined(Thread* self, mirror::ArtMethod* m) Handle<mirror::ClassLoader> class_loader(hs.NewHandle(mh.GetClassLoader())); verifier::MethodVerifier verifier(&mh.GetDexFile(), &dex_cache, &class_loader, &mh.GetClassDef(), code_item, m->GetDexMethodIndex(), m, - m->GetAccessFlags(), false, true); + m->GetAccessFlags(), false, true, false); // Note: we don't need to verify the method. return InlineMethodAnalyser::AnalyseMethodCode(&verifier, nullptr); } diff --git a/runtime/deoptimize_stack_visitor.cc b/runtime/deoptimize_stack_visitor.cc index c7fbc87572..449ccce64f 100644 --- a/runtime/deoptimize_stack_visitor.cc +++ b/runtime/deoptimize_stack_visitor.cc @@ -55,7 +55,7 @@ bool DeoptimizeStackVisitor::HandleDeoptimization(mirror::ArtMethod* m) { Handle<mirror::ClassLoader> class_loader(hs.NewHandle(mh.GetClassLoader())); verifier::MethodVerifier verifier(&mh.GetDexFile(), &dex_cache, &class_loader, &mh.GetClassDef(), code_item, m->GetDexMethodIndex(), m, - m->GetAccessFlags(), false, true); + m->GetAccessFlags(), false, true, true); verifier.Verify(); std::vector<int32_t> kinds = verifier.DescribeVRegs(dex_pc); for (uint16_t reg = 0; reg < num_regs; ++reg) { diff --git a/runtime/dex_instruction.h b/runtime/dex_instruction.h index 560e5ff8c2..1ff5c196b0 100644 --- a/runtime/dex_instruction.h +++ b/runtime/dex_instruction.h @@ -118,13 +118,30 @@ class Instruction { }; enum Flags { - kBranch = 0x01, // conditional or unconditional branch - kContinue = 0x02, // flow can continue to next statement - kSwitch = 0x04, // switch statement - kThrow = 0x08, // could cause an exception to be thrown - kReturn = 0x10, // returns, no additional statements - kInvoke = 0x20, // a flavor of invoke - kUnconditional = 0x40, // unconditional branch + kBranch = 0x000001, // conditional or unconditional branch + kContinue = 0x000002, // flow can continue to next statement + kSwitch = 0x000004, // switch statement + kThrow = 0x000008, // could cause an exception to be thrown + kReturn = 0x000010, // returns, no additional statements + kInvoke = 0x000020, // a flavor of invoke + kUnconditional = 0x000040, // unconditional branch + kAdd = 0x000080, // addition + kSubtract = 0x000100, // subtract + kMultiply = 0x000200, // multiply + kDivide = 0x000400, // division + kRemainder = 0x000800, // remainder + kAnd = 0x001000, // and + kOr = 0x002000, // or + kXor = 0x004000, // xor + kShl = 0x008000, // shl + kShr = 0x010000, // shr + kUshr = 0x020000, // ushr + kCast = 0x040000, // cast + kStore = 0x080000, // store opcode + kLoad = 0x100000, // load opcode + kClobber = 0x200000, // clobbers memory in a big way (not just a write) + kRegCFieldOrConstant = 0x400000, // is the third virtual register a field or literal constant (vC) + kRegBFieldOrConstant = 0x800000, // is the second virtual register a field or literal constant (vB) }; enum VerifyFlag { diff --git a/runtime/dex_instruction_list.h b/runtime/dex_instruction_list.h index c2cd65ade5..f43e42f042 100644 --- a/runtime/dex_instruction_list.h +++ b/runtime/dex_instruction_list.h @@ -36,27 +36,27 @@ V(0x0F, RETURN, "return", k11x, false, kNone, kReturn, kVerifyRegA) \ V(0x10, RETURN_WIDE, "return-wide", k11x, false, kNone, kReturn, kVerifyRegAWide) \ V(0x11, RETURN_OBJECT, "return-object", k11x, false, kNone, kReturn, kVerifyRegA) \ - V(0x12, CONST_4, "const/4", k11n, true, kNone, kContinue, kVerifyRegA) \ - V(0x13, CONST_16, "const/16", k21s, true, kNone, kContinue, kVerifyRegA) \ - V(0x14, CONST, "const", k31i, true, kNone, kContinue, kVerifyRegA) \ - V(0x15, CONST_HIGH16, "const/high16", k21h, true, kNone, kContinue, kVerifyRegA) \ - V(0x16, CONST_WIDE_16, "const-wide/16", k21s, true, kNone, kContinue, kVerifyRegAWide) \ - V(0x17, CONST_WIDE_32, "const-wide/32", k31i, true, kNone, kContinue, kVerifyRegAWide) \ - V(0x18, CONST_WIDE, "const-wide", k51l, true, kNone, kContinue, kVerifyRegAWide) \ - V(0x19, CONST_WIDE_HIGH16, "const-wide/high16", k21h, true, kNone, kContinue, kVerifyRegAWide) \ + V(0x12, CONST_4, "const/4", k11n, true, kNone, kContinue | kRegBFieldOrConstant, kVerifyRegA) \ + V(0x13, CONST_16, "const/16", k21s, true, kNone, kContinue | kRegBFieldOrConstant, kVerifyRegA) \ + V(0x14, CONST, "const", k31i, true, kNone, kContinue | kRegBFieldOrConstant, kVerifyRegA) \ + V(0x15, CONST_HIGH16, "const/high16", k21h, true, kNone, kContinue | kRegBFieldOrConstant, kVerifyRegA) \ + V(0x16, CONST_WIDE_16, "const-wide/16", k21s, true, kNone, kContinue | kRegBFieldOrConstant, kVerifyRegAWide) \ + V(0x17, CONST_WIDE_32, "const-wide/32", k31i, true, kNone, kContinue | kRegBFieldOrConstant, kVerifyRegAWide) \ + V(0x18, CONST_WIDE, "const-wide", k51l, true, kNone, kContinue | kRegBFieldOrConstant, kVerifyRegAWide) \ + V(0x19, CONST_WIDE_HIGH16, "const-wide/high16", k21h, true, kNone, kContinue | kRegBFieldOrConstant, kVerifyRegAWide) \ V(0x1A, CONST_STRING, "const-string", k21c, true, kStringRef, kContinue | kThrow, kVerifyRegA | kVerifyRegBString) \ V(0x1B, CONST_STRING_JUMBO, "const-string/jumbo", k31c, true, kStringRef, kContinue | kThrow, kVerifyRegA | kVerifyRegBString) \ V(0x1C, CONST_CLASS, "const-class", k21c, true, kTypeRef, kContinue | kThrow, kVerifyRegA | kVerifyRegBType) \ - V(0x1D, MONITOR_ENTER, "monitor-enter", k11x, false, kNone, kContinue | kThrow, kVerifyRegA) \ - V(0x1E, MONITOR_EXIT, "monitor-exit", k11x, false, kNone, kContinue | kThrow, kVerifyRegA) \ + V(0x1D, MONITOR_ENTER, "monitor-enter", k11x, false, kNone, kContinue | kThrow | kClobber, kVerifyRegA) \ + V(0x1E, MONITOR_EXIT, "monitor-exit", k11x, false, kNone, kContinue | kThrow | kClobber, kVerifyRegA) \ V(0x1F, CHECK_CAST, "check-cast", k21c, true, kTypeRef, kContinue | kThrow, kVerifyRegA | kVerifyRegBType) \ V(0x20, INSTANCE_OF, "instance-of", k22c, true, kTypeRef, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegCType) \ V(0x21, ARRAY_LENGTH, "array-length", k12x, true, kNone, kContinue | kThrow, kVerifyRegA | kVerifyRegB) \ - V(0x22, NEW_INSTANCE, "new-instance", k21c, true, kTypeRef, kContinue | kThrow, kVerifyRegA | kVerifyRegBNewInstance) \ - V(0x23, NEW_ARRAY, "new-array", k22c, true, kTypeRef, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegCNewArray) \ - V(0x24, FILLED_NEW_ARRAY, "filled-new-array", k35c, false, kTypeRef, kContinue | kThrow, kVerifyRegBType | kVerifyVarArg) \ - V(0x25, FILLED_NEW_ARRAY_RANGE, "filled-new-array/range", k3rc, false, kTypeRef, kContinue | kThrow, kVerifyRegBType | kVerifyVarArgRange) \ - V(0x26, FILL_ARRAY_DATA, "fill-array-data", k31t, false, kNone, kContinue | kThrow, kVerifyRegA | kVerifyArrayData) \ + V(0x22, NEW_INSTANCE, "new-instance", k21c, true, kTypeRef, kContinue | kThrow | kClobber, kVerifyRegA | kVerifyRegBNewInstance) \ + V(0x23, NEW_ARRAY, "new-array", k22c, true, kTypeRef, kContinue | kThrow | kClobber, kVerifyRegA | kVerifyRegB | kVerifyRegCNewArray) \ + V(0x24, FILLED_NEW_ARRAY, "filled-new-array", k35c, false, kTypeRef, kContinue | kThrow | kClobber, kVerifyRegBType | kVerifyVarArg) \ + V(0x25, FILLED_NEW_ARRAY_RANGE, "filled-new-array/range", k3rc, false, kTypeRef, kContinue | kThrow | kClobber, kVerifyRegBType | kVerifyVarArgRange) \ + V(0x26, FILL_ARRAY_DATA, "fill-array-data", k31t, false, kNone, kContinue | kThrow | kClobber, kVerifyRegA | kVerifyArrayData) \ V(0x27, THROW, "throw", k11x, false, kNone, kThrow, kVerifyRegA) \ V(0x28, GOTO, "goto", k10t, false, kNone, kBranch | kUnconditional, kVerifyBranchTarget) \ V(0x29, GOTO_16, "goto/16", k20t, false, kNone, kBranch | kUnconditional, kVerifyBranchTarget) \ @@ -86,48 +86,48 @@ V(0x41, UNUSED_41, "unused-41", k10x, false, kUnknown, 0, kVerifyError) \ V(0x42, UNUSED_42, "unused-42", k10x, false, kUnknown, 0, kVerifyError) \ V(0x43, UNUSED_43, "unused-43", k10x, false, kUnknown, 0, kVerifyError) \ - V(0x44, AGET, "aget", k23x, true, kNone, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ - V(0x45, AGET_WIDE, "aget-wide", k23x, true, kNone, kContinue | kThrow, kVerifyRegAWide | kVerifyRegB | kVerifyRegC) \ - V(0x46, AGET_OBJECT, "aget-object", k23x, true, kNone, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ - V(0x47, AGET_BOOLEAN, "aget-boolean", k23x, true, kNone, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ - V(0x48, AGET_BYTE, "aget-byte", k23x, true, kNone, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ - V(0x49, AGET_CHAR, "aget-char", k23x, true, kNone, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ - V(0x4A, AGET_SHORT, "aget-short", k23x, true, kNone, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ - V(0x4B, APUT, "aput", k23x, false, kNone, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ - V(0x4C, APUT_WIDE, "aput-wide", k23x, false, kNone, kContinue | kThrow, kVerifyRegAWide | kVerifyRegB | kVerifyRegC) \ - V(0x4D, APUT_OBJECT, "aput-object", k23x, false, kNone, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ - V(0x4E, APUT_BOOLEAN, "aput-boolean", k23x, false, kNone, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ - V(0x4F, APUT_BYTE, "aput-byte", k23x, false, kNone, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ - V(0x50, APUT_CHAR, "aput-char", k23x, false, kNone, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ - V(0x51, APUT_SHORT, "aput-short", k23x, false, kNone, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ - V(0x52, IGET, "iget", k22c, true, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \ - V(0x53, IGET_WIDE, "iget-wide", k22c, true, kFieldRef, kContinue | kThrow, kVerifyRegAWide | kVerifyRegB | kVerifyRegCField) \ - V(0x54, IGET_OBJECT, "iget-object", k22c, true, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \ - V(0x55, IGET_BOOLEAN, "iget-boolean", k22c, true, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \ - V(0x56, IGET_BYTE, "iget-byte", k22c, true, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \ - V(0x57, IGET_CHAR, "iget-char", k22c, true, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \ - V(0x58, IGET_SHORT, "iget-short", k22c, true, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \ - V(0x59, IPUT, "iput", k22c, false, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \ - V(0x5A, IPUT_WIDE, "iput-wide", k22c, false, kFieldRef, kContinue | kThrow, kVerifyRegAWide | kVerifyRegB | kVerifyRegCField) \ - V(0x5B, IPUT_OBJECT, "iput-object", k22c, false, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \ - V(0x5C, IPUT_BOOLEAN, "iput-boolean", k22c, false, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \ - V(0x5D, IPUT_BYTE, "iput-byte", k22c, false, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \ - V(0x5E, IPUT_CHAR, "iput-char", k22c, false, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \ - V(0x5F, IPUT_SHORT, "iput-short", k22c, false, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \ - V(0x60, SGET, "sget", k21c, true, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegBField) \ - V(0x61, SGET_WIDE, "sget-wide", k21c, true, kFieldRef, kContinue | kThrow, kVerifyRegAWide | kVerifyRegBField) \ - V(0x62, SGET_OBJECT, "sget-object", k21c, true, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegBField) \ - V(0x63, SGET_BOOLEAN, "sget-boolean", k21c, true, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegBField) \ - V(0x64, SGET_BYTE, "sget-byte", k21c, true, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegBField) \ - V(0x65, SGET_CHAR, "sget-char", k21c, true, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegBField) \ - V(0x66, SGET_SHORT, "sget-short", k21c, true, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegBField) \ - V(0x67, SPUT, "sput", k21c, false, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegBField) \ - V(0x68, SPUT_WIDE, "sput-wide", k21c, false, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegBField) \ - V(0x69, SPUT_OBJECT, "sput-object", k21c, false, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegBField) \ - V(0x6A, SPUT_BOOLEAN, "sput-boolean", k21c, false, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegBField) \ - V(0x6B, SPUT_BYTE, "sput-byte", k21c, false, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegBField) \ - V(0x6C, SPUT_CHAR, "sput-char", k21c, false, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegBField) \ - V(0x6D, SPUT_SHORT, "sput-short", k21c, false, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegBField) \ + V(0x44, AGET, "aget", k23x, true, kNone, kContinue | kThrow | kLoad, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ + V(0x45, AGET_WIDE, "aget-wide", k23x, true, kNone, kContinue | kThrow | kLoad, kVerifyRegAWide | kVerifyRegB | kVerifyRegC) \ + V(0x46, AGET_OBJECT, "aget-object", k23x, true, kNone, kContinue | kThrow | kLoad, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ + V(0x47, AGET_BOOLEAN, "aget-boolean", k23x, true, kNone, kContinue | kThrow | kLoad, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ + V(0x48, AGET_BYTE, "aget-byte", k23x, true, kNone, kContinue | kThrow | kLoad, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ + V(0x49, AGET_CHAR, "aget-char", k23x, true, kNone, kContinue | kThrow | kLoad, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ + V(0x4A, AGET_SHORT, "aget-short", k23x, true, kNone, kContinue | kThrow | kLoad, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ + V(0x4B, APUT, "aput", k23x, false, kNone, kContinue | kThrow | kStore, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ + V(0x4C, APUT_WIDE, "aput-wide", k23x, false, kNone, kContinue | kThrow | kStore, kVerifyRegAWide | kVerifyRegB | kVerifyRegC) \ + V(0x4D, APUT_OBJECT, "aput-object", k23x, false, kNone, kContinue | kThrow | kStore, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ + V(0x4E, APUT_BOOLEAN, "aput-boolean", k23x, false, kNone, kContinue | kThrow | kStore, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ + V(0x4F, APUT_BYTE, "aput-byte", k23x, false, kNone, kContinue | kThrow | kStore, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ + V(0x50, APUT_CHAR, "aput-char", k23x, false, kNone, kContinue | kThrow | kStore, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ + V(0x51, APUT_SHORT, "aput-short", k23x, false, kNone, kContinue | kThrow | kStore, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ + V(0x52, IGET, "iget", k22c, true, kFieldRef, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \ + V(0x53, IGET_WIDE, "iget-wide", k22c, true, kFieldRef, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegAWide | kVerifyRegB | kVerifyRegCField) \ + V(0x54, IGET_OBJECT, "iget-object", k22c, true, kFieldRef, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \ + V(0x55, IGET_BOOLEAN, "iget-boolean", k22c, true, kFieldRef, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \ + V(0x56, IGET_BYTE, "iget-byte", k22c, true, kFieldRef, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \ + V(0x57, IGET_CHAR, "iget-char", k22c, true, kFieldRef, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \ + V(0x58, IGET_SHORT, "iget-short", k22c, true, kFieldRef, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \ + V(0x59, IPUT, "iput", k22c, false, kFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \ + V(0x5A, IPUT_WIDE, "iput-wide", k22c, false, kFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegAWide | kVerifyRegB | kVerifyRegCField) \ + V(0x5B, IPUT_OBJECT, "iput-object", k22c, false, kFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \ + V(0x5C, IPUT_BOOLEAN, "iput-boolean", k22c, false, kFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \ + V(0x5D, IPUT_BYTE, "iput-byte", k22c, false, kFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \ + V(0x5E, IPUT_CHAR, "iput-char", k22c, false, kFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \ + V(0x5F, IPUT_SHORT, "iput-short", k22c, false, kFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \ + V(0x60, SGET, "sget", k21c, true, kFieldRef, kContinue | kThrow | kLoad | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \ + V(0x61, SGET_WIDE, "sget-wide", k21c, true, kFieldRef, kContinue | kThrow | kLoad | kRegBFieldOrConstant, kVerifyRegAWide | kVerifyRegBField) \ + V(0x62, SGET_OBJECT, "sget-object", k21c, true, kFieldRef, kContinue | kThrow | kLoad | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \ + V(0x63, SGET_BOOLEAN, "sget-boolean", k21c, true, kFieldRef, kContinue | kThrow | kLoad | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \ + V(0x64, SGET_BYTE, "sget-byte", k21c, true, kFieldRef, kContinue | kThrow | kLoad | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \ + V(0x65, SGET_CHAR, "sget-char", k21c, true, kFieldRef, kContinue | kThrow | kLoad | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \ + V(0x66, SGET_SHORT, "sget-short", k21c, true, kFieldRef, kContinue | kThrow | kLoad | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \ + V(0x67, SPUT, "sput", k21c, false, kFieldRef, kContinue | kThrow | kStore | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \ + V(0x68, SPUT_WIDE, "sput-wide", k21c, false, kFieldRef, kContinue | kThrow | kStore | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \ + V(0x69, SPUT_OBJECT, "sput-object", k21c, false, kFieldRef, kContinue | kThrow | kStore | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \ + V(0x6A, SPUT_BOOLEAN, "sput-boolean", k21c, false, kFieldRef, kContinue | kThrow | kStore | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \ + V(0x6B, SPUT_BYTE, "sput-byte", k21c, false, kFieldRef, kContinue | kThrow | kStore | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \ + V(0x6C, SPUT_CHAR, "sput-char", k21c, false, kFieldRef, kContinue | kThrow | kStore | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \ + V(0x6D, SPUT_SHORT, "sput-short", k21c, false, kFieldRef, kContinue | kThrow | kStore | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \ V(0x6E, INVOKE_VIRTUAL, "invoke-virtual", k35c, false, kMethodRef, kContinue | kThrow | kInvoke, kVerifyRegBMethod | kVerifyVarArg) \ V(0x6F, INVOKE_SUPER, "invoke-super", k35c, false, kMethodRef, kContinue | kThrow | kInvoke, kVerifyRegBMethod | kVerifyVarArg) \ V(0x70, INVOKE_DIRECT, "invoke-direct", k35c, false, kMethodRef, kContinue | kThrow | kInvoke, kVerifyRegBMethod | kVerifyVarArg) \ @@ -147,110 +147,110 @@ V(0x7E, NOT_LONG, "not-long", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide) \ V(0x7F, NEG_FLOAT, "neg-float", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \ V(0x80, NEG_DOUBLE, "neg-double", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide) \ - V(0x81, INT_TO_LONG, "int-to-long", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegB) \ - V(0x82, INT_TO_FLOAT, "int-to-float", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \ - V(0x83, INT_TO_DOUBLE, "int-to-double", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegB) \ - V(0x84, LONG_TO_INT, "long-to-int", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegBWide) \ - V(0x85, LONG_TO_FLOAT, "long-to-float", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegBWide) \ - V(0x86, LONG_TO_DOUBLE, "long-to-double", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide) \ - V(0x87, FLOAT_TO_INT, "float-to-int", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \ - V(0x88, FLOAT_TO_LONG, "float-to-long", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegB) \ - V(0x89, FLOAT_TO_DOUBLE, "float-to-double", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegB) \ - V(0x8A, DOUBLE_TO_INT, "double-to-int", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegBWide) \ - V(0x8B, DOUBLE_TO_LONG, "double-to-long", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide) \ - V(0x8C, DOUBLE_TO_FLOAT, "double-to-float", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegBWide) \ - V(0x8D, INT_TO_BYTE, "int-to-byte", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \ - V(0x8E, INT_TO_CHAR, "int-to-char", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \ - V(0x8F, INT_TO_SHORT, "int-to-short", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \ - V(0x90, ADD_INT, "add-int", k23x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ - V(0x91, SUB_INT, "sub-int", k23x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ - V(0x92, MUL_INT, "mul-int", k23x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ - V(0x93, DIV_INT, "div-int", k23x, true, kNone, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ - V(0x94, REM_INT, "rem-int", k23x, true, kNone, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ - V(0x95, AND_INT, "and-int", k23x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ - V(0x96, OR_INT, "or-int", k23x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ - V(0x97, XOR_INT, "xor-int", k23x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ - V(0x98, SHL_INT, "shl-int", k23x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ - V(0x99, SHR_INT, "shr-int", k23x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ - V(0x9A, USHR_INT, "ushr-int", k23x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ - V(0x9B, ADD_LONG, "add-long", k23x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \ - V(0x9C, SUB_LONG, "sub-long", k23x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \ - V(0x9D, MUL_LONG, "mul-long", k23x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \ - V(0x9E, DIV_LONG, "div-long", k23x, true, kNone, kContinue | kThrow, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \ - V(0x9F, REM_LONG, "rem-long", k23x, true, kNone, kContinue | kThrow, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \ - V(0xA0, AND_LONG, "and-long", k23x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \ - V(0xA1, OR_LONG, "or-long", k23x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \ - V(0xA2, XOR_LONG, "xor-long", k23x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \ - V(0xA3, SHL_LONG, "shl-long", k23x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegC) \ - V(0xA4, SHR_LONG, "shr-long", k23x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegC) \ - V(0xA5, USHR_LONG, "ushr-long", k23x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegC) \ - V(0xA6, ADD_FLOAT, "add-float", k23x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ - V(0xA7, SUB_FLOAT, "sub-float", k23x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ - V(0xA8, MUL_FLOAT, "mul-float", k23x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ - V(0xA9, DIV_FLOAT, "div-float", k23x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ - V(0xAA, REM_FLOAT, "rem-float", k23x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ - V(0xAB, ADD_DOUBLE, "add-double", k23x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \ - V(0xAC, SUB_DOUBLE, "sub-double", k23x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \ - V(0xAD, MUL_DOUBLE, "mul-double", k23x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \ - V(0xAE, DIV_DOUBLE, "div-double", k23x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \ - V(0xAF, REM_DOUBLE, "rem-double", k23x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \ - V(0xB0, ADD_INT_2ADDR, "add-int/2addr", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \ - V(0xB1, SUB_INT_2ADDR, "sub-int/2addr", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \ - V(0xB2, MUL_INT_2ADDR, "mul-int/2addr", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \ - V(0xB3, DIV_INT_2ADDR, "div-int/2addr", k12x, true, kNone, kContinue | kThrow, kVerifyRegA | kVerifyRegB) \ - V(0xB4, REM_INT_2ADDR, "rem-int/2addr", k12x, true, kNone, kContinue | kThrow, kVerifyRegA | kVerifyRegB) \ - V(0xB5, AND_INT_2ADDR, "and-int/2addr", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \ - V(0xB6, OR_INT_2ADDR, "or-int/2addr", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \ - V(0xB7, XOR_INT_2ADDR, "xor-int/2addr", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \ - V(0xB8, SHL_INT_2ADDR, "shl-int/2addr", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \ - V(0xB9, SHR_INT_2ADDR, "shr-int/2addr", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \ - V(0xBA, USHR_INT_2ADDR, "ushr-int/2addr", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \ - V(0xBB, ADD_LONG_2ADDR, "add-long/2addr", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide) \ - V(0xBC, SUB_LONG_2ADDR, "sub-long/2addr", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide) \ - V(0xBD, MUL_LONG_2ADDR, "mul-long/2addr", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide) \ - V(0xBE, DIV_LONG_2ADDR, "div-long/2addr", k12x, true, kNone, kContinue | kThrow, kVerifyRegAWide | kVerifyRegBWide) \ - V(0xBF, REM_LONG_2ADDR, "rem-long/2addr", k12x, true, kNone, kContinue | kThrow, kVerifyRegAWide | kVerifyRegBWide) \ - V(0xC0, AND_LONG_2ADDR, "and-long/2addr", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide) \ - V(0xC1, OR_LONG_2ADDR, "or-long/2addr", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide) \ - V(0xC2, XOR_LONG_2ADDR, "xor-long/2addr", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide) \ - V(0xC3, SHL_LONG_2ADDR, "shl-long/2addr", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegB) \ - V(0xC4, SHR_LONG_2ADDR, "shr-long/2addr", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegB) \ - V(0xC5, USHR_LONG_2ADDR, "ushr-long/2addr", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegB) \ - V(0xC6, ADD_FLOAT_2ADDR, "add-float/2addr", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \ - V(0xC7, SUB_FLOAT_2ADDR, "sub-float/2addr", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \ - V(0xC8, MUL_FLOAT_2ADDR, "mul-float/2addr", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \ - V(0xC9, DIV_FLOAT_2ADDR, "div-float/2addr", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \ - V(0xCA, REM_FLOAT_2ADDR, "rem-float/2addr", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \ - V(0xCB, ADD_DOUBLE_2ADDR, "add-double/2addr", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide) \ - V(0xCC, SUB_DOUBLE_2ADDR, "sub-double/2addr", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide) \ - V(0xCD, MUL_DOUBLE_2ADDR, "mul-double/2addr", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide) \ - V(0xCE, DIV_DOUBLE_2ADDR, "div-double/2addr", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide) \ - V(0xCF, REM_DOUBLE_2ADDR, "rem-double/2addr", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide) \ - V(0xD0, ADD_INT_LIT16, "add-int/lit16", k22s, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \ - V(0xD1, RSUB_INT, "rsub-int", k22s, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \ - V(0xD2, MUL_INT_LIT16, "mul-int/lit16", k22s, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \ - V(0xD3, DIV_INT_LIT16, "div-int/lit16", k22s, true, kNone, kContinue | kThrow, kVerifyRegA | kVerifyRegB) \ - V(0xD4, REM_INT_LIT16, "rem-int/lit16", k22s, true, kNone, kContinue | kThrow, kVerifyRegA | kVerifyRegB) \ - V(0xD5, AND_INT_LIT16, "and-int/lit16", k22s, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \ - V(0xD6, OR_INT_LIT16, "or-int/lit16", k22s, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \ - V(0xD7, XOR_INT_LIT16, "xor-int/lit16", k22s, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \ - V(0xD8, ADD_INT_LIT8, "add-int/lit8", k22b, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \ - V(0xD9, RSUB_INT_LIT8, "rsub-int/lit8", k22b, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \ - V(0xDA, MUL_INT_LIT8, "mul-int/lit8", k22b, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \ - V(0xDB, DIV_INT_LIT8, "div-int/lit8", k22b, true, kNone, kContinue | kThrow, kVerifyRegA | kVerifyRegB) \ - V(0xDC, REM_INT_LIT8, "rem-int/lit8", k22b, true, kNone, kContinue | kThrow, kVerifyRegA | kVerifyRegB) \ - V(0xDD, AND_INT_LIT8, "and-int/lit8", k22b, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \ - V(0xDE, OR_INT_LIT8, "or-int/lit8", k22b, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \ - V(0xDF, XOR_INT_LIT8, "xor-int/lit8", k22b, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \ - V(0xE0, SHL_INT_LIT8, "shl-int/lit8", k22b, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \ - V(0xE1, SHR_INT_LIT8, "shr-int/lit8", k22b, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \ - V(0xE2, USHR_INT_LIT8, "ushr-int/lit8", k22b, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \ - V(0xE3, IGET_QUICK, "iget-quick", k22c, true, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegB) \ - V(0xE4, IGET_WIDE_QUICK, "iget-wide-quick", k22c, true, kFieldRef, kContinue | kThrow, kVerifyRegAWide | kVerifyRegB) \ - V(0xE5, IGET_OBJECT_QUICK, "iget-object-quick", k22c, true, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegB) \ - V(0xE6, IPUT_QUICK, "iput-quick", k22c, false, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegB) \ - V(0xE7, IPUT_WIDE_QUICK, "iput-wide-quick", k22c, false, kFieldRef, kContinue | kThrow, kVerifyRegAWide | kVerifyRegB) \ - V(0xE8, IPUT_OBJECT_QUICK, "iput-object-quick", k22c, false, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegB) \ + V(0x81, INT_TO_LONG, "int-to-long", k12x, true, kNone, kContinue | kCast, kVerifyRegAWide | kVerifyRegB) \ + V(0x82, INT_TO_FLOAT, "int-to-float", k12x, true, kNone, kContinue | kCast, kVerifyRegA | kVerifyRegB) \ + V(0x83, INT_TO_DOUBLE, "int-to-double", k12x, true, kNone, kContinue | kCast, kVerifyRegAWide | kVerifyRegB) \ + V(0x84, LONG_TO_INT, "long-to-int", k12x, true, kNone, kContinue | kCast, kVerifyRegA | kVerifyRegBWide) \ + V(0x85, LONG_TO_FLOAT, "long-to-float", k12x, true, kNone, kContinue | kCast, kVerifyRegA | kVerifyRegBWide) \ + V(0x86, LONG_TO_DOUBLE, "long-to-double", k12x, true, kNone, kContinue | kCast, kVerifyRegAWide | kVerifyRegBWide) \ + V(0x87, FLOAT_TO_INT, "float-to-int", k12x, true, kNone, kContinue | kCast, kVerifyRegA | kVerifyRegB) \ + V(0x88, FLOAT_TO_LONG, "float-to-long", k12x, true, kNone, kContinue | kCast, kVerifyRegAWide | kVerifyRegB) \ + V(0x89, FLOAT_TO_DOUBLE, "float-to-double", k12x, true, kNone, kContinue | kCast, kVerifyRegAWide | kVerifyRegB) \ + V(0x8A, DOUBLE_TO_INT, "double-to-int", k12x, true, kNone, kContinue | kCast, kVerifyRegA | kVerifyRegBWide) \ + V(0x8B, DOUBLE_TO_LONG, "double-to-long", k12x, true, kNone, kContinue | kCast, kVerifyRegAWide | kVerifyRegBWide) \ + V(0x8C, DOUBLE_TO_FLOAT, "double-to-float", k12x, true, kNone, kContinue | kCast, kVerifyRegA | kVerifyRegBWide) \ + V(0x8D, INT_TO_BYTE, "int-to-byte", k12x, true, kNone, kContinue | kCast, kVerifyRegA | kVerifyRegB) \ + V(0x8E, INT_TO_CHAR, "int-to-char", k12x, true, kNone, kContinue | kCast, kVerifyRegA | kVerifyRegB) \ + V(0x8F, INT_TO_SHORT, "int-to-short", k12x, true, kNone, kContinue | kCast, kVerifyRegA | kVerifyRegB) \ + V(0x90, ADD_INT, "add-int", k23x, true, kNone, kContinue | kAdd, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ + V(0x91, SUB_INT, "sub-int", k23x, true, kNone, kContinue | kSubtract, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ + V(0x92, MUL_INT, "mul-int", k23x, true, kNone, kContinue | kMultiply, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ + V(0x93, DIV_INT, "div-int", k23x, true, kNone, kContinue | kThrow | kDivide, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ + V(0x94, REM_INT, "rem-int", k23x, true, kNone, kContinue | kThrow | kRemainder, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ + V(0x95, AND_INT, "and-int", k23x, true, kNone, kContinue | kAnd, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ + V(0x96, OR_INT, "or-int", k23x, true, kNone, kContinue | kOr, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ + V(0x97, XOR_INT, "xor-int", k23x, true, kNone, kContinue | kXor, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ + V(0x98, SHL_INT, "shl-int", k23x, true, kNone, kContinue | kShl, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ + V(0x99, SHR_INT, "shr-int", k23x, true, kNone, kContinue | kShr, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ + V(0x9A, USHR_INT, "ushr-int", k23x, true, kNone, kContinue | kUshr, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ + V(0x9B, ADD_LONG, "add-long", k23x, true, kNone, kContinue | kAdd, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \ + V(0x9C, SUB_LONG, "sub-long", k23x, true, kNone, kContinue | kSubtract, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \ + V(0x9D, MUL_LONG, "mul-long", k23x, true, kNone, kContinue | kMultiply, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \ + V(0x9E, DIV_LONG, "div-long", k23x, true, kNone, kContinue | kThrow | kDivide, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \ + V(0x9F, REM_LONG, "rem-long", k23x, true, kNone, kContinue | kThrow | kRemainder, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \ + V(0xA0, AND_LONG, "and-long", k23x, true, kNone, kContinue | kAnd, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \ + V(0xA1, OR_LONG, "or-long", k23x, true, kNone, kContinue | kOr, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \ + V(0xA2, XOR_LONG, "xor-long", k23x, true, kNone, kContinue | kXor, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \ + V(0xA3, SHL_LONG, "shl-long", k23x, true, kNone, kContinue | kShl, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegC) \ + V(0xA4, SHR_LONG, "shr-long", k23x, true, kNone, kContinue | kShr, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegC) \ + V(0xA5, USHR_LONG, "ushr-long", k23x, true, kNone, kContinue | kUshr, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegC) \ + V(0xA6, ADD_FLOAT, "add-float", k23x, true, kNone, kContinue | kAdd, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ + V(0xA7, SUB_FLOAT, "sub-float", k23x, true, kNone, kContinue | kSubtract, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ + V(0xA8, MUL_FLOAT, "mul-float", k23x, true, kNone, kContinue | kMultiply, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ + V(0xA9, DIV_FLOAT, "div-float", k23x, true, kNone, kContinue | kDivide, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ + V(0xAA, REM_FLOAT, "rem-float", k23x, true, kNone, kContinue | kRemainder, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ + V(0xAB, ADD_DOUBLE, "add-double", k23x, true, kNone, kContinue | kAdd, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \ + V(0xAC, SUB_DOUBLE, "sub-double", k23x, true, kNone, kContinue | kSubtract, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \ + V(0xAD, MUL_DOUBLE, "mul-double", k23x, true, kNone, kContinue | kMultiply, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \ + V(0xAE, DIV_DOUBLE, "div-double", k23x, true, kNone, kContinue | kDivide, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \ + V(0xAF, REM_DOUBLE, "rem-double", k23x, true, kNone, kContinue | kRemainder, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \ + V(0xB0, ADD_INT_2ADDR, "add-int/2addr", k12x, true, kNone, kContinue | kAdd, kVerifyRegA | kVerifyRegB) \ + V(0xB1, SUB_INT_2ADDR, "sub-int/2addr", k12x, true, kNone, kContinue | kSubtract, kVerifyRegA | kVerifyRegB) \ + V(0xB2, MUL_INT_2ADDR, "mul-int/2addr", k12x, true, kNone, kContinue | kMultiply, kVerifyRegA | kVerifyRegB) \ + V(0xB3, DIV_INT_2ADDR, "div-int/2addr", k12x, true, kNone, kContinue | kThrow | kDivide, kVerifyRegA | kVerifyRegB) \ + V(0xB4, REM_INT_2ADDR, "rem-int/2addr", k12x, true, kNone, kContinue | kThrow | kRemainder, kVerifyRegA | kVerifyRegB) \ + V(0xB5, AND_INT_2ADDR, "and-int/2addr", k12x, true, kNone, kContinue | kAnd, kVerifyRegA | kVerifyRegB) \ + V(0xB6, OR_INT_2ADDR, "or-int/2addr", k12x, true, kNone, kContinue | kOr, kVerifyRegA | kVerifyRegB) \ + V(0xB7, XOR_INT_2ADDR, "xor-int/2addr", k12x, true, kNone, kContinue | kXor, kVerifyRegA | kVerifyRegB) \ + V(0xB8, SHL_INT_2ADDR, "shl-int/2addr", k12x, true, kNone, kContinue | kShl, kVerifyRegA | kVerifyRegB) \ + V(0xB9, SHR_INT_2ADDR, "shr-int/2addr", k12x, true, kNone, kContinue | kShr, kVerifyRegA | kVerifyRegB) \ + V(0xBA, USHR_INT_2ADDR, "ushr-int/2addr", k12x, true, kNone, kContinue | kUshr, kVerifyRegA | kVerifyRegB) \ + V(0xBB, ADD_LONG_2ADDR, "add-long/2addr", k12x, true, kNone, kContinue | kAdd, kVerifyRegAWide | kVerifyRegBWide) \ + V(0xBC, SUB_LONG_2ADDR, "sub-long/2addr", k12x, true, kNone, kContinue | kSubtract, kVerifyRegAWide | kVerifyRegBWide) \ + V(0xBD, MUL_LONG_2ADDR, "mul-long/2addr", k12x, true, kNone, kContinue | kMultiply, kVerifyRegAWide | kVerifyRegBWide) \ + V(0xBE, DIV_LONG_2ADDR, "div-long/2addr", k12x, true, kNone, kContinue | kThrow | kDivide, kVerifyRegAWide | kVerifyRegBWide) \ + V(0xBF, REM_LONG_2ADDR, "rem-long/2addr", k12x, true, kNone, kContinue | kThrow | kRemainder, kVerifyRegAWide | kVerifyRegBWide) \ + V(0xC0, AND_LONG_2ADDR, "and-long/2addr", k12x, true, kNone, kContinue | kAnd, kVerifyRegAWide | kVerifyRegBWide) \ + V(0xC1, OR_LONG_2ADDR, "or-long/2addr", k12x, true, kNone, kContinue | kOr, kVerifyRegAWide | kVerifyRegBWide) \ + V(0xC2, XOR_LONG_2ADDR, "xor-long/2addr", k12x, true, kNone, kContinue | kXor, kVerifyRegAWide | kVerifyRegBWide) \ + V(0xC3, SHL_LONG_2ADDR, "shl-long/2addr", k12x, true, kNone, kContinue | kShl, kVerifyRegAWide | kVerifyRegB) \ + V(0xC4, SHR_LONG_2ADDR, "shr-long/2addr", k12x, true, kNone, kContinue | kShr, kVerifyRegAWide | kVerifyRegB) \ + V(0xC5, USHR_LONG_2ADDR, "ushr-long/2addr", k12x, true, kNone, kContinue | kUshr, kVerifyRegAWide | kVerifyRegB) \ + V(0xC6, ADD_FLOAT_2ADDR, "add-float/2addr", k12x, true, kNone, kContinue | kAdd, kVerifyRegA | kVerifyRegB) \ + V(0xC7, SUB_FLOAT_2ADDR, "sub-float/2addr", k12x, true, kNone, kContinue | kSubtract, kVerifyRegA | kVerifyRegB) \ + V(0xC8, MUL_FLOAT_2ADDR, "mul-float/2addr", k12x, true, kNone, kContinue | kMultiply, kVerifyRegA | kVerifyRegB) \ + V(0xC9, DIV_FLOAT_2ADDR, "div-float/2addr", k12x, true, kNone, kContinue | kDivide, kVerifyRegA | kVerifyRegB) \ + V(0xCA, REM_FLOAT_2ADDR, "rem-float/2addr", k12x, true, kNone, kContinue | kRemainder, kVerifyRegA | kVerifyRegB) \ + V(0xCB, ADD_DOUBLE_2ADDR, "add-double/2addr", k12x, true, kNone, kContinue | kAdd, kVerifyRegAWide | kVerifyRegBWide) \ + V(0xCC, SUB_DOUBLE_2ADDR, "sub-double/2addr", k12x, true, kNone, kContinue | kSubtract, kVerifyRegAWide | kVerifyRegBWide) \ + V(0xCD, MUL_DOUBLE_2ADDR, "mul-double/2addr", k12x, true, kNone, kContinue | kMultiply, kVerifyRegAWide | kVerifyRegBWide) \ + V(0xCE, DIV_DOUBLE_2ADDR, "div-double/2addr", k12x, true, kNone, kContinue | kDivide, kVerifyRegAWide | kVerifyRegBWide) \ + V(0xCF, REM_DOUBLE_2ADDR, "rem-double/2addr", k12x, true, kNone, kContinue | kRemainder, kVerifyRegAWide | kVerifyRegBWide) \ + V(0xD0, ADD_INT_LIT16, "add-int/lit16", k22s, true, kNone, kContinue | kAdd | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \ + V(0xD1, RSUB_INT, "rsub-int", k22s, true, kNone, kContinue | kSubtract | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \ + V(0xD2, MUL_INT_LIT16, "mul-int/lit16", k22s, true, kNone, kContinue | kMultiply | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \ + V(0xD3, DIV_INT_LIT16, "div-int/lit16", k22s, true, kNone, kContinue | kThrow | kDivide | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \ + V(0xD4, REM_INT_LIT16, "rem-int/lit16", k22s, true, kNone, kContinue | kThrow | kRemainder | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \ + V(0xD5, AND_INT_LIT16, "and-int/lit16", k22s, true, kNone, kContinue | kAnd | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \ + V(0xD6, OR_INT_LIT16, "or-int/lit16", k22s, true, kNone, kContinue | kOr | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \ + V(0xD7, XOR_INT_LIT16, "xor-int/lit16", k22s, true, kNone, kContinue | kXor | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \ + V(0xD8, ADD_INT_LIT8, "add-int/lit8", k22b, true, kNone, kContinue | kAdd | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \ + V(0xD9, RSUB_INT_LIT8, "rsub-int/lit8", k22b, true, kNone, kContinue | kSubtract | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \ + V(0xDA, MUL_INT_LIT8, "mul-int/lit8", k22b, true, kNone, kContinue | kMultiply | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \ + V(0xDB, DIV_INT_LIT8, "div-int/lit8", k22b, true, kNone, kContinue | kThrow | kDivide | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \ + V(0xDC, REM_INT_LIT8, "rem-int/lit8", k22b, true, kNone, kContinue | kThrow | kRemainder | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \ + V(0xDD, AND_INT_LIT8, "and-int/lit8", k22b, true, kNone, kContinue | kAnd | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \ + V(0xDE, OR_INT_LIT8, "or-int/lit8", k22b, true, kNone, kContinue | kOr | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \ + V(0xDF, XOR_INT_LIT8, "xor-int/lit8", k22b, true, kNone, kContinue | kXor | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \ + V(0xE0, SHL_INT_LIT8, "shl-int/lit8", k22b, true, kNone, kContinue | kShl | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \ + V(0xE1, SHR_INT_LIT8, "shr-int/lit8", k22b, true, kNone, kContinue | kShr | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \ + V(0xE2, USHR_INT_LIT8, "ushr-int/lit8", k22b, true, kNone, kContinue | kUshr | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \ + V(0xE3, IGET_QUICK, "iget-quick", k22c, true, kFieldRef, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \ + V(0xE4, IGET_WIDE_QUICK, "iget-wide-quick", k22c, true, kFieldRef, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegAWide | kVerifyRegB) \ + V(0xE5, IGET_OBJECT_QUICK, "iget-object-quick", k22c, true, kFieldRef, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \ + V(0xE6, IPUT_QUICK, "iput-quick", k22c, false, kFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \ + V(0xE7, IPUT_WIDE_QUICK, "iput-wide-quick", k22c, false, kFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegAWide | kVerifyRegB) \ + V(0xE8, IPUT_OBJECT_QUICK, "iput-object-quick", k22c, false, kFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \ V(0xE9, INVOKE_VIRTUAL_QUICK, "invoke-virtual-quick", k35c, false, kMethodRef, kContinue | kThrow | kInvoke, kVerifyVarArg) \ V(0xEA, INVOKE_VIRTUAL_RANGE_QUICK, "invoke-virtual/range-quick", k3rc, false, kMethodRef, kContinue | kThrow | kInvoke, kVerifyVarArgRange) \ V(0xEB, UNUSED_EB, "unused-eb", k10x, false, kUnknown, 0, kVerifyError) \ diff --git a/runtime/intern_table.cc b/runtime/intern_table.cc index 817d1045cf..339eb36178 100644 --- a/runtime/intern_table.cc +++ b/runtime/intern_table.cc @@ -84,7 +84,8 @@ void InternTable::VisitRoots(RootCallback* callback, void* arg, VisitRootFlags f mirror::String* InternTable::Lookup(Table& table, mirror::String* s, int32_t hash_code) { Locks::intern_table_lock_->AssertHeld(Thread::Current()); - for (auto it = table.find(hash_code), end = table.end(); it != end; ++it) { + for (auto it = table.lower_bound(hash_code), end = table.end(); + it != end && it->first == hash_code; ++it) { mirror::String* existing_string = it->second; if (existing_string->Equals(s)) { return existing_string; @@ -123,7 +124,8 @@ void InternTable::RemoveWeak(mirror::String* s, int32_t hash_code) { } void InternTable::Remove(Table& table, mirror::String* s, int32_t hash_code) { - for (auto it = table.find(hash_code), end = table.end(); it != end; ++it) { + for (auto it = table.lower_bound(hash_code), end = table.end(); + it != end && it->first == hash_code; ++it) { if (it->second == s) { table.erase(it); return; diff --git a/runtime/monitor.cc b/runtime/monitor.cc index c53520de12..3123fd7787 100644 --- a/runtime/monitor.cc +++ b/runtime/monitor.cc @@ -983,7 +983,7 @@ void Monitor::VisitLocks(StackVisitor* stack_visitor, void (*callback)(mirror::O // Ask the verifier for the dex pcs of all the monitor-enter instructions corresponding to // the locks held in this stack frame. std::vector<uint32_t> monitor_enter_dex_pcs; - verifier::MethodVerifier::FindLocksAtDexPc(m, stack_visitor->GetDexPc(), monitor_enter_dex_pcs); + verifier::MethodVerifier::FindLocksAtDexPc(m, stack_visitor->GetDexPc(), &monitor_enter_dex_pcs); if (monitor_enter_dex_pcs.empty()) { return; } diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc index 4863b8367b..743fd1bd9f 100644 --- a/runtime/verifier/method_verifier.cc +++ b/runtime/verifier/method_verifier.cc @@ -165,7 +165,8 @@ MethodVerifier::FailureKind MethodVerifier::VerifyClass(const DexFile* dex_file, it.GetMethodCodeItem(), method, it.GetMemberAccessFlags(), - allow_soft_failures); + allow_soft_failures, + false); if (result != kNoFailure) { if (result == kHardFailure) { hard_fail = true; @@ -207,7 +208,8 @@ MethodVerifier::FailureKind MethodVerifier::VerifyClass(const DexFile* dex_file, it.GetMethodCodeItem(), method, it.GetMemberAccessFlags(), - allow_soft_failures); + allow_soft_failures, + false); if (result != kNoFailure) { if (result == kHardFailure) { hard_fail = true; @@ -238,32 +240,34 @@ MethodVerifier::FailureKind MethodVerifier::VerifyMethod(uint32_t method_idx, const DexFile::CodeItem* code_item, mirror::ArtMethod* method, uint32_t method_access_flags, - bool allow_soft_failures) { + bool allow_soft_failures, + bool need_precise_constants) { MethodVerifier::FailureKind result = kNoFailure; uint64_t start_ns = NanoTime(); - MethodVerifier verifier_(dex_file, &dex_cache, &class_loader, class_def, code_item, - method_idx, method, method_access_flags, true, allow_soft_failures); - if (verifier_.Verify()) { + MethodVerifier verifier(dex_file, &dex_cache, &class_loader, class_def, code_item, + method_idx, method, method_access_flags, true, allow_soft_failures, + need_precise_constants); + if (verifier.Verify()) { // Verification completed, however failures may be pending that didn't cause the verification // to hard fail. - CHECK(!verifier_.have_pending_hard_failure_); - if (verifier_.failures_.size() != 0) { + CHECK(!verifier.have_pending_hard_failure_); + if (verifier.failures_.size() != 0) { if (VLOG_IS_ON(verifier)) { - verifier_.DumpFailures(VLOG_STREAM(verifier) << "Soft verification failures in " + verifier.DumpFailures(VLOG_STREAM(verifier) << "Soft verification failures in " << PrettyMethod(method_idx, *dex_file) << "\n"); } result = kSoftFailure; } } else { // Bad method data. - CHECK_NE(verifier_.failures_.size(), 0U); - CHECK(verifier_.have_pending_hard_failure_); - verifier_.DumpFailures(LOG(INFO) << "Verification error in " + CHECK_NE(verifier.failures_.size(), 0U); + CHECK(verifier.have_pending_hard_failure_); + verifier.DumpFailures(LOG(INFO) << "Verification error in " << PrettyMethod(method_idx, *dex_file) << "\n"); if (gDebugVerify) { - std::cout << "\n" << verifier_.info_messages_.str(); - verifier_.Dump(std::cout); + std::cout << "\n" << verifier.info_messages_.str(); + verifier.Dump(std::cout); } result = kHardFailure; } @@ -284,7 +288,7 @@ void MethodVerifier::VerifyMethodAndDump(std::ostream& os, uint32_t dex_method_i mirror::ArtMethod* method, uint32_t method_access_flags) { MethodVerifier verifier(dex_file, &dex_cache, &class_loader, class_def, code_item, - dex_method_idx, method, method_access_flags, true, true); + dex_method_idx, method, method_access_flags, true, true, true); verifier.Verify(); verifier.DumpFailures(os); os << verifier.info_messages_.str(); @@ -296,7 +300,8 @@ MethodVerifier::MethodVerifier(const DexFile* dex_file, Handle<mirror::DexCache> const DexFile::ClassDef* class_def, const DexFile::CodeItem* code_item, uint32_t dex_method_idx, mirror::ArtMethod* method, uint32_t method_access_flags, - bool can_load_classes, bool allow_soft_failures) + bool can_load_classes, bool allow_soft_failures, + bool need_precise_constants) : reg_types_(can_load_classes), work_insn_idx_(-1), dex_method_idx_(dex_method_idx), @@ -317,6 +322,7 @@ MethodVerifier::MethodVerifier(const DexFile* dex_file, Handle<mirror::DexCache> monitor_enter_count_(0), can_load_classes_(can_load_classes), allow_soft_failures_(allow_soft_failures), + need_precise_constants_(need_precise_constants), has_check_casts_(false), has_virtual_or_interface_invokes_(false) { Runtime::Current()->AddMethodVerifier(this); @@ -329,16 +335,16 @@ MethodVerifier::~MethodVerifier() { } void MethodVerifier::FindLocksAtDexPc(mirror::ArtMethod* m, uint32_t dex_pc, - std::vector<uint32_t>& monitor_enter_dex_pcs) { + std::vector<uint32_t>* monitor_enter_dex_pcs) { MethodHelper mh(m); StackHandleScope<2> hs(Thread::Current()); Handle<mirror::DexCache> dex_cache(hs.NewHandle(mh.GetDexCache())); Handle<mirror::ClassLoader> class_loader(hs.NewHandle(mh.GetClassLoader())); MethodVerifier verifier(&mh.GetDexFile(), &dex_cache, &class_loader, &mh.GetClassDef(), mh.GetCodeItem(), m->GetDexMethodIndex(), m, m->GetAccessFlags(), false, - true); + true, false); verifier.interesting_dex_pc_ = dex_pc; - verifier.monitor_enter_dex_pcs_ = &monitor_enter_dex_pcs; + verifier.monitor_enter_dex_pcs_ = monitor_enter_dex_pcs; verifier.FindLocksAtDexPc(); } @@ -354,14 +360,14 @@ void MethodVerifier::FindLocksAtDexPc() { } mirror::ArtField* MethodVerifier::FindAccessedFieldAtDexPc(mirror::ArtMethod* m, - uint32_t dex_pc) { + uint32_t dex_pc) { MethodHelper mh(m); StackHandleScope<2> hs(Thread::Current()); Handle<mirror::DexCache> dex_cache(hs.NewHandle(mh.GetDexCache())); Handle<mirror::ClassLoader> class_loader(hs.NewHandle(mh.GetClassLoader())); MethodVerifier verifier(&mh.GetDexFile(), &dex_cache, &class_loader, &mh.GetClassDef(), mh.GetCodeItem(), m->GetDexMethodIndex(), m, m->GetAccessFlags(), true, - true); + true, false); return verifier.FindAccessedFieldAtDexPc(dex_pc); } @@ -392,7 +398,7 @@ mirror::ArtMethod* MethodVerifier::FindInvokedMethodAtDexPc(mirror::ArtMethod* m Handle<mirror::ClassLoader> class_loader(hs.NewHandle(mh.GetClassLoader())); MethodVerifier verifier(&mh.GetDexFile(), &dex_cache, &class_loader, &mh.GetClassDef(), mh.GetCodeItem(), m->GetDexMethodIndex(), m, m->GetAccessFlags(), true, - true); + true, false); return verifier.FindInvokedMethodAtDexPc(dex_pc); } @@ -1436,9 +1442,6 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) { std::unique_ptr<RegisterLine> branch_line; std::unique_ptr<RegisterLine> fallthrough_line; - // We need precise constant types only for deoptimization which happens at runtime. - const bool need_precise_constant = !Runtime::Current()->IsCompiler(); - switch (inst->Opcode()) { case Instruction::NOP: /* @@ -1590,25 +1593,25 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) { case Instruction::CONST_4: { int32_t val = static_cast<int32_t>(inst->VRegB_11n() << 28) >> 28; work_line_->SetRegisterType(inst->VRegA_11n(), - DetermineCat1Constant(val, need_precise_constant)); + DetermineCat1Constant(val, need_precise_constants_)); break; } case Instruction::CONST_16: { int16_t val = static_cast<int16_t>(inst->VRegB_21s()); work_line_->SetRegisterType(inst->VRegA_21s(), - DetermineCat1Constant(val, need_precise_constant)); + DetermineCat1Constant(val, need_precise_constants_)); break; } case Instruction::CONST: { int32_t val = inst->VRegB_31i(); work_line_->SetRegisterType(inst->VRegA_31i(), - DetermineCat1Constant(val, need_precise_constant)); + DetermineCat1Constant(val, need_precise_constants_)); break; } case Instruction::CONST_HIGH16: { int32_t val = static_cast<int32_t>(inst->VRegB_21h() << 16); work_line_->SetRegisterType(inst->VRegA_21h(), - DetermineCat1Constant(val, need_precise_constant)); + DetermineCat1Constant(val, need_precise_constants_)); break; } /* could be long or double; resolved upon use */ diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h index 495d3c5353..9bb915acc8 100644 --- a/runtime/verifier/method_verifier.h +++ b/runtime/verifier/method_verifier.h @@ -185,7 +185,7 @@ class MethodVerifier { // Fills 'monitor_enter_dex_pcs' with the dex pcs of the monitor-enter instructions corresponding // to the locks held at 'dex_pc' in method 'm'. static void FindLocksAtDexPc(mirror::ArtMethod* m, uint32_t dex_pc, - std::vector<uint32_t>& monitor_enter_dex_pcs) + std::vector<uint32_t>* monitor_enter_dex_pcs) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Returns the accessed field corresponding to the quick instruction's field @@ -208,7 +208,8 @@ class MethodVerifier { MethodVerifier(const DexFile* dex_file, Handle<mirror::DexCache>* dex_cache, Handle<mirror::ClassLoader>* class_loader, const DexFile::ClassDef* class_def, const DexFile::CodeItem* code_item, uint32_t method_idx, mirror::ArtMethod* method, - uint32_t access_flags, bool can_load_classes, bool allow_soft_failures) + uint32_t access_flags, bool can_load_classes, bool allow_soft_failures, + bool need_precise_constants) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); ~MethodVerifier(); @@ -260,7 +261,7 @@ class MethodVerifier { const DexFile::ClassDef* class_def_idx, const DexFile::CodeItem* code_item, mirror::ArtMethod* method, uint32_t method_access_flags, - bool allow_soft_failures) + bool allow_soft_failures, bool need_precise_constants) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); void FindLocksAtDexPc() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); @@ -672,6 +673,12 @@ class MethodVerifier { // running and the verifier is called from the class linker. const bool allow_soft_failures_; + // An optimization where instead of generating unique RegTypes for constants we use imprecise + // constants that cover a range of constants. This isn't good enough for deoptimization that + // avoids loading from registers in the case of a constant as the dex instruction set lost the + // notion of whether a value should be in a floating point or general purpose register file. + const bool need_precise_constants_; + // Indicates the method being verified contains at least one check-cast or aput-object // instruction. Aput-object operations implicitly check for array-store exceptions, similar to // check-cast. diff --git a/test/079-phantom/src/Bitmap.java b/test/079-phantom/src/Bitmap.java index 9d03cbd3d4..85eb3ccb97 100644 --- a/test/079-phantom/src/Bitmap.java +++ b/test/079-phantom/src/Bitmap.java @@ -29,6 +29,7 @@ public class Bitmap { new ReferenceQueue<PhantomWrapper>(); private static BitmapWatcher sWatcher = new BitmapWatcher(sPhantomQueue); static { + sWatcher.setDaemon(true); sWatcher.start(); }; |
