| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "third_party/courgette/adjustment_method.h" | |
| 6 | |
| 7 #include <algorithm> | |
| 8 #include <list> | |
| 9 #include <map> | |
| 10 #include <set> | |
| 11 #include <string> | |
| 12 #include <vector> | |
| 13 | |
| 14 #include "base/basictypes.h" | |
| 15 #include "base/logging.h" | |
| 16 #include "base/string_util.h" | |
| 17 | |
| 18 #include "third_party/courgette/assembly_program.h" | |
| 19 #include "third_party/courgette/courgette.h" | |
| 20 #include "third_party/courgette/encoded_program.h" | |
| 21 #include "third_party/courgette/image_info.h" | |
| 22 | |
| 23 namespace courgette { | |
| 24 | |
| 25 // We have three discretionary information logging levels for algorithm | |
| 26 // development. For now just configure with #defines. | |
| 27 // TODO(sra): make dependent of some configurable setting. | |
| 28 #define NO_LOG DLOG_IF(INFO, false) | |
| 29 // #define ALOG1 LOG(INFO) | |
| 30 // #define ALOG2 LOG(INFO) | |
| 31 // #define ALOG3 LOG(INFO) | |
| 32 #define ALOG1 NO_LOG | |
| 33 #define ALOG2 NO_LOG | |
| 34 #define ALOG3 NO_LOG | |
| 35 | |
| 36 //////////////////////////////////////////////////////////////////////////////// | |
| 37 | |
| 38 class NullAdjustmentMethod : public AdjustmentMethod { | |
| 39 bool Adjust(const AssemblyProgram& model, AssemblyProgram* program) { | |
| 40 return true; | |
| 41 } | |
| 42 }; | |
| 43 | |
| 44 //////////////////////////////////////////////////////////////////////////////// | |
| 45 | |
| 46 // The purpose of adjustment is to assign indexes to Labels of a program 'p' to | |
| 47 // make the sequence of indexes similar to a 'model' program 'm'. Labels | |
| 48 // themselves don't have enough information to do this job, so we work with a | |
| 49 // LabelInfo surrogate for each label. | |
| 50 // | |
| 51 class LabelInfo { | |
| 52 public: | |
| 53 Label* label_; // The label that this info a surrogate for. | |
| 54 | |
| 55 // Information used only in debugging messages. | |
| 56 uint32 is_model_ : 1; // Is the label in the model? | |
| 57 uint32 debug_index_ : 31; // An unique small number for naming the label. | |
| 58 | |
| 59 uint32 refs_; // Number of times this Label is referenced. | |
| 60 | |
| 61 LabelInfo* assignment_; // Label from other program corresponding to this. | |
| 62 | |
| 63 // LabelInfos are in a doubly linked list ordered by address (label_->rva_) so | |
| 64 // we can quickly find Labels adjacent in address order. | |
| 65 LabelInfo* next_addr_; // Label(Info) at next highest address. | |
| 66 LabelInfo* prev_addr_; // Label(Info) at next lowest address. | |
| 67 | |
| 68 std::vector<uint32> positions_; // Offsets into the trace of references. | |
| 69 | |
| 70 // Just a no-argument constructor and copy constructor. Actual LabelInfo | |
| 71 // objects are allocated in std::pair structs in a std::map. | |
| 72 LabelInfo() | |
| 73 : label_(NULL), is_model_(false), debug_index_(0), refs_(0), | |
| 74 assignment_(NULL), | |
| 75 next_addr_(NULL), | |
| 76 prev_addr_(NULL) {} | |
| 77 | |
| 78 private: | |
| 79 void operator=(const LabelInfo*); // Disallow assignment only. | |
| 80 | |
| 81 // Public compiler generated copy constructor is needed to constuct | |
| 82 // std::pair<Label*, LabelInfo> so that fresh LabelInfos can be allocated | |
| 83 // inside a std::map. | |
| 84 }; | |
| 85 | |
| 86 struct OrderLabelInfoByAddressAscending { | |
| 87 bool operator()(const LabelInfo* a, const LabelInfo* b) const { | |
| 88 return a->label_->rva_ < b->label_->rva_; | |
| 89 } | |
| 90 }; | |
| 91 | |
| 92 static std::string ToString(LabelInfo* info) { | |
| 93 std::string s; | |
| 94 StringAppendF(&s, "%c%d", "pm"[info->is_model_], info->debug_index_); | |
| 95 if (info->label_->index_ != Label::kNoIndex) | |
| 96 StringAppendF(&s, " (%d)", info->label_->index_); | |
| 97 | |
| 98 StringAppendF(&s, " #%u", info->refs_); | |
| 99 return s; | |
| 100 } | |
| 101 | |
| 102 // General graph matching is exponential, essentially trying all permutations. | |
| 103 // The exponential algorithm can be made faster by avoiding consideration of | |
| 104 // impossible or unlikely matches. We can make the matching practical by eager | |
| 105 // matching - by looking for likely matches and commiting to them, and using the | |
| 106 // committed assignment as the basis for further matching. | |
| 107 // | |
| 108 // The basic eager graph-matching assignment is based on several ideas: | |
| 109 // | |
| 110 // * The strongest match will be for parts of the program that have not | |
| 111 // changed. If part of a program has not changed, then the number of | |
| 112 // references to a label will be the same, and corresponding pairs of | |
| 113 // adjacent labels will have the same RVA difference. | |
| 114 // | |
| 115 // * Some assignments are 'obvious' if you look at the distribution. Example: | |
| 116 // if both the program and the model have a label that is referred to much | |
| 117 // more often than the next most refered-to label, it is likely the two | |
| 118 // labels correspond. | |
| 119 // | |
| 120 // * If a label from the program corresponds to a label in the model, it is | |
| 121 // likely that the labels near the corresponding labels also match. A | |
| 122 // conservative way of extending the match is to assign only those labels | |
| 123 // which have exactly the same address offset and reference count. | |
| 124 // | |
| 125 // * If two labels correspond, then we can try to match up the references | |
| 126 // before and after the labels in the reference stream. For this to be | |
| 127 // practical, the number of references has to be small, e.g. each label has | |
| 128 // exactly one reference. | |
| 129 // | |
| 130 | |
| 131 // Note: we also tried a completely different approach: random assignment | |
| 132 // followed by simulated annealing. This produced similar results. The results | |
| 133 // were not as good for very small differences because the simulated annealing | |
| 134 // never quite hit the groove. And simulated annealing was several orders of | |
| 135 // magnitude slower. | |
| 136 | |
| 137 | |
| 138 // TRIE node for suffix strings in the label reference sequence. | |
| 139 // | |
| 140 // We dynamically build a trie for both the program and model, growing the trie | |
| 141 // as necessary. The trie node for a (possibly) empty string of label | |
| 142 // references contains the distribution of labels following the string. The | |
| 143 // roots node (for the empty string) thus contains the simple distribution of | |
| 144 // labels within the label reference stream. | |
| 145 | |
| 146 struct Node { | |
| 147 Node(LabelInfo* in_edge, Node* prev) | |
| 148 : in_edge_(in_edge), prev_(prev), count_(0), | |
| 149 in_queue_(false) { | |
| 150 length_ = 1 + (prev_ ? prev_->length_ : 0); | |
| 151 } | |
| 152 LabelInfo* in_edge_; // | |
| 153 Node* prev_; // Node at shorter length. | |
| 154 int count_; // Frequency of this path in Trie. | |
| 155 int length_; | |
| 156 typedef std::map<LabelInfo*, Node*> Edges; | |
| 157 Edges edges_; | |
| 158 std::vector<int> places_; // Indexes into sequence of this item. | |
| 159 std::list<Node*> edges_in_frequency_order; | |
| 160 | |
| 161 bool in_queue_; | |
| 162 bool Extended() const { return edges_.size() > 0; } | |
| 163 | |
| 164 uint32 Weight() const { | |
| 165 return edges_in_frequency_order.front()->count_; | |
| 166 } | |
| 167 }; | |
| 168 | |
| 169 static std::string ToString(Node* node) { | |
| 170 std::vector<std::string> prefix; | |
| 171 for (Node* n = node; n->prev_; n = n->prev_) | |
| 172 prefix.push_back(ToString(n->in_edge_)); | |
| 173 | |
| 174 std::string s; | |
| 175 s += "{"; | |
| 176 const char* sep = ""; | |
| 177 while (!prefix.empty()) { | |
| 178 s += sep; | |
| 179 sep = ","; | |
| 180 s += prefix.back(); | |
| 181 prefix.pop_back(); | |
| 182 } | |
| 183 | |
| 184 s += StringPrintf("%u", node->count_); | |
| 185 s += " @"; | |
| 186 s += Uint64ToString(node->edges_in_frequency_order.size()); | |
| 187 s += "}"; | |
| 188 return s; | |
| 189 } | |
| 190 | |
| 191 typedef std::vector<LabelInfo*> Trace; | |
| 192 | |
| 193 struct OrderNodeByCountDecreasing { | |
| 194 bool operator()(Node* a, Node* b) const { | |
| 195 if (a->count_ != b->count_) | |
| 196 return (a->count_) > (b->count_); | |
| 197 return a->places_.at(0) < b->places_.at(0); // Prefer first occuring. | |
| 198 } | |
| 199 }; | |
| 200 | |
| 201 struct OrderNodeByWeightDecreasing { | |
| 202 bool operator()(Node* a, Node* b) const { | |
| 203 // (Maybe tie-break on total count, followed by lowest assigned node indexes | |
| 204 // in path.) | |
| 205 uint32 a_weight = a->Weight(); | |
| 206 uint32 b_weight = b->Weight(); | |
| 207 if (a_weight != b_weight) | |
| 208 return a_weight > b_weight; | |
| 209 if (a->length_ != b->length_) | |
| 210 return a->length_ > b->length_; // Prefer longer. | |
| 211 return a->places_.at(0) < b->places_.at(0); // Prefer first occuring. | |
| 212 } | |
| 213 }; | |
| 214 | |
| 215 typedef std::set<Node*, OrderNodeByWeightDecreasing> NodeQueue; | |
| 216 | |
| 217 class AssignmentProblem { | |
| 218 public: | |
| 219 AssignmentProblem(const Trace& model, | |
| 220 const Trace& problem) | |
| 221 : m_trace_(model), | |
| 222 p_trace_(problem) { | |
| 223 } | |
| 224 | |
| 225 ~AssignmentProblem() { | |
| 226 for (size_t i = 0; i < all_nodes_.size(); ++i) | |
| 227 delete all_nodes_[i]; | |
| 228 } | |
| 229 | |
| 230 bool Solve() { | |
| 231 m_root_ = MakeRootNode(m_trace_); | |
| 232 p_root_ = MakeRootNode(p_trace_); | |
| 233 AddToQueue(p_root_); | |
| 234 | |
| 235 while (!worklist_.empty()) { | |
| 236 Node* node = *worklist_.begin(); | |
| 237 node->in_queue_ = false; | |
| 238 worklist_.erase(node); | |
| 239 TrySolveNode(node); | |
| 240 } | |
| 241 | |
| 242 ALOG1 << unsolved_.size() << " unsolved items"; | |
| 243 return true; | |
| 244 } | |
| 245 | |
| 246 private: | |
| 247 void AddToQueue(Node* node) { | |
| 248 if (node->length_ >= 10) { | |
| 249 ALOG3 << "Length clipped " << ToString(node->prev_); | |
| 250 return; | |
| 251 } | |
| 252 if (node->in_queue_) { | |
| 253 LOG(ERROR) << "Double add " << ToString(node); | |
| 254 return; | |
| 255 } | |
| 256 // just to be sure data for prioritizing is available | |
| 257 ExtendNode(node, p_trace_); | |
| 258 // SkipCommittedLabels(node); | |
| 259 if (node->edges_in_frequency_order.empty()) | |
| 260 return; | |
| 261 node->in_queue_ = true; | |
| 262 worklist_.insert(node); | |
| 263 } | |
| 264 | |
| 265 void SkipCommittedLabels(Node* node) { | |
| 266 ExtendNode(node, p_trace_); | |
| 267 uint32 skipped = 0; | |
| 268 while (!node->edges_in_frequency_order.empty() && | |
| 269 node->edges_in_frequency_order.front()->in_edge_->assignment_) { | |
| 270 ++skipped; | |
| 271 node->edges_in_frequency_order.pop_front(); | |
| 272 } | |
| 273 if (skipped > 0) | |
| 274 ALOG3 << "Skipped " << skipped << " at " << ToString(node); | |
| 275 } | |
| 276 | |
| 277 void TrySolveNode(Node* p_node) { | |
| 278 Node* front = p_node->edges_in_frequency_order.front(); | |
| 279 if (front->in_edge_->assignment_) { | |
| 280 p_node->edges_in_frequency_order.pop_front(); | |
| 281 AddToQueue(front); | |
| 282 AddToQueue(p_node); | |
| 283 return; | |
| 284 } | |
| 285 | |
| 286 // Compare frequencies of unassigned edges, and either make | |
| 287 // assignment(s) or move node to unsolved list | |
| 288 | |
| 289 Node* m_node = FindModelNode(p_node); | |
| 290 | |
| 291 if (m_node == NULL) { | |
| 292 ALOG1 << "Can't find model node"; | |
| 293 unsolved_.insert(p_node); | |
| 294 return; | |
| 295 } | |
| 296 ExtendNode(m_node, m_trace_); | |
| 297 | |
| 298 // Lets just try greedy | |
| 299 | |
| 300 SkipCommittedLabels(m_node); | |
| 301 if (m_node->edges_in_frequency_order.empty()) { | |
| 302 ALOG3 << "Punting, no elements left in model vs " | |
| 303 << p_node->edges_in_frequency_order.size(); | |
| 304 unsolved_.insert(p_node); | |
| 305 return; | |
| 306 } | |
| 307 Node* m_match = m_node->edges_in_frequency_order.front(); | |
| 308 Node* p_match = p_node->edges_in_frequency_order.front(); | |
| 309 | |
| 310 if (p_match->count_ > 1.1 * m_match->count_ || | |
| 311 m_match->count_ > 1.1 * p_match->count_) { | |
| 312 ALOG2 << "Tricky distribution " | |
| 313 << p_match->count_ << ":" << m_match->count_ << " " | |
| 314 << ToString(p_match) << " vs " << ToString(m_match); | |
| 315 return; | |
| 316 } | |
| 317 | |
| 318 m_node->edges_in_frequency_order.pop_front(); | |
| 319 p_node->edges_in_frequency_order.pop_front(); | |
| 320 | |
| 321 LabelInfo* p_label_info = p_match->in_edge_; | |
| 322 LabelInfo* m_label_info = m_match->in_edge_; | |
| 323 int m_index = p_label_info->label_->index_; | |
| 324 if (m_index != Label::kNoIndex) { | |
| 325 ALOG1 << "Cant use unassigned label from model " << m_index; | |
| 326 unsolved_.insert(p_node); | |
| 327 return; | |
| 328 } | |
| 329 | |
| 330 Assign(p_label_info, m_label_info); | |
| 331 | |
| 332 AddToQueue(p_match); // find matches within new match | |
| 333 AddToQueue(p_node); // and more matches within this node | |
| 334 } | |
| 335 | |
| 336 void Assign(LabelInfo* p_info, LabelInfo* m_info) { | |
| 337 AssignOne(p_info, m_info); | |
| 338 ALOG3 << "Assign " << ToString(p_info) << " := " << ToString(m_info); | |
| 339 // Now consider unassigned adjacent addresses | |
| 340 TryExtendAssignment(p_info, m_info); | |
| 341 } | |
| 342 | |
| 343 void AssignOne(LabelInfo* p_info, LabelInfo* m_info) { | |
| 344 p_info->label_->index_ = m_info->label_->index_; | |
| 345 | |
| 346 // Mark as assigned | |
| 347 m_info->assignment_ = p_info; | |
| 348 p_info->assignment_ = m_info; | |
| 349 } | |
| 350 | |
| 351 void TryExtendAssignment(LabelInfo* p_info, LabelInfo* m_info) { | |
| 352 RVA m_rva_base = m_info->label_->rva_; | |
| 353 RVA p_rva_base = p_info->label_->rva_; | |
| 354 | |
| 355 LabelInfo* m_info_next = m_info->next_addr_; | |
| 356 LabelInfo* p_info_next = p_info->next_addr_; | |
| 357 for ( ; m_info_next && p_info_next; ) { | |
| 358 if (m_info_next->assignment_) | |
| 359 break; | |
| 360 | |
| 361 RVA m_rva = m_info_next->label_->rva_; | |
| 362 RVA p_rva = p_info_next->label_->rva_; | |
| 363 | |
| 364 if (m_rva - m_rva_base != p_rva - p_rva_base) { | |
| 365 // previous label was pointing to something that is different size | |
| 366 break; | |
| 367 } | |
| 368 LabelInfo* m_info_next_next = m_info_next->next_addr_; | |
| 369 LabelInfo* p_info_next_next = p_info_next->next_addr_; | |
| 370 if (m_info_next_next && p_info_next_next) { | |
| 371 RVA m_rva_next = m_info_next_next->label_->rva_; | |
| 372 RVA p_rva_next = p_info_next_next->label_->rva_; | |
| 373 if (m_rva_next - m_rva != p_rva_next - p_rva) { | |
| 374 // Since following labels are no longer in address lockstep, assume | |
| 375 // this address has a difference. | |
| 376 break; | |
| 377 } | |
| 378 } | |
| 379 | |
| 380 // The label has inconsistent numbers of references, it is probably not | |
| 381 // the same thing. | |
| 382 if (m_info_next->refs_ != p_info_next->refs_) { | |
| 383 break; | |
| 384 } | |
| 385 | |
| 386 ALOG3 << " Extending assignment -> " | |
| 387 << ToString(p_info_next) << " := " << ToString(m_info_next); | |
| 388 | |
| 389 AssignOne(p_info_next, m_info_next); | |
| 390 | |
| 391 if (p_info_next->refs_ == m_info_next->refs_ && | |
| 392 p_info_next->refs_ == 1) { | |
| 393 TryExtendSequence(p_info_next->positions_[0], | |
| 394 m_info_next->positions_[0]); | |
| 395 TryExtendSequenceBackwards(p_info_next->positions_[0], | |
| 396 m_info_next->positions_[0]); | |
| 397 } | |
| 398 | |
| 399 p_info_next = p_info_next_next; | |
| 400 m_info_next = m_info_next_next; | |
| 401 } | |
| 402 | |
| 403 LabelInfo* m_info_prev = m_info->prev_addr_; | |
| 404 LabelInfo* p_info_prev = p_info->prev_addr_; | |
| 405 for ( ; m_info_prev && p_info_prev; ) { | |
| 406 if (m_info_prev->assignment_) | |
| 407 break; | |
| 408 | |
| 409 RVA m_rva = m_info_prev->label_->rva_; | |
| 410 RVA p_rva = p_info_prev->label_->rva_; | |
| 411 | |
| 412 if (m_rva - m_rva_base != p_rva - p_rva_base) { | |
| 413 // previous label was pointing to something that is different size | |
| 414 break; | |
| 415 } | |
| 416 LabelInfo* m_info_prev_prev = m_info_prev->prev_addr_; | |
| 417 LabelInfo* p_info_prev_prev = p_info_prev->prev_addr_; | |
| 418 | |
| 419 // The the label has inconsistent numbers of references, it is | |
| 420 // probably not the same thing | |
| 421 if (m_info_prev->refs_ != p_info_prev->refs_) { | |
| 422 break; | |
| 423 } | |
| 424 | |
| 425 AssignOne(p_info_prev, m_info_prev); | |
| 426 ALOG3 << " Extending assignment <- " << ToString(p_info_prev) << " := " | |
| 427 << ToString(m_info_prev); | |
| 428 | |
| 429 p_info_prev = p_info_prev_prev; | |
| 430 m_info_prev = m_info_prev_prev; | |
| 431 } | |
| 432 } | |
| 433 | |
| 434 uint32 TryExtendSequence(uint32 p_pos_start, uint32 m_pos_start) { | |
| 435 uint32 p_pos = p_pos_start + 1; | |
| 436 uint32 m_pos = m_pos_start + 1; | |
| 437 | |
| 438 while (p_pos < p_trace_.size() && m_pos < m_trace_.size()) { | |
| 439 LabelInfo* p_info = p_trace_[p_pos]; | |
| 440 LabelInfo* m_info = m_trace_[m_pos]; | |
| 441 | |
| 442 // To match, either (1) both are assigned or (2) both are unassigned. | |
| 443 if ((p_info->assignment_ == NULL) != (m_info->assignment_ == NULL)) | |
| 444 break; | |
| 445 | |
| 446 // If they are assigned, it needs to be consistent (same index). | |
| 447 if (p_info->assignment_ && m_info->assignment_) { | |
| 448 if (p_info->label_->index_ != m_info->label_->index_) | |
| 449 break; | |
| 450 ++p_pos; | |
| 451 ++m_pos; | |
| 452 continue; | |
| 453 } | |
| 454 | |
| 455 if (p_info->refs_ != m_info->refs_) | |
| 456 break; | |
| 457 | |
| 458 AssignOne(p_info, m_info); | |
| 459 ALOG3 << " Extending assignment seq" | |
| 460 << "[+" << p_pos - p_pos_start << "]" | |
| 461 << " -> " | |
| 462 << ToString(p_info) << " := " << ToString(m_info); | |
| 463 | |
| 464 ++p_pos; | |
| 465 ++m_pos; | |
| 466 } | |
| 467 | |
| 468 return p_pos - p_pos_start; | |
| 469 } | |
| 470 | |
| 471 uint32 TryExtendSequenceBackwards(uint32 p_pos_start, uint32 m_pos_start) { | |
| 472 if (p_pos_start == 0 || m_pos_start == 0) | |
| 473 return 0; | |
| 474 | |
| 475 uint32 p_pos = p_pos_start - 1; | |
| 476 uint32 m_pos = m_pos_start - 1; | |
| 477 | |
| 478 while (p_pos > 0 && m_pos > 0) { | |
| 479 LabelInfo* p_info = p_trace_[p_pos]; | |
| 480 LabelInfo* m_info = m_trace_[m_pos]; | |
| 481 | |
| 482 if ((p_info->assignment_ == NULL) != (m_info->assignment_ == NULL)) | |
| 483 break; | |
| 484 | |
| 485 if (p_info->assignment_ && m_info->assignment_) { | |
| 486 if (p_info->label_->index_ != m_info->label_->index_) | |
| 487 break; | |
| 488 --p_pos; | |
| 489 --m_pos; | |
| 490 continue; | |
| 491 } | |
| 492 | |
| 493 if (p_info->refs_ != m_info->refs_) | |
| 494 break; | |
| 495 | |
| 496 AssignOne(p_info, m_info); | |
| 497 ALOG3 << " Extending assignment seq" | |
| 498 << "[-" << p_pos_start - p_pos << "]" | |
| 499 << " <- " | |
| 500 << ToString(p_info) << " := " << ToString(m_info); | |
| 501 | |
| 502 --p_pos; | |
| 503 --m_pos; | |
| 504 } | |
| 505 | |
| 506 return p_pos - p_pos_start; | |
| 507 } | |
| 508 | |
| 509 Node* FindModelNode(Node* node) { | |
| 510 if (node->prev_ == NULL) | |
| 511 return m_root_; | |
| 512 | |
| 513 Node* m_parent = FindModelNode(node->prev_); | |
| 514 if (m_parent == NULL) { | |
| 515 return NULL; | |
| 516 } | |
| 517 | |
| 518 ExtendNode(m_parent, m_trace_); | |
| 519 | |
| 520 LabelInfo* p_label = node->in_edge_; | |
| 521 LabelInfo* m_label = p_label->assignment_; | |
| 522 if (m_label == NULL) { | |
| 523 ALOG1 << "Expected assigned prefix"; | |
| 524 return NULL; | |
| 525 } | |
| 526 | |
| 527 Node::Edges::iterator e = m_parent->edges_.find(m_label); | |
| 528 if (e == m_parent->edges_.end()) { | |
| 529 ALOG2 << "Expected defined edge in parent"; | |
| 530 return NULL; | |
| 531 } | |
| 532 | |
| 533 return e->second; | |
| 534 } | |
| 535 | |
| 536 Node* MakeRootNode(const Trace& trace) { | |
| 537 Node* node = new Node(NULL, NULL); | |
| 538 all_nodes_.push_back(node); | |
| 539 for (size_t i = 0; i < trace.size(); ++i) { | |
| 540 ++node->count_; | |
| 541 node->places_.push_back(i); | |
| 542 } | |
| 543 return node; | |
| 544 } | |
| 545 | |
| 546 void ExtendNode(Node* node, const Trace& trace) { | |
| 547 // Make sure trie is filled in at this node. | |
| 548 if (node->Extended()) | |
| 549 return; | |
| 550 for (size_t i = 0; i < node->places_.size(); ++i) { | |
| 551 uint32 index = node->places_.at(i); | |
| 552 if (index < trace.size()) { | |
| 553 LabelInfo* item = trace.at(index); | |
| 554 Node*& slot = node->edges_[item]; | |
| 555 if (slot == NULL) { | |
| 556 slot = new Node(item, node); | |
| 557 all_nodes_.push_back(slot); | |
| 558 node->edges_in_frequency_order.push_back(slot); | |
| 559 } | |
| 560 slot->places_.push_back(index + 1); | |
| 561 ++slot->count_; | |
| 562 } | |
| 563 } | |
| 564 node->edges_in_frequency_order.sort(OrderNodeByCountDecreasing()); | |
| 565 } | |
| 566 | |
| 567 const Trace& m_trace_; | |
| 568 const Trace& p_trace_; | |
| 569 Node* m_root_; | |
| 570 Node* p_root_; | |
| 571 | |
| 572 NodeQueue worklist_; | |
| 573 NodeQueue unsolved_; | |
| 574 | |
| 575 std::vector<Node*> all_nodes_; | |
| 576 | |
| 577 DISALLOW_COPY_AND_ASSIGN(AssignmentProblem); | |
| 578 }; | |
| 579 | |
| 580 class GraphAdjuster : public AdjustmentMethod { | |
| 581 public: | |
| 582 GraphAdjuster() {} | |
| 583 ~GraphAdjuster() {} | |
| 584 | |
| 585 bool Adjust(const AssemblyProgram& model, AssemblyProgram* program) { | |
| 586 LOG(INFO) << "GraphAdjuster::Adjust"; | |
| 587 prog_ = program; | |
| 588 model_ = &model; | |
| 589 debug_label_index_gen_ = 0; | |
| 590 return Finish(); | |
| 591 } | |
| 592 | |
| 593 bool Finish() { | |
| 594 prog_->UnassignIndexes(); | |
| 595 CollectTraces(model_, &model_abs32_, &model_rel32_, true); | |
| 596 CollectTraces(prog_, &prog_abs32_, &prog_rel32_, false); | |
| 597 Solve(model_abs32_, prog_abs32_); | |
| 598 Solve(model_rel32_, prog_rel32_); | |
| 599 prog_->AssignRemainingIndexes(); | |
| 600 return true; | |
| 601 } | |
| 602 | |
| 603 private: | |
| 604 | |
| 605 void CollectTraces(const AssemblyProgram* program, Trace* abs32, Trace* rel32, | |
| 606 bool is_model) { | |
| 607 const std::vector<Instruction*>& instructions = program->instructions(); | |
| 608 for (size_t i = 0; i < instructions.size(); ++i) { | |
| 609 Instruction* instruction = instructions.at(i); | |
| 610 if (Label* label = program->InstructionAbs32Label(instruction)) | |
| 611 ReferenceLabel(abs32, label, is_model); | |
| 612 if (Label* label = program->InstructionRel32Label(instruction)) | |
| 613 ReferenceLabel(rel32, label, is_model); | |
| 614 } | |
| 615 // TODO(sra): we could simply append all the labels in index order to | |
| 616 // incorporate some costing for entropy (bigger deltas) that will be | |
| 617 // introduced into the label address table by non-monotonic ordering. This | |
| 618 // would have some knock-on effects to parts of the algorithm that work on | |
| 619 // single-occurence labels. | |
| 620 } | |
| 621 | |
| 622 void Solve(const Trace& model, const Trace& problem) { | |
| 623 LinkLabelInfos(model); | |
| 624 LinkLabelInfos(problem); | |
| 625 AssignmentProblem a(model, problem); | |
| 626 a.Solve(); | |
| 627 } | |
| 628 | |
| 629 void LinkLabelInfos(const Trace& trace) { | |
| 630 typedef std::set<LabelInfo*, OrderLabelInfoByAddressAscending> Ordered; | |
| 631 Ordered ordered; | |
| 632 for (Trace::const_iterator p = trace.begin(); p != trace.end(); ++p) | |
| 633 ordered.insert(*p); | |
| 634 LabelInfo* prev = NULL; | |
| 635 for (Ordered::iterator p = ordered.begin(); p != ordered.end(); ++p) { | |
| 636 LabelInfo* curr = *p; | |
| 637 if (prev) prev->next_addr_ = curr; | |
| 638 curr->prev_addr_ = prev; | |
| 639 prev = curr; | |
| 640 | |
| 641 if (curr->positions_.size() != curr->refs_) | |
| 642 NOTREACHED(); | |
| 643 } | |
| 644 } | |
| 645 | |
| 646 void ReferenceLabel(Trace* trace, Label* label, bool is_model) { | |
| 647 trace->push_back(MakeLabelInfo(label, is_model, trace->size())); | |
| 648 } | |
| 649 | |
| 650 LabelInfo* MakeLabelInfo(Label* label, bool is_model, uint32 position) { | |
| 651 LabelInfo& slot = label_infos_[label]; | |
| 652 if (slot.label_ == NULL) { | |
| 653 slot.label_ = label; | |
| 654 slot.is_model_ = is_model; | |
| 655 slot.debug_index_ = ++debug_label_index_gen_; | |
| 656 } | |
| 657 slot.positions_.push_back(position); | |
| 658 ++slot.refs_; | |
| 659 return &slot; | |
| 660 } | |
| 661 | |
| 662 AssemblyProgram* prog_; // Program to be adjusted, owned by caller. | |
| 663 const AssemblyProgram* model_; // Program to be mimicked, owned by caller. | |
| 664 | |
| 665 Trace model_abs32_; | |
| 666 Trace model_rel32_; | |
| 667 Trace prog_abs32_; | |
| 668 Trace prog_rel32_; | |
| 669 | |
| 670 int debug_label_index_gen_; | |
| 671 | |
| 672 // Note LabelInfo is allocated inside map, so the LabelInfo lifetimes are | |
| 673 // managed by the map. | |
| 674 std::map<Label*, LabelInfo> label_infos_; | |
| 675 | |
| 676 private: | |
| 677 DISALLOW_COPY_AND_ASSIGN(GraphAdjuster); | |
| 678 }; | |
| 679 | |
| 680 | |
| 681 //////////////////////////////////////////////////////////////////////////////// | |
| 682 | |
| 683 void AdjustmentMethod::Destroy() { delete this; } | |
| 684 | |
| 685 AdjustmentMethod* AdjustmentMethod::MakeNullAdjustmentMethod() { | |
| 686 return new NullAdjustmentMethod(); | |
| 687 } | |
| 688 | |
| 689 AdjustmentMethod* AdjustmentMethod::MakeProductionAdjustmentMethod() { | |
| 690 return new GraphAdjuster(); | |
| 691 } | |
| 692 | |
| 693 Status Adjust(const AssemblyProgram& model, AssemblyProgram* program) { | |
| 694 AdjustmentMethod* method = AdjustmentMethod::MakeProductionAdjustmentMethod(); | |
| 695 bool ok = method->Adjust(model, program); | |
| 696 method->Destroy(); | |
| 697 if (ok) | |
| 698 return C_OK; | |
| 699 else | |
| 700 return C_ADJUSTMENT_FAILED; | |
| 701 } | |
| 702 | |
| 703 } // namespace courgette | |
| OLD | NEW |