OLD | NEW |
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
59 USE(no_failure); | 59 USE(no_failure); |
60 } | 60 } |
61 | 61 |
62 // A simple implementation of dynamic programming algorithm. It solves | 62 // A simple implementation of dynamic programming algorithm. It solves |
63 // the problem of finding the difference of 2 arrays. It uses a table of results | 63 // the problem of finding the difference of 2 arrays. It uses a table of results |
64 // of subproblems. Each cell contains a number together with 2-bit flag | 64 // of subproblems. Each cell contains a number together with 2-bit flag |
65 // that helps building the chunk list. | 65 // that helps building the chunk list. |
66 class Differencer { | 66 class Differencer { |
67 public: | 67 public: |
68 explicit Differencer(Comparator::Input* input) | 68 explicit Differencer(Comparator::Input* input) |
69 : input_(input), len1_(input->getLength1()), len2_(input->getLength2()) { | 69 : input_(input), len1_(input->GetLength1()), len2_(input->GetLength2()) { |
70 buffer_ = NewArray<int>(len1_ * len2_); | 70 buffer_ = NewArray<int>(len1_ * len2_); |
71 } | 71 } |
72 ~Differencer() { | 72 ~Differencer() { |
73 DeleteArray(buffer_); | 73 DeleteArray(buffer_); |
74 } | 74 } |
75 | 75 |
76 void Initialize() { | 76 void Initialize() { |
77 int array_size = len1_ * len2_; | 77 int array_size = len1_ * len2_; |
78 for (int i = 0; i < array_size; i++) { | 78 for (int i = 0; i < array_size; i++) { |
79 buffer_[i] = kEmptyCellValue; | 79 buffer_[i] = kEmptyCellValue; |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
144 | 144 |
145 // Computes result for a subtask and optionally caches it in the buffer table. | 145 // Computes result for a subtask and optionally caches it in the buffer table. |
146 // All results values are shifted to make space for flags in the lower bits. | 146 // All results values are shifted to make space for flags in the lower bits. |
147 int CompareUpToTail(int pos1, int pos2) { | 147 int CompareUpToTail(int pos1, int pos2) { |
148 if (pos1 < len1_) { | 148 if (pos1 < len1_) { |
149 if (pos2 < len2_) { | 149 if (pos2 < len2_) { |
150 int cached_res = get_value4(pos1, pos2); | 150 int cached_res = get_value4(pos1, pos2); |
151 if (cached_res == kEmptyCellValue) { | 151 if (cached_res == kEmptyCellValue) { |
152 Direction dir; | 152 Direction dir; |
153 int res; | 153 int res; |
154 if (input_->equals(pos1, pos2)) { | 154 if (input_->Equals(pos1, pos2)) { |
155 res = CompareUpToTail(pos1 + 1, pos2 + 1); | 155 res = CompareUpToTail(pos1 + 1, pos2 + 1); |
156 dir = EQ; | 156 dir = EQ; |
157 } else { | 157 } else { |
158 int res1 = CompareUpToTail(pos1 + 1, pos2) + | 158 int res1 = CompareUpToTail(pos1 + 1, pos2) + |
159 (1 << kDirectionSizeBits); | 159 (1 << kDirectionSizeBits); |
160 int res2 = CompareUpToTail(pos1, pos2 + 1) + | 160 int res2 = CompareUpToTail(pos1, pos2 + 1) + |
161 (1 << kDirectionSizeBits); | 161 (1 << kDirectionSizeBits); |
162 if (res1 == res2) { | 162 if (res1 == res2) { |
163 res = res1; | 163 res = res1; |
164 dir = SKIP_ANY; | 164 dir = SKIP_ANY; |
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
272 Handle<String> s2, int pos2, int len) { | 272 Handle<String> s2, int pos2, int len) { |
273 for (int i = 0; i < len; i++) { | 273 for (int i = 0; i < len; i++) { |
274 if (s1->Get(i + pos1) != s2->Get(i + pos2)) { | 274 if (s1->Get(i + pos1) != s2->Get(i + pos2)) { |
275 return false; | 275 return false; |
276 } | 276 } |
277 } | 277 } |
278 return true; | 278 return true; |
279 } | 279 } |
280 | 280 |
281 | 281 |
| 282 // Additional to Input interface. Lets switch Input range to subrange. |
| 283 // More elegant way would be to wrap one Input as another Input object |
| 284 // and translate positions there, but that would cost us additional virtual |
| 285 // call per comparison. |
| 286 class SubrangableInput : public Comparator::Input { |
| 287 public: |
| 288 virtual void SetSubrange1(int offset, int len) = 0; |
| 289 virtual void SetSubrange2(int offset, int len) = 0; |
| 290 }; |
| 291 |
| 292 |
| 293 class SubrangableOutput : public Comparator::Output { |
| 294 public: |
| 295 virtual void SetSubrange1(int offset, int len) = 0; |
| 296 virtual void SetSubrange2(int offset, int len) = 0; |
| 297 }; |
| 298 |
| 299 |
| 300 static int min(int a, int b) { |
| 301 return a < b ? a : b; |
| 302 } |
| 303 |
| 304 |
| 305 // Finds common prefix and suffix in input. This parts shouldn't take space in |
| 306 // linear programming table. Enable subranging in input and output. |
| 307 static void NarrowDownInput(SubrangableInput* input, |
| 308 SubrangableOutput* output) { |
| 309 const int len1 = input->GetLength1(); |
| 310 const int len2 = input->GetLength2(); |
| 311 |
| 312 int common_prefix_len; |
| 313 int common_suffix_len; |
| 314 |
| 315 { |
| 316 common_prefix_len = 0; |
| 317 int prefix_limit = min(len1, len2); |
| 318 while (common_prefix_len < prefix_limit && |
| 319 input->Equals(common_prefix_len, common_prefix_len)) { |
| 320 common_prefix_len++; |
| 321 } |
| 322 |
| 323 common_suffix_len = 0; |
| 324 int suffix_limit = min(len1 - common_prefix_len, len2 - common_prefix_len); |
| 325 |
| 326 while (common_suffix_len < suffix_limit && |
| 327 input->Equals(len1 - common_suffix_len - 1, |
| 328 len2 - common_suffix_len - 1)) { |
| 329 common_suffix_len++; |
| 330 } |
| 331 } |
| 332 |
| 333 if (common_prefix_len > 0 || common_suffix_len > 0) { |
| 334 int new_len1 = len1 - common_suffix_len - common_prefix_len; |
| 335 int new_len2 = len2 - common_suffix_len - common_prefix_len; |
| 336 |
| 337 input->SetSubrange1(common_prefix_len, new_len1); |
| 338 input->SetSubrange2(common_prefix_len, new_len2); |
| 339 |
| 340 output->SetSubrange1(common_prefix_len, new_len1); |
| 341 output->SetSubrange2(common_prefix_len, new_len2); |
| 342 } |
| 343 } |
| 344 |
| 345 |
282 // A helper class that writes chunk numbers into JSArray. | 346 // A helper class that writes chunk numbers into JSArray. |
283 // Each chunk is stored as 3 array elements: (pos1_begin, pos1_end, pos2_end). | 347 // Each chunk is stored as 3 array elements: (pos1_begin, pos1_end, pos2_end). |
284 class CompareOutputArrayWriter { | 348 class CompareOutputArrayWriter { |
285 public: | 349 public: |
286 CompareOutputArrayWriter() | 350 CompareOutputArrayWriter() |
287 : array_(FACTORY->NewJSArray(10)), current_size_(0) {} | 351 : array_(FACTORY->NewJSArray(10)), current_size_(0) {} |
288 | 352 |
289 Handle<JSArray> GetResult() { | 353 Handle<JSArray> GetResult() { |
290 return array_; | 354 return array_; |
291 } | 355 } |
(...skipping 20 matching lines...) Expand all Loading... |
312 // Represents 2 strings as 2 arrays of tokens. | 376 // Represents 2 strings as 2 arrays of tokens. |
313 // TODO(LiveEdit): Currently it's actually an array of charactres. | 377 // TODO(LiveEdit): Currently it's actually an array of charactres. |
314 // Make array of tokens instead. | 378 // Make array of tokens instead. |
315 class TokensCompareInput : public Comparator::Input { | 379 class TokensCompareInput : public Comparator::Input { |
316 public: | 380 public: |
317 TokensCompareInput(Handle<String> s1, int offset1, int len1, | 381 TokensCompareInput(Handle<String> s1, int offset1, int len1, |
318 Handle<String> s2, int offset2, int len2) | 382 Handle<String> s2, int offset2, int len2) |
319 : s1_(s1), offset1_(offset1), len1_(len1), | 383 : s1_(s1), offset1_(offset1), len1_(len1), |
320 s2_(s2), offset2_(offset2), len2_(len2) { | 384 s2_(s2), offset2_(offset2), len2_(len2) { |
321 } | 385 } |
322 virtual int getLength1() { | 386 virtual int GetLength1() { |
323 return len1_; | 387 return len1_; |
324 } | 388 } |
325 virtual int getLength2() { | 389 virtual int GetLength2() { |
326 return len2_; | 390 return len2_; |
327 } | 391 } |
328 bool equals(int index1, int index2) { | 392 bool Equals(int index1, int index2) { |
329 return s1_->Get(offset1_ + index1) == s2_->Get(offset2_ + index2); | 393 return s1_->Get(offset1_ + index1) == s2_->Get(offset2_ + index2); |
330 } | 394 } |
331 | 395 |
332 private: | 396 private: |
333 Handle<String> s1_; | 397 Handle<String> s1_; |
334 int offset1_; | 398 int offset1_; |
335 int len1_; | 399 int len1_; |
336 Handle<String> s2_; | 400 Handle<String> s2_; |
337 int offset2_; | 401 int offset2_; |
338 int len2_; | 402 int len2_; |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
394 Handle<FixedArray> ends_array_; | 458 Handle<FixedArray> ends_array_; |
395 int string_len_; | 459 int string_len_; |
396 | 460 |
397 int GetPosAfterNewLine(int index) { | 461 int GetPosAfterNewLine(int index) { |
398 return Smi::cast(ends_array_->get(index))->value() + 1; | 462 return Smi::cast(ends_array_->get(index))->value() + 1; |
399 } | 463 } |
400 }; | 464 }; |
401 | 465 |
402 | 466 |
403 // Represents 2 strings as 2 arrays of lines. | 467 // Represents 2 strings as 2 arrays of lines. |
404 class LineArrayCompareInput : public Comparator::Input { | 468 class LineArrayCompareInput : public SubrangableInput { |
405 public: | 469 public: |
406 LineArrayCompareInput(Handle<String> s1, Handle<String> s2, | 470 LineArrayCompareInput(Handle<String> s1, Handle<String> s2, |
407 LineEndsWrapper line_ends1, LineEndsWrapper line_ends2) | 471 LineEndsWrapper line_ends1, LineEndsWrapper line_ends2) |
408 : s1_(s1), s2_(s2), line_ends1_(line_ends1), | 472 : s1_(s1), s2_(s2), line_ends1_(line_ends1), |
409 line_ends2_(line_ends2) { | 473 line_ends2_(line_ends2), |
| 474 subrange_offset1_(0), subrange_offset2_(0), |
| 475 subrange_len1_(line_ends1_.length()), |
| 476 subrange_len2_(line_ends2_.length()) { |
410 } | 477 } |
411 int getLength1() { | 478 int GetLength1() { |
412 return line_ends1_.length(); | 479 return subrange_len1_; |
413 } | 480 } |
414 int getLength2() { | 481 int GetLength2() { |
415 return line_ends2_.length(); | 482 return subrange_len2_; |
416 } | 483 } |
417 bool equals(int index1, int index2) { | 484 bool Equals(int index1, int index2) { |
| 485 index1 += subrange_offset1_; |
| 486 index2 += subrange_offset2_; |
| 487 |
418 int line_start1 = line_ends1_.GetLineStart(index1); | 488 int line_start1 = line_ends1_.GetLineStart(index1); |
419 int line_start2 = line_ends2_.GetLineStart(index2); | 489 int line_start2 = line_ends2_.GetLineStart(index2); |
420 int line_end1 = line_ends1_.GetLineEnd(index1); | 490 int line_end1 = line_ends1_.GetLineEnd(index1); |
421 int line_end2 = line_ends2_.GetLineEnd(index2); | 491 int line_end2 = line_ends2_.GetLineEnd(index2); |
422 int len1 = line_end1 - line_start1; | 492 int len1 = line_end1 - line_start1; |
423 int len2 = line_end2 - line_start2; | 493 int len2 = line_end2 - line_start2; |
424 if (len1 != len2) { | 494 if (len1 != len2) { |
425 return false; | 495 return false; |
426 } | 496 } |
427 return CompareSubstrings(s1_, line_start1, s2_, line_start2, | 497 return CompareSubstrings(s1_, line_start1, s2_, line_start2, |
428 len1); | 498 len1); |
429 } | 499 } |
| 500 void SetSubrange1(int offset, int len) { |
| 501 subrange_offset1_ = offset; |
| 502 subrange_len1_ = len; |
| 503 } |
| 504 void SetSubrange2(int offset, int len) { |
| 505 subrange_offset2_ = offset; |
| 506 subrange_len2_ = len; |
| 507 } |
430 | 508 |
431 private: | 509 private: |
432 Handle<String> s1_; | 510 Handle<String> s1_; |
433 Handle<String> s2_; | 511 Handle<String> s2_; |
434 LineEndsWrapper line_ends1_; | 512 LineEndsWrapper line_ends1_; |
435 LineEndsWrapper line_ends2_; | 513 LineEndsWrapper line_ends2_; |
| 514 int subrange_offset1_; |
| 515 int subrange_offset2_; |
| 516 int subrange_len1_; |
| 517 int subrange_len2_; |
436 }; | 518 }; |
437 | 519 |
438 | 520 |
439 // Stores compare result in JSArray. For each chunk tries to conduct | 521 // Stores compare result in JSArray. For each chunk tries to conduct |
440 // a fine-grained nested diff token-wise. | 522 // a fine-grained nested diff token-wise. |
441 class TokenizingLineArrayCompareOutput : public Comparator::Output { | 523 class TokenizingLineArrayCompareOutput : public SubrangableOutput { |
442 public: | 524 public: |
443 TokenizingLineArrayCompareOutput(LineEndsWrapper line_ends1, | 525 TokenizingLineArrayCompareOutput(LineEndsWrapper line_ends1, |
444 LineEndsWrapper line_ends2, | 526 LineEndsWrapper line_ends2, |
445 Handle<String> s1, Handle<String> s2) | 527 Handle<String> s1, Handle<String> s2) |
446 : line_ends1_(line_ends1), line_ends2_(line_ends2), s1_(s1), s2_(s2) { | 528 : line_ends1_(line_ends1), line_ends2_(line_ends2), s1_(s1), s2_(s2), |
| 529 subrange_offset1_(0), subrange_offset2_(0) { |
447 } | 530 } |
448 | 531 |
449 void AddChunk(int line_pos1, int line_pos2, int line_len1, int line_len2) { | 532 void AddChunk(int line_pos1, int line_pos2, int line_len1, int line_len2) { |
| 533 line_pos1 += subrange_offset1_; |
| 534 line_pos2 += subrange_offset2_; |
| 535 |
450 int char_pos1 = line_ends1_.GetLineStart(line_pos1); | 536 int char_pos1 = line_ends1_.GetLineStart(line_pos1); |
451 int char_pos2 = line_ends2_.GetLineStart(line_pos2); | 537 int char_pos2 = line_ends2_.GetLineStart(line_pos2); |
452 int char_len1 = line_ends1_.GetLineStart(line_pos1 + line_len1) - char_pos1; | 538 int char_len1 = line_ends1_.GetLineStart(line_pos1 + line_len1) - char_pos1; |
453 int char_len2 = line_ends2_.GetLineStart(line_pos2 + line_len2) - char_pos2; | 539 int char_len2 = line_ends2_.GetLineStart(line_pos2 + line_len2) - char_pos2; |
454 | 540 |
455 if (char_len1 < CHUNK_LEN_LIMIT && char_len2 < CHUNK_LEN_LIMIT) { | 541 if (char_len1 < CHUNK_LEN_LIMIT && char_len2 < CHUNK_LEN_LIMIT) { |
456 // Chunk is small enough to conduct a nested token-level diff. | 542 // Chunk is small enough to conduct a nested token-level diff. |
457 HandleScope subTaskScope; | 543 HandleScope subTaskScope; |
458 | 544 |
459 TokensCompareInput tokens_input(s1_, char_pos1, char_len1, | 545 TokensCompareInput tokens_input(s1_, char_pos1, char_len1, |
460 s2_, char_pos2, char_len2); | 546 s2_, char_pos2, char_len2); |
461 TokensCompareOutput tokens_output(&array_writer_, char_pos1, | 547 TokensCompareOutput tokens_output(&array_writer_, char_pos1, |
462 char_pos2); | 548 char_pos2); |
463 | 549 |
464 Comparator::CalculateDifference(&tokens_input, &tokens_output); | 550 Comparator::CalculateDifference(&tokens_input, &tokens_output); |
465 } else { | 551 } else { |
466 array_writer_.WriteChunk(char_pos1, char_pos2, char_len1, char_len2); | 552 array_writer_.WriteChunk(char_pos1, char_pos2, char_len1, char_len2); |
467 } | 553 } |
468 } | 554 } |
| 555 void SetSubrange1(int offset, int len) { |
| 556 subrange_offset1_ = offset; |
| 557 } |
| 558 void SetSubrange2(int offset, int len) { |
| 559 subrange_offset2_ = offset; |
| 560 } |
469 | 561 |
470 Handle<JSArray> GetResult() { | 562 Handle<JSArray> GetResult() { |
471 return array_writer_.GetResult(); | 563 return array_writer_.GetResult(); |
472 } | 564 } |
473 | 565 |
474 private: | 566 private: |
475 static const int CHUNK_LEN_LIMIT = 800; | 567 static const int CHUNK_LEN_LIMIT = 800; |
476 | 568 |
477 CompareOutputArrayWriter array_writer_; | 569 CompareOutputArrayWriter array_writer_; |
478 LineEndsWrapper line_ends1_; | 570 LineEndsWrapper line_ends1_; |
479 LineEndsWrapper line_ends2_; | 571 LineEndsWrapper line_ends2_; |
480 Handle<String> s1_; | 572 Handle<String> s1_; |
481 Handle<String> s2_; | 573 Handle<String> s2_; |
| 574 int subrange_offset1_; |
| 575 int subrange_offset2_; |
482 }; | 576 }; |
483 | 577 |
484 | 578 |
485 Handle<JSArray> LiveEdit::CompareStrings(Handle<String> s1, | 579 Handle<JSArray> LiveEdit::CompareStrings(Handle<String> s1, |
486 Handle<String> s2) { | 580 Handle<String> s2) { |
487 s1 = FlattenGetString(s1); | 581 s1 = FlattenGetString(s1); |
488 s2 = FlattenGetString(s2); | 582 s2 = FlattenGetString(s2); |
489 | 583 |
490 LineEndsWrapper line_ends1(s1); | 584 LineEndsWrapper line_ends1(s1); |
491 LineEndsWrapper line_ends2(s2); | 585 LineEndsWrapper line_ends2(s2); |
492 | 586 |
493 LineArrayCompareInput input(s1, s2, line_ends1, line_ends2); | 587 LineArrayCompareInput input(s1, s2, line_ends1, line_ends2); |
494 TokenizingLineArrayCompareOutput output(line_ends1, line_ends2, s1, s2); | 588 TokenizingLineArrayCompareOutput output(line_ends1, line_ends2, s1, s2); |
495 | 589 |
| 590 NarrowDownInput(&input, &output); |
| 591 |
496 Comparator::CalculateDifference(&input, &output); | 592 Comparator::CalculateDifference(&input, &output); |
497 | 593 |
498 return output.GetResult(); | 594 return output.GetResult(); |
499 } | 595 } |
500 | 596 |
501 | 597 |
502 static void CompileScriptForTracker(Isolate* isolate, Handle<Script> script) { | 598 static void CompileScriptForTracker(Isolate* isolate, Handle<Script> script) { |
503 // TODO(635): support extensions. | 599 // TODO(635): support extensions. |
504 PostponeInterruptsScope postpone(isolate); | 600 PostponeInterruptsScope postpone(isolate); |
505 | 601 |
(...skipping 1176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1682 | 1778 |
1683 bool LiveEditFunctionTracker::IsActive(Isolate* isolate) { | 1779 bool LiveEditFunctionTracker::IsActive(Isolate* isolate) { |
1684 return false; | 1780 return false; |
1685 } | 1781 } |
1686 | 1782 |
1687 #endif // ENABLE_DEBUGGER_SUPPORT | 1783 #endif // ENABLE_DEBUGGER_SUPPORT |
1688 | 1784 |
1689 | 1785 |
1690 | 1786 |
1691 } } // namespace v8::internal | 1787 } } // namespace v8::internal |
OLD | NEW |