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_OPTIMIZING_UNIT_TEST_H_ 18 #define ART_COMPILER_OPTIMIZING_OPTIMIZING_UNIT_TEST_H_ 19 20 #include <memory> 21 #include <vector> 22 23 #include "base/scoped_arena_allocator.h" 24 #include "builder.h" 25 #include "common_compiler_test.h" 26 #include "dex/code_item_accessors-inl.h" 27 #include "dex/dex_file.h" 28 #include "dex/dex_instruction.h" 29 #include "dex/standard_dex_file.h" 30 #include "driver/dex_compilation_unit.h" 31 #include "handle_scope-inl.h" 32 #include "mirror/class_loader.h" 33 #include "mirror/dex_cache.h" 34 #include "nodes.h" 35 #include "scoped_thread_state_change.h" 36 #include "ssa_builder.h" 37 #include "ssa_liveness_analysis.h" 38 39 #include "gtest/gtest.h" 40 41 namespace art { 42 43 #define NUM_INSTRUCTIONS(...) \ 44 (sizeof((uint16_t[]) {__VA_ARGS__}) /sizeof(uint16_t)) 45 46 #define N_REGISTERS_CODE_ITEM(NUM_REGS, ...) \ 47 { NUM_REGS, 0, 0, 0, 0, 0, NUM_INSTRUCTIONS(__VA_ARGS__), 0, __VA_ARGS__ } 48 49 #define ZERO_REGISTER_CODE_ITEM(...) N_REGISTERS_CODE_ITEM(0, __VA_ARGS__) 50 #define ONE_REGISTER_CODE_ITEM(...) N_REGISTERS_CODE_ITEM(1, __VA_ARGS__) 51 #define TWO_REGISTERS_CODE_ITEM(...) N_REGISTERS_CODE_ITEM(2, __VA_ARGS__) 52 #define THREE_REGISTERS_CODE_ITEM(...) N_REGISTERS_CODE_ITEM(3, __VA_ARGS__) 53 #define FOUR_REGISTERS_CODE_ITEM(...) N_REGISTERS_CODE_ITEM(4, __VA_ARGS__) 54 #define FIVE_REGISTERS_CODE_ITEM(...) N_REGISTERS_CODE_ITEM(5, __VA_ARGS__) 55 #define SIX_REGISTERS_CODE_ITEM(...) N_REGISTERS_CODE_ITEM(6, __VA_ARGS__) 56 57 LiveInterval* BuildInterval(const size_t ranges[][2], 58 size_t number_of_ranges, 59 ScopedArenaAllocator* allocator, 60 int reg = -1, 61 HInstruction* defined_by = nullptr) { 62 LiveInterval* interval = 63 LiveInterval::MakeInterval(allocator, DataType::Type::kInt32, defined_by); 64 if (defined_by != nullptr) { 65 defined_by->SetLiveInterval(interval); 66 } 67 for (size_t i = number_of_ranges; i > 0; --i) { 68 interval->AddRange(ranges[i - 1][0], ranges[i - 1][1]); 69 } 70 interval->SetRegister(reg); 71 return interval; 72 } 73 74 void RemoveSuspendChecks(HGraph* graph) { 75 for (HBasicBlock* block : graph->GetBlocks()) { 76 if (block != nullptr) { 77 if (block->GetLoopInformation() != nullptr) { 78 block->GetLoopInformation()->SetSuspendCheck(nullptr); 79 } 80 for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) { 81 HInstruction* current = it.Current(); 82 if (current->IsSuspendCheck()) { 83 current->GetBlock()->RemoveInstruction(current); 84 } 85 } 86 } 87 } 88 } 89 90 class ArenaPoolAndAllocator { 91 public: 92 ArenaPoolAndAllocator() 93 : pool_(), allocator_(&pool_), arena_stack_(&pool_), scoped_allocator_(&arena_stack_) { } 94 95 ArenaAllocator* GetAllocator() { return &allocator_; } 96 ArenaStack* GetArenaStack() { return &arena_stack_; } 97 ScopedArenaAllocator* GetScopedAllocator() { return &scoped_allocator_; } 98 99 private: 100 ArenaPool pool_; 101 ArenaAllocator allocator_; 102 ArenaStack arena_stack_; 103 ScopedArenaAllocator scoped_allocator_; 104 }; 105 106 // Have a separate helper so the OptimizingCFITest can inherit it without causing 107 // multiple inheritance errors from having two gtest as a parent twice. 108 class OptimizingUnitTestHelper { 109 public: 110 OptimizingUnitTestHelper() : pool_and_allocator_(new ArenaPoolAndAllocator()) { } 111 112 ArenaAllocator* GetAllocator() { return pool_and_allocator_->GetAllocator(); } 113 ArenaStack* GetArenaStack() { return pool_and_allocator_->GetArenaStack(); } 114 ScopedArenaAllocator* GetScopedAllocator() { return pool_and_allocator_->GetScopedAllocator(); } 115 116 void ResetPoolAndAllocator() { 117 pool_and_allocator_.reset(new ArenaPoolAndAllocator()); 118 handles_.reset(); // When getting rid of the old HGraph, we can also reset handles_. 119 } 120 121 HGraph* CreateGraph() { 122 ArenaAllocator* const allocator = pool_and_allocator_->GetAllocator(); 123 124 // Reserve a big array of 0s so the dex file constructor can offsets from the header. 125 static constexpr size_t kDexDataSize = 4 * KB; 126 const uint8_t* dex_data = reinterpret_cast<uint8_t*>(allocator->Alloc(kDexDataSize)); 127 128 // Create the dex file based on the fake data. Call the constructor so that we can use virtual 129 // functions. Don't use the arena for the StandardDexFile otherwise the dex location leaks. 130 dex_files_.emplace_back(new StandardDexFile( 131 dex_data, 132 sizeof(StandardDexFile::Header), 133 "no_location", 134 /*location_checksum*/ 0, 135 /*oat_dex_file*/ nullptr, 136 /*container*/ nullptr)); 137 138 return new (allocator) HGraph( 139 allocator, 140 pool_and_allocator_->GetArenaStack(), 141 *dex_files_.back(), 142 /*method_idx*/-1, 143 kRuntimeISA); 144 } 145 146 // Create a control-flow graph from Dex instructions. 147 HGraph* CreateCFG(const std::vector<uint16_t>& data, 148 DataType::Type return_type = DataType::Type::kInt32) { 149 HGraph* graph = CreateGraph(); 150 151 // The code item data might not aligned to 4 bytes, copy it to ensure that. 152 const size_t code_item_size = data.size() * sizeof(data.front()); 153 void* aligned_data = GetAllocator()->Alloc(code_item_size); 154 memcpy(aligned_data, &data[0], code_item_size); 155 CHECK_ALIGNED(aligned_data, StandardDexFile::CodeItem::kAlignment); 156 const DexFile::CodeItem* code_item = reinterpret_cast<const DexFile::CodeItem*>(aligned_data); 157 158 { 159 ScopedObjectAccess soa(Thread::Current()); 160 if (handles_ == nullptr) { 161 handles_.reset(new VariableSizedHandleScope(soa.Self())); 162 } 163 const DexCompilationUnit* dex_compilation_unit = 164 new (graph->GetAllocator()) DexCompilationUnit( 165 handles_->NewHandle<mirror::ClassLoader>(nullptr), 166 /* class_linker */ nullptr, 167 graph->GetDexFile(), 168 code_item, 169 /* class_def_index */ DexFile::kDexNoIndex16, 170 /* method_idx */ dex::kDexNoIndex, 171 /* access_flags */ 0u, 172 /* verified_method */ nullptr, 173 handles_->NewHandle<mirror::DexCache>(nullptr)); 174 CodeItemDebugInfoAccessor accessor(graph->GetDexFile(), code_item, /*dex_method_idx*/ 0u); 175 HGraphBuilder builder(graph, dex_compilation_unit, accessor, handles_.get(), return_type); 176 bool graph_built = (builder.BuildGraph() == kAnalysisSuccess); 177 return graph_built ? graph : nullptr; 178 } 179 } 180 181 private: 182 std::vector<std::unique_ptr<const StandardDexFile>> dex_files_; 183 std::unique_ptr<ArenaPoolAndAllocator> pool_and_allocator_; 184 std::unique_ptr<VariableSizedHandleScope> handles_; 185 }; 186 187 class OptimizingUnitTest : public CommonCompilerTest, public OptimizingUnitTestHelper {}; 188 189 // Naive string diff data type. 190 typedef std::list<std::pair<std::string, std::string>> diff_t; 191 192 // An alias for the empty string used to make it clear that a line is 193 // removed in a diff. 194 static const std::string removed = ""; // NOLINT [runtime/string] [4] 195 196 // Naive patch command: apply a diff to a string. 197 inline std::string Patch(const std::string& original, const diff_t& diff) { 198 std::string result = original; 199 for (const auto& p : diff) { 200 std::string::size_type pos = result.find(p.first); 201 DCHECK_NE(pos, std::string::npos) 202 << "Could not find: \"" << p.first << "\" in \"" << result << "\""; 203 result.replace(pos, p.first.size(), p.second); 204 } 205 return result; 206 } 207 208 // Returns if the instruction is removed from the graph. 209 inline bool IsRemoved(HInstruction* instruction) { 210 return instruction->GetBlock() == nullptr; 211 } 212 213 } // namespace art 214 215 #endif // ART_COMPILER_OPTIMIZING_OPTIMIZING_UNIT_TEST_H_ 216