| Nicolas Geoffray | 3ff386a | 2014-03-04 14:46:47 +0000 | [diff] [blame] | 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 |  | 
| Mathieu Chartier | fa3db3d | 2018-01-12 14:42:18 -0800 | [diff] [blame] | 20 | #include <memory> | 
 | 21 | #include <vector> | 
 | 22 |  | 
| Vladimir Marko | e272715 | 2019-10-10 10:46:42 +0100 | [diff] [blame^] | 23 | #include "base/macros.h" | 
| David Sehr | 3215fff | 2018-04-03 17:10:12 -0700 | [diff] [blame] | 24 | #include "base/malloc_arena_pool.h" | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 25 | #include "base/scoped_arena_allocator.h" | 
| Roland Levillain | ccc07a9 | 2014-09-16 14:48:16 +0100 | [diff] [blame] | 26 | #include "builder.h" | 
| David Brazdil | 4833f5a | 2015-12-16 10:37:39 +0000 | [diff] [blame] | 27 | #include "common_compiler_test.h" | 
| David Sehr | 9e734c7 | 2018-01-04 17:56:19 -0800 | [diff] [blame] | 28 | #include "dex/code_item_accessors-inl.h" | 
 | 29 | #include "dex/dex_file.h" | 
 | 30 | #include "dex/dex_instruction.h" | 
| Mathieu Chartier | fa3db3d | 2018-01-12 14:42:18 -0800 | [diff] [blame] | 31 | #include "dex/standard_dex_file.h" | 
| Vladimir Marko | 92f7f3c | 2017-10-31 11:38:30 +0000 | [diff] [blame] | 32 | #include "driver/dex_compilation_unit.h" | 
| Artem Serov | 15f95b1 | 2018-06-29 15:30:36 +0100 | [diff] [blame] | 33 | #include "graph_checker.h" | 
| Vladimir Marko | 69d310e | 2017-10-09 14:12:23 +0100 | [diff] [blame] | 34 | #include "handle_scope-inl.h" | 
 | 35 | #include "mirror/class_loader.h" | 
 | 36 | #include "mirror/dex_cache.h" | 
| Andreas Gampe | 8cf9cb3 | 2017-07-19 09:28:38 -0700 | [diff] [blame] | 37 | #include "nodes.h" | 
| David Brazdil | 4833f5a | 2015-12-16 10:37:39 +0000 | [diff] [blame] | 38 | #include "scoped_thread_state_change.h" | 
 | 39 | #include "ssa_builder.h" | 
| Nicolas Geoffray | a7062e0 | 2014-05-22 12:50:17 +0100 | [diff] [blame] | 40 | #include "ssa_liveness_analysis.h" | 
 | 41 |  | 
| Roland Levillain | 72bceff | 2014-09-15 18:29:00 +0100 | [diff] [blame] | 42 | #include "gtest/gtest.h" | 
 | 43 |  | 
| Vladimir Marko | e272715 | 2019-10-10 10:46:42 +0100 | [diff] [blame^] | 44 | namespace art HIDDEN { | 
| Nicolas Geoffray | a7062e0 | 2014-05-22 12:50:17 +0100 | [diff] [blame] | 45 |  | 
| Nicolas Geoffray | 3ff386a | 2014-03-04 14:46:47 +0000 | [diff] [blame] | 46 | #define NUM_INSTRUCTIONS(...)  \ | 
 | 47 |   (sizeof((uint16_t[]) {__VA_ARGS__}) /sizeof(uint16_t)) | 
 | 48 |  | 
| Roland Levillain | 55dcfb5 | 2014-10-24 18:09:09 +0100 | [diff] [blame] | 49 | #define N_REGISTERS_CODE_ITEM(NUM_REGS, ...)                            \ | 
 | 50 |     { NUM_REGS, 0, 0, 0, 0, 0, NUM_INSTRUCTIONS(__VA_ARGS__), 0, __VA_ARGS__ } | 
| Nicolas Geoffray | 3ff386a | 2014-03-04 14:46:47 +0000 | [diff] [blame] | 51 |  | 
| Roland Levillain | 55dcfb5 | 2014-10-24 18:09:09 +0100 | [diff] [blame] | 52 | #define ZERO_REGISTER_CODE_ITEM(...)   N_REGISTERS_CODE_ITEM(0, __VA_ARGS__) | 
 | 53 | #define ONE_REGISTER_CODE_ITEM(...)    N_REGISTERS_CODE_ITEM(1, __VA_ARGS__) | 
 | 54 | #define TWO_REGISTERS_CODE_ITEM(...)   N_REGISTERS_CODE_ITEM(2, __VA_ARGS__) | 
 | 55 | #define THREE_REGISTERS_CODE_ITEM(...) N_REGISTERS_CODE_ITEM(3, __VA_ARGS__) | 
 | 56 | #define FOUR_REGISTERS_CODE_ITEM(...)  N_REGISTERS_CODE_ITEM(4, __VA_ARGS__) | 
 | 57 | #define FIVE_REGISTERS_CODE_ITEM(...)  N_REGISTERS_CODE_ITEM(5, __VA_ARGS__) | 
 | 58 | #define SIX_REGISTERS_CODE_ITEM(...)   N_REGISTERS_CODE_ITEM(6, __VA_ARGS__) | 
| Nicolas Geoffray | 3ff386a | 2014-03-04 14:46:47 +0000 | [diff] [blame] | 59 |  | 
| Nicolas Geoffray | a7062e0 | 2014-05-22 12:50:17 +0100 | [diff] [blame] | 60 | LiveInterval* BuildInterval(const size_t ranges[][2], | 
 | 61 |                             size_t number_of_ranges, | 
| Vladimir Marko | e764d2e | 2017-10-05 14:35:55 +0100 | [diff] [blame] | 62 |                             ScopedArenaAllocator* allocator, | 
| Nicolas Geoffray | dd8f887 | 2015-01-15 15:37:37 +0000 | [diff] [blame] | 63 |                             int reg = -1, | 
 | 64 |                             HInstruction* defined_by = nullptr) { | 
| Vladimir Marko | 0ebe0d8 | 2017-09-21 22:50:39 +0100 | [diff] [blame] | 65 |   LiveInterval* interval = | 
 | 66 |       LiveInterval::MakeInterval(allocator, DataType::Type::kInt32, defined_by); | 
| Nicolas Geoffray | dd8f887 | 2015-01-15 15:37:37 +0000 | [diff] [blame] | 67 |   if (defined_by != nullptr) { | 
 | 68 |     defined_by->SetLiveInterval(interval); | 
 | 69 |   } | 
| Nicolas Geoffray | a7062e0 | 2014-05-22 12:50:17 +0100 | [diff] [blame] | 70 |   for (size_t i = number_of_ranges; i > 0; --i) { | 
 | 71 |     interval->AddRange(ranges[i - 1][0], ranges[i - 1][1]); | 
 | 72 |   } | 
 | 73 |   interval->SetRegister(reg); | 
 | 74 |   return interval; | 
 | 75 | } | 
 | 76 |  | 
| Nicolas Geoffray | fbc695f | 2014-09-15 15:33:30 +0000 | [diff] [blame] | 77 | void RemoveSuspendChecks(HGraph* graph) { | 
| Vladimir Marko | fa6b93c | 2015-09-15 10:15:55 +0100 | [diff] [blame] | 78 |   for (HBasicBlock* block : graph->GetBlocks()) { | 
| David Brazdil | badd826 | 2016-02-02 16:28:56 +0000 | [diff] [blame] | 79 |     if (block != nullptr) { | 
| Alexandre Rames | 22aa54b | 2016-10-18 09:32:29 +0100 | [diff] [blame] | 80 |       if (block->GetLoopInformation() != nullptr) { | 
 | 81 |         block->GetLoopInformation()->SetSuspendCheck(nullptr); | 
 | 82 |       } | 
| David Brazdil | badd826 | 2016-02-02 16:28:56 +0000 | [diff] [blame] | 83 |       for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) { | 
 | 84 |         HInstruction* current = it.Current(); | 
 | 85 |         if (current->IsSuspendCheck()) { | 
 | 86 |           current->GetBlock()->RemoveInstruction(current); | 
 | 87 |         } | 
| Nicolas Geoffray | fbc695f | 2014-09-15 15:33:30 +0000 | [diff] [blame] | 88 |       } | 
 | 89 |     } | 
 | 90 |   } | 
 | 91 | } | 
 | 92 |  | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 93 | class ArenaPoolAndAllocator { | 
 | 94 |  public: | 
| Vladimir Marko | e764d2e | 2017-10-05 14:35:55 +0100 | [diff] [blame] | 95 |   ArenaPoolAndAllocator() | 
 | 96 |       : pool_(), allocator_(&pool_), arena_stack_(&pool_), scoped_allocator_(&arena_stack_) { } | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 97 |  | 
 | 98 |   ArenaAllocator* GetAllocator() { return &allocator_; } | 
 | 99 |   ArenaStack* GetArenaStack() { return &arena_stack_; } | 
| Vladimir Marko | e764d2e | 2017-10-05 14:35:55 +0100 | [diff] [blame] | 100 |   ScopedArenaAllocator* GetScopedAllocator() { return &scoped_allocator_; } | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 101 |  | 
 | 102 |  private: | 
| David Sehr | 3215fff | 2018-04-03 17:10:12 -0700 | [diff] [blame] | 103 |   MallocArenaPool pool_; | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 104 |   ArenaAllocator allocator_; | 
 | 105 |   ArenaStack arena_stack_; | 
| Vladimir Marko | e764d2e | 2017-10-05 14:35:55 +0100 | [diff] [blame] | 106 |   ScopedArenaAllocator scoped_allocator_; | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 107 | }; | 
 | 108 |  | 
| Mathieu Chartier | fa3db3d | 2018-01-12 14:42:18 -0800 | [diff] [blame] | 109 | // Have a separate helper so the OptimizingCFITest can inherit it without causing | 
 | 110 | // multiple inheritance errors from having two gtest as a parent twice. | 
 | 111 | class OptimizingUnitTestHelper { | 
 | 112 |  public: | 
 | 113 |   OptimizingUnitTestHelper() : pool_and_allocator_(new ArenaPoolAndAllocator()) { } | 
| David Brazdil | badd826 | 2016-02-02 16:28:56 +0000 | [diff] [blame] | 114 |  | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 115 |   ArenaAllocator* GetAllocator() { return pool_and_allocator_->GetAllocator(); } | 
 | 116 |   ArenaStack* GetArenaStack() { return pool_and_allocator_->GetArenaStack(); } | 
| Vladimir Marko | e764d2e | 2017-10-05 14:35:55 +0100 | [diff] [blame] | 117 |   ScopedArenaAllocator* GetScopedAllocator() { return pool_and_allocator_->GetScopedAllocator(); } | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 118 |  | 
 | 119 |   void ResetPoolAndAllocator() { | 
 | 120 |     pool_and_allocator_.reset(new ArenaPoolAndAllocator()); | 
 | 121 |     handles_.reset();  // When getting rid of the old HGraph, we can also reset handles_. | 
| David Brazdil | badd826 | 2016-02-02 16:28:56 +0000 | [diff] [blame] | 122 |   } | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 123 |  | 
 | 124 |   HGraph* CreateGraph() { | 
| Mathieu Chartier | fa3db3d | 2018-01-12 14:42:18 -0800 | [diff] [blame] | 125 |     ArenaAllocator* const allocator = pool_and_allocator_->GetAllocator(); | 
 | 126 |  | 
 | 127 |     // Reserve a big array of 0s so the dex file constructor can offsets from the header. | 
 | 128 |     static constexpr size_t kDexDataSize = 4 * KB; | 
 | 129 |     const uint8_t* dex_data = reinterpret_cast<uint8_t*>(allocator->Alloc(kDexDataSize)); | 
 | 130 |  | 
 | 131 |     // Create the dex file based on the fake data. Call the constructor so that we can use virtual | 
 | 132 |     // functions. Don't use the arena for the StandardDexFile otherwise the dex location leaks. | 
 | 133 |     dex_files_.emplace_back(new StandardDexFile( | 
| David Sehr | 0b42677 | 2018-07-03 23:03:42 +0000 | [diff] [blame] | 134 |         dex_data, | 
 | 135 |         sizeof(StandardDexFile::Header), | 
| Mathieu Chartier | fa3db3d | 2018-01-12 14:42:18 -0800 | [diff] [blame] | 136 |         "no_location", | 
 | 137 |         /*location_checksum*/ 0, | 
| David Sehr | 0b42677 | 2018-07-03 23:03:42 +0000 | [diff] [blame] | 138 |         /*oat_dex_file*/ nullptr, | 
 | 139 |         /*container*/ nullptr)); | 
| Mathieu Chartier | fa3db3d | 2018-01-12 14:42:18 -0800 | [diff] [blame] | 140 |  | 
 | 141 |     return new (allocator) HGraph( | 
 | 142 |         allocator, | 
 | 143 |         pool_and_allocator_->GetArenaStack(), | 
 | 144 |         *dex_files_.back(), | 
 | 145 |         /*method_idx*/-1, | 
 | 146 |         kRuntimeISA); | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 147 |   } | 
 | 148 |  | 
 | 149 |   // Create a control-flow graph from Dex instructions. | 
| Mathieu Chartier | fa3db3d | 2018-01-12 14:42:18 -0800 | [diff] [blame] | 150 |   HGraph* CreateCFG(const std::vector<uint16_t>& data, | 
 | 151 |                     DataType::Type return_type = DataType::Type::kInt32) { | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 152 |     HGraph* graph = CreateGraph(); | 
 | 153 |  | 
| Mathieu Chartier | fa3db3d | 2018-01-12 14:42:18 -0800 | [diff] [blame] | 154 |     // The code item data might not aligned to 4 bytes, copy it to ensure that. | 
 | 155 |     const size_t code_item_size = data.size() * sizeof(data.front()); | 
 | 156 |     void* aligned_data = GetAllocator()->Alloc(code_item_size); | 
 | 157 |     memcpy(aligned_data, &data[0], code_item_size); | 
 | 158 |     CHECK_ALIGNED(aligned_data, StandardDexFile::CodeItem::kAlignment); | 
| Andreas Gampe | 3f1dcd3 | 2018-12-28 09:39:56 -0800 | [diff] [blame] | 159 |     const dex::CodeItem* code_item = reinterpret_cast<const dex::CodeItem*>(aligned_data); | 
| Mathieu Chartier | fa3db3d | 2018-01-12 14:42:18 -0800 | [diff] [blame] | 160 |  | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 161 |     { | 
 | 162 |       ScopedObjectAccess soa(Thread::Current()); | 
 | 163 |       if (handles_ == nullptr) { | 
 | 164 |         handles_.reset(new VariableSizedHandleScope(soa.Self())); | 
 | 165 |       } | 
| Vladimir Marko | 69d310e | 2017-10-09 14:12:23 +0100 | [diff] [blame] | 166 |       const DexCompilationUnit* dex_compilation_unit = | 
 | 167 |           new (graph->GetAllocator()) DexCompilationUnit( | 
 | 168 |               handles_->NewHandle<mirror::ClassLoader>(nullptr), | 
| Andreas Gampe | 3db7068 | 2018-12-26 15:12:03 -0800 | [diff] [blame] | 169 |               /* class_linker= */ nullptr, | 
| Vladimir Marko | 92f7f3c | 2017-10-31 11:38:30 +0000 | [diff] [blame] | 170 |               graph->GetDexFile(), | 
| Vladimir Marko | 69d310e | 2017-10-09 14:12:23 +0100 | [diff] [blame] | 171 |               code_item, | 
| Andreas Gampe | 3db7068 | 2018-12-26 15:12:03 -0800 | [diff] [blame] | 172 |               /* class_def_index= */ DexFile::kDexNoIndex16, | 
 | 173 |               /* method_idx= */ dex::kDexNoIndex, | 
 | 174 |               /* access_flags= */ 0u, | 
 | 175 |               /* verified_method= */ nullptr, | 
| Vladimir Marko | 69d310e | 2017-10-09 14:12:23 +0100 | [diff] [blame] | 176 |               handles_->NewHandle<mirror::DexCache>(nullptr)); | 
| Mathieu Chartier | fa3db3d | 2018-01-12 14:42:18 -0800 | [diff] [blame] | 177 |       CodeItemDebugInfoAccessor accessor(graph->GetDexFile(), code_item, /*dex_method_idx*/ 0u); | 
| Mathieu Chartier | 808c7a5 | 2017-12-15 11:19:33 -0800 | [diff] [blame] | 178 |       HGraphBuilder builder(graph, dex_compilation_unit, accessor, handles_.get(), return_type); | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 179 |       bool graph_built = (builder.BuildGraph() == kAnalysisSuccess); | 
 | 180 |       return graph_built ? graph : nullptr; | 
 | 181 |     } | 
 | 182 |   } | 
 | 183 |  | 
 | 184 |  private: | 
| Mathieu Chartier | fa3db3d | 2018-01-12 14:42:18 -0800 | [diff] [blame] | 185 |   std::vector<std::unique_ptr<const StandardDexFile>> dex_files_; | 
| Vladimir Marko | ca6fff8 | 2017-10-03 14:49:14 +0100 | [diff] [blame] | 186 |   std::unique_ptr<ArenaPoolAndAllocator> pool_and_allocator_; | 
 | 187 |   std::unique_ptr<VariableSizedHandleScope> handles_; | 
 | 188 | }; | 
| Roland Levillain | ccc07a9 | 2014-09-16 14:48:16 +0100 | [diff] [blame] | 189 |  | 
| Mathieu Chartier | fa3db3d | 2018-01-12 14:42:18 -0800 | [diff] [blame] | 190 | class OptimizingUnitTest : public CommonCompilerTest, public OptimizingUnitTestHelper {}; | 
 | 191 |  | 
| Artem Serov | 15f95b1 | 2018-06-29 15:30:36 +0100 | [diff] [blame] | 192 | // OptimizingUnitTest with some handy functions to ease the graph creation. | 
 | 193 | class ImprovedOptimizingUnitTest : public OptimizingUnitTest { | 
 | 194 |  public: | 
 | 195 |   ImprovedOptimizingUnitTest() : graph_(CreateGraph()), | 
 | 196 |                                  entry_block_(nullptr), | 
 | 197 |                                  return_block_(nullptr), | 
 | 198 |                                  exit_block_(nullptr), | 
 | 199 |                                  parameter_(nullptr) {} | 
 | 200 |  | 
 | 201 |   virtual ~ImprovedOptimizingUnitTest() {} | 
 | 202 |  | 
 | 203 |   void InitGraph() { | 
 | 204 |     entry_block_ = new (GetAllocator()) HBasicBlock(graph_); | 
 | 205 |     graph_->AddBlock(entry_block_); | 
 | 206 |     graph_->SetEntryBlock(entry_block_); | 
 | 207 |  | 
 | 208 |     return_block_ = new (GetAllocator()) HBasicBlock(graph_); | 
 | 209 |     graph_->AddBlock(return_block_); | 
 | 210 |  | 
 | 211 |     exit_block_ = new (GetAllocator()) HBasicBlock(graph_); | 
 | 212 |     graph_->AddBlock(exit_block_); | 
 | 213 |     graph_->SetExitBlock(exit_block_); | 
 | 214 |  | 
 | 215 |     entry_block_->AddSuccessor(return_block_); | 
 | 216 |     return_block_->AddSuccessor(exit_block_); | 
 | 217 |  | 
 | 218 |     parameter_ = new (GetAllocator()) HParameterValue(graph_->GetDexFile(), | 
 | 219 |                                                       dex::TypeIndex(0), | 
 | 220 |                                                       0, | 
 | 221 |                                                       DataType::Type::kInt32); | 
 | 222 |     entry_block_->AddInstruction(parameter_); | 
 | 223 |     return_block_->AddInstruction(new (GetAllocator()) HReturnVoid()); | 
 | 224 |     exit_block_->AddInstruction(new (GetAllocator()) HExit()); | 
 | 225 |   } | 
 | 226 |  | 
 | 227 |   bool CheckGraph() { | 
 | 228 |     GraphChecker checker(graph_); | 
 | 229 |     checker.Run(); | 
 | 230 |     if (!checker.IsValid()) { | 
 | 231 |       for (const std::string& error : checker.GetErrors()) { | 
 | 232 |         std::cout << error << std::endl; | 
 | 233 |       } | 
 | 234 |       return false; | 
 | 235 |     } | 
 | 236 |     return true; | 
 | 237 |   } | 
 | 238 |  | 
 | 239 |   HEnvironment* ManuallyBuildEnvFor(HInstruction* instruction, | 
 | 240 |                                     ArenaVector<HInstruction*>* current_locals) { | 
 | 241 |     HEnvironment* environment = new (GetAllocator()) HEnvironment( | 
 | 242 |         (GetAllocator()), | 
 | 243 |         current_locals->size(), | 
 | 244 |         graph_->GetArtMethod(), | 
 | 245 |         instruction->GetDexPc(), | 
 | 246 |         instruction); | 
 | 247 |  | 
 | 248 |     environment->CopyFrom(ArrayRef<HInstruction* const>(*current_locals)); | 
 | 249 |     instruction->SetRawEnvironment(environment); | 
 | 250 |     return environment; | 
 | 251 |   } | 
 | 252 |  | 
 | 253 |  protected: | 
 | 254 |   HGraph* graph_; | 
 | 255 |  | 
 | 256 |   HBasicBlock* entry_block_; | 
 | 257 |   HBasicBlock* return_block_; | 
 | 258 |   HBasicBlock* exit_block_; | 
 | 259 |  | 
 | 260 |   HInstruction* parameter_; | 
 | 261 | }; | 
 | 262 |  | 
| Roland Levillain | 72bceff | 2014-09-15 18:29:00 +0100 | [diff] [blame] | 263 | // Naive string diff data type. | 
 | 264 | typedef std::list<std::pair<std::string, std::string>> diff_t; | 
 | 265 |  | 
 | 266 | // An alias for the empty string used to make it clear that a line is | 
 | 267 | // removed in a diff. | 
| Igor Murashkin | 2ffb703 | 2017-11-08 13:35:21 -0800 | [diff] [blame] | 268 | static const std::string removed = "";  // NOLINT [runtime/string] [4] | 
| Roland Levillain | 72bceff | 2014-09-15 18:29:00 +0100 | [diff] [blame] | 269 |  | 
 | 270 | // Naive patch command: apply a diff to a string. | 
 | 271 | inline std::string Patch(const std::string& original, const diff_t& diff) { | 
 | 272 |   std::string result = original; | 
 | 273 |   for (const auto& p : diff) { | 
 | 274 |     std::string::size_type pos = result.find(p.first); | 
| David Brazdil | 86ea7ee | 2016-02-16 09:26:07 +0000 | [diff] [blame] | 275 |     DCHECK_NE(pos, std::string::npos) | 
 | 276 |         << "Could not find: \"" << p.first << "\" in \"" << result << "\""; | 
| Roland Levillain | 72bceff | 2014-09-15 18:29:00 +0100 | [diff] [blame] | 277 |     result.replace(pos, p.first.size(), p.second); | 
 | 278 |   } | 
 | 279 |   return result; | 
 | 280 | } | 
 | 281 |  | 
| Mingyao Yang | f384f88 | 2014-10-22 16:08:18 -0700 | [diff] [blame] | 282 | // Returns if the instruction is removed from the graph. | 
 | 283 | inline bool IsRemoved(HInstruction* instruction) { | 
 | 284 |   return instruction->GetBlock() == nullptr; | 
 | 285 | } | 
 | 286 |  | 
| Nicolas Geoffray | a7062e0 | 2014-05-22 12:50:17 +0100 | [diff] [blame] | 287 | }  // namespace art | 
 | 288 |  | 
| Nicolas Geoffray | 3ff386a | 2014-03-04 14:46:47 +0000 | [diff] [blame] | 289 | #endif  // ART_COMPILER_OPTIMIZING_OPTIMIZING_UNIT_TEST_H_ |