1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef ART_COMPILER_OPTIMIZING_GRAPH_CHECKER_H_ 18 #define ART_COMPILER_OPTIMIZING_GRAPH_CHECKER_H_ 19 20 #include <ostream> 21 22 #include "base/arena_bit_vector.h" 23 #include "base/bit_vector-inl.h" 24 #include "base/macros.h" 25 #include "base/scoped_arena_containers.h" 26 #include "nodes.h" 27 28 namespace art HIDDEN { 29 30 class CodeGenerator; 31 32 // A control-flow graph visitor performing various checks. 33 class GraphChecker final : public HGraphDelegateVisitor { 34 public: 35 explicit GraphChecker(HGraph* graph, 36 CodeGenerator* codegen = nullptr, 37 const char* dump_prefix = "art::GraphChecker: ") HGraphDelegateVisitor(graph)38 : HGraphDelegateVisitor(graph), 39 errors_(graph->GetAllocator()->Adapter(kArenaAllocGraphChecker)), 40 dump_prefix_(dump_prefix), 41 allocator_(graph->GetArenaStack()), 42 seen_ids_(&allocator_, graph->GetCurrentInstructionId(), false, kArenaAllocGraphChecker), 43 uses_per_instruction_(allocator_.Adapter(kArenaAllocGraphChecker)), 44 instructions_per_block_(allocator_.Adapter(kArenaAllocGraphChecker)), 45 phis_per_block_(allocator_.Adapter(kArenaAllocGraphChecker)), 46 codegen_(codegen) {} 47 48 // Check the whole graph. The pass_change parameter indicates whether changes 49 // may have occurred during the just executed pass. The default value is 50 // conservatively "true" (something may have changed). The last_size parameter 51 // and return value pass along the observed graph sizes. 52 size_t Run(bool pass_change = true, size_t last_size = 0); 53 54 void VisitBasicBlock(HBasicBlock* block) override; 55 56 void VisitInstruction(HInstruction* instruction) override; 57 void VisitPhi(HPhi* phi) override; 58 59 void VisitArraySet(HArraySet* instruction) override; 60 void VisitInstanceFieldSet(HInstanceFieldSet* instruction) override; 61 void VisitStaticFieldSet(HStaticFieldSet* instruction) override; 62 void VisitBinaryOperation(HBinaryOperation* op) override; 63 void VisitBooleanNot(HBooleanNot* instruction) override; 64 void VisitBoundType(HBoundType* instruction) override; 65 void VisitBoundsCheck(HBoundsCheck* check) override; 66 void VisitCheckCast(HCheckCast* check) override; 67 void VisitCondition(HCondition* op) override; 68 void VisitConstant(HConstant* instruction) override; 69 void VisitDeoptimize(HDeoptimize* instruction) override; 70 void VisitIf(HIf* instruction) override; 71 void VisitInstanceOf(HInstanceOf* check) override; 72 void VisitInvoke(HInvoke* invoke) override; 73 void VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) override; 74 void VisitLoadClass(HLoadClass* load) override; 75 void VisitLoadException(HLoadException* load) override; 76 void VisitMonitorOperation(HMonitorOperation* monitor_operation) override; 77 void VisitNeg(HNeg* instruction) override; 78 void VisitPackedSwitch(HPackedSwitch* instruction) override; 79 void VisitReturn(HReturn* ret) override; 80 void VisitReturnVoid(HReturnVoid* ret) override; 81 void VisitSelect(HSelect* instruction) override; 82 void VisitTryBoundary(HTryBoundary* try_boundary) override; 83 void VisitTypeConversion(HTypeConversion* instruction) override; 84 85 void VisitVecOperation(HVecOperation* instruction) override; 86 87 void CheckTypeCheckBitstringInput(HTypeCheckInstruction* check, 88 size_t input_pos, 89 bool check_value, 90 uint32_t expected_value, 91 const char* name); 92 void HandleTypeCheckInstruction(HTypeCheckInstruction* instruction); 93 void HandleLoop(HBasicBlock* loop_header); 94 void HandleBooleanInput(HInstruction* instruction, size_t input_index); 95 96 template <typename GetWriteBarrierKind> 97 void CheckWriteBarrier(HInstruction* instruction, GetWriteBarrierKind&& get_write_barrier_kind); 98 99 // Was the last visit of the graph valid? IsValid()100 bool IsValid() const { 101 return errors_.empty(); 102 } 103 104 // Get the list of detected errors. GetErrors()105 const ArenaVector<std::string>& GetErrors() const { 106 return errors_; 107 } 108 109 // Print detected errors on output stream `os`. Dump(std::ostream & os)110 void Dump(std::ostream& os) const { 111 for (size_t i = 0, e = errors_.size(); i < e; ++i) { 112 os << dump_prefix_ << errors_[i] << std::endl; 113 } 114 } 115 116 private: 117 // Report a new error. AddError(const std::string & error)118 void AddError(const std::string& error) { 119 errors_.push_back(error); 120 } 121 122 // The block currently visited. 123 HBasicBlock* current_block_ = nullptr; 124 // Errors encountered while checking the graph. 125 ArenaVector<std::string> errors_; 126 127 void VisitReversePostOrder(); 128 129 // Checks that the graph's flags are set correctly. 130 void CheckGraphFlags(); 131 132 // Checks if `instruction` is in its block's instruction/phi list. To do so, it searches 133 // instructions_per_block_/phis_per_block_ which are set versions of that. If the set to 134 // check hasn't been populated yet, it does so now. 135 bool ContainedInItsBlockList(HInstruction* instruction); 136 137 // String displayed before dumped errors. 138 const char* const dump_prefix_; 139 ScopedArenaAllocator allocator_; 140 ArenaBitVector seen_ids_; 141 142 // As part of VisitInstruction, we verify that the instruction's input_record is present in the 143 // corresponding input's GetUses. If an instruction is used in many places (e.g. 200K+ uses), the 144 // linear search through GetUses is too slow. We can use bookkeeping to search in a set, instead 145 // of a list. 146 ScopedArenaSafeMap<int, ScopedArenaSet<const art::HUseListNode<art::HInstruction*>*>> 147 uses_per_instruction_; 148 149 // Extra bookkeeping to increase GraphChecker's speed while asking if an instruction is contained 150 // in a list of instructions/phis. 151 ScopedArenaSafeMap<HBasicBlock*, ScopedArenaHashSet<HInstruction*>> instructions_per_block_; 152 ScopedArenaSafeMap<HBasicBlock*, ScopedArenaHashSet<HInstruction*>> phis_per_block_; 153 154 // Used to access target information. 155 CodeGenerator* codegen_; 156 157 struct FlagInfo { 158 bool seen_try_boundary = false; 159 bool seen_monitor_operation = false; 160 bool seen_loop = false; 161 bool seen_irreducible_loop = false; 162 bool seen_SIMD = false; 163 bool seen_bounds_checks = false; 164 bool seen_always_throwing_invokes = false; 165 }; 166 FlagInfo flag_info_; 167 168 DISALLOW_COPY_AND_ASSIGN(GraphChecker); 169 }; 170 171 } // namespace art 172 173 #endif // ART_COMPILER_OPTIMIZING_GRAPH_CHECKER_H_ 174