LCOV - code coverage report
Current view: top level - src/debug - liveedit.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 519 539 96.3 %
Date: 2019-01-20 Functions: 49 68 72.1 %

          Line data    Source code
       1             : // Copyright 2012 the V8 project 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 "src/debug/liveedit.h"
       6             : 
       7             : #include "src/api-inl.h"
       8             : #include "src/ast/ast-traversal-visitor.h"
       9             : #include "src/ast/ast.h"
      10             : #include "src/ast/scopes.h"
      11             : #include "src/compilation-cache.h"
      12             : #include "src/compiler.h"
      13             : #include "src/debug/debug-interface.h"
      14             : #include "src/debug/debug.h"
      15             : #include "src/frames-inl.h"
      16             : #include "src/isolate-inl.h"
      17             : #include "src/objects-inl.h"
      18             : #include "src/objects/hash-table-inl.h"
      19             : #include "src/objects/js-generator-inl.h"
      20             : #include "src/parsing/parse-info.h"
      21             : #include "src/parsing/parsing.h"
      22             : #include "src/source-position-table.h"
      23             : #include "src/v8.h"
      24             : 
      25             : namespace v8 {
      26             : namespace internal {
      27             : namespace {
      28             : // A general-purpose comparator between 2 arrays.
      29             : class Comparator {
      30             :  public:
      31             :   // Holds 2 arrays of some elements allowing to compare any pair of
      32             :   // element from the first array and element from the second array.
      33        2417 :   class Input {
      34             :    public:
      35             :     virtual int GetLength1() = 0;
      36             :     virtual int GetLength2() = 0;
      37             :     virtual bool Equals(int index1, int index2) = 0;
      38             : 
      39             :    protected:
      40        1201 :     virtual ~Input() = default;
      41             :   };
      42             : 
      43             :   // Receives compare result as a series of chunks.
      44        2417 :   class Output {
      45             :    public:
      46             :     // Puts another chunk in result list. Note that technically speaking
      47             :     // only 3 arguments actually needed with 4th being derivable.
      48             :     virtual void AddChunk(int pos1, int pos2, int len1, int len2) = 0;
      49             : 
      50             :    protected:
      51        1201 :     virtual ~Output() = default;
      52             :   };
      53             : 
      54             :   // Finds the difference between 2 arrays of elements.
      55             :   static void CalculateDifference(Input* input, Output* result_writer);
      56             : };
      57             : 
      58             : // A simple implementation of dynamic programming algorithm. It solves
      59             : // the problem of finding the difference of 2 arrays. It uses a table of results
      60             : // of subproblems. Each cell contains a number together with 2-bit flag
      61             : // that helps building the chunk list.
      62             : class Differencer {
      63             :  public:
      64        2417 :   explicit Differencer(Comparator::Input* input)
      65        2417 :       : input_(input), len1_(input->GetLength1()), len2_(input->GetLength2()) {
      66        2417 :     buffer_ = NewArray<int>(len1_ * len2_);
      67        2417 :   }
      68             :   ~Differencer() {
      69        2417 :     DeleteArray(buffer_);
      70             :   }
      71             : 
      72             :   void Initialize() {
      73        2417 :     int array_size = len1_ * len2_;
      74     1358361 :     for (int i = 0; i < array_size; i++) {
      75     1358361 :       buffer_[i] = kEmptyCellValue;
      76             :     }
      77             :   }
      78             : 
      79             :   // Makes sure that result for the full problem is calculated and stored
      80             :   // in the table together with flags showing a path through subproblems.
      81             :   void FillTable() {
      82        2417 :     CompareUpToTail(0, 0);
      83             :   }
      84             : 
      85        2417 :   void SaveResult(Comparator::Output* chunk_writer) {
      86             :     ResultWriter writer(chunk_writer);
      87             : 
      88             :     int pos1 = 0;
      89             :     int pos2 = 0;
      90             :     while (true) {
      91       39270 :       if (pos1 < len1_) {
      92       38090 :         if (pos2 < len2_) {
      93             :           Direction dir = get_direction(pos1, pos2);
      94       36853 :           switch (dir) {
      95             :             case EQ:
      96             :               writer.eq();
      97       25117 :               pos1++;
      98       25117 :               pos2++;
      99       25117 :               break;
     100             :             case SKIP1:
     101             :               writer.skip1(1);
     102        3129 :               pos1++;
     103        3129 :               break;
     104             :             case SKIP2:
     105             :             case SKIP_ANY:
     106             :               writer.skip2(1);
     107        8607 :               pos2++;
     108        8607 :               break;
     109             :             default:
     110           0 :               UNREACHABLE();
     111             :           }
     112             :         } else {
     113        1237 :           writer.skip1(len1_ - pos1);
     114             :           break;
     115             :         }
     116             :       } else {
     117        1180 :         if (len2_ != pos2) {
     118         212 :           writer.skip2(len2_ - pos2);
     119             :         }
     120             :         break;
     121             :       }
     122             :     }
     123             :     writer.close();
     124        2417 :   }
     125             : 
     126             :  private:
     127             :   Comparator::Input* input_;
     128             :   int* buffer_;
     129             :   int len1_;
     130             :   int len2_;
     131             : 
     132             :   enum Direction {
     133             :     EQ = 0,
     134             :     SKIP1,
     135             :     SKIP2,
     136             :     SKIP_ANY,
     137             : 
     138             :     MAX_DIRECTION_FLAG_VALUE = SKIP_ANY
     139             :   };
     140             : 
     141             :   // Computes result for a subtask and optionally caches it in the buffer table.
     142             :   // All results values are shifted to make space for flags in the lower bits.
     143      802109 :   int CompareUpToTail(int pos1, int pos2) {
     144      802109 :     if (pos1 < len1_) {
     145      783931 :       if (pos2 < len2_) {
     146             :         int cached_res = get_value4(pos1, pos2);
     147      770683 :         if (cached_res == kEmptyCellValue) {
     148             :           Direction dir;
     149             :           int res;
     150      426627 :           if (input_->Equals(pos1, pos2)) {
     151       53562 :             res = CompareUpToTail(pos1 + 1, pos2 + 1);
     152             :             dir = EQ;
     153             :           } else {
     154      373065 :             int res1 = CompareUpToTail(pos1 + 1, pos2) +
     155      373065 :                 (1 << kDirectionSizeBits);
     156      373065 :             int res2 = CompareUpToTail(pos1, pos2 + 1) +
     157      373065 :                 (1 << kDirectionSizeBits);
     158      373065 :             if (res1 == res2) {
     159             :               res = res1;
     160             :               dir = SKIP_ANY;
     161      318671 :             } else if (res1 < res2) {
     162             :               res = res1;
     163             :               dir = SKIP1;
     164             :             } else {
     165             :               res = res2;
     166             :               dir = SKIP2;
     167             :             }
     168             :           }
     169             :           set_value4_and_dir(pos1, pos2, res, dir);
     170             :           cached_res = res;
     171             :         }
     172      770683 :         return cached_res;
     173             :       } else {
     174       13248 :         return (len1_ - pos1) << kDirectionSizeBits;
     175             :       }
     176             :     } else {
     177       18178 :       return (len2_ - pos2) << kDirectionSizeBits;
     178             :     }
     179             :   }
     180             : 
     181             :   inline int& get_cell(int i1, int i2) {
     182     1234163 :     return buffer_[i1 + i2 * len1_];
     183             :   }
     184             : 
     185             :   // Each cell keeps a value plus direction. Value is multiplied by 4.
     186      426627 :   void set_value4_and_dir(int i1, int i2, int value4, Direction dir) {
     187             :     DCHECK_EQ(0, value4 & kDirectionMask);
     188      426627 :     get_cell(i1, i2) = value4 | dir;
     189             :   }
     190             : 
     191      770683 :   int get_value4(int i1, int i2) {
     192      770683 :     return get_cell(i1, i2) & (kMaxUInt32 ^ kDirectionMask);
     193             :   }
     194       36853 :   Direction get_direction(int i1, int i2) {
     195       36853 :     return static_cast<Direction>(get_cell(i1, i2) & kDirectionMask);
     196             :   }
     197             : 
     198             :   static const int kDirectionSizeBits = 2;
     199             :   static const int kDirectionMask = (1 << kDirectionSizeBits) - 1;
     200             :   static const int kEmptyCellValue = ~0u << kDirectionSizeBits;
     201             : 
     202             :   // This method only holds static assert statement (unfortunately you cannot
     203             :   // place one in class scope).
     204             :   void StaticAssertHolder() {
     205             :     STATIC_ASSERT(MAX_DIRECTION_FLAG_VALUE < (1 << kDirectionSizeBits));
     206             :   }
     207             : 
     208             :   class ResultWriter {
     209             :    public:
     210             :     explicit ResultWriter(Comparator::Output* chunk_writer)
     211             :         : chunk_writer_(chunk_writer), pos1_(0), pos2_(0),
     212        2417 :           pos1_begin_(-1), pos2_begin_(-1), has_open_chunk_(false) {
     213             :     }
     214             :     void eq() {
     215       25117 :       FlushChunk();
     216       25117 :       pos1_++;
     217       25117 :       pos2_++;
     218             :     }
     219             :     void skip1(int len1) {
     220             :       StartChunk();
     221        4366 :       pos1_ += len1;
     222             :     }
     223             :     void skip2(int len2) {
     224             :       StartChunk();
     225        8819 :       pos2_ += len2;
     226             :     }
     227             :     void close() {
     228        2417 :       FlushChunk();
     229             :     }
     230             : 
     231             :    private:
     232             :     Comparator::Output* chunk_writer_;
     233             :     int pos1_;
     234             :     int pos2_;
     235             :     int pos1_begin_;
     236             :     int pos2_begin_;
     237             :     bool has_open_chunk_;
     238             : 
     239             :     void StartChunk() {
     240       13185 :       if (!has_open_chunk_) {
     241        3797 :         pos1_begin_ = pos1_;
     242        3797 :         pos2_begin_ = pos2_;
     243        3797 :         has_open_chunk_ = true;
     244             :       }
     245             :     }
     246             : 
     247       27534 :     void FlushChunk() {
     248       27534 :       if (has_open_chunk_) {
     249             :         chunk_writer_->AddChunk(pos1_begin_, pos2_begin_,
     250        3797 :                                 pos1_ - pos1_begin_, pos2_ - pos2_begin_);
     251        3797 :         has_open_chunk_ = false;
     252             :       }
     253       27534 :     }
     254             :   };
     255             : };
     256             : 
     257        2417 : void Comparator::CalculateDifference(Comparator::Input* input,
     258             :                                      Comparator::Output* result_writer) {
     259        2417 :   Differencer differencer(input);
     260        2417 :   differencer.Initialize();
     261             :   differencer.FillTable();
     262        2417 :   differencer.SaveResult(result_writer);
     263        2417 : }
     264             : 
     265       10785 : bool CompareSubstrings(Handle<String> s1, int pos1, Handle<String> s2, int pos2,
     266             :                        int len) {
     267      213243 :   for (int i = 0; i < len; i++) {
     268     1015880 :     if (s1->Get(i + pos1) != s2->Get(i + pos2)) return false;
     269             :   }
     270             :   return true;
     271             : }
     272             : 
     273             : // Additional to Input interface. Lets switch Input range to subrange.
     274             : // More elegant way would be to wrap one Input as another Input object
     275             : // and translate positions there, but that would cost us additional virtual
     276             : // call per comparison.
     277        1216 : class SubrangableInput : public Comparator::Input {
     278             :  public:
     279             :   virtual void SetSubrange1(int offset, int len) = 0;
     280             :   virtual void SetSubrange2(int offset, int len) = 0;
     281             : };
     282             : 
     283             : 
     284        1216 : class SubrangableOutput : public Comparator::Output {
     285             :  public:
     286             :   virtual void SetSubrange1(int offset, int len) = 0;
     287             :   virtual void SetSubrange2(int offset, int len) = 0;
     288             : };
     289             : 
     290             : // Finds common prefix and suffix in input. This parts shouldn't take space in
     291             : // linear programming table. Enable subranging in input and output.
     292        1216 : void NarrowDownInput(SubrangableInput* input, SubrangableOutput* output) {
     293        1216 :   const int len1 = input->GetLength1();
     294        1216 :   const int len2 = input->GetLength2();
     295             : 
     296             :   int common_prefix_len;
     297             :   int common_suffix_len;
     298             : 
     299             :   {
     300             :     common_prefix_len = 0;
     301        1216 :     int prefix_limit = std::min(len1, len2);
     302       11722 :     while (common_prefix_len < prefix_limit &&
     303        5218 :         input->Equals(common_prefix_len, common_prefix_len)) {
     304        4072 :       common_prefix_len++;
     305             :     }
     306             : 
     307             :     common_suffix_len = 0;
     308             :     int suffix_limit =
     309        2432 :         std::min(len1 - common_prefix_len, len2 - common_prefix_len);
     310             : 
     311       15209 :     while (common_suffix_len < suffix_limit &&
     312        6924 :         input->Equals(len1 - common_suffix_len - 1,
     313       13848 :         len2 - common_suffix_len - 1)) {
     314        5853 :       common_suffix_len++;
     315             :     }
     316             :   }
     317             : 
     318        1216 :   if (common_prefix_len > 0 || common_suffix_len > 0) {
     319         705 :     int new_len1 = len1 - common_suffix_len - common_prefix_len;
     320         705 :     int new_len2 = len2 - common_suffix_len - common_prefix_len;
     321             : 
     322         705 :     input->SetSubrange1(common_prefix_len, new_len1);
     323         705 :     input->SetSubrange2(common_prefix_len, new_len2);
     324             : 
     325         705 :     output->SetSubrange1(common_prefix_len, new_len1);
     326         705 :     output->SetSubrange2(common_prefix_len, new_len2);
     327             :   }
     328        1216 : }
     329             : 
     330             : // Represents 2 strings as 2 arrays of tokens.
     331             : // TODO(LiveEdit): Currently it's actually an array of charactres.
     332             : //     Make array of tokens instead.
     333        1201 : class TokensCompareInput : public Comparator::Input {
     334             :  public:
     335             :   TokensCompareInput(Handle<String> s1, int offset1, int len1,
     336             :                        Handle<String> s2, int offset2, int len2)
     337             :       : s1_(s1), offset1_(offset1), len1_(len1),
     338        1201 :         s2_(s2), offset2_(offset2), len2_(len2) {
     339             :   }
     340        1201 :   int GetLength1() override { return len1_; }
     341        1201 :   int GetLength2() override { return len2_; }
     342      423085 :   bool Equals(int index1, int index2) override {
     343     2115425 :     return s1_->Get(offset1_ + index1) == s2_->Get(offset2_ + index2);
     344             :   }
     345             : 
     346             :  private:
     347             :   Handle<String> s1_;
     348             :   int offset1_;
     349             :   int len1_;
     350             :   Handle<String> s2_;
     351             :   int offset2_;
     352             :   int len2_;
     353             : };
     354             : 
     355             : // Stores compare result in std::vector. Converts substring positions
     356             : // to absolute positions.
     357        1201 : class TokensCompareOutput : public Comparator::Output {
     358             :  public:
     359             :   TokensCompareOutput(int offset1, int offset2,
     360             :                       std::vector<SourceChangeRange>* output)
     361        1201 :       : output_(output), offset1_(offset1), offset2_(offset2) {}
     362             : 
     363        2596 :   void AddChunk(int pos1, int pos2, int len1, int len2) override {
     364             :     output_->emplace_back(
     365        5192 :         SourceChangeRange{pos1 + offset1_, pos1 + len1 + offset1_,
     366        5192 :                           pos2 + offset2_, pos2 + offset2_ + len2});
     367        2596 :   }
     368             : 
     369             :  private:
     370             :   std::vector<SourceChangeRange>* output_;
     371             :   int offset1_;
     372             :   int offset2_;
     373             : };
     374             : 
     375             : // Wraps raw n-elements line_ends array as a list of n+1 lines. The last line
     376             : // never has terminating new line character.
     377             : class LineEndsWrapper {
     378             :  public:
     379        2432 :   explicit LineEndsWrapper(Isolate* isolate, Handle<String> string)
     380             :       : ends_array_(String::CalculateLineEnds(isolate, string, false)),
     381        4864 :         string_len_(string->length()) {}
     382        2432 :   int length() {
     383        2432 :     return ends_array_->length() + 1;
     384             :   }
     385             :   // Returns start for any line including start of the imaginary line after
     386             :   // the last line.
     387       36172 :   int GetLineStart(int index) { return index == 0 ? 0 : GetLineEnd(index - 1); }
     388       61080 :   int GetLineEnd(int index) {
     389       61080 :     if (index == ends_array_->length()) {
     390             :       // End of the last line is always an end of the whole string.
     391             :       // If the string ends with a new line character, the last line is an
     392             :       // empty string after this character.
     393        6273 :       return string_len_;
     394             :     } else {
     395       54807 :       return GetPosAfterNewLine(index);
     396             :     }
     397             :   }
     398             : 
     399             :  private:
     400             :   Handle<FixedArray> ends_array_;
     401             :   int string_len_;
     402             : 
     403       54807 :   int GetPosAfterNewLine(int index) {
     404       54807 :     return Smi::ToInt(ends_array_->get(index)) + 1;
     405             :   }
     406             : };
     407             : 
     408             : // Represents 2 strings as 2 arrays of lines.
     409           0 : class LineArrayCompareInput : public SubrangableInput {
     410             :  public:
     411        1216 :   LineArrayCompareInput(Handle<String> s1, Handle<String> s2,
     412             :                         LineEndsWrapper line_ends1, LineEndsWrapper line_ends2)
     413             :       : s1_(s1), s2_(s2), line_ends1_(line_ends1),
     414             :         line_ends2_(line_ends2),
     415             :         subrange_offset1_(0), subrange_offset2_(0),
     416        1216 :         subrange_len1_(line_ends1_.length()),
     417        2432 :         subrange_len2_(line_ends2_.length()) {
     418        1216 :   }
     419        2432 :   int GetLength1() override { return subrange_len1_; }
     420        2432 :   int GetLength2() override { return subrange_len2_; }
     421       15684 :   bool Equals(int index1, int index2) override {
     422       15684 :     index1 += subrange_offset1_;
     423       15684 :     index2 += subrange_offset2_;
     424             : 
     425       15684 :     int line_start1 = line_ends1_.GetLineStart(index1);
     426       15684 :     int line_start2 = line_ends2_.GetLineStart(index2);
     427       15684 :     int line_end1 = line_ends1_.GetLineEnd(index1);
     428       15684 :     int line_end2 = line_ends2_.GetLineEnd(index2);
     429       15684 :     int len1 = line_end1 - line_start1;
     430       15684 :     int len2 = line_end2 - line_start2;
     431       15684 :     if (len1 != len2) {
     432             :       return false;
     433             :     }
     434             :     return CompareSubstrings(s1_, line_start1, s2_, line_start2,
     435       10785 :                              len1);
     436             :   }
     437         705 :   void SetSubrange1(int offset, int len) override {
     438         705 :     subrange_offset1_ = offset;
     439         705 :     subrange_len1_ = len;
     440         705 :   }
     441         705 :   void SetSubrange2(int offset, int len) override {
     442         705 :     subrange_offset2_ = offset;
     443         705 :     subrange_len2_ = len;
     444         705 :   }
     445             : 
     446             :  private:
     447             :   Handle<String> s1_;
     448             :   Handle<String> s2_;
     449             :   LineEndsWrapper line_ends1_;
     450             :   LineEndsWrapper line_ends2_;
     451             :   int subrange_offset1_;
     452             :   int subrange_offset2_;
     453             :   int subrange_len1_;
     454             :   int subrange_len2_;
     455             : };
     456             : 
     457             : // Stores compare result in std::vector. For each chunk tries to conduct
     458             : // a fine-grained nested diff token-wise.
     459           0 : class TokenizingLineArrayCompareOutput : public SubrangableOutput {
     460             :  public:
     461             :   TokenizingLineArrayCompareOutput(Isolate* isolate, LineEndsWrapper line_ends1,
     462             :                                    LineEndsWrapper line_ends2,
     463             :                                    Handle<String> s1, Handle<String> s2,
     464             :                                    std::vector<SourceChangeRange>* output)
     465             :       : isolate_(isolate),
     466             :         line_ends1_(line_ends1),
     467             :         line_ends2_(line_ends2),
     468             :         s1_(s1),
     469             :         s2_(s2),
     470             :         subrange_offset1_(0),
     471             :         subrange_offset2_(0),
     472        1216 :         output_(output) {}
     473             : 
     474        1201 :   void AddChunk(int line_pos1, int line_pos2, int line_len1,
     475             :                 int line_len2) override {
     476        1201 :     line_pos1 += subrange_offset1_;
     477        1201 :     line_pos2 += subrange_offset2_;
     478             : 
     479        1201 :     int char_pos1 = line_ends1_.GetLineStart(line_pos1);
     480        1201 :     int char_pos2 = line_ends2_.GetLineStart(line_pos2);
     481        2402 :     int char_len1 = line_ends1_.GetLineStart(line_pos1 + line_len1) - char_pos1;
     482        2402 :     int char_len2 = line_ends2_.GetLineStart(line_pos2 + line_len2) - char_pos2;
     483             : 
     484        1201 :     if (char_len1 < CHUNK_LEN_LIMIT && char_len2 < CHUNK_LEN_LIMIT) {
     485             :       // Chunk is small enough to conduct a nested token-level diff.
     486        1201 :       HandleScope subTaskScope(isolate_);
     487             : 
     488             :       TokensCompareInput tokens_input(s1_, char_pos1, char_len1,
     489             :                                       s2_, char_pos2, char_len2);
     490        1201 :       TokensCompareOutput tokens_output(char_pos1, char_pos2, output_);
     491             : 
     492        1201 :       Comparator::CalculateDifference(&tokens_input, &tokens_output);
     493             :     } else {
     494             :       output_->emplace_back(SourceChangeRange{
     495           0 :           char_pos1, char_pos1 + char_len1, char_pos2, char_pos2 + char_len2});
     496             :     }
     497        1201 :   }
     498         705 :   void SetSubrange1(int offset, int len) override {
     499         705 :     subrange_offset1_ = offset;
     500         705 :   }
     501         705 :   void SetSubrange2(int offset, int len) override {
     502         705 :     subrange_offset2_ = offset;
     503         705 :   }
     504             : 
     505             :  private:
     506             :   static const int CHUNK_LEN_LIMIT = 800;
     507             : 
     508             :   Isolate* isolate_;
     509             :   LineEndsWrapper line_ends1_;
     510             :   LineEndsWrapper line_ends2_;
     511             :   Handle<String> s1_;
     512             :   Handle<String> s2_;
     513             :   int subrange_offset1_;
     514             :   int subrange_offset2_;
     515             :   std::vector<SourceChangeRange>* output_;
     516             : };
     517             : 
     518             : struct SourcePositionEvent {
     519             :   enum Type { LITERAL_STARTS, LITERAL_ENDS, DIFF_STARTS, DIFF_ENDS };
     520             : 
     521             :   int position;
     522             :   Type type;
     523             : 
     524             :   union {
     525             :     FunctionLiteral* literal;
     526             :     int pos_diff;
     527             :   };
     528             : 
     529        4262 :   SourcePositionEvent(FunctionLiteral* literal, bool is_start)
     530             :       : position(is_start ? literal->start_position()
     531             :                           : literal->end_position()),
     532             :         type(is_start ? LITERAL_STARTS : LITERAL_ENDS),
     533        4262 :         literal(literal) {}
     534             :   SourcePositionEvent(const SourceChangeRange& change, bool is_start)
     535             :       : position(is_start ? change.start_position : change.end_position),
     536             :         type(is_start ? DIFF_STARTS : DIFF_ENDS),
     537        5628 :         pos_diff((change.new_end_position - change.new_start_position) -
     538        8442 :                  (change.end_position - change.start_position)) {}
     539             : 
     540       22572 :   static bool LessThan(const SourcePositionEvent& a,
     541             :                        const SourcePositionEvent& b) {
     542       22572 :     if (a.position != b.position) return a.position < b.position;
     543         672 :     if (a.type != b.type) return a.type < b.type;
     544         165 :     if (a.type == LITERAL_STARTS && b.type == LITERAL_STARTS) {
     545             :       // If the literals start in the same position, we want the one with the
     546             :       // furthest (i.e. largest) end position to be first.
     547          45 :       if (a.literal->end_position() != b.literal->end_position()) {
     548           0 :         return a.literal->end_position() > b.literal->end_position();
     549             :       }
     550             :       // If they also end in the same position, we want the first in order of
     551             :       // literal ids to be first.
     552           9 :       return a.literal->function_literal_id() <
     553          18 :              b.literal->function_literal_id();
     554         156 :     } else if (a.type == LITERAL_ENDS && b.type == LITERAL_ENDS) {
     555             :       // If the literals end in the same position, we want the one with the
     556             :       // nearest (i.e. largest) start position to be first.
     557         156 :       if (a.literal->start_position() != b.literal->start_position()) {
     558         147 :         return a.literal->start_position() > b.literal->start_position();
     559             :       }
     560             :       // If they also end in the same position, we want the last in order of
     561             :       // literal ids to be first.
     562           9 :       return a.literal->function_literal_id() >
     563          18 :              b.literal->function_literal_id();
     564             :     } else {
     565           0 :       return a.pos_diff < b.pos_diff;
     566             :     }
     567             :   }
     568             : };
     569             : 
     570             : struct FunctionLiteralChange {
     571             :   // If any of start/end position is kNoSourcePosition, this literal is
     572             :   // considered damaged and will not be mapped and edited at all.
     573             :   int new_start_position;
     574             :   int new_end_position;
     575             :   bool has_changes;
     576             :   FunctionLiteral* outer_literal;
     577             : 
     578             :   explicit FunctionLiteralChange(int new_start_position, FunctionLiteral* outer)
     579             :       : new_start_position(new_start_position),
     580             :         new_end_position(kNoSourcePosition),
     581             :         has_changes(false),
     582             :         outer_literal(outer) {}
     583             : };
     584             : 
     585             : using FunctionLiteralChanges =
     586             :     std::unordered_map<FunctionLiteral*, FunctionLiteralChange>;
     587         732 : void CalculateFunctionLiteralChanges(
     588         732 :     const std::vector<FunctionLiteral*>& literals,
     589         732 :     const std::vector<SourceChangeRange>& diffs,
     590             :     FunctionLiteralChanges* result) {
     591             :   std::vector<SourcePositionEvent> events;
     592         732 :   events.reserve(literals.size() * 2 + diffs.size() * 2);
     593        3595 :   for (FunctionLiteral* literal : literals) {
     594        2131 :     events.emplace_back(literal, true);
     595        2131 :     events.emplace_back(literal, false);
     596             :   }
     597        2871 :   for (const SourceChangeRange& diff : diffs) {
     598        1407 :     events.emplace_back(diff, true);
     599        1407 :     events.emplace_back(diff, false);
     600             :   }
     601         732 :   std::sort(events.begin(), events.end(), SourcePositionEvent::LessThan);
     602             :   bool inside_diff = false;
     603             :   int delta = 0;
     604         732 :   std::stack<std::pair<FunctionLiteral*, FunctionLiteralChange>> literal_stack;
     605        8540 :   for (const SourcePositionEvent& event : events) {
     606        7076 :     switch (event.type) {
     607             :       case SourcePositionEvent::DIFF_ENDS:
     608             :         DCHECK(inside_diff);
     609             :         inside_diff = false;
     610        1407 :         delta += event.pos_diff;
     611        1407 :         break;
     612             :       case SourcePositionEvent::LITERAL_ENDS: {
     613             :         DCHECK_EQ(literal_stack.top().first, event.literal);
     614             :         FunctionLiteralChange& change = literal_stack.top().second;
     615             :         change.new_end_position = inside_diff
     616             :                                       ? kNoSourcePosition
     617        2131 :                                       : event.literal->end_position() + delta;
     618        2131 :         result->insert(literal_stack.top());
     619             :         literal_stack.pop();
     620             :         break;
     621             :       }
     622             :       case SourcePositionEvent::LITERAL_STARTS:
     623             :         literal_stack.push(std::make_pair(
     624             :             event.literal,
     625             :             FunctionLiteralChange(
     626             :                 inside_diff ? kNoSourcePosition
     627        2131 :                             : event.literal->start_position() + delta,
     628        7792 :                 literal_stack.empty() ? nullptr : literal_stack.top().first)));
     629        2131 :         break;
     630             :       case SourcePositionEvent::DIFF_STARTS:
     631             :         DCHECK(!inside_diff);
     632             :         inside_diff = true;
     633        1407 :         if (!literal_stack.empty()) {
     634             :           // Note that outer literal has not necessarily changed, unless the
     635             :           // diff goes past the end of this literal. In this case, we'll mark
     636             :           // this function as damaged and parent as changed later in
     637             :           // MapLiterals.
     638        1407 :           literal_stack.top().second.has_changes = true;
     639             :         }
     640             :         break;
     641             :     }
     642             :   }
     643         732 : }
     644             : 
     645             : // Function which has not changed itself, but if any variable in its
     646             : // outer context has been added/removed, we must consider this function
     647             : // as damaged and not update references to it.
     648             : // This is because old compiled function has hardcoded references to
     649             : // it's outer context.
     650        4222 : bool HasChangedScope(FunctionLiteral* a, FunctionLiteral* b) {
     651        5322 :   Scope* scope_a = a->scope()->outer_scope();
     652        5322 :   Scope* scope_b = b->scope()->outer_scope();
     653        7433 :   while (scope_a && scope_b) {
     654        3240 :     std::unordered_map<int, Handle<String>> vars;
     655       17268 :     for (Variable* var : *scope_a->locals()) {
     656        6558 :       if (!var->IsContextSlot()) continue;
     657        4230 :       vars[var->index()] = var->name();
     658             :     }
     659       17188 :     for (Variable* var : *scope_b->locals()) {
     660        6511 :       if (!var->IsContextSlot()) continue;
     661        4240 :       auto it = vars.find(var->index());
     662        2120 :       if (it == vars.end()) return true;
     663        2106 :       if (*it->second != *var->name()) return true;
     664             :     }
     665             :     scope_a = scope_a->outer_scope();
     666             :     scope_b = scope_b->outer_scope();
     667             :   }
     668        2082 :   return scope_a != scope_b;
     669             : }
     670             : 
     671             : enum ChangeState { UNCHANGED, CHANGED, DAMAGED };
     672             : 
     673             : using LiteralMap = std::unordered_map<FunctionLiteral*, FunctionLiteral*>;
     674         732 : void MapLiterals(const FunctionLiteralChanges& changes,
     675             :                  const std::vector<FunctionLiteral*>& new_literals,
     676             :                  LiteralMap* unchanged, LiteralMap* changed) {
     677             :   // Track the top-level script function separately as it can overlap fully with
     678             :   // another function, e.g. the script "()=>42".
     679             :   const std::pair<int, int> kTopLevelMarker = std::make_pair(-1, -1);
     680             :   std::map<std::pair<int, int>, FunctionLiteral*> position_to_new_literal;
     681        3609 :   for (FunctionLiteral* literal : new_literals) {
     682             :     DCHECK(literal->start_position() != kNoSourcePosition);
     683             :     DCHECK(literal->end_position() != kNoSourcePosition);
     684             :     std::pair<int, int> key =
     685             :         literal->function_literal_id() == FunctionLiteral::kIdTypeTopLevel
     686             :             ? kTopLevelMarker
     687        1413 :             : std::make_pair(literal->start_position(),
     688        3558 :                              literal->end_position());
     689             :     // Make sure there are no duplicate keys.
     690             :     DCHECK_EQ(position_to_new_literal.find(key), position_to_new_literal.end());
     691        2145 :     position_to_new_literal[key] = literal;
     692             :   }
     693         732 :   LiteralMap mappings;
     694         732 :   std::unordered_map<FunctionLiteral*, ChangeState> change_state;
     695        3595 :   for (const auto& change_pair : changes) {
     696        2131 :     FunctionLiteral* literal = change_pair.first;
     697             :     const FunctionLiteralChange& change = change_pair.second;
     698             :     std::pair<int, int> key =
     699        2131 :         literal->function_literal_id() == FunctionLiteral::kIdTypeTopLevel
     700             :             ? kTopLevelMarker
     701             :             : std::make_pair(change.new_start_position,
     702        2131 :                              change.new_end_position);
     703             :     auto it = position_to_new_literal.find(key);
     704        4242 :     if (it == position_to_new_literal.end() ||
     705        2111 :         HasChangedScope(literal, it->second)) {
     706          49 :       change_state[literal] = ChangeState::DAMAGED;
     707          49 :       if (!change.outer_literal) continue;
     708          98 :       if (change_state[change.outer_literal] != ChangeState::DAMAGED) {
     709          49 :         change_state[change.outer_literal] = ChangeState::CHANGED;
     710             :       }
     711             :     } else {
     712        2082 :       mappings[literal] = it->second;
     713        2082 :       if (change_state.find(literal) == change_state.end()) {
     714             :         change_state[literal] =
     715        2082 :             change.has_changes ? ChangeState::CHANGED : ChangeState::UNCHANGED;
     716             :       }
     717             :     }
     718             :   }
     719        3546 :   for (const auto& mapping : mappings) {
     720        4164 :     if (change_state[mapping.first] == ChangeState::UNCHANGED) {
     721        1268 :       (*unchanged)[mapping.first] = mapping.second;
     722         814 :     } else if (change_state[mapping.first] == ChangeState::CHANGED) {
     723         814 :       (*changed)[mapping.first] = mapping.second;
     724             :     }
     725             :   }
     726         732 : }
     727             : 
     728             : class CollectFunctionLiterals final
     729             :     : public AstTraversalVisitor<CollectFunctionLiterals> {
     730             :  public:
     731             :   CollectFunctionLiterals(Isolate* isolate, AstNode* root)
     732             :       : AstTraversalVisitor<CollectFunctionLiterals>(isolate, root) {}
     733        4348 :   void VisitFunctionLiteral(FunctionLiteral* lit) {
     734        4348 :     AstTraversalVisitor::VisitFunctionLiteral(lit);
     735        4348 :     literals_->push_back(lit);
     736        4348 :   }
     737             :   void Run(std::vector<FunctionLiteral*>* literals) {
     738        1493 :     literals_ = literals;
     739             :     AstTraversalVisitor::Run();
     740        1493 :     literals_ = nullptr;
     741             :   }
     742             : 
     743             :  private:
     744             :   std::vector<FunctionLiteral*>* literals_;
     745             : };
     746             : 
     747        3015 : bool ParseScript(Isolate* isolate, ParseInfo* parse_info, bool compile_as_well,
     748             :                  std::vector<FunctionLiteral*>* literals,
     749             :                  debug::LiveEditResult* result) {
     750             :   parse_info->set_eager();
     751        1522 :   v8::TryCatch try_catch(reinterpret_cast<v8::Isolate*>(isolate));
     752             :   Handle<SharedFunctionInfo> shared;
     753             :   bool success = false;
     754        1522 :   if (compile_as_well) {
     755             :     success =
     756        1522 :         Compiler::CompileForLiveEdit(parse_info, isolate).ToHandle(&shared);
     757             :   } else {
     758         761 :     success = parsing::ParseProgram(parse_info, isolate);
     759         761 :     if (success) {
     760         761 :       success = Compiler::Analyze(parse_info);
     761         761 :       parse_info->ast_value_factory()->Internalize(isolate);
     762             :     }
     763             :   }
     764        1522 :   if (!success) {
     765          29 :     isolate->OptionalRescheduleException(false);
     766             :     DCHECK(try_catch.HasCaught());
     767          58 :     result->message = try_catch.Message()->Get();
     768          58 :     auto self = Utils::OpenHandle(*try_catch.Message());
     769          29 :     auto msg = i::Handle<i::JSMessageObject>::cast(self);
     770          29 :     result->line_number = msg->GetLineNumber();
     771          29 :     result->column_number = msg->GetColumnNumber();
     772          29 :     result->status = debug::LiveEditResult::COMPILE_ERROR;
     773             :     return false;
     774             :   }
     775        1493 :   CollectFunctionLiterals(isolate, parse_info->literal()).Run(literals);
     776        1493 :   return true;
     777             : }
     778             : 
     779       17376 : struct FunctionData {
     780             :   FunctionData(FunctionLiteral* literal, bool should_restart)
     781             :       : literal(literal),
     782             :         stack_position(NOT_ON_STACK),
     783        5792 :         should_restart(should_restart) {}
     784             : 
     785             :   FunctionLiteral* literal;
     786             :   MaybeHandle<SharedFunctionInfo> shared;
     787             :   std::vector<Handle<JSFunction>> js_functions;
     788             :   std::vector<Handle<JSGeneratorObject>> running_generators;
     789             :   // In case of multiple functions with different stack position, the latest
     790             :   // one (in the order below) is used, since it is the most restrictive.
     791             :   // This is important only for functions to be restarted.
     792             :   enum StackPosition {
     793             :     NOT_ON_STACK,
     794             :     ABOVE_BREAK_FRAME,
     795             :     PATCHABLE,
     796             :     BELOW_NON_DROPPABLE_FRAME,
     797             :     ARCHIVED_THREAD,
     798             :   };
     799             :   StackPosition stack_position;
     800             :   bool should_restart;
     801             : };
     802             : 
     803        1464 : class FunctionDataMap : public ThreadVisitor {
     804             :  public:
     805        2896 :   void AddInterestingLiteral(int script_id, FunctionLiteral* literal,
     806             :                              bool should_restart) {
     807             :     map_.emplace(GetFuncId(script_id, literal),
     808        5792 :                  FunctionData{literal, should_restart});
     809        2896 :   }
     810             : 
     811     1213397 :   bool Lookup(SharedFunctionInfo sfi, FunctionData** data) {
     812     1213397 :     int start_position = sfi->StartPosition();
     813     2426794 :     if (!sfi->script()->IsScript() || start_position == -1) {
     814             :       return false;
     815             :     }
     816      197542 :     Script script = Script::cast(sfi->script());
     817      395084 :     return Lookup(GetFuncId(script->id(), sfi), data);
     818             :   }
     819             : 
     820        4547 :   bool Lookup(Handle<Script> script, FunctionLiteral* literal,
     821             :               FunctionData** data) {
     822        4547 :     return Lookup(GetFuncId(script->id(), literal), data);
     823             :   }
     824             : 
     825         732 :   void Fill(Isolate* isolate, Address* restart_frame_fp) {
     826             :     {
     827        8685 :       HeapIterator iterator(isolate->heap(), HeapIterator::kFilterUnreachable);
     828    12618234 :       for (HeapObject obj = iterator.next(); !obj.is_null();
     829             :            obj = iterator.next()) {
     830     6308385 :         if (obj->IsSharedFunctionInfo()) {
     831             :           SharedFunctionInfo sfi = SharedFunctionInfo::cast(obj);
     832      592034 :           FunctionData* data = nullptr;
     833     1181201 :           if (!Lookup(sfi, &data)) continue;
     834        5734 :           data->shared = handle(sfi, isolate);
     835     5716351 :         } else if (obj->IsJSFunction()) {
     836      615033 :           JSFunction js_function = JSFunction::cast(obj);
     837      615033 :           SharedFunctionInfo sfi = js_function->shared();
     838      615033 :           FunctionData* data = nullptr;
     839     1227506 :           if (!Lookup(sfi, &data)) continue;
     840        2560 :           data->js_functions.emplace_back(js_function, isolate);
     841     5101318 :         } else if (obj->IsJSGeneratorObject()) {
     842         197 :           JSGeneratorObject gen = JSGeneratorObject::cast(obj);
     843         340 :           if (gen->is_closed()) continue;
     844         143 :           SharedFunctionInfo sfi = gen->function()->shared();
     845         143 :           FunctionData* data = nullptr;
     846         143 :           if (!Lookup(sfi, &data)) continue;
     847          54 :           data->running_generators.emplace_back(gen, isolate);
     848             :         }
     849         732 :       }
     850             :     }
     851             :     FunctionData::StackPosition stack_position =
     852        1464 :         isolate->debug()->break_frame_id() == StackFrame::NO_ID
     853             :             ? FunctionData::PATCHABLE
     854         732 :             : FunctionData::ABOVE_BREAK_FRAME;
     855       10874 :     for (StackFrameIterator it(isolate); !it.done(); it.Advance()) {
     856         342 :       StackFrame* frame = it.frame();
     857       10142 :       if (stack_position == FunctionData::ABOVE_BREAK_FRAME) {
     858       12978 :         if (frame->id() == isolate->debug()->break_frame_id()) {
     859             :           stack_position = FunctionData::PATCHABLE;
     860             :         }
     861             :       }
     862       23115 :       if (stack_position == FunctionData::PATCHABLE &&
     863        2650 :           (frame->is_exit() || frame->is_builtin_exit())) {
     864             :         stack_position = FunctionData::BELOW_NON_DROPPABLE_FRAME;
     865        5025 :         continue;
     866             :       }
     867        9961 :       if (!frame->is_java_script()) continue;
     868             :       std::vector<Handle<SharedFunctionInfo>> sfis;
     869        5117 :       JavaScriptFrame::cast(frame)->GetFunctions(&sfis);
     870       15351 :       for (auto& sfi : sfis) {
     871        6917 :         if (stack_position == FunctionData::PATCHABLE &&
     872        1800 :             IsResumableFunction(sfi->kind())) {
     873             :           stack_position = FunctionData::BELOW_NON_DROPPABLE_FRAME;
     874             :         }
     875        5117 :         FunctionData* data = nullptr;
     876        9892 :         if (!Lookup(*sfi, &data)) continue;
     877         984 :         if (!data->should_restart) continue;
     878         342 :         data->stack_position = stack_position;
     879         342 :         *restart_frame_fp = frame->fp();
     880             :       }
     881             :     }
     882             : 
     883        1464 :     isolate->thread_manager()->IterateArchivedThreads(this);
     884         732 :   }
     885             : 
     886             :  private:
     887             :   // Unique id for a function: script_id + start_position, where start_position
     888             :   // is special cased to -1 for top-level so that it does not overlap with a
     889             :   // function whose start position is 0.
     890             :   using FuncId = std::pair<int, int>;
     891             : 
     892        7443 :   FuncId GetFuncId(int script_id, FunctionLiteral* literal) {
     893        7443 :     int start_position = literal->start_position();
     894        7443 :     if (literal->function_literal_id() == 0) {
     895             :       // This is the top-level script function literal, so special case its
     896             :       // start position
     897             :       DCHECK_EQ(start_position, 0);
     898             :       start_position = -1;
     899             :     }
     900             :     return FuncId(script_id, start_position);
     901             :   }
     902             : 
     903      197542 :   FuncId GetFuncId(int script_id, SharedFunctionInfo sfi) {
     904             :     DCHECK_EQ(script_id, Script::cast(sfi->script())->id());
     905      197542 :     int start_position = sfi->StartPosition();
     906             :     DCHECK_NE(start_position, -1);
     907      197542 :     if (sfi->is_toplevel()) {
     908             :       // This is the top-level function, so special case its start position
     909             :       DCHECK_EQ(start_position, 0);
     910             :       start_position = -1;
     911             :     }
     912      197542 :     return FuncId(script_id, start_position);
     913             :   }
     914             : 
     915             :   bool Lookup(FuncId id, FunctionData** data) {
     916             :     auto it = map_.find(id);
     917      202089 :     if (it == map_.end()) return false;
     918       11987 :     *data = &it->second;
     919             :     return true;
     920             :   }
     921             : 
     922           0 :   void VisitThread(Isolate* isolate, ThreadLocalTop* top) override {
     923           0 :     for (JavaScriptFrameIterator it(isolate, top); !it.done(); it.Advance()) {
     924             :       std::vector<Handle<SharedFunctionInfo>> sfis;
     925           0 :       it.frame()->GetFunctions(&sfis);
     926           0 :       for (auto& sfi : sfis) {
     927           0 :         FunctionData* data = nullptr;
     928           0 :         if (!Lookup(*sfi, &data)) continue;
     929           0 :         data->stack_position = FunctionData::ARCHIVED_THREAD;
     930             :       }
     931             :     }
     932           0 :   }
     933             : 
     934             :   std::map<FuncId, FunctionData> map_;
     935             : };
     936             : 
     937         732 : bool CanPatchScript(const LiteralMap& changed, Handle<Script> script,
     938             :                     Handle<Script> new_script,
     939             :                     FunctionDataMap& function_data_map,
     940             :                     debug::LiveEditResult* result) {
     941             :   debug::LiveEditResult::Status status = debug::LiveEditResult::OK;
     942        1474 :   for (const auto& mapping : changed) {
     943         814 :     FunctionData* data = nullptr;
     944         814 :     function_data_map.Lookup(script, mapping.first, &data);
     945         814 :     FunctionData* new_data = nullptr;
     946         814 :     function_data_map.Lookup(new_script, mapping.second, &new_data);
     947             :     Handle<SharedFunctionInfo> sfi;
     948        1628 :     if (!data->shared.ToHandle(&sfi)) {
     949          24 :       continue;
     950         790 :     } else if (!data->should_restart) {
     951           0 :       UNREACHABLE();
     952         790 :     } else if (data->stack_position == FunctionData::ABOVE_BREAK_FRAME) {
     953             :       status = debug::LiveEditResult::BLOCKED_BY_FUNCTION_ABOVE_BREAK_FRAME;
     954         790 :     } else if (data->stack_position ==
     955             :                FunctionData::BELOW_NON_DROPPABLE_FRAME) {
     956             :       status =
     957             :           debug::LiveEditResult::BLOCKED_BY_FUNCTION_BELOW_NON_DROPPABLE_FRAME;
     958         736 :     } else if (!data->running_generators.empty()) {
     959             :       status = debug::LiveEditResult::BLOCKED_BY_RUNNING_GENERATOR;
     960         718 :     } else if (data->stack_position == FunctionData::ARCHIVED_THREAD) {
     961             :       status = debug::LiveEditResult::BLOCKED_BY_ACTIVE_FUNCTION;
     962             :     }
     963         790 :     if (status != debug::LiveEditResult::OK) {
     964          72 :       result->status = status;
     965          72 :       return false;
     966             :     }
     967             :   }
     968             :   return true;
     969             : }
     970             : 
     971         261 : bool CanRestartFrame(Isolate* isolate, Address fp,
     972             :                      FunctionDataMap& function_data_map,
     973             :                      const LiteralMap& changed, debug::LiveEditResult* result) {
     974             :   DCHECK_GT(fp, 0);
     975             :   StackFrame* restart_frame = nullptr;
     976         261 :   StackFrameIterator it(isolate);
     977        4148 :   for (; !it.done(); it.Advance()) {
     978        4409 :     if (it.frame()->fp() == fp) {
     979             :       restart_frame = it.frame();
     980             :       break;
     981             :     }
     982             :   }
     983             :   DCHECK(restart_frame && restart_frame->is_java_script());
     984         261 :   if (!LiveEdit::kFrameDropperSupported) {
     985           0 :     result->status = debug::LiveEditResult::FRAME_RESTART_IS_NOT_SUPPORTED;
     986             :     return false;
     987             :   }
     988             :   std::vector<Handle<SharedFunctionInfo>> sfis;
     989         261 :   JavaScriptFrame::cast(restart_frame)->GetFunctions(&sfis);
     990         486 :   for (auto& sfi : sfis) {
     991         261 :     FunctionData* data = nullptr;
     992         261 :     if (!function_data_map.Lookup(*sfi, &data)) continue;
     993         261 :     auto new_literal_it = changed.find(data->literal);
     994         261 :     if (new_literal_it == changed.end()) continue;
     995         261 :     if (new_literal_it->second->scope()->new_target_var()) {
     996             :       result->status =
     997          36 :           debug::LiveEditResult::BLOCKED_BY_NEW_TARGET_IN_RESTART_FRAME;
     998          36 :       return false;
     999             :     }
    1000             :   }
    1001             :   return true;
    1002             : }
    1003             : 
    1004        2134 : void TranslateSourcePositionTable(Isolate* isolate, Handle<BytecodeArray> code,
    1005             :                                   const std::vector<SourceChangeRange>& diffs) {
    1006        1067 :   SourcePositionTableBuilder builder;
    1007             : 
    1008        2134 :   Handle<ByteArray> source_position_table(code->SourcePositionTable(), isolate);
    1009       13459 :   for (SourcePositionTableIterator iterator(*source_position_table);
    1010       11325 :        !iterator.done(); iterator.Advance()) {
    1011       11325 :     SourcePosition position = iterator.source_position();
    1012             :     position.SetScriptOffset(
    1013       11325 :         LiveEdit::TranslatePosition(diffs, position.ScriptOffset()));
    1014       11325 :     builder.AddPosition(iterator.code_offset(), position,
    1015       22650 :                         iterator.is_statement());
    1016             :   }
    1017             : 
    1018             :   Handle<ByteArray> new_source_position_table(
    1019        1067 :       builder.ToSourcePositionTable(isolate));
    1020        2134 :   code->set_source_position_table(*new_source_position_table);
    1021        1067 :   LOG_CODE_EVENT(isolate,
    1022             :                  CodeLinePosInfoRecordEvent(code->GetFirstBytecodeAddress(),
    1023             :                                             *new_source_position_table));
    1024        1067 : }
    1025             : 
    1026        1137 : void UpdatePositions(Isolate* isolate, Handle<SharedFunctionInfo> sfi,
    1027             :                      const std::vector<SourceChangeRange>& diffs) {
    1028        1137 :   int old_start_position = sfi->StartPosition();
    1029             :   int new_start_position =
    1030        1137 :       LiveEdit::TranslatePosition(diffs, old_start_position);
    1031        1137 :   int new_end_position = LiveEdit::TranslatePosition(diffs, sfi->EndPosition());
    1032             :   int new_function_token_position =
    1033        1137 :       LiveEdit::TranslatePosition(diffs, sfi->function_token_position());
    1034        1137 :   sfi->SetPosition(new_start_position, new_end_position);
    1035             :   sfi->SetFunctionTokenPosition(new_function_token_position,
    1036        1137 :                                 new_start_position);
    1037        1137 :   if (sfi->HasBytecodeArray()) {
    1038             :     TranslateSourcePositionTable(
    1039        2134 :         isolate, handle(sfi->GetBytecodeArray(), isolate), diffs);
    1040             :   }
    1041        1137 : }
    1042             : }  // anonymous namespace
    1043             : 
    1044        4712 : void LiveEdit::PatchScript(Isolate* isolate, Handle<Script> script,
    1045             :                            Handle<String> new_source, bool preview,
    1046             :                            debug::LiveEditResult* result) {
    1047             :   std::vector<SourceChangeRange> diffs;
    1048             :   LiveEdit::CompareStrings(isolate,
    1049             :                            handle(String::cast(script->source()), isolate),
    1050        1532 :                            new_source, &diffs);
    1051         766 :   if (diffs.empty()) {
    1052           5 :     result->status = debug::LiveEditResult::OK;
    1053           5 :     return;
    1054             :   }
    1055             : 
    1056        1385 :   ParseInfo parse_info(isolate, script);
    1057             :   std::vector<FunctionLiteral*> literals;
    1058         761 :   if (!ParseScript(isolate, &parse_info, false, &literals, result)) return;
    1059             : 
    1060         761 :   Handle<Script> new_script = isolate->factory()->CloneScript(script);
    1061        1522 :   new_script->set_source(*new_source);
    1062             :   std::vector<FunctionLiteral*> new_literals;
    1063        1385 :   ParseInfo new_parse_info(isolate, new_script);
    1064         761 :   if (!ParseScript(isolate, &new_parse_info, true, &new_literals, result)) {
    1065         137 :     return;
    1066             :   }
    1067             : 
    1068         732 :   FunctionLiteralChanges literal_changes;
    1069         732 :   CalculateFunctionLiteralChanges(literals, diffs, &literal_changes);
    1070             : 
    1071         732 :   LiteralMap changed;
    1072         732 :   LiteralMap unchanged;
    1073         732 :   MapLiterals(literal_changes, new_literals, &unchanged, &changed);
    1074             : 
    1075             :   FunctionDataMap function_data_map;
    1076        2278 :   for (const auto& mapping : changed) {
    1077        1628 :     function_data_map.AddInterestingLiteral(script->id(), mapping.first, true);
    1078             :     function_data_map.AddInterestingLiteral(new_script->id(), mapping.second,
    1079        1628 :                                             false);
    1080             :   }
    1081        2732 :   for (const auto& mapping : unchanged) {
    1082        2536 :     function_data_map.AddInterestingLiteral(script->id(), mapping.first, false);
    1083             :   }
    1084         732 :   Address restart_frame_fp = 0;
    1085         732 :   function_data_map.Fill(isolate, &restart_frame_fp);
    1086             : 
    1087         732 :   if (!CanPatchScript(changed, script, new_script, function_data_map, result)) {
    1088             :     return;
    1089             :   }
    1090         921 :   if (restart_frame_fp &&
    1091             :       !CanRestartFrame(isolate, restart_frame_fp, function_data_map, changed,
    1092         261 :                        result)) {
    1093             :     return;
    1094             :   }
    1095             : 
    1096         624 :   if (preview) {
    1097           0 :     result->status = debug::LiveEditResult::OK;
    1098           0 :     return;
    1099             :   }
    1100             : 
    1101             :   std::map<int, int> start_position_to_unchanged_id;
    1102        2390 :   for (const auto& mapping : unchanged) {
    1103        1142 :     FunctionData* data = nullptr;
    1104        1217 :     if (!function_data_map.Lookup(script, mapping.first, &data)) continue;
    1105             :     Handle<SharedFunctionInfo> sfi;
    1106        2284 :     if (!data->shared.ToHandle(&sfi)) continue;
    1107             :     DCHECK_EQ(sfi->script(), *script);
    1108             : 
    1109        1137 :     isolate->compilation_cache()->Remove(sfi);
    1110        1137 :     isolate->debug()->DeoptimizeFunction(sfi);
    1111        1137 :     if (sfi->HasDebugInfo()) {
    1112         166 :       Handle<DebugInfo> debug_info(sfi->GetDebugInfo(), isolate);
    1113          83 :       isolate->debug()->RemoveBreakInfoAndMaybeFree(debug_info);
    1114             :     }
    1115        1137 :     UpdatePositions(isolate, sfi, diffs);
    1116             : 
    1117        2274 :     sfi->set_script(*new_script);
    1118        1137 :     if (sfi->HasUncompiledData()) {
    1119         140 :       sfi->uncompiled_data()->set_function_literal_id(
    1120        2484 :           mapping.second->function_literal_id());
    1121             :     }
    1122        2274 :     new_script->shared_function_infos()->Set(
    1123        3411 :         mapping.second->function_literal_id(), HeapObjectReference::Weak(*sfi));
    1124             :     DCHECK_EQ(sfi->FunctionLiteralId(isolate),
    1125             :               mapping.second->function_literal_id());
    1126             : 
    1127             :     // Save the new start_position -> id mapping, so that we can recover it when
    1128             :     // iterating over changed functions' constant pools.
    1129        2274 :     start_position_to_unchanged_id[mapping.second->start_position()] =
    1130        2274 :         mapping.second->function_literal_id();
    1131             : 
    1132        1137 :     if (sfi->HasUncompiledDataWithPreparseData()) {
    1133           0 :       sfi->ClearPreparseData();
    1134             :     }
    1135             : 
    1136        4185 :     for (auto& js_function : data->js_functions) {
    1137             :       js_function->set_raw_feedback_cell(
    1138         774 :           *isolate->factory()->many_closures_cell());
    1139         774 :       if (!js_function->is_compiled()) continue;
    1140         704 :       JSFunction::EnsureFeedbackVector(js_function);
    1141             :     }
    1142             : 
    1143        1137 :     if (!sfi->HasBytecodeArray()) continue;
    1144        1067 :     FixedArray constants = sfi->GetBytecodeArray()->constant_pool();
    1145       12656 :     for (int i = 0; i < constants->length(); ++i) {
    1146       15418 :       if (!constants->get(i)->IsSharedFunctionInfo()) continue;
    1147         809 :       FunctionData* data = nullptr;
    1148         809 :       if (!function_data_map.Lookup(SharedFunctionInfo::cast(constants->get(i)),
    1149         809 :                                     &data)) {
    1150             :         continue;
    1151             :       }
    1152         714 :       auto change_it = changed.find(data->literal);
    1153         714 :       if (change_it == changed.end()) continue;
    1154         365 :       if (!function_data_map.Lookup(new_script, change_it->second, &data)) {
    1155             :         continue;
    1156             :       }
    1157             :       Handle<SharedFunctionInfo> new_sfi;
    1158         730 :       if (!data->shared.ToHandle(&new_sfi)) continue;
    1159         365 :       constants->set(i, *new_sfi);
    1160             :     }
    1161             :   }
    1162        1954 :   for (const auto& mapping : changed) {
    1163         706 :     FunctionData* data = nullptr;
    1164         730 :     if (!function_data_map.Lookup(new_script, mapping.second, &data)) continue;
    1165         706 :     Handle<SharedFunctionInfo> new_sfi = data->shared.ToHandleChecked();
    1166             :     DCHECK_EQ(new_sfi->script(), *new_script);
    1167             : 
    1168         706 :     if (!function_data_map.Lookup(script, mapping.first, &data)) continue;
    1169             :     Handle<SharedFunctionInfo> sfi;
    1170        1412 :     if (!data->shared.ToHandle(&sfi)) continue;
    1171             : 
    1172         682 :     isolate->debug()->DeoptimizeFunction(sfi);
    1173         682 :     isolate->compilation_cache()->Remove(sfi);
    1174        3696 :     for (auto& js_function : data->js_functions) {
    1175        1650 :       js_function->set_shared(*new_sfi);
    1176        3300 :       js_function->set_code(js_function->shared()->GetCode());
    1177             : 
    1178             :       js_function->set_raw_feedback_cell(
    1179        1650 :           *isolate->factory()->many_closures_cell());
    1180        1650 :       if (!js_function->is_compiled()) continue;
    1181        1650 :       JSFunction::EnsureFeedbackVector(js_function);
    1182             :     }
    1183             :   }
    1184         624 :   SharedFunctionInfo::ScriptIterator it(isolate, *new_script);
    1185        5070 :   for (SharedFunctionInfo sfi = it.Next(); !sfi.is_null(); sfi = it.Next()) {
    1186        1981 :     if (!sfi->HasBytecodeArray()) continue;
    1187        1841 :     FixedArray constants = sfi->GetBytecodeArray()->constant_pool();
    1188       16924 :     for (int i = 0; i < constants->length(); ++i) {
    1189       19827 :       if (!constants->get(i)->IsSharedFunctionInfo()) continue;
    1190             :       SharedFunctionInfo inner_sfi =
    1191         927 :           SharedFunctionInfo::cast(constants->get(i));
    1192             :       // See if there is a mapping from this function's start position to a
    1193             :       // unchanged function's id.
    1194             :       auto unchanged_it =
    1195        1854 :           start_position_to_unchanged_id.find(inner_sfi->StartPosition());
    1196         927 :       if (unchanged_it == start_position_to_unchanged_id.end()) continue;
    1197             : 
    1198             :       // Grab that function id from the new script's SFI list, which should have
    1199             :       // already been updated in in the unchanged pass.
    1200             :       SharedFunctionInfo old_unchanged_inner_sfi =
    1201         960 :           SharedFunctionInfo::cast(new_script->shared_function_infos()
    1202        1440 :                                        ->Get(unchanged_it->second)
    1203         960 :                                        ->GetHeapObject());
    1204         480 :       if (old_unchanged_inner_sfi == inner_sfi) continue;
    1205             :       DCHECK_NE(old_unchanged_inner_sfi, inner_sfi);
    1206             :       // Now some sanity checks. Make sure that the unchanged SFI has already
    1207             :       // been processed and patched to be on the new script ...
    1208             :       DCHECK_EQ(old_unchanged_inner_sfi->script(), *new_script);
    1209          36 :       constants->set(i, old_unchanged_inner_sfi);
    1210             :     }
    1211             :   }
    1212             : #ifdef DEBUG
    1213             :   {
    1214             :     // Check that all the functions in the new script are valid, that their
    1215             :     // function literals match what is expected, and that start positions are
    1216             :     // unique.
    1217             :     DisallowHeapAllocation no_gc;
    1218             : 
    1219             :     SharedFunctionInfo::ScriptIterator it(isolate, *new_script);
    1220             :     std::set<int> start_positions;
    1221             :     for (SharedFunctionInfo sfi = it.Next(); !sfi.is_null(); sfi = it.Next()) {
    1222             :       DCHECK_EQ(sfi->script(), *new_script);
    1223             :       DCHECK_EQ(sfi->FunctionLiteralId(isolate), it.CurrentIndex());
    1224             :       // Don't check the start position of the top-level function, as it can
    1225             :       // overlap with a function in the script.
    1226             :       if (sfi->is_toplevel()) {
    1227             :         DCHECK_EQ(start_positions.find(sfi->StartPosition()),
    1228             :                   start_positions.end());
    1229             :         start_positions.insert(sfi->StartPosition());
    1230             :       }
    1231             : 
    1232             :       if (!sfi->HasBytecodeArray()) continue;
    1233             :       // Check that all the functions in this function's constant pool are also
    1234             :       // on the new script, and that their id matches their index in the new
    1235             :       // scripts function list.
    1236             :       FixedArray constants = sfi->GetBytecodeArray()->constant_pool();
    1237             :       for (int i = 0; i < constants->length(); ++i) {
    1238             :         if (!constants->get(i)->IsSharedFunctionInfo()) continue;
    1239             :         SharedFunctionInfo inner_sfi =
    1240             :             SharedFunctionInfo::cast(constants->get(i));
    1241             :         DCHECK_EQ(inner_sfi->script(), *new_script);
    1242             :         DCHECK_EQ(inner_sfi, new_script->shared_function_infos()
    1243             :                                  ->Get(inner_sfi->FunctionLiteralId(isolate))
    1244             :                                  ->GetHeapObject());
    1245             :       }
    1246             :     }
    1247             :   }
    1248             : #endif
    1249             : 
    1250         624 :   if (restart_frame_fp) {
    1251        3684 :     for (StackFrameIterator it(isolate); !it.done(); it.Advance()) {
    1252        3684 :       if (it.frame()->fp() == restart_frame_fp) {
    1253         225 :         isolate->debug()->ScheduleFrameRestart(it.frame());
    1254         225 :         result->stack_changed = true;
    1255         225 :         break;
    1256             :       }
    1257             :     }
    1258             :   }
    1259             : 
    1260             :   int script_id = script->id();
    1261             :   script->set_id(new_script->id());
    1262             :   new_script->set_id(script_id);
    1263         624 :   result->status = debug::LiveEditResult::OK;
    1264         624 :   result->script = ToApiHandle<v8::debug::Script>(new_script);
    1265             : }
    1266             : 
    1267      133492 : void LiveEdit::InitializeThreadLocal(Debug* debug) {
    1268      133492 :   debug->thread_local_.restart_fp_ = 0;
    1269      133492 : }
    1270             : 
    1271          99 : bool LiveEdit::RestartFrame(JavaScriptFrame* frame) {
    1272          99 :   if (!LiveEdit::kFrameDropperSupported) return false;
    1273        2212 :   Isolate* isolate = frame->isolate();
    1274          99 :   StackFrame::Id break_frame_id = isolate->debug()->break_frame_id();
    1275          99 :   bool break_frame_found = break_frame_id == StackFrame::NO_ID;
    1276        2014 :   for (StackFrameIterator it(isolate); !it.done(); it.Advance()) {
    1277        2014 :     StackFrame* current = it.frame();
    1278        3722 :     break_frame_found = break_frame_found || break_frame_id == current->id();
    1279        2014 :     if (current->fp() == frame->fp()) {
    1280          99 :       if (break_frame_found) {
    1281          99 :         isolate->debug()->ScheduleFrameRestart(current);
    1282          99 :         return true;
    1283             :       } else {
    1284             :         return false;
    1285             :       }
    1286             :     }
    1287        3623 :     if (!break_frame_found) continue;
    1288         612 :     if (current->is_exit() || current->is_builtin_exit()) {
    1289             :       return false;
    1290             :     }
    1291         306 :     if (!current->is_java_script()) continue;
    1292             :     std::vector<Handle<SharedFunctionInfo>> shareds;
    1293         207 :     JavaScriptFrame::cast(current)->GetFunctions(&shareds);
    1294         621 :     for (auto& shared : shareds) {
    1295         207 :       if (IsResumableFunction(shared->kind())) {
    1296             :         return false;
    1297             :       }
    1298             :     }
    1299             :   }
    1300           0 :   return false;
    1301             : }
    1302             : 
    1303        1216 : void LiveEdit::CompareStrings(Isolate* isolate, Handle<String> s1,
    1304             :                               Handle<String> s2,
    1305             :                               std::vector<SourceChangeRange>* diffs) {
    1306        1216 :   s1 = String::Flatten(isolate, s1);
    1307        1216 :   s2 = String::Flatten(isolate, s2);
    1308             : 
    1309        1216 :   LineEndsWrapper line_ends1(isolate, s1);
    1310        1216 :   LineEndsWrapper line_ends2(isolate, s2);
    1311             : 
    1312        1216 :   LineArrayCompareInput input(s1, s2, line_ends1, line_ends2);
    1313             :   TokenizingLineArrayCompareOutput output(isolate, line_ends1, line_ends2, s1,
    1314             :                                           s2, diffs);
    1315             : 
    1316        1216 :   NarrowDownInput(&input, &output);
    1317             : 
    1318        1216 :   Comparator::CalculateDifference(&input, &output);
    1319        1216 : }
    1320             : 
    1321       14876 : int LiveEdit::TranslatePosition(const std::vector<SourceChangeRange>& diffs,
    1322             :                                 int position) {
    1323             :   auto it = std::lower_bound(diffs.begin(), diffs.end(), position,
    1324             :                              [](const SourceChangeRange& change, int position) {
    1325             :                                return change.end_position < position;
    1326             :                              });
    1327       14876 :   if (it != diffs.end() && position == it->end_position) {
    1328          50 :     return it->new_end_position;
    1329             :   }
    1330       14826 :   if (it == diffs.begin()) return position;
    1331             :   DCHECK(it == diffs.end() || position <= it->start_position);
    1332             :   it = std::prev(it);
    1333        8715 :   return position + (it->new_end_position - it->end_position);
    1334             : }
    1335             : }  // namespace internal
    1336      183867 : }  // namespace v8

Generated by: LCOV version 1.10