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