LCOV - code coverage report
Current view: top level - src/debug - liveedit.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 544 557 97.7 %
Date: 2017-10-20 Functions: 66 81 81.5 %

          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/assembler-inl.h"
       8             : #include "src/ast/scopes.h"
       9             : #include "src/code-stubs.h"
      10             : #include "src/compilation-cache.h"
      11             : #include "src/compiler.h"
      12             : #include "src/debug/debug.h"
      13             : #include "src/deoptimizer.h"
      14             : #include "src/frames-inl.h"
      15             : #include "src/global-handles.h"
      16             : #include "src/isolate-inl.h"
      17             : #include "src/messages.h"
      18             : #include "src/objects-inl.h"
      19             : #include "src/source-position-table.h"
      20             : #include "src/v8.h"
      21             : #include "src/v8memory.h"
      22             : 
      23             : namespace v8 {
      24             : namespace internal {
      25             : 
      26       28604 : void SetElementSloppy(Handle<JSObject> object,
      27             :                       uint32_t index,
      28             :                       Handle<Object> value) {
      29             :   // Ignore return value from SetElement. It can only be a failure if there
      30             :   // are element setters causing exceptions and the debugger context has none
      31             :   // of these.
      32             :   Object::SetElement(object->GetIsolate(), object, index, value,
      33       28604 :                      LanguageMode::kSloppy)
      34       28604 :       .Assert();
      35       28604 : }
      36             : 
      37             : 
      38             : // A simple implementation of dynamic programming algorithm. It solves
      39             : // the problem of finding the difference of 2 arrays. It uses a table of results
      40             : // of subproblems. Each cell contains a number together with 2-bit flag
      41             : // that helps building the chunk list.
      42             : class Differencer {
      43             :  public:
      44        1400 :   explicit Differencer(Comparator::Input* input)
      45        1400 :       : input_(input), len1_(input->GetLength1()), len2_(input->GetLength2()) {
      46        1400 :     buffer_ = NewArray<int>(len1_ * len2_);
      47        1400 :   }
      48             :   ~Differencer() {
      49        1400 :     DeleteArray(buffer_);
      50             :   }
      51             : 
      52             :   void Initialize() {
      53        1400 :     int array_size = len1_ * len2_;
      54      578134 :     for (int i = 0; i < array_size; i++) {
      55      578134 :       buffer_[i] = kEmptyCellValue;
      56             :     }
      57             :   }
      58             : 
      59             :   // Makes sure that result for the full problem is calculated and stored
      60             :   // in the table together with flags showing a path through subproblems.
      61             :   void FillTable() {
      62        1400 :     CompareUpToTail(0, 0);
      63             :   }
      64             : 
      65        1400 :   void SaveResult(Comparator::Output* chunk_writer) {
      66             :     ResultWriter writer(chunk_writer);
      67             : 
      68             :     int pos1 = 0;
      69             :     int pos2 = 0;
      70             :     while (true) {
      71       20962 :       if (pos1 < len1_) {
      72       20303 :         if (pos2 < len2_) {
      73             :           Direction dir = get_direction(pos1, pos2);
      74       19562 :           switch (dir) {
      75             :             case EQ:
      76             :               writer.eq();
      77       13357 :               pos1++;
      78       13357 :               pos2++;
      79       13357 :               break;
      80             :             case SKIP1:
      81             :               writer.skip1(1);
      82        2281 :               pos1++;
      83        2281 :               break;
      84             :             case SKIP2:
      85             :             case SKIP_ANY:
      86             :               writer.skip2(1);
      87        3924 :               pos2++;
      88        3924 :               break;
      89             :             default:
      90           0 :               UNREACHABLE();
      91             :           }
      92             :         } else {
      93         741 :           writer.skip1(len1_ - pos1);
      94             :           break;
      95             :         }
      96             :       } else {
      97         659 :         if (len2_ != pos2) {
      98         151 :           writer.skip2(len2_ - pos2);
      99             :         }
     100             :         break;
     101             :       }
     102             :     }
     103             :     writer.close();
     104        1400 :   }
     105             : 
     106             :  private:
     107             :   Comparator::Input* input_;
     108             :   int* buffer_;
     109             :   int len1_;
     110             :   int len2_;
     111             : 
     112             :   enum Direction {
     113             :     EQ = 0,
     114             :     SKIP1,
     115             :     SKIP2,
     116             :     SKIP_ANY,
     117             : 
     118             :     MAX_DIRECTION_FLAG_VALUE = SKIP_ANY
     119             :   };
     120             : 
     121             :   // Computes result for a subtask and optionally caches it in the buffer table.
     122             :   // All results values are shifted to make space for flags in the lower bits.
     123      527777 :   int CompareUpToTail(int pos1, int pos2) {
     124      527777 :     if (pos1 < len1_) {
     125      517564 :       if (pos2 < len2_) {
     126             :         int cached_res = get_value4(pos1, pos2);
     127      507923 :         if (cached_res == kEmptyCellValue) {
     128             :           Direction dir;
     129             :           int res;
     130      277639 :           if (input_->Equals(pos1, pos2)) {
     131       28901 :             res = CompareUpToTail(pos1 + 1, pos2 + 1);
     132             :             dir = EQ;
     133             :           } else {
     134      248738 :             int res1 = CompareUpToTail(pos1 + 1, pos2) +
     135      248738 :                 (1 << kDirectionSizeBits);
     136      248738 :             int res2 = CompareUpToTail(pos1, pos2 + 1) +
     137      248738 :                 (1 << kDirectionSizeBits);
     138      248738 :             if (res1 == res2) {
     139             :               res = res1;
     140             :               dir = SKIP_ANY;
     141      194378 :             } else if (res1 < res2) {
     142             :               res = res1;
     143             :               dir = SKIP1;
     144             :             } else {
     145             :               res = res2;
     146             :               dir = SKIP2;
     147             :             }
     148             :           }
     149             :           set_value4_and_dir(pos1, pos2, res, dir);
     150             :           cached_res = res;
     151             :         }
     152      507923 :         return cached_res;
     153             :       } else {
     154        9641 :         return (len1_ - pos1) << kDirectionSizeBits;
     155             :       }
     156             :     } else {
     157       10213 :       return (len2_ - pos2) << kDirectionSizeBits;
     158             :     }
     159             :   }
     160             : 
     161             :   inline int& get_cell(int i1, int i2) {
     162      805124 :     return buffer_[i1 + i2 * len1_];
     163             :   }
     164             : 
     165             :   // Each cell keeps a value plus direction. Value is multiplied by 4.
     166      277639 :   void set_value4_and_dir(int i1, int i2, int value4, Direction dir) {
     167             :     DCHECK_EQ(0, value4 & kDirectionMask);
     168      277639 :     get_cell(i1, i2) = value4 | dir;
     169             :   }
     170             : 
     171      507923 :   int get_value4(int i1, int i2) {
     172      507923 :     return get_cell(i1, i2) & (kMaxUInt32 ^ kDirectionMask);
     173             :   }
     174       19562 :   Direction get_direction(int i1, int i2) {
     175       19562 :     return static_cast<Direction>(get_cell(i1, i2) & kDirectionMask);
     176             :   }
     177             : 
     178             :   static const int kDirectionSizeBits = 2;
     179             :   static const int kDirectionMask = (1 << kDirectionSizeBits) - 1;
     180             :   static const int kEmptyCellValue = ~0u << kDirectionSizeBits;
     181             : 
     182             :   // This method only holds static assert statement (unfortunately you cannot
     183             :   // place one in class scope).
     184             :   void StaticAssertHolder() {
     185             :     STATIC_ASSERT(MAX_DIRECTION_FLAG_VALUE < (1 << kDirectionSizeBits));
     186             :   }
     187             : 
     188             :   class ResultWriter {
     189             :    public:
     190             :     explicit ResultWriter(Comparator::Output* chunk_writer)
     191             :         : chunk_writer_(chunk_writer), pos1_(0), pos2_(0),
     192        1400 :           pos1_begin_(-1), pos2_begin_(-1), has_open_chunk_(false) {
     193             :     }
     194             :     void eq() {
     195       13357 :       FlushChunk();
     196       13357 :       pos1_++;
     197       13357 :       pos2_++;
     198             :     }
     199             :     void skip1(int len1) {
     200             :       StartChunk();
     201        3022 :       pos1_ += len1;
     202             :     }
     203             :     void skip2(int len2) {
     204             :       StartChunk();
     205        4075 :       pos2_ += len2;
     206             :     }
     207             :     void close() {
     208        1400 :       FlushChunk();
     209             :     }
     210             : 
     211             :    private:
     212             :     Comparator::Output* chunk_writer_;
     213             :     int pos1_;
     214             :     int pos2_;
     215             :     int pos1_begin_;
     216             :     int pos2_begin_;
     217             :     bool has_open_chunk_;
     218             : 
     219             :     void StartChunk() {
     220        7097 :       if (!has_open_chunk_) {
     221        2644 :         pos1_begin_ = pos1_;
     222        2644 :         pos2_begin_ = pos2_;
     223        2644 :         has_open_chunk_ = true;
     224             :       }
     225             :     }
     226             : 
     227       14757 :     void FlushChunk() {
     228       14757 :       if (has_open_chunk_) {
     229             :         chunk_writer_->AddChunk(pos1_begin_, pos2_begin_,
     230        2644 :                                 pos1_ - pos1_begin_, pos2_ - pos2_begin_);
     231        2644 :         has_open_chunk_ = false;
     232             :       }
     233       14757 :     }
     234             :   };
     235             : };
     236             : 
     237             : 
     238        1400 : void Comparator::CalculateDifference(Comparator::Input* input,
     239             :                                      Comparator::Output* result_writer) {
     240        1400 :   Differencer differencer(input);
     241        1400 :   differencer.Initialize();
     242             :   differencer.FillTable();
     243        1400 :   differencer.SaveResult(result_writer);
     244        1400 : }
     245             : 
     246             : 
     247        3546 : static bool CompareSubstrings(Handle<String> s1, int pos1,
     248             :                               Handle<String> s2, int pos2, int len) {
     249       56227 :   for (int i = 0; i < len; i++) {
     250      159462 :     if (s1->Get(i + pos1) != s2->Get(i + pos2)) {
     251             :       return false;
     252             :     }
     253             :   }
     254             :   return true;
     255             : }
     256             : 
     257             : 
     258             : // Additional to Input interface. Lets switch Input range to subrange.
     259             : // More elegant way would be to wrap one Input as another Input object
     260             : // and translate positions there, but that would cost us additional virtual
     261             : // call per comparison.
     262         632 : class SubrangableInput : public Comparator::Input {
     263             :  public:
     264             :   virtual void SetSubrange1(int offset, int len) = 0;
     265             :   virtual void SetSubrange2(int offset, int len) = 0;
     266             : };
     267             : 
     268             : 
     269         632 : class SubrangableOutput : public Comparator::Output {
     270             :  public:
     271             :   virtual void SetSubrange1(int offset, int len) = 0;
     272             :   virtual void SetSubrange2(int offset, int len) = 0;
     273             : };
     274             : 
     275             : 
     276             : static int min(int a, int b) {
     277        1264 :   return a < b ? a : b;
     278             : }
     279             : 
     280             : 
     281             : // Finds common prefix and suffix in input. This parts shouldn't take space in
     282             : // linear programming table. Enable subranging in input and output.
     283         632 : static void NarrowDownInput(SubrangableInput* input,
     284             :     SubrangableOutput* output) {
     285         632 :   const int len1 = input->GetLength1();
     286         632 :   const int len2 = input->GetLength2();
     287             : 
     288             :   int common_prefix_len;
     289             :   int common_suffix_len;
     290             : 
     291             :   {
     292             :     common_prefix_len = 0;
     293             :     int prefix_limit = min(len1, len2);
     294        4751 :     while (common_prefix_len < prefix_limit &&
     295        2021 :         input->Equals(common_prefix_len, common_prefix_len)) {
     296        1466 :       common_prefix_len++;
     297             :     }
     298             : 
     299             :     common_suffix_len = 0;
     300         632 :     int suffix_limit = min(len1 - common_prefix_len, len2 - common_prefix_len);
     301             : 
     302        4761 :     while (common_suffix_len < suffix_limit &&
     303        2007 :         input->Equals(len1 - common_suffix_len - 1,
     304        4014 :         len2 - common_suffix_len - 1)) {
     305        1490 :       common_suffix_len++;
     306             :     }
     307             :   }
     308             : 
     309         632 :   if (common_prefix_len > 0 || common_suffix_len > 0) {
     310         285 :     int new_len1 = len1 - common_suffix_len - common_prefix_len;
     311         285 :     int new_len2 = len2 - common_suffix_len - common_prefix_len;
     312             : 
     313         285 :     input->SetSubrange1(common_prefix_len, new_len1);
     314         285 :     input->SetSubrange2(common_prefix_len, new_len2);
     315             : 
     316         285 :     output->SetSubrange1(common_prefix_len, new_len1);
     317         285 :     output->SetSubrange2(common_prefix_len, new_len2);
     318             :   }
     319         632 : }
     320             : 
     321             : 
     322             : // A helper class that writes chunk numbers into JSArray.
     323             : // Each chunk is stored as 3 array elements: (pos1_begin, pos1_end, pos2_end).
     324             : class CompareOutputArrayWriter {
     325             :  public:
     326             :   explicit CompareOutputArrayWriter(Isolate* isolate)
     327         632 :       : array_(isolate->factory()->NewJSArray(10)), current_size_(0) {}
     328             : 
     329             :   Handle<JSArray> GetResult() {
     330             :     return array_;
     331             :   }
     332             : 
     333        1762 :   void WriteChunk(int char_pos1, int char_pos2, int char_len1, int char_len2) {
     334             :     Isolate* isolate = array_->GetIsolate();
     335             :     SetElementSloppy(array_,
     336             :                      current_size_,
     337        3524 :                      Handle<Object>(Smi::FromInt(char_pos1), isolate));
     338             :     SetElementSloppy(array_,
     339        1762 :                      current_size_ + 1,
     340        1762 :                      Handle<Object>(Smi::FromInt(char_pos1 + char_len1),
     341        3524 :                                     isolate));
     342             :     SetElementSloppy(array_,
     343        1762 :                      current_size_ + 2,
     344        1762 :                      Handle<Object>(Smi::FromInt(char_pos2 + char_len2),
     345        3524 :                                     isolate));
     346        1762 :     current_size_ += 3;
     347        1762 :   }
     348             : 
     349             :  private:
     350             :   Handle<JSArray> array_;
     351             :   int current_size_;
     352             : };
     353             : 
     354             : 
     355             : // Represents 2 strings as 2 arrays of tokens.
     356             : // TODO(LiveEdit): Currently it's actually an array of charactres.
     357             : //     Make array of tokens instead.
     358         600 : class TokensCompareInput : public Comparator::Input {
     359             :  public:
     360             :   TokensCompareInput(Handle<String> s1, int offset1, int len1,
     361             :                        Handle<String> s2, int offset2, int len2)
     362             :       : s1_(s1), offset1_(offset1), len1_(len1),
     363         600 :         s2_(s2), offset2_(offset2), len2_(len2) {
     364             :   }
     365         600 :   virtual int GetLength1() {
     366         600 :     return len1_;
     367             :   }
     368         600 :   virtual int GetLength2() {
     369         600 :     return len2_;
     370             :   }
     371      264513 :   bool Equals(int index1, int index2) {
     372      793539 :     return s1_->Get(offset1_ + index1) == s2_->Get(offset2_ + index2);
     373             :   }
     374             : 
     375             :  private:
     376             :   Handle<String> s1_;
     377             :   int offset1_;
     378             :   int len1_;
     379             :   Handle<String> s2_;
     380             :   int offset2_;
     381             :   int len2_;
     382             : };
     383             : 
     384             : 
     385             : // Stores compare result in JSArray. Converts substring positions
     386             : // to absolute positions.
     387         600 : class TokensCompareOutput : public Comparator::Output {
     388             :  public:
     389             :   TokensCompareOutput(CompareOutputArrayWriter* array_writer,
     390             :                       int offset1, int offset2)
     391         600 :         : array_writer_(array_writer), offset1_(offset1), offset2_(offset2) {
     392             :   }
     393             : 
     394        1762 :   void AddChunk(int pos1, int pos2, int len1, int len2) {
     395        1762 :     array_writer_->WriteChunk(pos1 + offset1_, pos2 + offset2_, len1, len2);
     396        1762 :   }
     397             : 
     398             :  private:
     399             :   CompareOutputArrayWriter* array_writer_;
     400             :   int offset1_;
     401             :   int offset2_;
     402             : };
     403             : 
     404             : 
     405             : // Wraps raw n-elements line_ends array as a list of n+1 lines. The last line
     406             : // never has terminating new line character.
     407             : class LineEndsWrapper {
     408             :  public:
     409             :   explicit LineEndsWrapper(Handle<String> string)
     410             :       : ends_array_(String::CalculateLineEnds(string, false)),
     411        1264 :         string_len_(string->length()) {
     412             :   }
     413             :   int length() {
     414        1264 :     return ends_array_->length() + 1;
     415             :   }
     416             :   // Returns start for any line including start of the imaginary line after
     417             :   // the last line.
     418             :   int GetLineStart(int index) {
     419       17268 :     if (index == 0) {
     420             :       return 0;
     421             :     } else {
     422       12428 :       return GetLineEnd(index - 1);
     423             :     }
     424             :   }
     425       27296 :   int GetLineEnd(int index) {
     426       27296 :     if (index == ends_array_->length()) {
     427             :       // End of the last line is always an end of the whole string.
     428             :       // If the string ends with a new line character, the last line is an
     429             :       // empty string after this character.
     430        4624 :       return string_len_;
     431             :     } else {
     432       22672 :       return GetPosAfterNewLine(index);
     433             :     }
     434             :   }
     435             : 
     436             :  private:
     437             :   Handle<FixedArray> ends_array_;
     438             :   int string_len_;
     439             : 
     440       22672 :   int GetPosAfterNewLine(int index) {
     441       22672 :     return Smi::ToInt(ends_array_->get(index)) + 1;
     442             :   }
     443             : };
     444             : 
     445             : 
     446             : // Represents 2 strings as 2 arrays of lines.
     447           0 : class LineArrayCompareInput : public SubrangableInput {
     448             :  public:
     449             :   LineArrayCompareInput(Handle<String> s1, Handle<String> s2,
     450             :                         LineEndsWrapper line_ends1, LineEndsWrapper line_ends2)
     451             :       : s1_(s1), s2_(s2), line_ends1_(line_ends1),
     452             :         line_ends2_(line_ends2),
     453             :         subrange_offset1_(0), subrange_offset2_(0),
     454             :         subrange_len1_(line_ends1_.length()),
     455        1896 :         subrange_len2_(line_ends2_.length()) {
     456             :   }
     457        1264 :   int GetLength1() {
     458        1264 :     return subrange_len1_;
     459             :   }
     460        1264 :   int GetLength2() {
     461        1264 :     return subrange_len2_;
     462             :   }
     463        7434 :   bool Equals(int index1, int index2) {
     464        7434 :     index1 += subrange_offset1_;
     465        7434 :     index2 += subrange_offset2_;
     466             : 
     467        7434 :     int line_start1 = line_ends1_.GetLineStart(index1);
     468        7434 :     int line_start2 = line_ends2_.GetLineStart(index2);
     469        7434 :     int line_end1 = line_ends1_.GetLineEnd(index1);
     470        7434 :     int line_end2 = line_ends2_.GetLineEnd(index2);
     471        7434 :     int len1 = line_end1 - line_start1;
     472        7434 :     int len2 = line_end2 - line_start2;
     473        7434 :     if (len1 != len2) {
     474             :       return false;
     475             :     }
     476             :     return CompareSubstrings(s1_, line_start1, s2_, line_start2,
     477        3546 :                              len1);
     478             :   }
     479         285 :   void SetSubrange1(int offset, int len) {
     480         285 :     subrange_offset1_ = offset;
     481         285 :     subrange_len1_ = len;
     482         285 :   }
     483         285 :   void SetSubrange2(int offset, int len) {
     484         285 :     subrange_offset2_ = offset;
     485         285 :     subrange_len2_ = len;
     486         285 :   }
     487             : 
     488             :  private:
     489             :   Handle<String> s1_;
     490             :   Handle<String> s2_;
     491             :   LineEndsWrapper line_ends1_;
     492             :   LineEndsWrapper line_ends2_;
     493             :   int subrange_offset1_;
     494             :   int subrange_offset2_;
     495             :   int subrange_len1_;
     496             :   int subrange_len2_;
     497             : };
     498             : 
     499             : 
     500             : // Stores compare result in JSArray. For each chunk tries to conduct
     501             : // a fine-grained nested diff token-wise.
     502           0 : class TokenizingLineArrayCompareOutput : public SubrangableOutput {
     503             :  public:
     504         632 :   TokenizingLineArrayCompareOutput(LineEndsWrapper line_ends1,
     505             :                                    LineEndsWrapper line_ends2,
     506             :                                    Handle<String> s1, Handle<String> s2)
     507             :       : array_writer_(s1->GetIsolate()),
     508             :         line_ends1_(line_ends1), line_ends2_(line_ends2), s1_(s1), s2_(s2),
     509        1896 :         subrange_offset1_(0), subrange_offset2_(0) {
     510         632 :   }
     511             : 
     512         600 :   void AddChunk(int line_pos1, int line_pos2, int line_len1, int line_len2) {
     513         600 :     line_pos1 += subrange_offset1_;
     514         600 :     line_pos2 += subrange_offset2_;
     515             : 
     516         600 :     int char_pos1 = line_ends1_.GetLineStart(line_pos1);
     517         600 :     int char_pos2 = line_ends2_.GetLineStart(line_pos2);
     518        1200 :     int char_len1 = line_ends1_.GetLineStart(line_pos1 + line_len1) - char_pos1;
     519        1200 :     int char_len2 = line_ends2_.GetLineStart(line_pos2 + line_len2) - char_pos2;
     520             : 
     521         600 :     if (char_len1 < CHUNK_LEN_LIMIT && char_len2 < CHUNK_LEN_LIMIT) {
     522             :       // Chunk is small enough to conduct a nested token-level diff.
     523             :       HandleScope subTaskScope(s1_->GetIsolate());
     524             : 
     525             :       TokensCompareInput tokens_input(s1_, char_pos1, char_len1,
     526             :                                       s2_, char_pos2, char_len2);
     527             :       TokensCompareOutput tokens_output(&array_writer_, char_pos1,
     528         600 :                                           char_pos2);
     529             : 
     530         600 :       Comparator::CalculateDifference(&tokens_input, &tokens_output);
     531             :     } else {
     532           0 :       array_writer_.WriteChunk(char_pos1, char_pos2, char_len1, char_len2);
     533             :     }
     534         600 :   }
     535         285 :   void SetSubrange1(int offset, int len) {
     536         285 :     subrange_offset1_ = offset;
     537         285 :   }
     538         285 :   void SetSubrange2(int offset, int len) {
     539         285 :     subrange_offset2_ = offset;
     540         285 :   }
     541             : 
     542             :   Handle<JSArray> GetResult() {
     543             :     return array_writer_.GetResult();
     544             :   }
     545             : 
     546             :  private:
     547             :   static const int CHUNK_LEN_LIMIT = 800;
     548             : 
     549             :   CompareOutputArrayWriter array_writer_;
     550             :   LineEndsWrapper line_ends1_;
     551             :   LineEndsWrapper line_ends2_;
     552             :   Handle<String> s1_;
     553             :   Handle<String> s2_;
     554             :   int subrange_offset1_;
     555             :   int subrange_offset2_;
     556             : };
     557             : 
     558             : 
     559         632 : Handle<JSArray> LiveEdit::CompareStrings(Handle<String> s1,
     560             :                                          Handle<String> s2) {
     561         632 :   s1 = String::Flatten(s1);
     562         632 :   s2 = String::Flatten(s2);
     563             : 
     564             :   LineEndsWrapper line_ends1(s1);
     565             :   LineEndsWrapper line_ends2(s2);
     566             : 
     567             :   LineArrayCompareInput input(s1, s2, line_ends1, line_ends2);
     568         632 :   TokenizingLineArrayCompareOutput output(line_ends1, line_ends2, s1, s2);
     569             : 
     570         632 :   NarrowDownInput(&input, &output);
     571             : 
     572         632 :   Comparator::CalculateDifference(&input, &output);
     573             : 
     574         632 :   return output.GetResult();
     575             : }
     576             : 
     577             : 
     578             : // Unwraps JSValue object, returning its field "value"
     579         478 : static Handle<Object> UnwrapJSValue(Handle<JSValue> jsValue) {
     580         478 :   return Handle<Object>(jsValue->value(), jsValue->GetIsolate());
     581             : }
     582             : 
     583             : 
     584             : // Wraps any object into a OpaqueReference, that will hide the object
     585             : // from JavaScript.
     586        5292 : static Handle<JSValue> WrapInJSValue(Handle<HeapObject> object) {
     587             :   Isolate* isolate = object->GetIsolate();
     588        5292 :   Handle<JSFunction> constructor = isolate->opaque_reference_function();
     589             :   Handle<JSValue> result =
     590        5292 :       Handle<JSValue>::cast(isolate->factory()->NewJSObject(constructor));
     591        5292 :   result->set_value(*object);
     592        5292 :   return result;
     593             : }
     594             : 
     595             : 
     596       12909 : static Handle<SharedFunctionInfo> UnwrapSharedFunctionInfoFromJSValue(
     597             :     Handle<JSValue> jsValue) {
     598             :   Object* shared = jsValue->value();
     599       12909 :   CHECK(shared->IsSharedFunctionInfo());
     600       12909 :   return Handle<SharedFunctionInfo>(SharedFunctionInfo::cast(shared));
     601             : }
     602             : 
     603             : 
     604       21661 : static int GetArrayLength(Handle<JSArray> array) {
     605             :   Object* length = array->length();
     606       21661 :   CHECK(length->IsSmi());
     607       21661 :   return Smi::ToInt(length);
     608             : }
     609             : 
     610        3534 : void FunctionInfoWrapper::SetInitialProperties(Handle<String> name,
     611             :                                                int start_position,
     612             :                                                int end_position, int param_num,
     613             :                                                int parent_index,
     614             :                                                int function_literal_id) {
     615             :   HandleScope scope(isolate());
     616        3534 :   this->SetField(kFunctionNameOffset_, name);
     617        3534 :   this->SetSmiValueField(kStartPositionOffset_, start_position);
     618        3534 :   this->SetSmiValueField(kEndPositionOffset_, end_position);
     619        3534 :   this->SetSmiValueField(kParamNumOffset_, param_num);
     620        3534 :   this->SetSmiValueField(kParentIndexOffset_, parent_index);
     621        3534 :   this->SetSmiValueField(kFunctionLiteralIdOffset_, function_literal_id);
     622        3534 : }
     623             : 
     624        3534 : void FunctionInfoWrapper::SetSharedFunctionInfo(
     625             :     Handle<SharedFunctionInfo> info) {
     626        3534 :   Handle<JSValue> info_holder = WrapInJSValue(info);
     627        3534 :   this->SetField(kSharedFunctionInfoOffset_, info_holder);
     628        3534 : }
     629             : 
     630         478 : Handle<SharedFunctionInfo> FunctionInfoWrapper::GetSharedFunctionInfo() {
     631         478 :   Handle<Object> element = this->GetField(kSharedFunctionInfoOffset_);
     632         478 :   Handle<JSValue> value_wrapper = Handle<JSValue>::cast(element);
     633         478 :   Handle<Object> raw_result = UnwrapJSValue(value_wrapper);
     634         478 :   CHECK(raw_result->IsSharedFunctionInfo());
     635         478 :   return Handle<SharedFunctionInfo>::cast(raw_result);
     636             : }
     637             : 
     638        1758 : void SharedInfoWrapper::SetProperties(Handle<String> name,
     639             :                                       int start_position,
     640             :                                       int end_position,
     641             :                                       Handle<SharedFunctionInfo> info) {
     642             :   HandleScope scope(isolate());
     643        1758 :   this->SetField(kFunctionNameOffset_, name);
     644        1758 :   Handle<JSValue> info_holder = WrapInJSValue(info);
     645        1758 :   this->SetField(kSharedInfoOffset_, info_holder);
     646        1758 :   this->SetSmiValueField(kStartPositionOffset_, start_position);
     647        1758 :   this->SetSmiValueField(kEndPositionOffset_, end_position);
     648        1758 : }
     649             : 
     650             : 
     651        2510 : Handle<SharedFunctionInfo> SharedInfoWrapper::GetInfo() {
     652        2510 :   Handle<Object> element = this->GetField(kSharedInfoOffset_);
     653        2510 :   Handle<JSValue> value_wrapper = Handle<JSValue>::cast(element);
     654        2510 :   return UnwrapSharedFunctionInfoFromJSValue(value_wrapper);
     655             : }
     656             : 
     657             : 
     658      186123 : void LiveEdit::InitializeThreadLocal(Debug* debug) {
     659      186123 :   debug->thread_local_.restart_fp_ = 0;
     660      186123 : }
     661             : 
     662             : 
     663        1156 : MaybeHandle<JSArray> LiveEdit::GatherCompileInfo(Handle<Script> script,
     664             :                                                  Handle<String> source) {
     665          19 :   Isolate* isolate = script->GetIsolate();
     666             : 
     667             :   MaybeHandle<JSArray> infos;
     668             :   Handle<Object> original_source =
     669             :       Handle<Object>(script->source(), isolate);
     670        1156 :   script->set_source(*source);
     671             : 
     672             :   {
     673             :     // Creating verbose TryCatch from public API is currently the only way to
     674             :     // force code save location. We do not use this the object directly.
     675        1156 :     v8::TryCatch try_catch(reinterpret_cast<v8::Isolate*>(isolate));
     676        1156 :     try_catch.SetVerbose(true);
     677             : 
     678             :     // A logical 'try' section.
     679        1156 :     infos = Compiler::CompileForLiveEdit(script);
     680             :   }
     681             : 
     682             :   // A logical 'catch' section.
     683             :   Handle<JSObject> rethrow_exception;
     684        1156 :   if (isolate->has_pending_exception()) {
     685             :     Handle<Object> exception(isolate->pending_exception(), isolate);
     686          19 :     MessageLocation message_location = isolate->GetMessageLocation();
     687             : 
     688             :     isolate->clear_pending_message();
     689             :     isolate->clear_pending_exception();
     690             : 
     691             :     // If possible, copy positions from message object to exception object.
     692          19 :     if (exception->IsJSObject() && !message_location.script().is_null()) {
     693             :       rethrow_exception = Handle<JSObject>::cast(exception);
     694             : 
     695             :       Factory* factory = isolate->factory();
     696             :       Handle<String> start_pos_key = factory->InternalizeOneByteString(
     697          19 :           STATIC_CHAR_VECTOR("startPosition"));
     698             :       Handle<String> end_pos_key =
     699          19 :           factory->InternalizeOneByteString(STATIC_CHAR_VECTOR("endPosition"));
     700             :       Handle<String> script_obj_key =
     701          19 :           factory->InternalizeOneByteString(STATIC_CHAR_VECTOR("scriptObject"));
     702             :       Handle<Smi> start_pos(
     703          19 :           Smi::FromInt(message_location.start_pos()), isolate);
     704          19 :       Handle<Smi> end_pos(Smi::FromInt(message_location.end_pos()), isolate);
     705             :       Handle<JSObject> script_obj =
     706          19 :           Script::GetWrapper(message_location.script());
     707             :       Object::SetProperty(rethrow_exception, start_pos_key, start_pos,
     708          19 :                           LanguageMode::kSloppy)
     709          19 :           .Assert();
     710             :       Object::SetProperty(rethrow_exception, end_pos_key, end_pos,
     711          19 :                           LanguageMode::kSloppy)
     712          19 :           .Assert();
     713             :       Object::SetProperty(rethrow_exception, script_obj_key, script_obj,
     714          19 :                           LanguageMode::kSloppy)
     715          19 :           .Assert();
     716             :     }
     717             :   }
     718             : 
     719             :   // A logical 'finally' section.
     720        1156 :   script->set_source(*original_source);
     721             : 
     722        1156 :   if (rethrow_exception.is_null()) {
     723        1137 :     return infos.ToHandleChecked();
     724             :   } else {
     725             :     return isolate->Throw<JSArray>(rethrow_exception);
     726             :   }
     727             : }
     728             : 
     729             : // Patch function feedback vector.
     730             : // The feedback vector is a cache for complex object boilerplates and for a
     731             : // native context. We must clean cached values, or if the structure of the
     732             : // vector itself changes we need to allocate a new one.
     733             : class FeedbackVectorFixer {
     734             :  public:
     735         478 :   static void PatchFeedbackVector(FunctionInfoWrapper* compile_info_wrapper,
     736             :                                   Handle<SharedFunctionInfo> shared_info,
     737             :                                   Isolate* isolate) {
     738             :     // When feedback metadata changes, we have to create new array instances.
     739             :     // Since we cannot create instances when iterating heap, we should first
     740             :     // collect all functions and fix their literal arrays.
     741             :     Handle<FixedArray> function_instances =
     742         478 :         CollectJSFunctions(shared_info, isolate);
     743             : 
     744        3928 :     for (int i = 0; i < function_instances->length(); i++) {
     745             :       Handle<JSFunction> fun(JSFunction::cast(function_instances->get(i)));
     746             :       Handle<Cell> new_cell = isolate->factory()->NewManyClosuresCell(
     747        1486 :           isolate->factory()->undefined_value());
     748        1486 :       fun->set_feedback_vector_cell(*new_cell);
     749             :       // Only create feedback vectors if we already have the metadata.
     750        1486 :       if (shared_info->is_compiled()) JSFunction::EnsureLiterals(fun);
     751             :     }
     752         478 :   }
     753             : 
     754             :  private:
     755             :   // Iterates all function instances in the HEAP that refers to the
     756             :   // provided shared_info.
     757             :   template<typename Visitor>
     758         956 :   static void IterateJSFunctions(Handle<SharedFunctionInfo> shared_info,
     759             :                                  Visitor* visitor) {
     760         956 :     HeapIterator iterator(shared_info->GetHeap());
     761    17201716 :     for (HeapObject* obj = iterator.next(); obj != nullptr;
     762             :          obj = iterator.next()) {
     763    17200760 :       if (obj->IsJSFunction()) {
     764             :         JSFunction* function = JSFunction::cast(obj);
     765     2073412 :         if (function->shared() == *shared_info) {
     766             :           visitor->visit(function);
     767             :         }
     768             :       }
     769         956 :     }
     770         956 :   }
     771             : 
     772             :   // Finds all instances of JSFunction that refers to the provided shared_info
     773             :   // and returns array with them.
     774         478 :   static Handle<FixedArray> CollectJSFunctions(
     775             :       Handle<SharedFunctionInfo> shared_info, Isolate* isolate) {
     776             :     CountVisitor count_visitor;
     777         478 :     count_visitor.count = 0;
     778         478 :     IterateJSFunctions(shared_info, &count_visitor);
     779         478 :     int size = count_visitor.count;
     780             : 
     781         478 :     Handle<FixedArray> result = isolate->factory()->NewFixedArray(size);
     782         478 :     if (size > 0) {
     783             :       CollectVisitor collect_visitor(result);
     784         478 :       IterateJSFunctions(shared_info, &collect_visitor);
     785             :     }
     786         478 :     return result;
     787             :   }
     788             : 
     789             :   class CountVisitor {
     790             :    public:
     791             :     void visit(JSFunction* fun) {
     792        1486 :       count++;
     793             :     }
     794             :     int count;
     795             :   };
     796             : 
     797             :   class CollectVisitor {
     798             :    public:
     799             :     explicit CollectVisitor(Handle<FixedArray> output)
     800         478 :         : m_output(output), m_pos(0) {}
     801             : 
     802             :     void visit(JSFunction* fun) {
     803        2972 :       m_output->set(m_pos, fun);
     804        1486 :       m_pos++;
     805             :     }
     806             :    private:
     807             :     Handle<FixedArray> m_output;
     808             :     int m_pos;
     809             :   };
     810             : };
     811             : 
     812             : 
     813         478 : void LiveEdit::ReplaceFunctionCode(
     814             :     Handle<JSArray> new_compile_info_array,
     815             :     Handle<JSArray> shared_info_array) {
     816         505 :   Isolate* isolate = new_compile_info_array->GetIsolate();
     817             : 
     818             :   FunctionInfoWrapper compile_info_wrapper(new_compile_info_array);
     819             :   SharedInfoWrapper shared_info_wrapper(shared_info_array);
     820             : 
     821         478 :   Handle<SharedFunctionInfo> shared_info = shared_info_wrapper.GetInfo();
     822             :   Handle<SharedFunctionInfo> new_shared_info =
     823         478 :       compile_info_wrapper.GetSharedFunctionInfo();
     824             : 
     825         478 :   if (shared_info->is_compiled()) {
     826             :     // Take whatever code we can get from the new shared function info. We
     827             :     // expect activations of neither the old bytecode nor old FCG code, since
     828             :     // the lowest activation is going to be restarted.
     829             :     Handle<Code> old_code(shared_info->code());
     830             :     Handle<Code> new_code(new_shared_info->code());
     831             :     // Clear old bytecode. This will trigger self-healing if we do not install
     832             :     // new bytecode.
     833             :     shared_info->ClearBytecodeArray();
     834             :     shared_info->set_bytecode_array(new_shared_info->bytecode_array());
     835             : 
     836         442 :     if (shared_info->HasBreakInfo()) {
     837             :       // Existing break points will be re-applied. Reset the debug info here.
     838             :       isolate->debug()->RemoveBreakInfoAndMaybeFree(
     839          54 :           handle(shared_info->GetDebugInfo()));
     840             :     }
     841         442 :     shared_info->set_scope_info(new_shared_info->scope_info());
     842         442 :     shared_info->set_outer_scope_info(new_shared_info->outer_scope_info());
     843         442 :     shared_info->DisableOptimization(kLiveEdit);
     844             :     // Update the type feedback vector, if needed.
     845             :     Handle<FeedbackMetadata> new_feedback_metadata(
     846             :         new_shared_info->feedback_metadata());
     847         442 :     shared_info->set_feedback_metadata(*new_feedback_metadata);
     848             :   } else {
     849             :     shared_info->set_feedback_metadata(
     850          36 :         FeedbackMetadata::cast(isolate->heap()->empty_fixed_array()));
     851             :   }
     852             : 
     853             :   int start_position = compile_info_wrapper.GetStartPosition();
     854             :   int end_position = compile_info_wrapper.GetEndPosition();
     855             :   shared_info->set_start_position(start_position);
     856             :   shared_info->set_end_position(end_position);
     857             : 
     858             :   FeedbackVectorFixer::PatchFeedbackVector(&compile_info_wrapper, shared_info,
     859         478 :                                            isolate);
     860             : 
     861         478 :   isolate->debug()->DeoptimizeFunction(shared_info);
     862         478 : }
     863             : 
     864        1016 : void LiveEdit::FunctionSourceUpdated(Handle<JSArray> shared_info_array,
     865             :                                      int new_function_literal_id) {
     866             :   SharedInfoWrapper shared_info_wrapper(shared_info_array);
     867        1016 :   Handle<SharedFunctionInfo> shared_info = shared_info_wrapper.GetInfo();
     868             : 
     869             :   shared_info->set_function_literal_id(new_function_literal_id);
     870        1016 :   shared_info_array->GetIsolate()->debug()->DeoptimizeFunction(shared_info);
     871        1016 : }
     872             : 
     873         460 : void LiveEdit::FixupScript(Handle<Script> script, int max_function_literal_id) {
     874             :   Isolate* isolate = script->GetIsolate();
     875             :   Handle<FixedArray> old_infos(script->shared_function_infos(), isolate);
     876             :   Handle<FixedArray> new_infos(
     877         460 :       isolate->factory()->NewFixedArray(max_function_literal_id + 1));
     878         460 :   script->set_shared_function_infos(*new_infos);
     879         460 :   SharedFunctionInfo::ScriptIterator iterator(isolate, old_infos);
     880        1954 :   while (SharedFunctionInfo* shared = iterator.Next()) {
     881             :     // We can't use SharedFunctionInfo::SetScript(info, undefined_value()) here,
     882             :     // as we severed the link from the Script to the SharedFunctionInfo above.
     883             :     Handle<SharedFunctionInfo> info(shared, isolate);
     884        2988 :     info->set_script(isolate->heap()->undefined_value());
     885             :     Handle<Object> new_noscript_list = WeakFixedArray::Add(
     886        1494 :         isolate->factory()->noscript_shared_function_infos(), info);
     887             :     isolate->heap()->SetRootNoScriptSharedFunctionInfos(*new_noscript_list);
     888             : 
     889             :     // Put the SharedFunctionInfo at its new, correct location.
     890        1494 :     SharedFunctionInfo::SetScript(info, script);
     891        1494 :   }
     892         460 : }
     893             : 
     894        3576 : void LiveEdit::SetFunctionScript(Handle<JSValue> function_wrapper,
     895             :                                  Handle<Object> script_handle) {
     896             :   Handle<SharedFunctionInfo> shared_info =
     897        3576 :       UnwrapSharedFunctionInfoFromJSValue(function_wrapper);
     898             :   Isolate* isolate = function_wrapper->GetIsolate();
     899        7110 :   CHECK(script_handle->IsScript() || script_handle->IsUndefined(isolate));
     900        3576 :   SharedFunctionInfo::SetScript(shared_info, script_handle);
     901        3576 :   shared_info->DisableOptimization(kLiveEdit);
     902             : 
     903        3576 :   function_wrapper->GetIsolate()->compilation_cache()->Remove(shared_info);
     904        3576 : }
     905             : 
     906             : namespace {
     907             : // For a script text change (defined as position_change_array), translates
     908             : // position in unchanged text to position in changed text.
     909             : // Text change is a set of non-overlapping regions in text, that have changed
     910             : // their contents and length. It is specified as array of groups of 3 numbers:
     911             : // (change_begin, change_end, change_end_new_position).
     912             : // Each group describes a change in text; groups are sorted by change_begin.
     913             : // Only position in text beyond any changes may be successfully translated.
     914             : // If a positions is inside some region that changed, result is currently
     915             : // undefined.
     916       14300 : static int TranslatePosition(int original_position,
     917             :                              Handle<JSArray> position_change_array) {
     918             :   int position_diff = 0;
     919       14300 :   int array_len = GetArrayLength(position_change_array);
     920             :   Isolate* isolate = position_change_array->GetIsolate();
     921             :   // TODO(635): binary search may be used here
     922       46294 :   for (int i = 0; i < array_len; i += 3) {
     923             :     HandleScope scope(isolate);
     924             :     Handle<Object> element =
     925       29014 :         JSReceiver::GetElement(isolate, position_change_array, i)
     926       29014 :             .ToHandleChecked();
     927       14507 :     CHECK(element->IsSmi());
     928             :     int chunk_start = Handle<Smi>::cast(element)->value();
     929       14507 :     if (original_position < chunk_start) {
     930             :       break;
     931             :     }
     932       17694 :     element = JSReceiver::GetElement(isolate, position_change_array, i + 1)
     933       17694 :                   .ToHandleChecked();
     934        8847 :     CHECK(element->IsSmi());
     935             :     int chunk_end = Handle<Smi>::cast(element)->value();
     936             :     // Position mustn't be inside a chunk.
     937             :     DCHECK(original_position >= chunk_end);
     938       17694 :     element = JSReceiver::GetElement(isolate, position_change_array, i + 2)
     939       17694 :                   .ToHandleChecked();
     940        8847 :     CHECK(element->IsSmi());
     941             :     int chunk_changed_end = Handle<Smi>::cast(element)->value();
     942        8847 :     position_diff = chunk_changed_end - chunk_end;
     943             :   }
     944             : 
     945       14300 :   return original_position + position_diff;
     946             : }
     947             : 
     948         971 : void TranslateSourcePositionTable(Handle<BytecodeArray> code,
     949             :                                   Handle<JSArray> position_change_array) {
     950        1942 :   Isolate* isolate = code->GetIsolate();
     951         971 :   Zone zone(isolate->allocator(), ZONE_NAME);
     952         971 :   SourcePositionTableBuilder builder(&zone);
     953             : 
     954         971 :   Handle<ByteArray> source_position_table(code->SourcePositionTable());
     955       13194 :   for (SourcePositionTableIterator iterator(*source_position_table);
     956       11252 :        !iterator.done(); iterator.Advance()) {
     957       11252 :     SourcePosition position = iterator.source_position();
     958             :     position.SetScriptOffset(
     959       11252 :         TranslatePosition(position.ScriptOffset(), position_change_array));
     960       11252 :     builder.AddPosition(iterator.code_offset(), position,
     961       22504 :                         iterator.is_statement());
     962             :   }
     963             : 
     964             :   Handle<ByteArray> new_source_position_table(
     965         971 :       builder.ToSourcePositionTable(isolate));
     966         971 :   code->set_source_position_table(*new_source_position_table);
     967         971 :   LOG_CODE_EVENT(isolate,
     968             :                  CodeLinePosInfoRecordEvent(*Handle<AbstractCode>::cast(code),
     969         971 :                                             *new_source_position_table));
     970         971 : }
     971             : }  // namespace
     972             : 
     973        1016 : void LiveEdit::PatchFunctionPositions(Handle<JSArray> shared_info_array,
     974             :                                       Handle<JSArray> position_change_array) {
     975             :   SharedInfoWrapper shared_info_wrapper(shared_info_array);
     976        1016 :   Handle<SharedFunctionInfo> info = shared_info_wrapper.GetInfo();
     977             : 
     978             :   int old_function_start = info->start_position();
     979             :   int new_function_start = TranslatePosition(old_function_start,
     980        1016 :                                              position_change_array);
     981             :   int new_function_end = TranslatePosition(info->end_position(),
     982        1016 :                                            position_change_array);
     983             :   int new_function_token_pos =
     984        1016 :       TranslatePosition(info->function_token_position(), position_change_array);
     985             : 
     986             :   info->set_start_position(new_function_start);
     987             :   info->set_end_position(new_function_end);
     988             :   info->set_function_token_position(new_function_token_pos);
     989             : 
     990        1016 :   if (info->HasBytecodeArray()) {
     991             :     TranslateSourcePositionTable(handle(info->bytecode_array()),
     992         971 :                                  position_change_array);
     993             :   }
     994        1016 :   if (info->HasBreakInfo()) {
     995             :     // Existing break points will be re-applied. Reset the debug info here.
     996             :     info->GetIsolate()->debug()->RemoveBreakInfoAndMaybeFree(
     997          36 :         handle(info->GetDebugInfo()));
     998             :   }
     999        1016 : }
    1000             : 
    1001             : 
    1002          19 : static Handle<Script> CreateScriptCopy(Handle<Script> original) {
    1003             :   Isolate* isolate = original->GetIsolate();
    1004             : 
    1005             :   Handle<String> original_source(String::cast(original->source()));
    1006          19 :   Handle<Script> copy = isolate->factory()->NewScript(original_source);
    1007             : 
    1008          19 :   copy->set_name(original->name());
    1009             :   copy->set_line_offset(original->line_offset());
    1010             :   copy->set_column_offset(original->column_offset());
    1011             :   copy->set_type(original->type());
    1012          19 :   copy->set_context_data(original->context_data());
    1013          19 :   copy->set_eval_from_shared(original->eval_from_shared());
    1014             :   copy->set_eval_from_position(original->eval_from_position());
    1015             : 
    1016             :   Handle<FixedArray> infos(isolate->factory()->NewFixedArray(
    1017          19 :       original->shared_function_infos()->length()));
    1018          19 :   copy->set_shared_function_infos(*infos);
    1019             : 
    1020             :   // Copy all the flags, but clear compilation state.
    1021             :   copy->set_flags(original->flags());
    1022          19 :   copy->set_compilation_state(Script::COMPILATION_STATE_INITIAL);
    1023             : 
    1024          19 :   return copy;
    1025             : }
    1026             : 
    1027         460 : Handle<Object> LiveEdit::ChangeScriptSource(Handle<Script> original_script,
    1028             :                                             Handle<String> new_source,
    1029             :                                             Handle<Object> old_script_name) {
    1030          19 :   Isolate* isolate = original_script->GetIsolate();
    1031             :   Handle<Object> old_script_object;
    1032         460 :   if (old_script_name->IsString()) {
    1033          19 :     Handle<Script> old_script = CreateScriptCopy(original_script);
    1034          19 :     old_script->set_name(String::cast(*old_script_name));
    1035             :     old_script_object = old_script;
    1036          19 :     isolate->debug()->OnAfterCompile(old_script);
    1037             :   } else {
    1038             :     old_script_object = isolate->factory()->null_value();
    1039             :   }
    1040             : 
    1041         460 :   original_script->set_source(*new_source);
    1042             : 
    1043             :   // Drop line ends so that they will be recalculated.
    1044         920 :   original_script->set_line_ends(isolate->heap()->undefined_value());
    1045             : 
    1046         460 :   return old_script_object;
    1047             : }
    1048             : 
    1049             : 
    1050             : 
    1051          36 : void LiveEdit::ReplaceRefToNestedFunction(
    1052             :     Handle<JSValue> parent_function_wrapper,
    1053             :     Handle<JSValue> orig_function_wrapper,
    1054             :     Handle<JSValue> subst_function_wrapper) {
    1055             : 
    1056             :   Handle<SharedFunctionInfo> parent_shared =
    1057          36 :       UnwrapSharedFunctionInfoFromJSValue(parent_function_wrapper);
    1058             :   Handle<SharedFunctionInfo> orig_shared =
    1059          36 :       UnwrapSharedFunctionInfoFromJSValue(orig_function_wrapper);
    1060             :   Handle<SharedFunctionInfo> subst_shared =
    1061          36 :       UnwrapSharedFunctionInfoFromJSValue(subst_function_wrapper);
    1062             : 
    1063         576 :   for (RelocIterator it(parent_shared->code()); !it.done(); it.next()) {
    1064         540 :     if (it.rinfo()->rmode() == RelocInfo::EMBEDDED_OBJECT) {
    1065         216 :       if (it.rinfo()->target_object() == *orig_shared) {
    1066             :         it.rinfo()->set_target_object(*subst_shared);
    1067             :       }
    1068             :     }
    1069             :   }
    1070          36 : }
    1071             : 
    1072             : 
    1073             : // Check an activation against list of functions. If there is a function
    1074             : // that matches, its status in result array is changed to status argument value.
    1075       10374 : static bool CheckActivation(Handle<JSArray> shared_info_array,
    1076             :                             Handle<JSArray> result,
    1077             :                             StackFrame* frame,
    1078             :                             LiveEdit::FunctionPatchabilityStatus status) {
    1079       10374 :   if (!frame->is_java_script()) return false;
    1080             : 
    1081        5933 :   Handle<JSFunction> function(JavaScriptFrame::cast(frame)->function());
    1082             : 
    1083             :   Isolate* isolate = shared_info_array->GetIsolate();
    1084        5933 :   int len = GetArrayLength(shared_info_array);
    1085       11673 :   for (int i = 0; i < len; i++) {
    1086             :     HandleScope scope(isolate);
    1087             :     Handle<Object> element =
    1088       18015 :         JSReceiver::GetElement(isolate, shared_info_array, i).ToHandleChecked();
    1089        6005 :     Handle<JSValue> jsvalue = Handle<JSValue>::cast(element);
    1090             :     Handle<SharedFunctionInfo> shared =
    1091        6005 :         UnwrapSharedFunctionInfoFromJSValue(jsvalue);
    1092             : 
    1093       17750 :     if (function->shared() == *shared ||
    1094         459 :         (function->code()->is_optimized_code() &&
    1095         459 :          function->code()->Inlines(*shared))) {
    1096         530 :       SetElementSloppy(result, i, Handle<Smi>(Smi::FromInt(status), isolate));
    1097             :       return true;
    1098             :     }
    1099             :   }
    1100             :   return false;
    1101             : }
    1102             : 
    1103             : // Describes a set of call frames that execute any of listed functions.
    1104             : // Finding no such frames does not mean error.
    1105             : class MultipleFunctionTarget {
    1106             :  public:
    1107             :   MultipleFunctionTarget(Handle<JSArray> old_shared_array,
    1108             :                          Handle<JSArray> new_shared_array,
    1109             :                          Handle<JSArray> result)
    1110             :       : old_shared_array_(old_shared_array),
    1111             :         new_shared_array_(new_shared_array),
    1112         523 :         result_(result) {}
    1113             :   bool MatchActivation(StackFrame* frame,
    1114             :       LiveEdit::FunctionPatchabilityStatus status) {
    1115       10374 :     return CheckActivation(old_shared_array_, result_, frame, status);
    1116             :   }
    1117             :   const char* GetNotFoundMessage() const { return nullptr; }
    1118         496 :   bool FrameUsesNewTarget(StackFrame* frame) {
    1119         496 :     if (!frame->is_java_script()) return false;
    1120             :     JavaScriptFrame* jsframe = JavaScriptFrame::cast(frame);
    1121         328 :     Handle<SharedFunctionInfo> old_shared(jsframe->function()->shared());
    1122             :     Isolate* isolate = old_shared->GetIsolate();
    1123         328 :     int len = GetArrayLength(old_shared_array_);
    1124             :     // Find corresponding new shared function info and return whether it
    1125             :     // references new.target.
    1126         400 :     for (int i = 0; i < len; i++) {
    1127             :       HandleScope scope(isolate);
    1128             :       Handle<Object> old_element =
    1129         656 :           JSReceiver::GetElement(isolate, old_shared_array_, i)
    1130         656 :               .ToHandleChecked();
    1131         328 :       if (!old_shared.is_identical_to(UnwrapSharedFunctionInfoFromJSValue(
    1132         656 :               Handle<JSValue>::cast(old_element)))) {
    1133             :         continue;
    1134             :       }
    1135             : 
    1136             :       Handle<Object> new_element =
    1137         256 :           JSReceiver::GetElement(isolate, new_shared_array_, i)
    1138         512 :               .ToHandleChecked();
    1139         256 :       if (new_element->IsUndefined(isolate)) return false;
    1140             :       Handle<SharedFunctionInfo> new_shared =
    1141             :           UnwrapSharedFunctionInfoFromJSValue(
    1142         256 :               Handle<JSValue>::cast(new_element));
    1143         256 :       if (new_shared->scope_info()->HasNewTarget()) {
    1144             :         SetElementSloppy(
    1145             :             result_, i,
    1146             :             Handle<Smi>(
    1147             :                 Smi::FromInt(
    1148             :                     LiveEdit::FUNCTION_BLOCKED_NO_NEW_TARGET_ON_RESTART),
    1149          36 :                 isolate));
    1150          36 :         return true;
    1151             :       }
    1152             :       return false;
    1153             :     }
    1154             :     return false;
    1155             :   }
    1156             : 
    1157          18 :   void set_status(LiveEdit::FunctionPatchabilityStatus status) {
    1158             :     Isolate* isolate = old_shared_array_->GetIsolate();
    1159          18 :     int len = GetArrayLength(old_shared_array_);
    1160          36 :     for (int i = 0; i < len; ++i) {
    1161             :       Handle<Object> old_element =
    1162          54 :           JSReceiver::GetElement(isolate, result_, i).ToHandleChecked();
    1163          36 :       if (!old_element->IsSmi() ||
    1164             :           Smi::ToInt(*old_element) == LiveEdit::FUNCTION_AVAILABLE_FOR_PATCH) {
    1165             :         SetElementSloppy(result_, i,
    1166          36 :                          Handle<Smi>(Smi::FromInt(status), isolate));
    1167             :       }
    1168             :     }
    1169          18 :   }
    1170             : 
    1171             :  private:
    1172             :   Handle<JSArray> old_shared_array_;
    1173             :   Handle<JSArray> new_shared_array_;
    1174             :   Handle<JSArray> result_;
    1175             : };
    1176             : 
    1177             : 
    1178             : // Drops all call frame matched by target and all frames above them.
    1179             : template <typename TARGET>
    1180         622 : static const char* DropActivationsInActiveThreadImpl(Isolate* isolate,
    1181             :                                                      TARGET& target,  // NOLINT
    1182             :                                                      bool do_drop) {
    1183       10069 :   Debug* debug = isolate->debug();
    1184         622 :   Zone zone(isolate->allocator(), ZONE_NAME);
    1185         622 :   Vector<StackFrame*> frames = CreateStackMap(isolate, &zone);
    1186             : 
    1187             :   int top_frame_index = -1;
    1188             :   int frame_index = 0;
    1189       20138 :   for (; frame_index < frames.length(); frame_index++) {
    1190       20138 :     StackFrame* frame = frames[frame_index];
    1191       10069 :     if (frame->id() == debug->break_frame_id()) {
    1192             :       top_frame_index = frame_index;
    1193             :       break;
    1194             :     }
    1195        9447 :     if (target.MatchActivation(
    1196             :             frame, LiveEdit::FUNCTION_BLOCKED_UNDER_NATIVE_CODE)) {
    1197             :       // We are still above break_frame. It is not a target frame,
    1198             :       // it is a problem.
    1199             :       return "Debugger mark-up on stack is not found";
    1200             :     }
    1201             :   }
    1202             : 
    1203         622 :   if (top_frame_index == -1) {
    1204             :     // We haven't found break frame, but no function is blocking us anyway.
    1205             :     return target.GetNotFoundMessage();
    1206             :   }
    1207             : 
    1208             :   bool target_frame_found = false;
    1209             :   int bottom_js_frame_index = top_frame_index;
    1210             :   bool non_droppable_frame_found = false;
    1211             :   LiveEdit::FunctionPatchabilityStatus non_droppable_reason;
    1212             : 
    1213        3769 :   for (; frame_index < frames.length(); frame_index++) {
    1214        7628 :     StackFrame* frame = frames[frame_index];
    1215        7619 :     if (frame->is_exit() || frame->is_builtin_exit()) {
    1216             :       non_droppable_frame_found = true;
    1217             :       non_droppable_reason = LiveEdit::FUNCTION_BLOCKED_UNDER_NATIVE_CODE;
    1218             :       break;
    1219             :     }
    1220        3805 :     if (frame->is_java_script()) {
    1221             :       SharedFunctionInfo* shared =
    1222        2424 :           JavaScriptFrame::cast(frame)->function()->shared();
    1223        2424 :       if (IsResumableFunction(shared->kind())) {
    1224             :         non_droppable_frame_found = true;
    1225             :         non_droppable_reason = LiveEdit::FUNCTION_BLOCKED_UNDER_GENERATOR;
    1226             :         break;
    1227             :       }
    1228             :     }
    1229        3769 :     if (target.MatchActivation(
    1230             :             frame, LiveEdit::FUNCTION_BLOCKED_ON_ACTIVE_STACK)) {
    1231             :       target_frame_found = true;
    1232             :       bottom_js_frame_index = frame_index;
    1233             :     }
    1234             :   }
    1235             : 
    1236         622 :   if (non_droppable_frame_found) {
    1237             :     // There is a C or generator frame on stack.  We can't drop C frames, and we
    1238             :     // can't restart generators.  Check that there are no target frames below
    1239             :     // them.
    1240         143 :     for (; frame_index < frames.length(); frame_index++) {
    1241         340 :       StackFrame* frame = frames[frame_index];
    1242         170 :       if (frame->is_java_script()) {
    1243         117 :         if (target.MatchActivation(frame, non_droppable_reason)) {
    1244             :           // Fail.
    1245             :           return nullptr;
    1246             :         }
    1247         216 :         if (non_droppable_reason ==
    1248         108 :                 LiveEdit::FUNCTION_BLOCKED_UNDER_GENERATOR &&
    1249             :             !target_frame_found) {
    1250             :           // Fail.
    1251          18 :           target.set_status(non_droppable_reason);
    1252          18 :           return nullptr;
    1253             :         }
    1254             :       }
    1255             :     }
    1256             :   }
    1257             : 
    1258             :   // We cannot restart a frame that uses new.target.
    1259        1190 :   if (target.FrameUsesNewTarget(frames[bottom_js_frame_index])) return nullptr;
    1260             : 
    1261         559 :   if (!do_drop) {
    1262             :     // We are in check-only mode.
    1263             :     return nullptr;
    1264             :   }
    1265             : 
    1266         559 :   if (!target_frame_found) {
    1267             :     // Nothing to drop.
    1268             :     return target.GetNotFoundMessage();
    1269             :   }
    1270             : 
    1271         319 :   if (!LiveEdit::kFrameDropperSupported) {
    1272             :     return "Stack manipulations are not supported in this architecture.";
    1273             :   }
    1274             : 
    1275         319 :   debug->ScheduleFrameRestart(frames[bottom_js_frame_index]);
    1276         319 :   return nullptr;
    1277             : }
    1278             : 
    1279             : 
    1280             : // Fills result array with statuses of functions. Modifies the stack
    1281             : // removing all listed function if possible and if do_drop is true.
    1282         523 : static const char* DropActivationsInActiveThread(
    1283             :     Handle<JSArray> old_shared_array, Handle<JSArray> new_shared_array,
    1284             :     Handle<JSArray> result, bool do_drop) {
    1285             :   MultipleFunctionTarget target(old_shared_array, new_shared_array, result);
    1286             :   Isolate* isolate = old_shared_array->GetIsolate();
    1287             : 
    1288             :   const char* message =
    1289         523 :       DropActivationsInActiveThreadImpl(isolate, target, do_drop);
    1290         523 :   if (message) {
    1291             :     return message;
    1292             :   }
    1293             : 
    1294         523 :   int array_len = GetArrayLength(old_shared_array);
    1295             : 
    1296             :   // Replace "blocked on active" with "replaced on active" status.
    1297        1064 :   for (int i = 0; i < array_len; i++) {
    1298             :     Handle<Object> obj =
    1299        1623 :         JSReceiver::GetElement(isolate, result, i).ToHandleChecked();
    1300         541 :     if (*obj == Smi::FromInt(LiveEdit::FUNCTION_BLOCKED_ON_ACTIVE_STACK)) {
    1301             :       Handle<Object> replaced(
    1302             :           Smi::FromInt(LiveEdit::FUNCTION_REPLACED_ON_ACTIVE_STACK), isolate);
    1303         220 :       SetElementSloppy(result, i, replaced);
    1304             :     }
    1305             :   }
    1306             :   return nullptr;
    1307             : }
    1308             : 
    1309             : 
    1310         559 : bool LiveEdit::FindActiveGenerators(Handle<FixedArray> shared_info_array,
    1311             :                                     Handle<FixedArray> result,
    1312             :                                     int len) {
    1313             :   Isolate* isolate = shared_info_array->GetIsolate();
    1314             :   bool found_suspended_activations = false;
    1315             : 
    1316             :   DCHECK_LE(len, result->length());
    1317             : 
    1318             :   FunctionPatchabilityStatus active = FUNCTION_BLOCKED_ACTIVE_GENERATOR;
    1319             : 
    1320         559 :   Heap* heap = isolate->heap();
    1321         559 :   HeapIterator iterator(heap, HeapIterator::kFilterUnreachable);
    1322             :   HeapObject* obj = nullptr;
    1323     9671407 :   while ((obj = iterator.next()) != nullptr) {
    1324     9670289 :     if (!obj->IsJSGeneratorObject()) continue;
    1325             : 
    1326             :     JSGeneratorObject* gen = JSGeneratorObject::cast(obj);
    1327         180 :     if (gen->is_closed()) continue;
    1328             : 
    1329             :     HandleScope scope(isolate);
    1330             : 
    1331         252 :     for (int i = 0; i < len; i++) {
    1332             :       Handle<JSValue> jsvalue = Handle<JSValue>::cast(
    1333         126 :           FixedArray::get(*shared_info_array, i, isolate));
    1334             :       Handle<SharedFunctionInfo> shared =
    1335         126 :           UnwrapSharedFunctionInfoFromJSValue(jsvalue);
    1336             : 
    1337         126 :       if (gen->function()->shared() == *shared) {
    1338             :         result->set(i, Smi::FromInt(active));
    1339             :         found_suspended_activations = true;
    1340             :       }
    1341             :     }
    1342             :   }
    1343             : 
    1344         559 :   return found_suspended_activations;
    1345             : }
    1346             : 
    1347             : 
    1348           0 : class InactiveThreadActivationsChecker : public ThreadVisitor {
    1349             :  public:
    1350             :   InactiveThreadActivationsChecker(Handle<JSArray> old_shared_array,
    1351             :                                    Handle<JSArray> result)
    1352             :       : old_shared_array_(old_shared_array),
    1353             :         result_(result),
    1354         523 :         has_blocked_functions_(false) {}
    1355           0 :   void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
    1356           0 :     for (StackFrameIterator it(isolate, top); !it.done(); it.Advance()) {
    1357             :       has_blocked_functions_ |=
    1358             :           CheckActivation(old_shared_array_, result_, it.frame(),
    1359           0 :                           LiveEdit::FUNCTION_BLOCKED_ON_OTHER_STACK);
    1360             :     }
    1361           0 :   }
    1362             :   bool HasBlockedFunctions() {
    1363             :     return has_blocked_functions_;
    1364             :   }
    1365             : 
    1366             :  private:
    1367             :   Handle<JSArray> old_shared_array_;
    1368             :   Handle<JSArray> result_;
    1369             :   bool has_blocked_functions_;
    1370             : };
    1371             : 
    1372             : 
    1373         559 : Handle<JSArray> LiveEdit::CheckAndDropActivations(
    1374             :     Handle<JSArray> old_shared_array, Handle<JSArray> new_shared_array,
    1375             :     bool do_drop) {
    1376         523 :   Isolate* isolate = old_shared_array->GetIsolate();
    1377         559 :   int len = GetArrayLength(old_shared_array);
    1378             : 
    1379             :   DCHECK(old_shared_array->HasFastElements());
    1380             :   Handle<FixedArray> old_shared_array_elements(
    1381             :       FixedArray::cast(old_shared_array->elements()));
    1382             : 
    1383         559 :   Handle<JSArray> result = isolate->factory()->NewJSArray(len);
    1384             :   result->set_length(Smi::FromInt(len));
    1385         559 :   JSObject::EnsureWritableFastElements(result);
    1386             :   Handle<FixedArray> result_elements =
    1387             :       handle(FixedArray::cast(result->elements()), isolate);
    1388             : 
    1389             :   // Fill the default values.
    1390        1136 :   for (int i = 0; i < len; i++) {
    1391             :     FunctionPatchabilityStatus status = FUNCTION_AVAILABLE_FOR_PATCH;
    1392             :     result_elements->set(i, Smi::FromInt(status));
    1393             :   }
    1394             : 
    1395             :   // Scan the heap for active generators -- those that are either currently
    1396             :   // running (as we wouldn't want to restart them, because we don't know where
    1397             :   // to restart them from) or suspended.  Fail if any one corresponds to the set
    1398             :   // of functions being edited.
    1399         559 :   if (FindActiveGenerators(old_shared_array_elements, result_elements, len)) {
    1400          36 :     return result;
    1401             :   }
    1402             : 
    1403             :   // Check inactive threads. Fail if some functions are blocked there.
    1404             :   InactiveThreadActivationsChecker inactive_threads_checker(old_shared_array,
    1405             :                                                             result);
    1406             :   isolate->thread_manager()->IterateArchivedThreads(
    1407         523 :       &inactive_threads_checker);
    1408         523 :   if (inactive_threads_checker.HasBlockedFunctions()) {
    1409           0 :     return result;
    1410             :   }
    1411             : 
    1412             :   // Try to drop activations from the current stack.
    1413             :   const char* error_message = DropActivationsInActiveThread(
    1414         523 :       old_shared_array, new_shared_array, result, do_drop);
    1415         523 :   if (error_message != nullptr) {
    1416             :     // Add error message as an array extra element.
    1417             :     Handle<String> str =
    1418           0 :         isolate->factory()->NewStringFromAsciiChecked(error_message);
    1419           0 :     SetElementSloppy(result, len, str);
    1420             :   }
    1421         523 :   return result;
    1422             : }
    1423             : 
    1424             : 
    1425             : // Describes a single callframe a target. Not finding this frame
    1426             : // means an error.
    1427             : class SingleFrameTarget {
    1428             :  public:
    1429             :   explicit SingleFrameTarget(JavaScriptFrame* frame)
    1430             :       : m_frame(frame),
    1431          99 :         m_saved_status(LiveEdit::FUNCTION_AVAILABLE_FOR_PATCH) {}
    1432             : 
    1433        2959 :   bool MatchActivation(StackFrame* frame,
    1434             :       LiveEdit::FunctionPatchabilityStatus status) {
    1435        2959 :     if (frame->fp() == m_frame->fp()) {
    1436          99 :       m_saved_status = status;
    1437             :       return true;
    1438             :     }
    1439             :     return false;
    1440             :   }
    1441             :   const char* GetNotFoundMessage() const {
    1442             :     return "Failed to found requested frame";
    1443             :   }
    1444             :   LiveEdit::FunctionPatchabilityStatus saved_status() {
    1445             :     return m_saved_status;
    1446             :   }
    1447             :   void set_status(LiveEdit::FunctionPatchabilityStatus status) {
    1448           0 :     m_saved_status = status;
    1449             :   }
    1450             : 
    1451          99 :   bool FrameUsesNewTarget(StackFrame* frame) {
    1452          99 :     if (!frame->is_java_script()) return false;
    1453             :     JavaScriptFrame* jsframe = JavaScriptFrame::cast(frame);
    1454          99 :     Handle<SharedFunctionInfo> shared(jsframe->function()->shared());
    1455          99 :     return shared->scope_info()->HasNewTarget();
    1456             :   }
    1457             : 
    1458             :  private:
    1459             :   JavaScriptFrame* m_frame;
    1460             :   LiveEdit::FunctionPatchabilityStatus m_saved_status;
    1461             : };
    1462             : 
    1463             : // Finds a drops required frame and all frames above.
    1464             : // Returns error message or nullptr.
    1465          99 : const char* LiveEdit::RestartFrame(JavaScriptFrame* frame) {
    1466             :   SingleFrameTarget target(frame);
    1467             : 
    1468             :   const char* result =
    1469          99 :       DropActivationsInActiveThreadImpl(frame->isolate(), target, true);
    1470          99 :   if (result != nullptr) {
    1471             :     return result;
    1472             :   }
    1473          99 :   if (target.saved_status() == LiveEdit::FUNCTION_BLOCKED_UNDER_NATIVE_CODE) {
    1474             :     return "Function is blocked under native code";
    1475             :   }
    1476          99 :   if (target.saved_status() == LiveEdit::FUNCTION_BLOCKED_UNDER_GENERATOR) {
    1477             :     return "Function is blocked under a generator activation";
    1478             :   }
    1479          99 :   return nullptr;
    1480             : }
    1481             : 
    1482        1137 : Handle<JSArray> LiveEditFunctionTracker::Collect(FunctionLiteral* node,
    1483             :                                                  Handle<Script> script,
    1484             :                                                  Zone* zone, Isolate* isolate) {
    1485        1137 :   LiveEditFunctionTracker visitor(script, zone, isolate);
    1486        1137 :   visitor.VisitFunctionLiteral(node);
    1487        1137 :   return visitor.result_;
    1488             : }
    1489             : 
    1490        1137 : LiveEditFunctionTracker::LiveEditFunctionTracker(Handle<Script> script,
    1491             :                                                  Zone* zone, Isolate* isolate)
    1492             :     : AstTraversalVisitor<LiveEditFunctionTracker>(isolate) {
    1493        1137 :   current_parent_index_ = -1;
    1494        1137 :   isolate_ = isolate;
    1495        1137 :   len_ = 0;
    1496        1137 :   result_ = isolate->factory()->NewJSArray(10);
    1497        1137 :   script_ = script;
    1498        1137 :   zone_ = zone;
    1499        1137 : }
    1500             : 
    1501        7068 : void LiveEditFunctionTracker::VisitFunctionLiteral(FunctionLiteral* node) {
    1502             :   // FunctionStarted is called in pre-order.
    1503        3534 :   FunctionStarted(node);
    1504             :   // Recurse using the regular traversal.
    1505        3534 :   AstTraversalVisitor::VisitFunctionLiteral(node);
    1506             :   // FunctionDone are called in post-order.
    1507             :   Handle<SharedFunctionInfo> info =
    1508       10602 :       script_->FindSharedFunctionInfo(isolate_, node).ToHandleChecked();
    1509        3534 :   FunctionDone(info, node->scope());
    1510        3534 : }
    1511             : 
    1512       10602 : void LiveEditFunctionTracker::FunctionStarted(FunctionLiteral* fun) {
    1513        3534 :   HandleScope handle_scope(isolate_);
    1514        7068 :   FunctionInfoWrapper info = FunctionInfoWrapper::Create(isolate_);
    1515             :   info.SetInitialProperties(fun->name(isolate_), fun->start_position(),
    1516             :                             fun->end_position(), fun->parameter_count(),
    1517        7068 :                             current_parent_index_, fun->function_literal_id());
    1518        3534 :   current_parent_index_ = len_;
    1519        7068 :   SetElementSloppy(result_, len_, info.GetJSArray());
    1520        3534 :   len_++;
    1521        3534 : }
    1522             : 
    1523             : // Saves full information about a function: its code, its scope info
    1524             : // and a SharedFunctionInfo object.
    1525        3534 : void LiveEditFunctionTracker::FunctionDone(Handle<SharedFunctionInfo> shared,
    1526             :                                            Scope* scope) {
    1527        3534 :   HandleScope handle_scope(isolate_);
    1528             :   FunctionInfoWrapper info = FunctionInfoWrapper::cast(
    1529       10602 :       *JSReceiver::GetElement(isolate_, result_, current_parent_index_)
    1530        7068 :            .ToHandleChecked());
    1531        3534 :   info.SetSharedFunctionInfo(shared);
    1532             : 
    1533        3534 :   Handle<Object> scope_info_list = SerializeFunctionScope(scope);
    1534             :   info.SetFunctionScopeInfo(scope_info_list);
    1535             : 
    1536        3534 :   current_parent_index_ = info.GetParentIndex();
    1537        3534 : }
    1538             : 
    1539        3534 : Handle<Object> LiveEditFunctionTracker::SerializeFunctionScope(Scope* scope) {
    1540        3534 :   Handle<JSArray> scope_info_list = isolate_->factory()->NewJSArray(10);
    1541             :   int scope_info_length = 0;
    1542             : 
    1543             :   // Saves some description of scope. It stores name and indexes of
    1544             :   // variables in the whole scope chain. Null-named slots delimit
    1545             :   // scopes of this chain.
    1546        9669 :   Scope* current_scope = scope;
    1547       16737 :   while (current_scope != nullptr) {
    1548        9669 :     HandleScope handle_scope(isolate_);
    1549       57535 :     for (Variable* var : *current_scope->locals()) {
    1550       23833 :       if (!var->IsContextSlot()) continue;
    1551        4788 :       int context_index = var->index() - Context::MIN_CONTEXT_SLOTS;
    1552        4788 :       int location = scope_info_length + context_index * 2;
    1553        9576 :       SetElementSloppy(scope_info_list, location, var->name());
    1554        4788 :       SetElementSloppy(scope_info_list, location + 1,
    1555       14364 :                        handle(Smi::FromInt(var->index()), isolate_));
    1556             :     }
    1557        9669 :     scope_info_length += current_scope->ContextLocalCount() * 2;
    1558             :     SetElementSloppy(scope_info_list, scope_info_length,
    1559       29007 :                      isolate_->factory()->null_value());
    1560        9669 :     scope_info_length++;
    1561             : 
    1562             :     current_scope = current_scope->outer_scope();
    1563             :   }
    1564             : 
    1565        3534 :   return scope_info_list;
    1566             : }
    1567             : 
    1568             : }  // namespace internal
    1569             : }  // namespace v8

Generated by: LCOV version 1.10