Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(29)

Side by Side Diff: src/liveedit.cc

Issue 7080029: Fix Issue 1320: LiveEdit: text differencer fails with out of memory on large files (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: merge Created 9 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/liveedit.h ('k') | src/liveedit-debugger.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
52 Handle<Object> value) { 52 Handle<Object> value) {
53 // Ignore return value from SetElement. It can only be a failure if there 53 // Ignore return value from SetElement. It can only be a failure if there
54 // are element setters causing exceptions and the debugger context has none 54 // are element setters causing exceptions and the debugger context has none
55 // of these. 55 // of these.
56 Handle<Object> no_failure; 56 Handle<Object> no_failure;
57 no_failure = SetElement(object, index, value, kNonStrictMode); 57 no_failure = SetElement(object, index, value, kNonStrictMode);
58 ASSERT(!no_failure.is_null()); 58 ASSERT(!no_failure.is_null());
59 USE(no_failure); 59 USE(no_failure);
60 } 60 }
61 61
62 // Creates string expression and throws it in V8 isolate.
63 void ThrowStringException(const char* str, Isolate* isolate) {
64 Vector<const char> str_vector(str, strlen(str));
65 MaybeObject* maybe_exception =
66 isolate->heap()->AllocateStringFromAscii(str_vector);
67 Object* exception;
68 if (maybe_exception->ToObject(&exception)) {
69 isolate->Throw(exception, NULL);
70 }
71 }
72
62 // A simple implementation of dynamic programming algorithm. It solves 73 // 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 74 // the problem of finding the difference of 2 arrays. It uses a table of
64 // of subproblems. Each cell contains a number together with 2-bit flag 75 // results of subproblems. Each cell contains a number together with 2-bit flag
65 // that helps building the chunk list. 76 // that helps building the chunk list.
66 class Differencer { 77 class Differencer {
67 public: 78 public:
68 explicit Differencer(Comparator::Input* input) 79 explicit Differencer(Comparator::Input* input, Isolate* isolate,
69 : input_(input), len1_(input->getLength1()), len2_(input->getLength2()) { 80 bool* has_exception)
70 buffer_ = NewArray<int>(len1_ * len2_); 81 : input_(input), buffer_(NULL), len1_(input->getLength1()),
82 len2_(input->getLength2()) {
83 // Put multiply result into a bigger integer.
84 int64_t multiply =
85 static_cast<int64_t>(len1_) * static_cast<int64_t>(len2_);
86
87 // Maximum table size is max_int. Within this limit it's easy to check
88 // for multiply overflow. Should we support bigger numbers?
89 if (multiply > kMaxInt) {
90 ThrowStringException("Too many lines: differencer table size is too big",
91 isolate);
92 *has_exception = true;
93 return;
94 }
95 multiply *= sizeof(int); // NOLINT
96 size_t size = multiply;
97 if (size != multiply) {
98 // Shouldn't be reachable.
99 ThrowStringException(
100 "Too many lines: "
101 "differencer table buffer size doesn't fit into size_t", isolate);
102 *has_exception = true;
103 return;
104 }
105 void* p = malloc(size);
106 if (p == NULL) {
107 ThrowStringException(
108 "Too many lines: not enough memory for differencer table buffer",
109 isolate);
110 *has_exception = true;
111 return;
112 }
113 buffer_ = reinterpret_cast<int*>(p);
71 } 114 }
115
72 ~Differencer() { 116 ~Differencer() {
73 DeleteArray(buffer_); 117 if (buffer_ != NULL) {
118 free(buffer_);
119 }
74 } 120 }
75 121
76 void Initialize() { 122 void Initialize() {
77 int array_size = len1_ * len2_; 123 int array_size = len1_ * len2_;
78 for (int i = 0; i < array_size; i++) { 124 for (int i = 0; i < array_size; i++) {
79 buffer_[i] = kEmptyCellValue; 125 buffer_[i] = kEmptyCellValue;
80 } 126 }
81 } 127 }
82 128
83 // Makes sure that result for the full problem is calculated and stored 129 // Makes sure that result for the full problem is calculated and stored
(...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after
252 if (has_open_chunk_) { 298 if (has_open_chunk_) {
253 chunk_writer_->AddChunk(pos1_begin_, pos2_begin_, 299 chunk_writer_->AddChunk(pos1_begin_, pos2_begin_,
254 pos1_ - pos1_begin_, pos2_ - pos2_begin_); 300 pos1_ - pos1_begin_, pos2_ - pos2_begin_);
255 has_open_chunk_ = false; 301 has_open_chunk_ = false;
256 } 302 }
257 } 303 }
258 }; 304 };
259 }; 305 };
260 306
261 307
262 void Comparator::CalculateDifference(Comparator::Input* input, 308 MUST_USE_RESULT MaybeObject/*<void>*/* Comparator::CalculateDifference(
263 Comparator::Output* result_writer) { 309 Comparator::Input* input, Comparator::Output* result_writer,
264 Differencer differencer(input); 310 Isolate* isolate) {
311 bool has_exception = false;
312 Differencer differencer(input, isolate, &has_exception);
313 if (has_exception) {
314 return Failure::Exception();
315 }
265 differencer.Initialize(); 316 differencer.Initialize();
266 differencer.FillTable(); 317 differencer.FillTable();
267 differencer.SaveResult(result_writer); 318 differencer.SaveResult(result_writer);
319 return Smi::FromInt(0); // Unused value.
268 } 320 }
269 321
270 322
271 static bool CompareSubstrings(Handle<String> s1, int pos1, 323 static bool CompareSubstrings(Handle<String> s1, int pos1,
272 Handle<String> s2, int pos2, int len) { 324 Handle<String> s2, int pos2, int len) {
273 for (int i = 0; i < len; i++) { 325 for (int i = 0; i < len; i++) {
274 if (s1->Get(i + pos1) != s2->Get(i + pos2)) { 326 if (s1->Get(i + pos1) != s2->Get(i + pos2)) {
275 return false; 327 return false;
276 } 328 }
277 } 329 }
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after
435 LineEndsWrapper line_ends2_; 487 LineEndsWrapper line_ends2_;
436 }; 488 };
437 489
438 490
439 // Stores compare result in JSArray. For each chunk tries to conduct 491 // Stores compare result in JSArray. For each chunk tries to conduct
440 // a fine-grained nested diff token-wise. 492 // a fine-grained nested diff token-wise.
441 class TokenizingLineArrayCompareOutput : public Comparator::Output { 493 class TokenizingLineArrayCompareOutput : public Comparator::Output {
442 public: 494 public:
443 TokenizingLineArrayCompareOutput(LineEndsWrapper line_ends1, 495 TokenizingLineArrayCompareOutput(LineEndsWrapper line_ends1,
444 LineEndsWrapper line_ends2, 496 LineEndsWrapper line_ends2,
445 Handle<String> s1, Handle<String> s2) 497 Handle<String> s1, Handle<String> s2,
446 : line_ends1_(line_ends1), line_ends2_(line_ends2), s1_(s1), s2_(s2) { 498 Isolate* isolate)
499 : line_ends1_(line_ends1), line_ends2_(line_ends2), s1_(s1), s2_(s2),
500 isolate_(isolate) {
447 } 501 }
448 502
449 void AddChunk(int line_pos1, int line_pos2, int line_len1, int line_len2) { 503 void AddChunk(int line_pos1, int line_pos2, int line_len1, int line_len2) {
450 int char_pos1 = line_ends1_.GetLineStart(line_pos1); 504 int char_pos1 = line_ends1_.GetLineStart(line_pos1);
451 int char_pos2 = line_ends2_.GetLineStart(line_pos2); 505 int char_pos2 = line_ends2_.GetLineStart(line_pos2);
452 int char_len1 = line_ends1_.GetLineStart(line_pos1 + line_len1) - char_pos1; 506 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; 507 int char_len2 = line_ends2_.GetLineStart(line_pos2 + line_len2) - char_pos2;
454 508
455 if (char_len1 < CHUNK_LEN_LIMIT && char_len2 < CHUNK_LEN_LIMIT) { 509 if (char_len1 < CHUNK_LEN_LIMIT && char_len2 < CHUNK_LEN_LIMIT) {
456 // Chunk is small enough to conduct a nested token-level diff. 510 // Chunk is small enough to conduct a nested token-level diff.
457 HandleScope subTaskScope; 511 HandleScope subTaskScope;
458 512
459 TokensCompareInput tokens_input(s1_, char_pos1, char_len1, 513 TokensCompareInput tokens_input(s1_, char_pos1, char_len1,
460 s2_, char_pos2, char_len2); 514 s2_, char_pos2, char_len2);
461 TokensCompareOutput tokens_output(&array_writer_, char_pos1, 515 TokensCompareOutput tokens_output(&array_writer_, char_pos1,
462 char_pos2); 516 char_pos2);
463 517
464 Comparator::CalculateDifference(&tokens_input, &tokens_output); 518 MaybeObject* res = Comparator::CalculateDifference(&tokens_input,
Søren Thygesen Gjesse 2011/05/31 08:03:09 All arguments on same line or each argument on sep
519 &tokens_output, isolate_);
520 if (res->IsFailure()) {
521 // We asked for a small amount of memory, this should not happen.
522 UNREACHABLE();
523 }
465 } else { 524 } else {
466 array_writer_.WriteChunk(char_pos1, char_pos2, char_len1, char_len2); 525 array_writer_.WriteChunk(char_pos1, char_pos2, char_len1, char_len2);
467 } 526 }
468 } 527 }
469 528
470 Handle<JSArray> GetResult() { 529 Handle<JSArray> GetResult() {
471 return array_writer_.GetResult(); 530 return array_writer_.GetResult();
472 } 531 }
473 532
474 private: 533 private:
475 static const int CHUNK_LEN_LIMIT = 800; 534 static const int CHUNK_LEN_LIMIT = 800;
476 535
477 CompareOutputArrayWriter array_writer_; 536 CompareOutputArrayWriter array_writer_;
478 LineEndsWrapper line_ends1_; 537 LineEndsWrapper line_ends1_;
479 LineEndsWrapper line_ends2_; 538 LineEndsWrapper line_ends2_;
480 Handle<String> s1_; 539 Handle<String> s1_;
481 Handle<String> s2_; 540 Handle<String> s2_;
541 Isolate* isolate_;
482 }; 542 };
483 543
484 544
485 Handle<JSArray> LiveEdit::CompareStrings(Handle<String> s1, 545 MUST_USE_RESULT MaybeObject/*<JSArray>*/* LiveEdit::CompareStrings(
486 Handle<String> s2) { 546 Handle<String> s1, Handle<String> s2) {
547
548 Isolate* isolate = Isolate::Current();
487 s1 = FlattenGetString(s1); 549 s1 = FlattenGetString(s1);
488 s2 = FlattenGetString(s2); 550 s2 = FlattenGetString(s2);
489 551
490 LineEndsWrapper line_ends1(s1); 552 LineEndsWrapper line_ends1(s1);
491 LineEndsWrapper line_ends2(s2); 553 LineEndsWrapper line_ends2(s2);
492 554
493 LineArrayCompareInput input(s1, s2, line_ends1, line_ends2); 555 LineArrayCompareInput input(s1, s2, line_ends1, line_ends2);
494 TokenizingLineArrayCompareOutput output(line_ends1, line_ends2, s1, s2); 556 TokenizingLineArrayCompareOutput output(line_ends1, line_ends2, s1, s2,
Søren Thygesen Gjesse 2011/05/31 08:03:09 All arguments on same line or each argument on sep
557 isolate);
495 558
496 Comparator::CalculateDifference(&input, &output); 559 MaybeObject* result = Comparator::CalculateDifference(&input, &output,
Søren Thygesen Gjesse 2011/05/31 08:03:09 All arguments on same line or each argument on sep
560 isolate);
561 if (result->IsFailure()) {
562 return result;
563 }
497 564
498 return output.GetResult(); 565 return *output.GetResult();
499 } 566 }
500 567
501 568
502 static void CompileScriptForTracker(Isolate* isolate, Handle<Script> script) { 569 static void CompileScriptForTracker(Isolate* isolate, Handle<Script> script) {
503 // TODO(635): support extensions. 570 // TODO(635): support extensions.
504 PostponeInterruptsScope postpone(isolate); 571 PostponeInterruptsScope postpone(isolate);
505 572
506 // Build AST. 573 // Build AST.
507 CompilationInfo info(script); 574 CompilationInfo info(script);
508 info.MarkAsGlobal(); 575 info.MarkAsGlobal();
(...skipping 1173 matching lines...) Expand 10 before | Expand all | Expand 10 after
1682 1749
1683 bool LiveEditFunctionTracker::IsActive(Isolate* isolate) { 1750 bool LiveEditFunctionTracker::IsActive(Isolate* isolate) {
1684 return false; 1751 return false;
1685 } 1752 }
1686 1753
1687 #endif // ENABLE_DEBUGGER_SUPPORT 1754 #endif // ENABLE_DEBUGGER_SUPPORT
1688 1755
1689 1756
1690 1757
1691 } } // namespace v8::internal 1758 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/liveedit.h ('k') | src/liveedit-debugger.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698