1 // Copyright (c) 2011 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 "courgette/adjustment_method.h" 6 7 #include <algorithm> 8 #include <limits> 9 #include <list> 10 #include <map> 11 #include <set> 12 #include <string> 13 #include <vector> 14 15 #include "base/basictypes.h" 16 #include "base/format_macros.h" 17 #include "base/logging.h" 18 #include "base/strings/stringprintf.h" 19 #include "base/time/time.h" 20 #include "courgette/assembly_program.h" 21 #include "courgette/courgette.h" 22 #include "courgette/encoded_program.h" 23 24 /* 25 26 Shingle weighting matching. 27 28 We have a sequence S1 of symbols from alphabet A1={A,B,C,...} called the 'model' 29 and a second sequence of S2 of symbols from alphabet A2={U,V,W,....} called the 30 'program'. Each symbol in A1 has a unique numerical name or index. We can 31 transcribe the sequence S1 to a sequence T1 of indexes of the symbols. We wish 32 to assign indexes to the symbols in A2 so that when we transcribe S2 into T2, T2 33 has long subsequences that occur in T1. This will ensure that the sequence 34 T1;T2 compresses to be only slightly larger than the compressed T1. 35 36 The algorithm for matching members of S2 with members of S1 is eager - it makes 37 matches without backtracking, until no more matches can be made. Each variable 38 (symbol) U,V,... in A2 has a set of candidates from A1, each candidate with a 39 weight summarizing the evidence for the match. We keep a VariableQueue of 40 U,V,... sorted by how much the evidence for the best choice outweighs the 41 evidence for the second choice, i.e. prioritized by how 'clear cut' the best 42 assignment is. We pick the variable with the most clear-cut candidate, make the 43 assignment, adjust the evidence and repeat. 44 45 What has not been described so far is how the evidence is gathered and 46 maintained. We are working under the assumption that S1 and S2 are largely 47 similar. (A different assumption might be that S1 and S2 are dissimilar except 48 for many long subsequences.) 49 50 A naive algorithm would consider all pairs (A,U) and for each pair assess the 51 benefit, or score, the assignment U:=A. The score might count the number of 52 occurrences of U in S2 which appear in similar contexts to A in S1. 53 54 To distinguish contexts we view S1 and S2 as a sequence of overlapping k-length 55 substrings or 'shingles'. Two shingles are compatible if the symbols in one 56 shingle could be matched with the symbols in the other symbol. For example, ABC 57 is *not* compatible with UVU because it would require conflicting matches A=U 58 and C=U. ABC is compatible with UVW, UWV, WUV, VUW etc. We can't tell which 59 until we make an assignment - the compatible shingles form an equivalence class. 60 After assigning U:=A then only UVW and UWV (equivalently AVW, AWV) are 61 compatible. As we make assignments the number of equivalence classes of 62 shingles increases and the number of members of each equivalence class 63 decreases. The compatibility test becomes more restrictive. 64 65 We gather evidence for the potential assignment U:=A by counting how many 66 shingles containing U are compatible with shingles containing A. Thus symbols 67 occurring a large number of times in compatible contexts will be assigned first. 68 69 Finding the 'most clear-cut' assignment by considering all pairs symbols and for 70 each pair comparing the contexts of each pair of occurrences of the symbols is 71 computationally infeasible. We get the job done in a reasonable time by 72 approaching it 'backwards' and making incremental changes as we make 73 assignments. 74 75 First the shingles are partitioned according to compatibility. In S1=ABCDD and 76 S2=UVWXX we have a total of 6 shingles, each occuring once. (ABC:1 BCD:1 CDD:1; 77 UVW:1 VWX: WXX:1) all fit the pattern <V0 V1 V2> or the pattern <V0 V1 V1>. The 78 first pattern indicates that each position matches a different symbol, the 79 second pattern indicates that the second symbol is repeated. 80 81 pattern S1 members S2 members 82 <V0 V1 V2>: {ABC:1, BCD:1}; {UVW:1, VWX:1} 83 <V0 V1 V1>: {CDD:1} {WXX:1} 84 85 The second pattern appears to have a unique assignment but we don't make the 86 assignment on such scant evidence. If S1 and S2 do not match exactly, there 87 will be numerous spurious low-score matches like this. Instead we must see what 88 assignments are indicated by considering all of the evidence. 89 90 First pattern has 2 x 2 = 4 shingle pairs. For each pair we count the number 91 of symbol assignments. For ABC:a * UVW:b accumulate min(a,b) to each of 92 {U:=A, V:=B, W:=C}. 93 After accumulating over all 2 x 2 pairs: 94 U: {A:1 B:1} 95 V: {A:1 B:2 C:1} 96 W: {B:1 C:2 D:1 } 97 X: {C:1 D:1} 98 The second pattern contributes: 99 W: {C:1} 100 X: {D:2} 101 Sum: 102 U: {A:1 B:1} 103 V: {A:1 B:2 C:1} 104 W: {B:1 C:3 D:1} 105 X: {C:1 D:3} 106 107 From this we decide to assign X:=D (because this assignment has both the largest 108 difference above the next candidate (X:=C) and this is also the largest 109 proportionately over the sum of alternatives). 110 111 Lets assume D has numerical 'name' 77. The assignment X:=D sets X to 77 too. 112 Next we repartition all the shingles containing X or D: 113 114 pattern S1 members S2 members 115 <V0 V1 V2>: {ABC:1}; {UVW:1} 116 <V0 V1 77>: {BCD:1}; {VWX:1} 117 <V0 77 77>: {CDD:1} {WXX:1} 118 As we repartition, we recalculate the contributions to the scores: 119 U: {A:1} 120 V: {B:2} 121 W: {C:3} 122 All the remaining assignments are now fixed. 123 124 There is one step in the incremental algorithm that is still infeasibly 125 expensive: the contributions due to the cross product of large equivalence 126 classes. We settle for making an approximation by computing the contribution of 127 the cross product of only the most common shingles. The hope is that the noise 128 from the long tail of uncounted shingles is well below the scores being used to 129 pick assignments. The second hope is that as assignment are made, the large 130 equivalence class will be partitioned into smaller equivalence classes, reducing 131 the noise over time. 132 133 In the code below the shingles are bigger (Shingle::kWidth = 5). 134 Class ShinglePattern holds the data for one pattern. 135 136 There is an optimization for this case: 137 <V0 V1 V1>: {CDD:1} {WXX:1} 138 139 Above we said that we don't make an assignment on this "scant evidence". There 140 is an exception: if there is only one variable unassigned (more like the <V0 77 141 77> pattern) AND there are no occurrences of C and W other than those counted in 142 this pattern, then there is no competing evidence and we go ahead with the 143 assignment immediately. This produces slightly better results because these 144 cases tend to be low-scoring and susceptible to small mistakes made in 145 low-scoring assignments in the approximation for large equivalence classes. 146 147 */ 148 149 namespace courgette { 150 namespace adjustment_method_2 { 151 152 //////////////////////////////////////////////////////////////////////////////// 153 154 class AssignmentCandidates; 155 class LabelInfoMaker; 156 class Shingle; 157 class ShinglePattern; 158 159 // The purpose of adjustment is to assign indexes to Labels of a program 'p' to 160 // make the sequence of indexes similar to a 'model' program 'm'. Labels 161 // themselves don't have enough information to do this job, so we work with a 162 // LabelInfo surrogate for each label. 163 // 164 class LabelInfo { 165 public: 166 // Just a no-argument constructor and copy constructor. Actual LabelInfo 167 // objects are allocated in std::pair structs in a std::map. 168 LabelInfo() 169 : label_(NULL), is_model_(false), debug_index_(0), refs_(0), 170 assignment_(NULL), candidates_(NULL) 171 {} 172 173 ~LabelInfo(); 174 175 AssignmentCandidates* candidates(); 176 177 Label* label_; // The label that this info a surrogate for. 178 179 uint32 is_model_ : 1; // Is the label in the model? 180 uint32 debug_index_ : 31; // A small number for naming the label in debug 181 // output. The pair (is_model_, debug_index_) is 182 // unique. 183 184 int refs_; // Number of times this Label is referenced. 185 186 LabelInfo* assignment_; // Label from other program corresponding to this. 187 188 std::vector<uint32> positions_; // Offsets into the trace of references. 189 190 private: 191 AssignmentCandidates* candidates_; 192 193 void operator=(const LabelInfo*); // Disallow assignment only. 194 // Public compiler generated copy constructor is needed to constuct 195 // std::pair<Label*, LabelInfo> so that fresh LabelInfos can be allocated 196 // inside a std::map. 197 }; 198 199 typedef std::vector<LabelInfo*> Trace; 200 201 std::string ToString(const LabelInfo* info) { 202 std::string s; 203 base::StringAppendF(&s, "%c%d", "pm"[info->is_model_], info->debug_index_); 204 if (info->label_->index_ != Label::kNoIndex) 205 base::StringAppendF(&s, " (%d)", info->label_->index_); 206 207 base::StringAppendF(&s, " #%u", info->refs_); 208 return s; 209 } 210 211 // LabelInfoMaker maps labels to their surrogate LabelInfo objects. 212 class LabelInfoMaker { 213 public: 214 LabelInfoMaker() : debug_label_index_gen_(0) {} 215 216 LabelInfo* MakeLabelInfo(Label* label, bool is_model, uint32 position) { 217 LabelInfo& slot = label_infos_[label]; 218 if (slot.label_ == NULL) { 219 slot.label_ = label; 220 slot.is_model_ = is_model; 221 slot.debug_index_ = ++debug_label_index_gen_; 222 } 223 slot.positions_.push_back(position); 224 ++slot.refs_; 225 return &slot; 226 } 227 228 void ResetDebugLabel() { debug_label_index_gen_ = 0; } 229 230 private: 231 int debug_label_index_gen_; 232 233 // Note LabelInfo is allocated 'flat' inside map::value_type, so the LabelInfo 234 // lifetimes are managed by the map. 235 std::map<Label*, LabelInfo> label_infos_; 236 237 DISALLOW_COPY_AND_ASSIGN(LabelInfoMaker); 238 }; 239 240 struct OrderLabelInfo { 241 bool operator()(const LabelInfo* a, const LabelInfo* b) const { 242 if (a->label_->rva_ < b->label_->rva_) return true; 243 if (a->label_->rva_ > b->label_->rva_) return false; 244 if (a == b) return false; 245 return a->positions_ < b->positions_; // Lexicographic ordering of vector. 246 } 247 }; 248 249 // AssignmentCandidates is a priority queue of candidate assignments to 250 // a single program LabelInfo, |program_info_|. 251 class AssignmentCandidates { 252 public: 253 explicit AssignmentCandidates(LabelInfo* program_info) 254 : program_info_(program_info) {} 255 256 LabelInfo* program_info() const { return program_info_; } 257 258 bool empty() const { return label_to_score_.empty(); } 259 260 LabelInfo* top_candidate() const { return queue_.begin()->second; } 261 262 void Update(LabelInfo* model_info, int delta_score) { 263 LOG_ASSERT(delta_score != 0); 264 int old_score = 0; 265 int new_score = 0; 266 LabelToScore::iterator p = label_to_score_.find(model_info); 267 if (p != label_to_score_.end()) { 268 old_score = p->second; 269 new_score = old_score + delta_score; 270 queue_.erase(ScoreAndLabel(old_score, p->first)); 271 if (new_score == 0) { 272 label_to_score_.erase(p); 273 } else { 274 p->second = new_score; 275 queue_.insert(ScoreAndLabel(new_score, model_info)); 276 } 277 } else { 278 new_score = delta_score; 279 label_to_score_.insert(std::make_pair(model_info, new_score)); 280 queue_.insert(ScoreAndLabel(new_score, model_info)); 281 } 282 LOG_ASSERT(queue_.size() == label_to_score_.size()); 283 } 284 285 int TopScore() const { 286 int first_value = 0; 287 int second_value = 0; 288 Queue::const_iterator p = queue_.begin(); 289 if (p != queue_.end()) { 290 first_value = p->first; 291 ++p; 292 if (p != queue_.end()) { 293 second_value = p->first; 294 } 295 } 296 return first_value - second_value; 297 } 298 299 bool HasPendingUpdates() { return !pending_updates_.empty(); } 300 301 void AddPendingUpdate(LabelInfo* model_info, int delta_score) { 302 LOG_ASSERT(delta_score != 0); 303 pending_updates_[model_info] += delta_score; 304 } 305 306 void ApplyPendingUpdates() { 307 // TODO(sra): try to walk |pending_updates_| and |label_to_score_| in 308 // lockstep. Try to batch updates to |queue_|. 309 size_t zeroes = 0; 310 for (LabelToScore::iterator p = pending_updates_.begin(); 311 p != pending_updates_.end(); 312 ++p) { 313 if (p->second != 0) 314 Update(p->first, p->second); 315 else 316 ++zeroes; 317 } 318 pending_updates_.clear(); 319 } 320 321 void Print(int max) { 322 VLOG(2) << "score " << TopScore() << " " << ToString(program_info_) 323 << " := ?"; 324 if (!pending_updates_.empty()) 325 VLOG(2) << pending_updates_.size() << " pending"; 326 int count = 0; 327 for (Queue::iterator q = queue_.begin(); q != queue_.end(); ++q) { 328 if (++count > max) break; 329 VLOG(2) << " " << q->first << " " << ToString(q->second); 330 } 331 } 332 333 private: 334 typedef std::map<LabelInfo*, int, OrderLabelInfo> LabelToScore; 335 typedef std::pair<int, LabelInfo*> ScoreAndLabel; 336 struct OrderScoreAndLabelByScoreDecreasing { 337 OrderLabelInfo tie_breaker; 338 bool operator()(const ScoreAndLabel& a, const ScoreAndLabel& b) const { 339 if (a.first > b.first) return true; 340 if (a.first < b.first) return false; 341 return tie_breaker(a.second, b.second); 342 } 343 }; 344 typedef std::set<ScoreAndLabel, OrderScoreAndLabelByScoreDecreasing> Queue; 345 346 LabelInfo* program_info_; 347 LabelToScore label_to_score_; 348 LabelToScore pending_updates_; 349 Queue queue_; 350 }; 351 352 AssignmentCandidates* LabelInfo::candidates() { 353 if (candidates_ == NULL) 354 candidates_ = new AssignmentCandidates(this); 355 return candidates_; 356 } 357 358 LabelInfo::~LabelInfo() { 359 delete candidates_; 360 } 361 362 // A Shingle is a short fixed-length string of LabelInfos that actually occurs 363 // in a Trace. A Shingle may occur many times. We repesent the Shingle by the 364 // position of one of the occurrences in the Trace. 365 class Shingle { 366 public: 367 static const size_t kWidth = 5; 368 369 struct InterningLess { 370 bool operator()(const Shingle& a, const Shingle& b) const; 371 }; 372 373 typedef std::set<Shingle, InterningLess> OwningSet; 374 375 static Shingle* Find(const Trace& trace, size_t position, 376 OwningSet* owning_set) { 377 std::pair<OwningSet::iterator, bool> pair = 378 owning_set->insert(Shingle(trace, position)); 379 // pair.first iterator 'points' to the newly inserted Shingle or the 380 // previouly inserted one that looks the same according to the comparator. 381 382 // const_cast required because key is const. We modify the Shingle 383 // extensively but not in a way that affects InterningLess. 384 Shingle* shingle = const_cast<Shingle*>(&*pair.first); 385 shingle->add_position(position); 386 return shingle; 387 } 388 389 LabelInfo* at(size_t i) const { return trace_[exemplar_position_ + i]; } 390 void add_position(size_t position) { 391 positions_.push_back(static_cast<uint32>(position)); 392 } 393 int position_count() const { return static_cast<int>(positions_.size()); } 394 395 bool InModel() const { return at(0)->is_model_; } 396 397 ShinglePattern* pattern() const { return pattern_; } 398 void set_pattern(ShinglePattern* pattern) { pattern_ = pattern; } 399 400 struct PointerLess { 401 bool operator()(const Shingle* a, const Shingle* b) const { 402 // Arbitrary but repeatable (memory-address) independent ordering: 403 return a->exemplar_position_ < b->exemplar_position_; 404 // return InterningLess()(*a, *b); 405 } 406 }; 407 408 private: 409 Shingle(const Trace& trace, size_t exemplar_position) 410 : trace_(trace), 411 exemplar_position_(exemplar_position), 412 pattern_(NULL) { 413 } 414 415 const Trace& trace_; // The shingle lives inside trace_. 416 size_t exemplar_position_; // At this position (and other positions). 417 std::vector<uint32> positions_; // Includes exemplar_position_. 418 419 ShinglePattern* pattern_; // Pattern changes as LabelInfos are assigned. 420 421 friend std::string ToString(const Shingle* instance); 422 423 // We can't disallow the copy constructor because we use std::set<Shingle> and 424 // VS2005's implementation of std::set<T>::set() requires T to have a copy 425 // constructor. 426 // DISALLOW_COPY_AND_ASSIGN(Shingle); 427 void operator=(const Shingle&); // Disallow assignment only. 428 }; 429 430 std::string ToString(const Shingle* instance) { 431 std::string s; 432 const char* sep = "<"; 433 for (size_t i = 0; i < Shingle::kWidth; ++i) { 434 // base::StringAppendF(&s, "%s%x ", sep, instance.at(i)->label_->rva_); 435 s += sep; 436 s += ToString(instance->at(i)); 437 sep = ", "; 438 } 439 base::StringAppendF(&s, ">(%" PRIuS ")@{%d}", 440 instance->exemplar_position_, 441 instance->position_count()); 442 return s; 443 } 444 445 446 bool Shingle::InterningLess::operator()( 447 const Shingle& a, 448 const Shingle& b) const { 449 for (size_t i = 0; i < kWidth; ++i) { 450 LabelInfo* info_a = a.at(i); 451 LabelInfo* info_b = b.at(i); 452 if (info_a->label_->rva_ < info_b->label_->rva_) 453 return true; 454 if (info_a->label_->rva_ > info_b->label_->rva_) 455 return false; 456 if (info_a->is_model_ < info_b->is_model_) 457 return true; 458 if (info_a->is_model_ > info_b->is_model_) 459 return false; 460 if (info_a != info_b) { 461 NOTREACHED(); 462 } 463 } 464 return false; 465 } 466 467 class ShinglePattern { 468 public: 469 enum { kOffsetMask = 7, // Offset lives in low bits. 470 kFixed = 0, // kind & kVariable == 0 => fixed. 471 kVariable = 8 // kind & kVariable == 1 => variable. 472 }; 473 // sequence[position + (kinds_[i] & kOffsetMask)] gives LabelInfo for position 474 // i of shingle. Below, second 'A' is duplicate of position 1, second '102' 475 // is duplicate of position 0. 476 // 477 // <102, A, 103, A , 102> 478 // --> <kFixed+0, kVariable+1, kFixed+2, kVariable+1, kFixed+0> 479 struct Index { 480 explicit Index(const Shingle* instance); 481 uint8 kinds_[Shingle::kWidth]; 482 uint8 variables_; 483 uint8 unique_variables_; 484 uint8 first_variable_index_; 485 uint32 hash_; 486 int assigned_indexes_[Shingle::kWidth]; 487 }; 488 489 // ShinglePattern keeps histograms of member Shingle instances, ordered by 490 // decreasing number of occurrences. We don't have a pair (occurrence count, 491 // Shingle instance), so we use a FreqView adapter to make the instance 492 // pointer look like the pair. 493 class FreqView { 494 public: 495 explicit FreqView(const Shingle* instance) : instance_(instance) {} 496 int count() const { return instance_->position_count(); } 497 const Shingle* instance() const { return instance_; } 498 struct Greater { 499 bool operator()(const FreqView& a, const FreqView& b) const { 500 if (a.count() > b.count()) return true; 501 if (a.count() < b.count()) return false; 502 return resolve_ties(a.instance(), b.instance()); 503 } 504 private: 505 Shingle::PointerLess resolve_ties; 506 }; 507 private: 508 const Shingle* instance_; 509 }; 510 511 typedef std::set<FreqView, FreqView::Greater> Histogram; 512 513 ShinglePattern() : index_(NULL), model_coverage_(0), program_coverage_(0) {} 514 515 const Index* index_; // Points to the key in the owning map value_type. 516 Histogram model_histogram_; 517 Histogram program_histogram_; 518 int model_coverage_; 519 int program_coverage_; 520 }; 521 522 std::string ToString(const ShinglePattern::Index* index) { 523 std::string s; 524 if (index == NULL) { 525 s = "<null>"; 526 } else { 527 base::StringAppendF(&s, "<%d: ", index->variables_); 528 const char* sep = ""; 529 for (size_t i = 0; i < Shingle::kWidth; ++i) { 530 s += sep; 531 sep = ", "; 532 uint32 kind = index->kinds_[i]; 533 int offset = kind & ShinglePattern::kOffsetMask; 534 if (kind & ShinglePattern::kVariable) 535 base::StringAppendF(&s, "V%d", offset); 536 else 537 base::StringAppendF(&s, "%d", index->assigned_indexes_[offset]); 538 } 539 base::StringAppendF(&s, " %x", index->hash_); 540 s += ">"; 541 } 542 return s; 543 } 544 545 std::string HistogramToString(const ShinglePattern::Histogram& histogram, 546 size_t snippet_max) { 547 std::string s; 548 size_t histogram_size = histogram.size(); 549 size_t snippet_size = 0; 550 for (ShinglePattern::Histogram::const_iterator p = histogram.begin(); 551 p != histogram.end(); 552 ++p) { 553 if (++snippet_size > snippet_max && snippet_size != histogram_size) { 554 s += " ..."; 555 break; 556 } 557 base::StringAppendF(&s, " %d", p->count()); 558 } 559 return s; 560 } 561 562 std::string HistogramToStringFull(const ShinglePattern::Histogram& histogram, 563 const char* indent, 564 size_t snippet_max) { 565 std::string s; 566 567 size_t histogram_size = histogram.size(); 568 size_t snippet_size = 0; 569 for (ShinglePattern::Histogram::const_iterator p = histogram.begin(); 570 p != histogram.end(); 571 ++p) { 572 s += indent; 573 if (++snippet_size > snippet_max && snippet_size != histogram_size) { 574 s += "...\n"; 575 break; 576 } 577 base::StringAppendF(&s, "(%d) ", p->count()); 578 s += ToString(&(*p->instance())); 579 s += "\n"; 580 } 581 return s; 582 } 583 584 std::string ToString(const ShinglePattern* pattern, size_t snippet_max = 3) { 585 std::string s; 586 if (pattern == NULL) { 587 s = "<null>"; 588 } else { 589 s = "{"; 590 s += ToString(pattern->index_); 591 base::StringAppendF(&s, "; %d(%d):", 592 static_cast<int>(pattern->model_histogram_.size()), 593 pattern->model_coverage_); 594 595 s += HistogramToString(pattern->model_histogram_, snippet_max); 596 base::StringAppendF(&s, "; %d(%d):", 597 static_cast<int>(pattern->program_histogram_.size()), 598 pattern->program_coverage_); 599 s += HistogramToString(pattern->program_histogram_, snippet_max); 600 s += "}"; 601 } 602 return s; 603 } 604 605 std::string ShinglePatternToStringFull(const ShinglePattern* pattern, 606 size_t max) { 607 std::string s; 608 s += ToString(pattern->index_); 609 s += "\n"; 610 size_t model_size = pattern->model_histogram_.size(); 611 size_t program_size = pattern->program_histogram_.size(); 612 base::StringAppendF(&s, " model shingles %" PRIuS "\n", model_size); 613 s += HistogramToStringFull(pattern->model_histogram_, " ", max); 614 base::StringAppendF(&s, " program shingles %" PRIuS "\n", program_size); 615 s += HistogramToStringFull(pattern->program_histogram_, " ", max); 616 return s; 617 } 618 619 struct ShinglePatternIndexLess { 620 bool operator()(const ShinglePattern::Index& a, 621 const ShinglePattern::Index& b) const { 622 if (a.hash_ < b.hash_) return true; 623 if (a.hash_ > b.hash_) return false; 624 625 for (size_t i = 0; i < Shingle::kWidth; ++i) { 626 if (a.kinds_[i] < b.kinds_[i]) return true; 627 if (a.kinds_[i] > b.kinds_[i]) return false; 628 if ((a.kinds_[i] & ShinglePattern::kVariable) == 0) { 629 if (a.assigned_indexes_[i] < b.assigned_indexes_[i]) 630 return true; 631 if (a.assigned_indexes_[i] > b.assigned_indexes_[i]) 632 return false; 633 } 634 } 635 return false; 636 } 637 }; 638 639 static uint32 hash_combine(uint32 h, uint32 v) { 640 h += v; 641 return (h * (37 + 0x0000d100)) ^ (h >> 13); 642 } 643 644 ShinglePattern::Index::Index(const Shingle* instance) { 645 uint32 hash = 0; 646 variables_ = 0; 647 unique_variables_ = 0; 648 first_variable_index_ = 255; 649 650 for (uint32 i = 0; i < Shingle::kWidth; ++i) { 651 LabelInfo* info = instance->at(i); 652 uint32 kind = 0; 653 int code = -1; 654 size_t j = 0; 655 for ( ; j < i; ++j) { 656 if (info == instance->at(j)) { // Duplicate LabelInfo 657 kind = kinds_[j]; 658 break; 659 } 660 } 661 if (j == i) { // Not found above. 662 if (info->assignment_) { 663 code = info->label_->index_; 664 assigned_indexes_[i] = code; 665 kind = kFixed + i; 666 } else { 667 kind = kVariable + i; 668 ++unique_variables_; 669 if (i < first_variable_index_) 670 first_variable_index_ = i; 671 } 672 } 673 if (kind & kVariable) ++variables_; 674 hash = hash_combine(hash, code); 675 hash = hash_combine(hash, kind); 676 kinds_[i] = kind; 677 assigned_indexes_[i] = code; 678 } 679 hash_ = hash; 680 } 681 682 struct ShinglePatternLess { 683 bool operator()(const ShinglePattern& a, const ShinglePattern& b) const { 684 return index_less(*a.index_, *b.index_); 685 } 686 ShinglePatternIndexLess index_less; 687 }; 688 689 struct ShinglePatternPointerLess { 690 bool operator()(const ShinglePattern* a, const ShinglePattern* b) const { 691 return pattern_less(*a, *b); 692 } 693 ShinglePatternLess pattern_less; 694 }; 695 696 template<int (*Scorer)(const ShinglePattern*)> 697 struct OrderShinglePatternByScoreDescending { 698 bool operator()(const ShinglePattern* a, const ShinglePattern* b) const { 699 int score_a = Scorer(a); 700 int score_b = Scorer(b); 701 if (score_a > score_b) return true; 702 if (score_a < score_b) return false; 703 return break_ties(a, b); 704 } 705 ShinglePatternPointerLess break_ties; 706 }; 707 708 // Returns a score for a 'Single Use' rule. Returns -1 if the rule is not 709 // applicable. 710 int SingleUseScore(const ShinglePattern* pattern) { 711 if (pattern->index_->variables_ != 1) 712 return -1; 713 714 if (pattern->model_histogram_.size() != 1 || 715 pattern->program_histogram_.size() != 1) 716 return -1; 717 718 // Does this pattern account for all uses of the variable? 719 const ShinglePattern::FreqView& program_freq = 720 *pattern->program_histogram_.begin(); 721 const ShinglePattern::FreqView& model_freq = 722 *pattern->model_histogram_.begin(); 723 int p1 = program_freq.count(); 724 int m1 = model_freq.count(); 725 if (p1 == m1) { 726 const Shingle* program_instance = program_freq.instance(); 727 const Shingle* model_instance = model_freq.instance(); 728 size_t variable_index = pattern->index_->first_variable_index_; 729 LabelInfo* program_info = program_instance->at(variable_index); 730 LabelInfo* model_info = model_instance->at(variable_index); 731 if (!program_info->assignment_) { 732 if (program_info->refs_ == p1 && model_info->refs_ == m1) { 733 return p1; 734 } 735 } 736 } 737 return -1; 738 } 739 740 // The VariableQueue is a priority queue of unassigned LabelInfos from 741 // the 'program' (the 'variables') and their AssignmentCandidates. 742 class VariableQueue { 743 public: 744 typedef std::pair<int, LabelInfo*> ScoreAndLabel; 745 746 VariableQueue() {} 747 748 bool empty() const { return queue_.empty(); } 749 750 const ScoreAndLabel& first() const { return *queue_.begin(); } 751 752 // For debugging only. 753 void Print() const { 754 for (Queue::const_iterator p = queue_.begin(); p != queue_.end(); ++p) { 755 AssignmentCandidates* candidates = p->second->candidates(); 756 candidates->Print(std::numeric_limits<int>::max()); 757 } 758 } 759 760 void AddPendingUpdate(LabelInfo* program_info, LabelInfo* model_info, 761 int delta_score) { 762 AssignmentCandidates* candidates = program_info->candidates(); 763 if (!candidates->HasPendingUpdates()) { 764 pending_update_candidates_.push_back(candidates); 765 } 766 candidates->AddPendingUpdate(model_info, delta_score); 767 } 768 769 void ApplyPendingUpdates() { 770 for (size_t i = 0; i < pending_update_candidates_.size(); ++i) { 771 AssignmentCandidates* candidates = pending_update_candidates_[i]; 772 int old_score = candidates->TopScore(); 773 queue_.erase(ScoreAndLabel(old_score, candidates->program_info())); 774 candidates->ApplyPendingUpdates(); 775 if (!candidates->empty()) { 776 int new_score = candidates->TopScore(); 777 queue_.insert(ScoreAndLabel(new_score, candidates->program_info())); 778 } 779 } 780 pending_update_candidates_.clear(); 781 } 782 783 private: 784 struct OrderScoreAndLabelByScoreDecreasing { 785 bool operator()(const ScoreAndLabel& a, const ScoreAndLabel& b) const { 786 if (a.first > b.first) return true; 787 if (a.first < b.first) return false; 788 return OrderLabelInfo()(a.second, b.second); 789 } 790 }; 791 typedef std::set<ScoreAndLabel, OrderScoreAndLabelByScoreDecreasing> Queue; 792 793 Queue queue_; 794 std::vector<AssignmentCandidates*> pending_update_candidates_; 795 796 DISALLOW_COPY_AND_ASSIGN(VariableQueue); 797 }; 798 799 800 class AssignmentProblem { 801 public: 802 AssignmentProblem(const Trace& trace, size_t model_end) 803 : trace_(trace), 804 model_end_(model_end) { 805 VLOG(2) << "AssignmentProblem::AssignmentProblem " << model_end << ", " 806 << trace.size(); 807 } 808 809 bool Solve() { 810 if (model_end_ < Shingle::kWidth || 811 trace_.size() - model_end_ < Shingle::kWidth) { 812 // Nothing much we can do with such a short problem. 813 return true; 814 } 815 instances_.resize(trace_.size() - Shingle::kWidth + 1, NULL); 816 AddShingles(0, model_end_); 817 AddShingles(model_end_, trace_.size()); 818 InitialClassify(); 819 AddPatternsNeedingUpdatesToQueues(); 820 821 patterns_needing_updates_.clear(); 822 while (FindAndAssignBestLeader()) 823 patterns_needing_updates_.clear(); 824 PrintActivePatterns(); 825 826 return true; 827 } 828 829 private: 830 typedef std::set<Shingle*, Shingle::PointerLess> ShingleSet; 831 832 typedef std::set<const ShinglePattern*, ShinglePatternPointerLess> 833 ShinglePatternSet; 834 835 // Patterns are partitioned into the following sets: 836 837 // * Retired patterns (not stored). No shingles exist for this pattern (they 838 // all now match more specialized patterns). 839 // * Useless patterns (not stored). There are no 'program' shingles for this 840 // pattern (they all now match more specialized patterns). 841 // * Single-use patterns - single_use_pattern_queue_. 842 // * Other patterns - active_non_single_use_patterns_ / variable_queue_. 843 844 typedef std::set<const ShinglePattern*, 845 OrderShinglePatternByScoreDescending<&SingleUseScore> > 846 SingleUsePatternQueue; 847 848 void PrintPatternsHeader() const { 849 VLOG(2) << shingle_instances_.size() << " instances " 850 << trace_.size() << " trace length " 851 << patterns_.size() << " shingle indexes " 852 << single_use_pattern_queue_.size() << " single use patterns " 853 << active_non_single_use_patterns_.size() << " active patterns"; 854 } 855 856 void PrintActivePatterns() const { 857 for (ShinglePatternSet::const_iterator p = 858 active_non_single_use_patterns_.begin(); 859 p != active_non_single_use_patterns_.end(); 860 ++p) { 861 const ShinglePattern* pattern = *p; 862 VLOG(2) << ToString(pattern, 10); 863 } 864 } 865 866 void PrintPatterns() const { 867 PrintAllPatterns(); 868 PrintActivePatterns(); 869 PrintAllShingles(); 870 } 871 872 void PrintAllPatterns() const { 873 for (IndexToPattern::const_iterator p = patterns_.begin(); 874 p != patterns_.end(); 875 ++p) { 876 const ShinglePattern& pattern = p->second; 877 VLOG(2) << ToString(&pattern, 10); 878 } 879 } 880 881 void PrintAllShingles() const { 882 for (Shingle::OwningSet::const_iterator p = shingle_instances_.begin(); 883 p != shingle_instances_.end(); 884 ++p) { 885 const Shingle& instance = *p; 886 VLOG(2) << ToString(&instance) << " " << ToString(instance.pattern()); 887 } 888 } 889 890 891 void AddShingles(size_t begin, size_t end) { 892 for (size_t i = begin; i + Shingle::kWidth - 1 < end; ++i) { 893 instances_[i] = Shingle::Find(trace_, i, &shingle_instances_); 894 } 895 } 896 897 void Declassify(Shingle* shingle) { 898 ShinglePattern* pattern = shingle->pattern(); 899 if (shingle->InModel()) { 900 pattern->model_histogram_.erase(ShinglePattern::FreqView(shingle)); 901 pattern->model_coverage_ -= shingle->position_count(); 902 } else { 903 pattern->program_histogram_.erase(ShinglePattern::FreqView(shingle)); 904 pattern->program_coverage_ -= shingle->position_count(); 905 } 906 shingle->set_pattern(NULL); 907 } 908 909 void Reclassify(Shingle* shingle) { 910 ShinglePattern* pattern = shingle->pattern(); 911 LOG_ASSERT(pattern == NULL); 912 913 ShinglePattern::Index index(shingle); 914 if (index.variables_ == 0) 915 return; 916 917 std::pair<IndexToPattern::iterator, bool> inserted = 918 patterns_.insert(std::make_pair(index, ShinglePattern())); 919 920 pattern = &inserted.first->second; 921 pattern->index_ = &inserted.first->first; 922 shingle->set_pattern(pattern); 923 patterns_needing_updates_.insert(pattern); 924 925 if (shingle->InModel()) { 926 pattern->model_histogram_.insert(ShinglePattern::FreqView(shingle)); 927 pattern->model_coverage_ += shingle->position_count(); 928 } else { 929 pattern->program_histogram_.insert(ShinglePattern::FreqView(shingle)); 930 pattern->program_coverage_ += shingle->position_count(); 931 } 932 } 933 934 void InitialClassify() { 935 for (Shingle::OwningSet::iterator p = shingle_instances_.begin(); 936 p != shingle_instances_.end(); 937 ++p) { 938 // GCC's set<T>::iterator::operator *() returns a const object. 939 Reclassify(const_cast<Shingle*>(&*p)); 940 } 941 } 942 943 // For the positions in |info|, find the shingles that overlap that position. 944 void AddAffectedPositions(LabelInfo* info, ShingleSet* affected_shingles) { 945 const size_t kWidth = Shingle::kWidth; 946 for (size_t i = 0; i < info->positions_.size(); ++i) { 947 size_t position = info->positions_[i]; 948 // Find bounds to the subrange of |trace_| we are in. 949 size_t start = position < model_end_ ? 0 : model_end_; 950 size_t end = position < model_end_ ? model_end_ : trace_.size(); 951 952 // Clip [position-kWidth+1, position+1) 953 size_t low = position > start + kWidth - 1 954 ? position - kWidth + 1 955 : start; 956 size_t high = position + kWidth < end ? position + 1 : end - kWidth + 1; 957 958 for (size_t shingle_position = low; 959 shingle_position < high; 960 ++shingle_position) { 961 Shingle* overlapping_shingle = instances_.at(shingle_position); 962 affected_shingles->insert(overlapping_shingle); 963 } 964 } 965 } 966 967 void RemovePatternsNeedingUpdatesFromQueues() { 968 for (ShinglePatternSet::iterator p = patterns_needing_updates_.begin(); 969 p != patterns_needing_updates_.end(); 970 ++p) { 971 RemovePatternFromQueues(*p); 972 } 973 } 974 975 void AddPatternsNeedingUpdatesToQueues() { 976 for (ShinglePatternSet::iterator p = patterns_needing_updates_.begin(); 977 p != patterns_needing_updates_.end(); 978 ++p) { 979 AddPatternToQueues(*p); 980 } 981 variable_queue_.ApplyPendingUpdates(); 982 } 983 984 void RemovePatternFromQueues(const ShinglePattern* pattern) { 985 int single_use_score = SingleUseScore(pattern); 986 if (single_use_score > 0) { 987 size_t n = single_use_pattern_queue_.erase(pattern); 988 LOG_ASSERT(n == 1); 989 } else if (pattern->program_histogram_.empty() && 990 pattern->model_histogram_.empty()) { 991 NOTREACHED(); // Should not come back to life. 992 } else if (pattern->program_histogram_.empty()) { 993 // Useless pattern. 994 } else { 995 active_non_single_use_patterns_.erase(pattern); 996 AddPatternToLabelQueue(pattern, -1); 997 } 998 } 999 1000 void AddPatternToQueues(const ShinglePattern* pattern) { 1001 int single_use_score = SingleUseScore(pattern); 1002 if (single_use_score > 0) { 1003 single_use_pattern_queue_.insert(pattern); 1004 } else if (pattern->program_histogram_.empty() && 1005 pattern->model_histogram_.empty()) { 1006 } else if (pattern->program_histogram_.empty()) { 1007 // Useless pattern. 1008 } else { 1009 active_non_single_use_patterns_.insert(pattern); 1010 AddPatternToLabelQueue(pattern, +1); 1011 } 1012 } 1013 1014 void AddPatternToLabelQueue(const ShinglePattern* pattern, int sign) { 1015 // For each possible assignment in this pattern, update the potential 1016 // contributions to the LabelInfo queues. 1017 1018 // We want to find for each symbol (LabelInfo) the maximum contribution that 1019 // could be achieved by making shingle-wise assignments between shingles in 1020 // the model and shingles in the program. 1021 // 1022 // If the shingles in the histograms are independent (no two shingles have a 1023 // symbol in common) then any permutation of the assignments is possible, 1024 // and the maximum contribution can be found by taking the maximum over all 1025 // the pairs. 1026 // 1027 // If the shingles are dependent two things happen. The maximum 1028 // contribution to any given symbol is a sum because the symbol has 1029 // contributions from all the shingles containing it. Second, some 1030 // assignments are blocked by previous incompatible assignments. We want to 1031 // avoid a combinatorial search, so we ignore the blocking. 1032 1033 const size_t kUnwieldy = 5; 1034 1035 typedef std::map<LabelInfo*, int> LabelToScore; 1036 typedef std::map<LabelInfo*, LabelToScore > ScoreSet; 1037 ScoreSet maxima; 1038 1039 size_t n_model_samples = 0; 1040 for (ShinglePattern::Histogram::const_iterator model_iter = 1041 pattern->model_histogram_.begin(); 1042 model_iter != pattern->model_histogram_.end(); 1043 ++model_iter) { 1044 if (++n_model_samples > kUnwieldy) break; 1045 const ShinglePattern::FreqView& model_freq = *model_iter; 1046 int m1 = model_freq.count(); 1047 const Shingle* model_instance = model_freq.instance(); 1048 1049 ScoreSet sums; 1050 size_t n_program_samples = 0; 1051 for (ShinglePattern::Histogram::const_iterator program_iter = 1052 pattern->program_histogram_.begin(); 1053 program_iter != pattern->program_histogram_.end(); 1054 ++program_iter) { 1055 if (++n_program_samples > kUnwieldy) break; 1056 const ShinglePattern::FreqView& program_freq = *program_iter; 1057 int p1 = program_freq.count(); 1058 const Shingle* program_instance = program_freq.instance(); 1059 1060 // int score = p1; // ? weigh all equally?? 1061 int score = std::min(p1, m1); 1062 1063 for (size_t i = 0; i < Shingle::kWidth; ++i) { 1064 LabelInfo* program_info = program_instance->at(i); 1065 LabelInfo* model_info = model_instance->at(i); 1066 if ((model_info->assignment_ == NULL) != 1067 (program_info->assignment_ == NULL)) { 1068 VLOG(2) << "ERROR " << i 1069 << "\n\t" << ToString(pattern, 10) 1070 << "\n\t" << ToString(program_instance) 1071 << "\n\t" << ToString(model_instance); 1072 } 1073 if (!program_info->assignment_ && !model_info->assignment_) { 1074 sums[program_info][model_info] += score; 1075 } 1076 } 1077 1078 for (ScoreSet::iterator assignee_iterator = sums.begin(); 1079 assignee_iterator != sums.end(); 1080 ++assignee_iterator) { 1081 LabelInfo* program_info = assignee_iterator->first; 1082 for (LabelToScore::iterator p = assignee_iterator->second.begin(); 1083 p != assignee_iterator->second.end(); 1084 ++p) { 1085 LabelInfo* model_info = p->first; 1086 int score = p->second; 1087 int* slot = &maxima[program_info][model_info]; 1088 *slot = std::max(*slot, score); 1089 } 1090 } 1091 } 1092 } 1093 1094 for (ScoreSet::iterator assignee_iterator = maxima.begin(); 1095 assignee_iterator != maxima.end(); 1096 ++assignee_iterator) { 1097 LabelInfo* program_info = assignee_iterator->first; 1098 for (LabelToScore::iterator p = assignee_iterator->second.begin(); 1099 p != assignee_iterator->second.end(); 1100 ++p) { 1101 LabelInfo* model_info = p->first; 1102 int score = sign * p->second; 1103 variable_queue_.AddPendingUpdate(program_info, model_info, score); 1104 } 1105 } 1106 } 1107 1108 void AssignOne(LabelInfo* model_info, LabelInfo* program_info) { 1109 LOG_ASSERT(!model_info->assignment_); 1110 LOG_ASSERT(!program_info->assignment_); 1111 LOG_ASSERT(model_info->is_model_); 1112 LOG_ASSERT(!program_info->is_model_); 1113 1114 VLOG(3) << "Assign " << ToString(program_info) 1115 << " := " << ToString(model_info); 1116 1117 ShingleSet affected_shingles; 1118 AddAffectedPositions(model_info, &affected_shingles); 1119 AddAffectedPositions(program_info, &affected_shingles); 1120 1121 for (ShingleSet::iterator p = affected_shingles.begin(); 1122 p != affected_shingles.end(); 1123 ++p) { 1124 patterns_needing_updates_.insert((*p)->pattern()); 1125 } 1126 1127 RemovePatternsNeedingUpdatesFromQueues(); 1128 1129 for (ShingleSet::iterator p = affected_shingles.begin(); 1130 p != affected_shingles.end(); 1131 ++p) { 1132 Declassify(*p); 1133 } 1134 1135 program_info->label_->index_ = model_info->label_->index_; 1136 // Mark as assigned 1137 model_info->assignment_ = program_info; 1138 program_info->assignment_ = model_info; 1139 1140 for (ShingleSet::iterator p = affected_shingles.begin(); 1141 p != affected_shingles.end(); 1142 ++p) { 1143 Reclassify(*p); 1144 } 1145 1146 AddPatternsNeedingUpdatesToQueues(); 1147 } 1148 1149 bool AssignFirstVariableOfHistogramHead(const ShinglePattern& pattern) { 1150 const ShinglePattern::FreqView& program_1 = 1151 *pattern.program_histogram_.begin(); 1152 const ShinglePattern::FreqView& model_1 = *pattern.model_histogram_.begin(); 1153 const Shingle* program_instance = program_1.instance(); 1154 const Shingle* model_instance = model_1.instance(); 1155 size_t variable_index = pattern.index_->first_variable_index_; 1156 LabelInfo* program_info = program_instance->at(variable_index); 1157 LabelInfo* model_info = model_instance->at(variable_index); 1158 AssignOne(model_info, program_info); 1159 return true; 1160 } 1161 1162 bool FindAndAssignBestLeader() { 1163 LOG_ASSERT(patterns_needing_updates_.empty()); 1164 1165 if (!single_use_pattern_queue_.empty()) { 1166 const ShinglePattern& pattern = **single_use_pattern_queue_.begin(); 1167 return AssignFirstVariableOfHistogramHead(pattern); 1168 } 1169 1170 if (variable_queue_.empty()) 1171 return false; 1172 1173 const VariableQueue::ScoreAndLabel best = variable_queue_.first(); 1174 int score = best.first; 1175 LabelInfo* assignee = best.second; 1176 1177 // TODO(sra): score (best.first) can be zero. A zero score means we are 1178 // blindly picking between two (or more) alternatives which look the same. 1179 // If we exit on the first zero-score we sometimes get 3-4% better total 1180 // compression. This indicates that 'infill' is doing a better job than 1181 // picking blindly. Perhaps we can use an extended region around the 1182 // undistinguished competing alternatives to break the tie. 1183 if (score == 0) { 1184 variable_queue_.Print(); 1185 return false; 1186 } 1187 1188 AssignmentCandidates* candidates = assignee->candidates(); 1189 if (candidates->empty()) 1190 return false; // Should not happen. 1191 1192 AssignOne(candidates->top_candidate(), assignee); 1193 return true; 1194 } 1195 1196 private: 1197 // The trace vector contains the model sequence [0, model_end_) followed by 1198 // the program sequence [model_end_, trace.end()) 1199 const Trace& trace_; 1200 size_t model_end_; 1201 1202 // |shingle_instances_| is the set of 'interned' shingles. 1203 Shingle::OwningSet shingle_instances_; 1204 1205 // |instances_| maps from position in |trace_| to Shingle at that position. 1206 std::vector<Shingle*> instances_; 1207 1208 SingleUsePatternQueue single_use_pattern_queue_; 1209 ShinglePatternSet active_non_single_use_patterns_; 1210 VariableQueue variable_queue_; 1211 1212 // Transient information: when we make an assignment, we need to recompute 1213 // priority queue information derived from these ShinglePatterns. 1214 ShinglePatternSet patterns_needing_updates_; 1215 1216 typedef std::map<ShinglePattern::Index, 1217 ShinglePattern, ShinglePatternIndexLess> IndexToPattern; 1218 IndexToPattern patterns_; 1219 1220 DISALLOW_COPY_AND_ASSIGN(AssignmentProblem); 1221 }; 1222 1223 class Adjuster : public AdjustmentMethod { 1224 public: 1225 Adjuster() : prog_(NULL), model_(NULL) {} 1226 ~Adjuster() {} 1227 1228 bool Adjust(const AssemblyProgram& model, AssemblyProgram* program) { 1229 VLOG(1) << "Adjuster::Adjust"; 1230 prog_ = program; 1231 model_ = &model; 1232 return Finish(); 1233 } 1234 1235 bool Finish() { 1236 prog_->UnassignIndexes(); 1237 Trace abs32_trace_; 1238 Trace rel32_trace_; 1239 CollectTraces(model_, &abs32_trace_, &rel32_trace_, true); 1240 size_t abs32_model_end = abs32_trace_.size(); 1241 size_t rel32_model_end = rel32_trace_.size(); 1242 CollectTraces(prog_, &abs32_trace_, &rel32_trace_, false); 1243 Solve(abs32_trace_, abs32_model_end); 1244 Solve(rel32_trace_, rel32_model_end); 1245 prog_->AssignRemainingIndexes(); 1246 return true; 1247 } 1248 1249 private: 1250 void CollectTraces(const AssemblyProgram* program, Trace* abs32, Trace* rel32, 1251 bool is_model) { 1252 label_info_maker_.ResetDebugLabel(); 1253 const InstructionVector& instructions = program->instructions(); 1254 for (size_t i = 0; i < instructions.size(); ++i) { 1255 Instruction* instruction = instructions[i]; 1256 if (Label* label = program->InstructionAbs32Label(instruction)) 1257 ReferenceLabel(abs32, label, is_model); 1258 if (Label* label = program->InstructionRel32Label(instruction)) 1259 ReferenceLabel(rel32, label, is_model); 1260 } 1261 // TODO(sra): we could simply append all the labels in index order to 1262 // incorporate some costing for entropy (bigger deltas) that will be 1263 // introduced into the label address table by non-monotonic ordering. This 1264 // would have some knock-on effects to parts of the algorithm that work on 1265 // single-occurrence labels. 1266 } 1267 1268 void Solve(const Trace& model, size_t model_end) { 1269 base::Time start_time = base::Time::Now(); 1270 AssignmentProblem a(model, model_end); 1271 a.Solve(); 1272 VLOG(1) << " Adjuster::Solve " 1273 << (base::Time::Now() - start_time).InSecondsF(); 1274 } 1275 1276 void ReferenceLabel(Trace* trace, Label* label, bool is_model) { 1277 trace->push_back( 1278 label_info_maker_.MakeLabelInfo(label, is_model, 1279 static_cast<uint32>(trace->size()))); 1280 } 1281 1282 AssemblyProgram* prog_; // Program to be adjusted, owned by caller. 1283 const AssemblyProgram* model_; // Program to be mimicked, owned by caller. 1284 1285 LabelInfoMaker label_info_maker_; 1286 1287 private: 1288 DISALLOW_COPY_AND_ASSIGN(Adjuster); 1289 }; 1290 1291 //////////////////////////////////////////////////////////////////////////////// 1292 1293 } // namespace adjustment_method_2 1294 1295 AdjustmentMethod* AdjustmentMethod::MakeShingleAdjustmentMethod() { 1296 return new adjustment_method_2::Adjuster(); 1297 } 1298 1299 } // namespace courgette 1300