LCOV - code coverage report
Current view: top level - src/debug - liveedit.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 558 573 97.4 %
Date: 2017-04-26 Functions: 69 86 80.2 %

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

Generated by: LCOV version 1.10