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/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 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       .Assert();
     34 }
     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   explicit Differencer(Comparator::Input* input)
     44       : input_(input), len1_(input->GetLength1()), len2_(input->GetLength2()) {
     45     buffer_ = NewArray<int>(len1_ * len2_);
     46   }
     47   ~Differencer() {
     48     DeleteArray(buffer_);
     49   }
     50 
     51   void Initialize() {
     52     int array_size = len1_ * len2_;
     53     for (int i = 0; i < array_size; i++) {
     54       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     CompareUpToTail(0, 0);
     62   }
     63 
     64   void SaveResult(Comparator::Output* chunk_writer) {
     65     ResultWriter writer(chunk_writer);
     66 
     67     int pos1 = 0;
     68     int pos2 = 0;
     69     while (true) {
     70       if (pos1 < len1_) {
     71         if (pos2 < len2_) {
     72           Direction dir = get_direction(pos1, pos2);
     73           switch (dir) {
     74             case EQ:
     75               writer.eq();
     76               pos1++;
     77               pos2++;
     78               break;
     79             case SKIP1:
     80               writer.skip1(1);
     81               pos1++;
     82               break;
     83             case SKIP2:
     84             case SKIP_ANY:
     85               writer.skip2(1);
     86               pos2++;
     87               break;
     88             default:
     89               UNREACHABLE();
     90           }
     91         } else {
     92           writer.skip1(len1_ - pos1);
     93           break;
     94         }
     95       } else {
     96         if (len2_ != pos2) {
     97           writer.skip2(len2_ - pos2);
     98         }
     99         break;
    100       }
    101     }
    102     writer.close();
    103   }
    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   int CompareUpToTail(int pos1, int pos2) {
    123     if (pos1 < len1_) {
    124       if (pos2 < len2_) {
    125         int cached_res = get_value4(pos1, pos2);
    126         if (cached_res == kEmptyCellValue) {
    127           Direction dir;
    128           int res;
    129           if (input_->Equals(pos1, pos2)) {
    130             res = CompareUpToTail(pos1 + 1, pos2 + 1);
    131             dir = EQ;
    132           } else {
    133             int res1 = CompareUpToTail(pos1 + 1, pos2) +
    134                 (1 << kDirectionSizeBits);
    135             int res2 = CompareUpToTail(pos1, pos2 + 1) +
    136                 (1 << kDirectionSizeBits);
    137             if (res1 == res2) {
    138               res = res1;
    139               dir = SKIP_ANY;
    140             } 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         return cached_res;
    152       } else {
    153         return (len1_ - pos1) << kDirectionSizeBits;
    154       }
    155     } else {
    156       return (len2_ - pos2) << kDirectionSizeBits;
    157     }
    158   }
    159 
    160   inline int& get_cell(int i1, int i2) {
    161     return buffer_[i1 + i2 * len1_];
    162   }
    163 
    164   // Each cell keeps a value plus direction. Value is multiplied by 4.
    165   void set_value4_and_dir(int i1, int i2, int value4, Direction dir) {
    166     DCHECK((value4 & kDirectionMask) == 0);
    167     get_cell(i1, i2) = value4 | dir;
    168   }
    169 
    170   int get_value4(int i1, int i2) {
    171     return get_cell(i1, i2) & (kMaxUInt32 ^ kDirectionMask);
    172   }
    173   Direction get_direction(int i1, int i2) {
    174     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           pos1_begin_(-1), pos2_begin_(-1), has_open_chunk_(false) {
    192     }
    193     void eq() {
    194       FlushChunk();
    195       pos1_++;
    196       pos2_++;
    197     }
    198     void skip1(int len1) {
    199       StartChunk();
    200       pos1_ += len1;
    201     }
    202     void skip2(int len2) {
    203       StartChunk();
    204       pos2_ += len2;
    205     }
    206     void close() {
    207       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       if (!has_open_chunk_) {
    220         pos1_begin_ = pos1_;
    221         pos2_begin_ = pos2_;
    222         has_open_chunk_ = true;
    223       }
    224     }
    225 
    226     void FlushChunk() {
    227       if (has_open_chunk_) {
    228         chunk_writer_->AddChunk(pos1_begin_, pos2_begin_,
    229                                 pos1_ - pos1_begin_, pos2_ - pos2_begin_);
    230         has_open_chunk_ = false;
    231       }
    232     }
    233   };
    234 };
    235 
    236 
    237 void Comparator::CalculateDifference(Comparator::Input* input,
    238                                      Comparator::Output* result_writer) {
    239   Differencer differencer(input);
    240   differencer.Initialize();
    241   differencer.FillTable();
    242   differencer.SaveResult(result_writer);
    243 }
    244 
    245 
    246 static bool CompareSubstrings(Handle<String> s1, int pos1,
    247                               Handle<String> s2, int pos2, int len) {
    248   for (int i = 0; i < len; i++) {
    249     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 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 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   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 static void NarrowDownInput(SubrangableInput* input,
    283     SubrangableOutput* output) {
    284   const int len1 = input->GetLength1();
    285   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     while (common_prefix_len < prefix_limit &&
    294         input->Equals(common_prefix_len, common_prefix_len)) {
    295       common_prefix_len++;
    296     }
    297 
    298     common_suffix_len = 0;
    299     int suffix_limit = min(len1 - common_prefix_len, len2 - common_prefix_len);
    300 
    301     while (common_suffix_len < suffix_limit &&
    302         input->Equals(len1 - common_suffix_len - 1,
    303         len2 - common_suffix_len - 1)) {
    304       common_suffix_len++;
    305     }
    306   }
    307 
    308   if (common_prefix_len > 0 || common_suffix_len > 0) {
    309     int new_len1 = len1 - common_suffix_len - common_prefix_len;
    310     int new_len2 = len2 - common_suffix_len - common_prefix_len;
    311 
    312     input->SetSubrange1(common_prefix_len, new_len1);
    313     input->SetSubrange2(common_prefix_len, new_len2);
    314 
    315     output->SetSubrange1(common_prefix_len, new_len1);
    316     output->SetSubrange2(common_prefix_len, new_len2);
    317   }
    318 }
    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       : array_(isolate->factory()->NewJSArray(10)), current_size_(0) {}
    327 
    328   Handle<JSArray> GetResult() {
    329     return array_;
    330   }
    331 
    332   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                      Handle<Object>(Smi::FromInt(char_pos1), isolate));
    337     SetElementSloppy(array_,
    338                      current_size_ + 1,
    339                      Handle<Object>(Smi::FromInt(char_pos1 + char_len1),
    340                                     isolate));
    341     SetElementSloppy(array_,
    342                      current_size_ + 2,
    343                      Handle<Object>(Smi::FromInt(char_pos2 + char_len2),
    344                                     isolate));
    345     current_size_ += 3;
    346   }
    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 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         s2_(s2), offset2_(offset2), len2_(len2) {
    363   }
    364   virtual int GetLength1() {
    365     return len1_;
    366   }
    367   virtual int GetLength2() {
    368     return len2_;
    369   }
    370   bool Equals(int index1, int index2) {
    371     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 class TokensCompareOutput : public Comparator::Output {
    387  public:
    388   TokensCompareOutput(CompareOutputArrayWriter* array_writer,
    389                       int offset1, int offset2)
    390         : array_writer_(array_writer), offset1_(offset1), offset2_(offset2) {
    391   }
    392 
    393   void AddChunk(int pos1, int pos2, int len1, int len2) {
    394     array_writer_->WriteChunk(pos1 + offset1_, pos2 + offset2_, len1, len2);
    395   }
    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         string_len_(string->length()) {
    411   }
    412   int length() {
    413     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     if (index == 0) {
    419       return 0;
    420     } else {
    421       return GetLineEnd(index - 1);
    422     }
    423   }
    424   int GetLineEnd(int index) {
    425     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       return string_len_;
    430     } else {
    431       return GetPosAfterNewLine(index);
    432     }
    433   }
    434 
    435  private:
    436   Handle<FixedArray> ends_array_;
    437   int string_len_;
    438 
    439   int GetPosAfterNewLine(int index) {
    440     return Smi::cast(ends_array_->get(index))->value() + 1;
    441   }
    442 };
    443 
    444 
    445 // Represents 2 strings as 2 arrays of lines.
    446 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         subrange_len2_(line_ends2_.length()) {
    455   }
    456   int GetLength1() {
    457     return subrange_len1_;
    458   }
    459   int GetLength2() {
    460     return subrange_len2_;
    461   }
    462   bool Equals(int index1, int index2) {
    463     index1 += subrange_offset1_;
    464     index2 += subrange_offset2_;
    465 
    466     int line_start1 = line_ends1_.GetLineStart(index1);
    467     int line_start2 = line_ends2_.GetLineStart(index2);
    468     int line_end1 = line_ends1_.GetLineEnd(index1);
    469     int line_end2 = line_ends2_.GetLineEnd(index2);
    470     int len1 = line_end1 - line_start1;
    471     int len2 = line_end2 - line_start2;
    472     if (len1 != len2) {
    473       return false;
    474     }
    475     return CompareSubstrings(s1_, line_start1, s2_, line_start2,
    476                              len1);
    477   }
    478   void SetSubrange1(int offset, int len) {
    479     subrange_offset1_ = offset;
    480     subrange_len1_ = len;
    481   }
    482   void SetSubrange2(int offset, int len) {
    483     subrange_offset2_ = offset;
    484     subrange_len2_ = len;
    485   }
    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 class TokenizingLineArrayCompareOutput : public SubrangableOutput {
    502  public:
    503   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         subrange_offset1_(0), subrange_offset2_(0) {
    509   }
    510 
    511   void AddChunk(int line_pos1, int line_pos2, int line_len1, int line_len2) {
    512     line_pos1 += subrange_offset1_;
    513     line_pos2 += subrange_offset2_;
    514 
    515     int char_pos1 = line_ends1_.GetLineStart(line_pos1);
    516     int char_pos2 = line_ends2_.GetLineStart(line_pos2);
    517     int char_len1 = line_ends1_.GetLineStart(line_pos1 + line_len1) - char_pos1;
    518     int char_len2 = line_ends2_.GetLineStart(line_pos2 + line_len2) - char_pos2;
    519 
    520     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                                           char_pos2);
    528 
    529       Comparator::CalculateDifference(&tokens_input, &tokens_output);
    530     } else {
    531       array_writer_.WriteChunk(char_pos1, char_pos2, char_len1, char_len2);
    532     }
    533   }
    534   void SetSubrange1(int offset, int len) {
    535     subrange_offset1_ = offset;
    536   }
    537   void SetSubrange2(int offset, int len) {
    538     subrange_offset2_ = offset;
    539   }
    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 Handle<JSArray> LiveEdit::CompareStrings(Handle<String> s1,
    559                                          Handle<String> s2) {
    560   s1 = String::Flatten(s1);
    561   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   TokenizingLineArrayCompareOutput output(line_ends1, line_ends2, s1, s2);
    568 
    569   NarrowDownInput(&input, &output);
    570 
    571   Comparator::CalculateDifference(&input, &output);
    572 
    573   return output.GetResult();
    574 }
    575 
    576 
    577 // Unwraps JSValue object, returning its field "value"
    578 static Handle<Object> UnwrapJSValue(Handle<JSValue> jsValue) {
    579   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 static Handle<JSValue> WrapInJSValue(Handle<HeapObject> object) {
    586   Isolate* isolate = object->GetIsolate();
    587   Handle<JSFunction> constructor = isolate->opaque_reference_function();
    588   Handle<JSValue> result =
    589       Handle<JSValue>::cast(isolate->factory()->NewJSObject(constructor));
    590   result->set_value(*object);
    591   return result;
    592 }
    593 
    594 
    595 static Handle<SharedFunctionInfo> UnwrapSharedFunctionInfoFromJSValue(
    596     Handle<JSValue> jsValue) {
    597   Object* shared = jsValue->value();
    598   CHECK(shared->IsSharedFunctionInfo());
    599   return Handle<SharedFunctionInfo>(SharedFunctionInfo::cast(shared));
    600 }
    601 
    602 
    603 static int GetArrayLength(Handle<JSArray> array) {
    604   Object* length = array->length();
    605   CHECK(length->IsSmi());
    606   return Smi::cast(length)->value();
    607 }
    608 
    609 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   this->SetField(kFunctionNameOffset_, name);
    616   this->SetSmiValueField(kStartPositionOffset_, start_position);
    617   this->SetSmiValueField(kEndPositionOffset_, end_position);
    618   this->SetSmiValueField(kParamNumOffset_, param_num);
    619   this->SetSmiValueField(kParentIndexOffset_, parent_index);
    620   this->SetSmiValueField(kFunctionLiteralIdOffset_, function_literal_id);
    621 }
    622 
    623 void FunctionInfoWrapper::SetSharedFunctionInfo(
    624     Handle<SharedFunctionInfo> info) {
    625   Handle<JSValue> info_holder = WrapInJSValue(info);
    626   this->SetField(kSharedFunctionInfoOffset_, info_holder);
    627 }
    628 
    629 Handle<SharedFunctionInfo> FunctionInfoWrapper::GetSharedFunctionInfo() {
    630   Handle<Object> element = this->GetField(kSharedFunctionInfoOffset_);
    631   Handle<JSValue> value_wrapper = Handle<JSValue>::cast(element);
    632   Handle<Object> raw_result = UnwrapJSValue(value_wrapper);
    633   CHECK(raw_result->IsSharedFunctionInfo());
    634   return Handle<SharedFunctionInfo>::cast(raw_result);
    635 }
    636 
    637 void SharedInfoWrapper::SetProperties(Handle<String> name,
    638                                       int start_position,
    639                                       int end_position,
    640                                       Handle<SharedFunctionInfo> info) {
    641   HandleScope scope(isolate());
    642   this->SetField(kFunctionNameOffset_, name);
    643   Handle<JSValue> info_holder = WrapInJSValue(info);
    644   this->SetField(kSharedInfoOffset_, info_holder);
    645   this->SetSmiValueField(kStartPositionOffset_, start_position);
    646   this->SetSmiValueField(kEndPositionOffset_, end_position);
    647 }
    648 
    649 
    650 Handle<SharedFunctionInfo> SharedInfoWrapper::GetInfo() {
    651   Handle<Object> element = this->GetField(kSharedInfoOffset_);
    652   Handle<JSValue> value_wrapper = Handle<JSValue>::cast(element);
    653   return UnwrapSharedFunctionInfoFromJSValue(value_wrapper);
    654 }
    655 
    656 
    657 void LiveEdit::InitializeThreadLocal(Debug* debug) {
    658   debug->thread_local_.restart_fp_ = 0;
    659 }
    660 
    661 
    662 MaybeHandle<JSArray> LiveEdit::GatherCompileInfo(Handle<Script> script,
    663                                                  Handle<String> source) {
    664   Isolate* isolate = script->GetIsolate();
    665 
    666   MaybeHandle<JSArray> infos;
    667   Handle<Object> original_source =
    668       Handle<Object>(script->source(), isolate);
    669   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     v8::TryCatch try_catch(reinterpret_cast<v8::Isolate*>(isolate));
    675     try_catch.SetVerbose(true);
    676 
    677     // A logical 'try' section.
    678     infos = Compiler::CompileForLiveEdit(script);
    679   }
    680 
    681   // A logical 'catch' section.
    682   Handle<JSObject> rethrow_exception;
    683   if (isolate->has_pending_exception()) {
    684     Handle<Object> exception(isolate->pending_exception(), isolate);
    685     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     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           STATIC_CHAR_VECTOR("startPosition"));
    697       Handle<String> end_pos_key =
    698           factory->InternalizeOneByteString(STATIC_CHAR_VECTOR("endPosition"));
    699       Handle<String> script_obj_key =
    700           factory->InternalizeOneByteString(STATIC_CHAR_VECTOR("scriptObject"));
    701       Handle<Smi> start_pos(
    702           Smi::FromInt(message_location.start_pos()), isolate);
    703       Handle<Smi> end_pos(Smi::FromInt(message_location.end_pos()), isolate);
    704       Handle<JSObject> script_obj =
    705           Script::GetWrapper(message_location.script());
    706       Object::SetProperty(rethrow_exception, start_pos_key, start_pos, SLOPPY)
    707           .Assert();
    708       Object::SetProperty(rethrow_exception, end_pos_key, end_pos, SLOPPY)
    709           .Assert();
    710       Object::SetProperty(rethrow_exception, script_obj_key, script_obj, SLOPPY)
    711           .Assert();
    712     }
    713   }
    714 
    715   // A logical 'finally' section.
    716   script->set_source(*original_source);
    717 
    718   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 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   HeapIterator iterator(heap, HeapIterator::kFilterUnreachable);
    735   // Now iterate over all pointers of all objects, including code_target
    736   // implicit pointers.
    737   for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
    738     if (obj->IsJSFunction()) {
    739       JSFunction* fun = JSFunction::cast(obj);
    740       if (fun->code() == *original) fun->ReplaceCode(*substitution);
    741     } else if (obj->IsSharedFunctionInfo()) {
    742       SharedFunctionInfo* info = SharedFunctionInfo::cast(obj);
    743       if (info->code() == *original) info->set_code(*substitution);
    744     }
    745   }
    746 }
    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   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         CollectJSFunctions(shared_info, isolate);
    762 
    763     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           isolate->factory()->undefined_value());
    767       fun->set_feedback_vector_cell(*new_cell);
    768       // Only create feedback vectors if we already have the metadata.
    769       if (shared_info->is_compiled()) JSFunction::EnsureLiterals(fun);
    770     }
    771   }
    772 
    773  private:
    774   // Iterates all function instances in the HEAP that refers to the
    775   // provided shared_info.
    776   template<typename Visitor>
    777   static void IterateJSFunctions(Handle<SharedFunctionInfo> shared_info,
    778                                  Visitor* visitor) {
    779     HeapIterator iterator(shared_info->GetHeap());
    780     for (HeapObject* obj = iterator.next(); obj != NULL;
    781         obj = iterator.next()) {
    782       if (obj->IsJSFunction()) {
    783         JSFunction* function = JSFunction::cast(obj);
    784         if (function->shared() == *shared_info) {
    785           visitor->visit(function);
    786         }
    787       }
    788     }
    789   }
    790 
    791   // Finds all instances of JSFunction that refers to the provided shared_info
    792   // and returns array with them.
    793   static Handle<FixedArray> CollectJSFunctions(
    794       Handle<SharedFunctionInfo> shared_info, Isolate* isolate) {
    795     CountVisitor count_visitor;
    796     count_visitor.count = 0;
    797     IterateJSFunctions(shared_info, &count_visitor);
    798     int size = count_visitor.count;
    799 
    800     Handle<FixedArray> result = isolate->factory()->NewFixedArray(size);
    801     if (size > 0) {
    802       CollectVisitor collect_visitor(result);
    803       IterateJSFunctions(shared_info, &collect_visitor);
    804     }
    805     return result;
    806   }
    807 
    808   class CountVisitor {
    809    public:
    810     void visit(JSFunction* fun) {
    811       count++;
    812     }
    813     int count;
    814   };
    815 
    816   class CollectVisitor {
    817    public:
    818     explicit CollectVisitor(Handle<FixedArray> output)
    819         : m_output(output), m_pos(0) {}
    820 
    821     void visit(JSFunction* fun) {
    822       m_output->set(m_pos, fun);
    823       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 class DependentFunctionMarker: public OptimizedFunctionVisitor {
    835  public:
    836   SharedFunctionInfo* shared_info_;
    837   bool found_;
    838 
    839   explicit DependentFunctionMarker(SharedFunctionInfo* shared_info)
    840     : shared_info_(shared_info), found_(false) { }
    841 
    842   virtual void EnterContext(Context* context) { }  // Don't care.
    843   virtual void LeaveContext(Context* context)  { }  // Don't care.
    844   virtual void VisitFunction(JSFunction* function) {
    845     // It should be guaranteed by the iterator that everything is optimized.
    846     DCHECK(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
    847     if (function->Inlines(shared_info_)) {
    848       // Mark the code for deoptimization.
    849       function->code()->set_marked_for_deoptimization(true);
    850       found_ = true;
    851     }
    852   }
    853 };
    854 
    855 
    856 static void DeoptimizeDependentFunctions(SharedFunctionInfo* function_info) {
    857   DisallowHeapAllocation no_allocation;
    858   DependentFunctionMarker marker(function_info);
    859   // TODO(titzer): need to traverse all optimized code to find OSR code here.
    860   Deoptimizer::VisitAllOptimizedFunctions(function_info->GetIsolate(), &marker);
    861 
    862   if (marker.found_) {
    863     // Only go through with the deoptimization if something was found.
    864     Deoptimizer::DeoptimizeMarkedCode(function_info->GetIsolate());
    865   }
    866 }
    867 
    868 
    869 void LiveEdit::ReplaceFunctionCode(
    870     Handle<JSArray> new_compile_info_array,
    871     Handle<JSArray> shared_info_array) {
    872   Isolate* isolate = new_compile_info_array->GetIsolate();
    873 
    874   FunctionInfoWrapper compile_info_wrapper(new_compile_info_array);
    875   SharedInfoWrapper shared_info_wrapper(shared_info_array);
    876 
    877   Handle<SharedFunctionInfo> shared_info = shared_info_wrapper.GetInfo();
    878   Handle<SharedFunctionInfo> new_shared_info =
    879       compile_info_wrapper.GetSharedFunctionInfo();
    880 
    881   if (shared_info->is_compiled()) {
    882     // Take whatever code we can get from the new shared function info. We
    883     // expect activations of neither the old bytecode nor old FCG code, since
    884     // the lowest activation is going to be restarted.
    885     Handle<Code> old_code(shared_info->code());
    886     Handle<Code> new_code(new_shared_info->code());
    887     // Clear old bytecode. This will trigger self-healing if we do not install
    888     // new bytecode.
    889     shared_info->ClearBytecodeArray();
    890     if (!shared_info->HasBaselineCode()) {
    891       // Every function from this SFI is interpreted.
    892       if (!new_shared_info->HasBaselineCode()) {
    893         // We have newly compiled bytecode. Simply replace the old one.
    894         shared_info->set_bytecode_array(new_shared_info->bytecode_array());
    895       } else {
    896         // Rely on self-healing for places that used to run bytecode.
    897         shared_info->ReplaceCode(*new_code);
    898       }
    899     } else {
    900       // Functions from this SFI can be either interpreted or running FCG.
    901       DCHECK(old_code->kind() == Code::FUNCTION);
    902       if (new_shared_info->HasBytecodeArray()) {
    903         // Start using new bytecode everywhere.
    904         shared_info->set_bytecode_array(new_shared_info->bytecode_array());
    905         ReplaceCodeObject(old_code,
    906                           isolate->builtins()->InterpreterEntryTrampoline());
    907       } else {
    908         // Start using new FCG code everywhere.
    909         // Rely on self-healing for places that used to run bytecode.
    910         DCHECK(new_code->kind() == Code::FUNCTION);
    911         ReplaceCodeObject(old_code, new_code);
    912       }
    913     }
    914 
    915     if (shared_info->HasDebugInfo()) {
    916       // Existing break points will be re-applied. Reset the debug info here.
    917       isolate->debug()->RemoveDebugInfoAndClearFromShared(
    918           handle(shared_info->GetDebugInfo()));
    919     }
    920     shared_info->set_scope_info(new_shared_info->scope_info());
    921     shared_info->set_outer_scope_info(new_shared_info->outer_scope_info());
    922     shared_info->DisableOptimization(kLiveEdit);
    923     // Update the type feedback vector, if needed.
    924     Handle<FeedbackMetadata> new_feedback_metadata(
    925         new_shared_info->feedback_metadata());
    926     shared_info->set_feedback_metadata(*new_feedback_metadata);
    927   } else {
    928     shared_info->set_feedback_metadata(
    929         FeedbackMetadata::cast(isolate->heap()->empty_fixed_array()));
    930   }
    931 
    932   int start_position = compile_info_wrapper.GetStartPosition();
    933   int end_position = compile_info_wrapper.GetEndPosition();
    934   shared_info->set_start_position(start_position);
    935   shared_info->set_end_position(end_position);
    936 
    937   FeedbackVectorFixer::PatchFeedbackVector(&compile_info_wrapper, shared_info,
    938                                            isolate);
    939 
    940   DeoptimizeDependentFunctions(*shared_info);
    941   isolate->compilation_cache()->Remove(shared_info);
    942 }
    943 
    944 void LiveEdit::FunctionSourceUpdated(Handle<JSArray> shared_info_array,
    945                                      int new_function_literal_id) {
    946   SharedInfoWrapper shared_info_wrapper(shared_info_array);
    947   Handle<SharedFunctionInfo> shared_info = shared_info_wrapper.GetInfo();
    948 
    949   shared_info->set_function_literal_id(new_function_literal_id);
    950   DeoptimizeDependentFunctions(*shared_info);
    951   shared_info_array->GetIsolate()->compilation_cache()->Remove(shared_info);
    952 }
    953 
    954 void LiveEdit::FixupScript(Handle<Script> script, int max_function_literal_id) {
    955   Isolate* isolate = script->GetIsolate();
    956   Handle<FixedArray> old_infos(script->shared_function_infos(), isolate);
    957   Handle<FixedArray> new_infos(
    958       isolate->factory()->NewFixedArray(max_function_literal_id + 1));
    959   script->set_shared_function_infos(*new_infos);
    960   SharedFunctionInfo::ScriptIterator iterator(isolate, old_infos);
    961   while (SharedFunctionInfo* shared = iterator.Next()) {
    962     // We can't use SharedFunctionInfo::SetScript(info, undefined_value()) here,
    963     // as we severed the link from the Script to the SharedFunctionInfo above.
    964     Handle<SharedFunctionInfo> info(shared, isolate);
    965     info->set_script(isolate->heap()->undefined_value());
    966     Handle<Object> new_noscript_list = WeakFixedArray::Add(
    967         isolate->factory()->noscript_shared_function_infos(), info);
    968     isolate->heap()->SetRootNoScriptSharedFunctionInfos(*new_noscript_list);
    969 
    970     // Put the SharedFunctionInfo at its new, correct location.
    971     SharedFunctionInfo::SetScript(info, script);
    972   }
    973 }
    974 
    975 void LiveEdit::SetFunctionScript(Handle<JSValue> function_wrapper,
    976                                  Handle<Object> script_handle) {
    977   Handle<SharedFunctionInfo> shared_info =
    978       UnwrapSharedFunctionInfoFromJSValue(function_wrapper);
    979   Isolate* isolate = function_wrapper->GetIsolate();
    980   CHECK(script_handle->IsScript() || script_handle->IsUndefined(isolate));
    981   SharedFunctionInfo::SetScript(shared_info, script_handle);
    982   shared_info->DisableOptimization(kLiveEdit);
    983 
    984   function_wrapper->GetIsolate()->compilation_cache()->Remove(shared_info);
    985 }
    986 
    987 namespace {
    988 // For a script text change (defined as position_change_array), translates
    989 // position in unchanged text to position in changed text.
    990 // Text change is a set of non-overlapping regions in text, that have changed
    991 // their contents and length. It is specified as array of groups of 3 numbers:
    992 // (change_begin, change_end, change_end_new_position).
    993 // Each group describes a change in text; groups are sorted by change_begin.
    994 // Only position in text beyond any changes may be successfully translated.
    995 // If a positions is inside some region that changed, result is currently
    996 // undefined.
    997 static int TranslatePosition(int original_position,
    998                              Handle<JSArray> position_change_array) {
    999   int position_diff = 0;
   1000   int array_len = GetArrayLength(position_change_array);
   1001   Isolate* isolate = position_change_array->GetIsolate();
   1002   // TODO(635): binary search may be used here
   1003   for (int i = 0; i < array_len; i += 3) {
   1004     HandleScope scope(isolate);
   1005     Handle<Object> element =
   1006         JSReceiver::GetElement(isolate, position_change_array, i)
   1007             .ToHandleChecked();
   1008     CHECK(element->IsSmi());
   1009     int chunk_start = Handle<Smi>::cast(element)->value();
   1010     if (original_position < chunk_start) {
   1011       break;
   1012     }
   1013     element = JSReceiver::GetElement(isolate, position_change_array, i + 1)
   1014                   .ToHandleChecked();
   1015     CHECK(element->IsSmi());
   1016     int chunk_end = Handle<Smi>::cast(element)->value();
   1017     // Position mustn't be inside a chunk.
   1018     DCHECK(original_position >= chunk_end);
   1019     element = JSReceiver::GetElement(isolate, position_change_array, i + 2)
   1020                   .ToHandleChecked();
   1021     CHECK(element->IsSmi());
   1022     int chunk_changed_end = Handle<Smi>::cast(element)->value();
   1023     position_diff = chunk_changed_end - chunk_end;
   1024   }
   1025 
   1026   return original_position + position_diff;
   1027 }
   1028 
   1029 void TranslateSourcePositionTable(Handle<AbstractCode> code,
   1030                                   Handle<JSArray> position_change_array) {
   1031   Isolate* isolate = code->GetIsolate();
   1032   Zone zone(isolate->allocator(), ZONE_NAME);
   1033   SourcePositionTableBuilder builder(&zone);
   1034 
   1035   Handle<ByteArray> source_position_table(code->source_position_table());
   1036   for (SourcePositionTableIterator iterator(*source_position_table);
   1037        !iterator.done(); iterator.Advance()) {
   1038     SourcePosition position = iterator.source_position();
   1039     position.SetScriptOffset(
   1040         TranslatePosition(position.ScriptOffset(), position_change_array));
   1041     builder.AddPosition(iterator.code_offset(), position,
   1042                         iterator.is_statement());
   1043   }
   1044 
   1045   Handle<ByteArray> new_source_position_table(
   1046       builder.ToSourcePositionTable(isolate, code));
   1047   code->set_source_position_table(*new_source_position_table);
   1048 }
   1049 }  // namespace
   1050 
   1051 void LiveEdit::PatchFunctionPositions(Handle<JSArray> shared_info_array,
   1052                                       Handle<JSArray> position_change_array) {
   1053   SharedInfoWrapper shared_info_wrapper(shared_info_array);
   1054   Handle<SharedFunctionInfo> info = shared_info_wrapper.GetInfo();
   1055 
   1056   int old_function_start = info->start_position();
   1057   int new_function_start = TranslatePosition(old_function_start,
   1058                                              position_change_array);
   1059   int new_function_end = TranslatePosition(info->end_position(),
   1060                                            position_change_array);
   1061   int new_function_token_pos =
   1062       TranslatePosition(info->function_token_position(), position_change_array);
   1063 
   1064   info->set_start_position(new_function_start);
   1065   info->set_end_position(new_function_end);
   1066   info->set_function_token_position(new_function_token_pos);
   1067 
   1068   if (info->HasBytecodeArray()) {
   1069     TranslateSourcePositionTable(
   1070         Handle<AbstractCode>(AbstractCode::cast(info->bytecode_array())),
   1071         position_change_array);
   1072   }
   1073   if (info->code()->kind() == Code::FUNCTION) {
   1074     TranslateSourcePositionTable(
   1075         Handle<AbstractCode>(AbstractCode::cast(info->code())),
   1076         position_change_array);
   1077   }
   1078   if (info->HasDebugInfo()) {
   1079     // Existing break points will be re-applied. Reset the debug info here.
   1080     info->GetIsolate()->debug()->RemoveDebugInfoAndClearFromShared(
   1081         handle(info->GetDebugInfo()));
   1082   }
   1083 }
   1084 
   1085 
   1086 static Handle<Script> CreateScriptCopy(Handle<Script> original) {
   1087   Isolate* isolate = original->GetIsolate();
   1088 
   1089   Handle<String> original_source(String::cast(original->source()));
   1090   Handle<Script> copy = isolate->factory()->NewScript(original_source);
   1091 
   1092   copy->set_name(original->name());
   1093   copy->set_line_offset(original->line_offset());
   1094   copy->set_column_offset(original->column_offset());
   1095   copy->set_type(original->type());
   1096   copy->set_context_data(original->context_data());
   1097   copy->set_eval_from_shared(original->eval_from_shared());
   1098   copy->set_eval_from_position(original->eval_from_position());
   1099 
   1100   Handle<FixedArray> infos(isolate->factory()->NewFixedArray(
   1101       original->shared_function_infos()->length()));
   1102   copy->set_shared_function_infos(*infos);
   1103 
   1104   // Copy all the flags, but clear compilation state.
   1105   copy->set_flags(original->flags());
   1106   copy->set_compilation_state(Script::COMPILATION_STATE_INITIAL);
   1107 
   1108   return copy;
   1109 }
   1110 
   1111 Handle<Object> LiveEdit::ChangeScriptSource(Handle<Script> original_script,
   1112                                             Handle<String> new_source,
   1113                                             Handle<Object> old_script_name) {
   1114   Isolate* isolate = original_script->GetIsolate();
   1115   Handle<Object> old_script_object;
   1116   if (old_script_name->IsString()) {
   1117     Handle<Script> old_script = CreateScriptCopy(original_script);
   1118     old_script->set_name(String::cast(*old_script_name));
   1119     old_script_object = old_script;
   1120     isolate->debug()->OnAfterCompile(old_script);
   1121   } else {
   1122     old_script_object = isolate->factory()->null_value();
   1123   }
   1124 
   1125   original_script->set_source(*new_source);
   1126 
   1127   // Drop line ends so that they will be recalculated.
   1128   original_script->set_line_ends(isolate->heap()->undefined_value());
   1129 
   1130   return old_script_object;
   1131 }
   1132 
   1133 
   1134 
   1135 void LiveEdit::ReplaceRefToNestedFunction(
   1136     Handle<JSValue> parent_function_wrapper,
   1137     Handle<JSValue> orig_function_wrapper,
   1138     Handle<JSValue> subst_function_wrapper) {
   1139 
   1140   Handle<SharedFunctionInfo> parent_shared =
   1141       UnwrapSharedFunctionInfoFromJSValue(parent_function_wrapper);
   1142   Handle<SharedFunctionInfo> orig_shared =
   1143       UnwrapSharedFunctionInfoFromJSValue(orig_function_wrapper);
   1144   Handle<SharedFunctionInfo> subst_shared =
   1145       UnwrapSharedFunctionInfoFromJSValue(subst_function_wrapper);
   1146 
   1147   for (RelocIterator it(parent_shared->code()); !it.done(); it.next()) {
   1148     if (it.rinfo()->rmode() == RelocInfo::EMBEDDED_OBJECT) {
   1149       if (it.rinfo()->target_object() == *orig_shared) {
   1150         it.rinfo()->set_target_object(*subst_shared);
   1151       }
   1152     }
   1153   }
   1154 }
   1155 
   1156 
   1157 // Check an activation against list of functions. If there is a function
   1158 // that matches, its status in result array is changed to status argument value.
   1159 static bool CheckActivation(Handle<JSArray> shared_info_array,
   1160                             Handle<JSArray> result,
   1161                             StackFrame* frame,
   1162                             LiveEdit::FunctionPatchabilityStatus status) {
   1163   if (!frame->is_java_script()) return false;
   1164 
   1165   Handle<JSFunction> function(JavaScriptFrame::cast(frame)->function());
   1166 
   1167   Isolate* isolate = shared_info_array->GetIsolate();
   1168   int len = GetArrayLength(shared_info_array);
   1169   for (int i = 0; i < len; i++) {
   1170     HandleScope scope(isolate);
   1171     Handle<Object> element =
   1172         JSReceiver::GetElement(isolate, shared_info_array, i).ToHandleChecked();
   1173     Handle<JSValue> jsvalue = Handle<JSValue>::cast(element);
   1174     Handle<SharedFunctionInfo> shared =
   1175         UnwrapSharedFunctionInfoFromJSValue(jsvalue);
   1176 
   1177     if (function->Inlines(*shared)) {
   1178       SetElementSloppy(result, i, Handle<Smi>(Smi::FromInt(status), isolate));
   1179       return true;
   1180     }
   1181   }
   1182   return false;
   1183 }
   1184 
   1185 // Describes a set of call frames that execute any of listed functions.
   1186 // Finding no such frames does not mean error.
   1187 class MultipleFunctionTarget {
   1188  public:
   1189   MultipleFunctionTarget(Handle<JSArray> old_shared_array,
   1190                          Handle<JSArray> new_shared_array,
   1191                          Handle<JSArray> result)
   1192       : old_shared_array_(old_shared_array),
   1193         new_shared_array_(new_shared_array),
   1194         result_(result) {}
   1195   bool MatchActivation(StackFrame* frame,
   1196       LiveEdit::FunctionPatchabilityStatus status) {
   1197     return CheckActivation(old_shared_array_, result_, frame, status);
   1198   }
   1199   const char* GetNotFoundMessage() const {
   1200     return NULL;
   1201   }
   1202   bool FrameUsesNewTarget(StackFrame* frame) {
   1203     if (!frame->is_java_script()) return false;
   1204     JavaScriptFrame* jsframe = JavaScriptFrame::cast(frame);
   1205     Handle<SharedFunctionInfo> old_shared(jsframe->function()->shared());
   1206     Isolate* isolate = old_shared->GetIsolate();
   1207     int len = GetArrayLength(old_shared_array_);
   1208     // Find corresponding new shared function info and return whether it
   1209     // references new.target.
   1210     for (int i = 0; i < len; i++) {
   1211       HandleScope scope(isolate);
   1212       Handle<Object> old_element =
   1213           JSReceiver::GetElement(isolate, old_shared_array_, i)
   1214               .ToHandleChecked();
   1215       if (!old_shared.is_identical_to(UnwrapSharedFunctionInfoFromJSValue(
   1216               Handle<JSValue>::cast(old_element)))) {
   1217         continue;
   1218       }
   1219 
   1220       Handle<Object> new_element =
   1221           JSReceiver::GetElement(isolate, new_shared_array_, i)
   1222               .ToHandleChecked();
   1223       if (new_element->IsUndefined(isolate)) return false;
   1224       Handle<SharedFunctionInfo> new_shared =
   1225           UnwrapSharedFunctionInfoFromJSValue(
   1226               Handle<JSValue>::cast(new_element));
   1227       if (new_shared->scope_info()->HasNewTarget()) {
   1228         SetElementSloppy(
   1229             result_, i,
   1230             Handle<Smi>(
   1231                 Smi::FromInt(
   1232                     LiveEdit::FUNCTION_BLOCKED_NO_NEW_TARGET_ON_RESTART),
   1233                 isolate));
   1234         return true;
   1235       }
   1236       return false;
   1237     }
   1238     return false;
   1239   }
   1240 
   1241   void set_status(LiveEdit::FunctionPatchabilityStatus status) {
   1242     Isolate* isolate = old_shared_array_->GetIsolate();
   1243     int len = GetArrayLength(old_shared_array_);
   1244     for (int i = 0; i < len; ++i) {
   1245       Handle<Object> old_element =
   1246           JSReceiver::GetElement(isolate, result_, i).ToHandleChecked();
   1247       if (!old_element->IsSmi() ||
   1248           Smi::cast(*old_element)->value() ==
   1249               LiveEdit::FUNCTION_AVAILABLE_FOR_PATCH) {
   1250         SetElementSloppy(result_, i,
   1251                          Handle<Smi>(Smi::FromInt(status), isolate));
   1252       }
   1253     }
   1254   }
   1255 
   1256  private:
   1257   Handle<JSArray> old_shared_array_;
   1258   Handle<JSArray> new_shared_array_;
   1259   Handle<JSArray> result_;
   1260 };
   1261 
   1262 
   1263 // Drops all call frame matched by target and all frames above them.
   1264 template <typename TARGET>
   1265 static const char* DropActivationsInActiveThreadImpl(Isolate* isolate,
   1266                                                      TARGET& target,  // NOLINT
   1267                                                      bool do_drop) {
   1268   Debug* debug = isolate->debug();
   1269   Zone zone(isolate->allocator(), ZONE_NAME);
   1270   Vector<StackFrame*> frames = CreateStackMap(isolate, &zone);
   1271 
   1272   int top_frame_index = -1;
   1273   int frame_index = 0;
   1274   for (; frame_index < frames.length(); frame_index++) {
   1275     StackFrame* frame = frames[frame_index];
   1276     if (frame->id() == debug->break_frame_id()) {
   1277       top_frame_index = frame_index;
   1278       break;
   1279     }
   1280     if (target.MatchActivation(
   1281             frame, LiveEdit::FUNCTION_BLOCKED_UNDER_NATIVE_CODE)) {
   1282       // We are still above break_frame. It is not a target frame,
   1283       // it is a problem.
   1284       return "Debugger mark-up on stack is not found";
   1285     }
   1286   }
   1287 
   1288   if (top_frame_index == -1) {
   1289     // We haven't found break frame, but no function is blocking us anyway.
   1290     return target.GetNotFoundMessage();
   1291   }
   1292 
   1293   bool target_frame_found = false;
   1294   int bottom_js_frame_index = top_frame_index;
   1295   bool non_droppable_frame_found = false;
   1296   LiveEdit::FunctionPatchabilityStatus non_droppable_reason;
   1297 
   1298   for (; frame_index < frames.length(); frame_index++) {
   1299     StackFrame* frame = frames[frame_index];
   1300     if (frame->is_exit() || frame->is_builtin_exit()) {
   1301       non_droppable_frame_found = true;
   1302       non_droppable_reason = LiveEdit::FUNCTION_BLOCKED_UNDER_NATIVE_CODE;
   1303       break;
   1304     }
   1305     if (frame->is_java_script()) {
   1306       SharedFunctionInfo* shared =
   1307           JavaScriptFrame::cast(frame)->function()->shared();
   1308       if (IsResumableFunction(shared->kind())) {
   1309         non_droppable_frame_found = true;
   1310         non_droppable_reason = LiveEdit::FUNCTION_BLOCKED_UNDER_GENERATOR;
   1311         break;
   1312       }
   1313     }
   1314     if (target.MatchActivation(
   1315             frame, LiveEdit::FUNCTION_BLOCKED_ON_ACTIVE_STACK)) {
   1316       target_frame_found = true;
   1317       bottom_js_frame_index = frame_index;
   1318     }
   1319   }
   1320 
   1321   if (non_droppable_frame_found) {
   1322     // There is a C or generator frame on stack.  We can't drop C frames, and we
   1323     // can't restart generators.  Check that there are no target frames below
   1324     // them.
   1325     for (; frame_index < frames.length(); frame_index++) {
   1326       StackFrame* frame = frames[frame_index];
   1327       if (frame->is_java_script()) {
   1328         if (target.MatchActivation(frame, non_droppable_reason)) {
   1329           // Fail.
   1330           return NULL;
   1331         }
   1332         if (non_droppable_reason ==
   1333                 LiveEdit::FUNCTION_BLOCKED_UNDER_GENERATOR &&
   1334             !target_frame_found) {
   1335           // Fail.
   1336           target.set_status(non_droppable_reason);
   1337           return NULL;
   1338         }
   1339       }
   1340     }
   1341   }
   1342 
   1343   // We cannot restart a frame that uses new.target.
   1344   if (target.FrameUsesNewTarget(frames[bottom_js_frame_index])) return NULL;
   1345 
   1346   if (!do_drop) {
   1347     // We are in check-only mode.
   1348     return NULL;
   1349   }
   1350 
   1351   if (!target_frame_found) {
   1352     // Nothing to drop.
   1353     return target.GetNotFoundMessage();
   1354   }
   1355 
   1356   if (!LiveEdit::kFrameDropperSupported) {
   1357     return "Stack manipulations are not supported in this architecture.";
   1358   }
   1359 
   1360   debug->ScheduleFrameRestart(frames[bottom_js_frame_index]);
   1361   return NULL;
   1362 }
   1363 
   1364 
   1365 // Fills result array with statuses of functions. Modifies the stack
   1366 // removing all listed function if possible and if do_drop is true.
   1367 static const char* DropActivationsInActiveThread(
   1368     Handle<JSArray> old_shared_array, Handle<JSArray> new_shared_array,
   1369     Handle<JSArray> result, bool do_drop) {
   1370   MultipleFunctionTarget target(old_shared_array, new_shared_array, result);
   1371   Isolate* isolate = old_shared_array->GetIsolate();
   1372 
   1373   const char* message =
   1374       DropActivationsInActiveThreadImpl(isolate, target, do_drop);
   1375   if (message) {
   1376     return message;
   1377   }
   1378 
   1379   int array_len = GetArrayLength(old_shared_array);
   1380 
   1381   // Replace "blocked on active" with "replaced on active" status.
   1382   for (int i = 0; i < array_len; i++) {
   1383     Handle<Object> obj =
   1384         JSReceiver::GetElement(isolate, result, i).ToHandleChecked();
   1385     if (*obj == Smi::FromInt(LiveEdit::FUNCTION_BLOCKED_ON_ACTIVE_STACK)) {
   1386       Handle<Object> replaced(
   1387           Smi::FromInt(LiveEdit::FUNCTION_REPLACED_ON_ACTIVE_STACK), isolate);
   1388       SetElementSloppy(result, i, replaced);
   1389     }
   1390   }
   1391   return NULL;
   1392 }
   1393 
   1394 
   1395 bool LiveEdit::FindActiveGenerators(Handle<FixedArray> shared_info_array,
   1396                                     Handle<FixedArray> result,
   1397                                     int len) {
   1398   Isolate* isolate = shared_info_array->GetIsolate();
   1399   bool found_suspended_activations = false;
   1400 
   1401   DCHECK_LE(len, result->length());
   1402 
   1403   FunctionPatchabilityStatus active = FUNCTION_BLOCKED_ACTIVE_GENERATOR;
   1404 
   1405   Heap* heap = isolate->heap();
   1406   HeapIterator iterator(heap, HeapIterator::kFilterUnreachable);
   1407   HeapObject* obj = NULL;
   1408   while ((obj = iterator.next()) != NULL) {
   1409     if (!obj->IsJSGeneratorObject()) continue;
   1410 
   1411     JSGeneratorObject* gen = JSGeneratorObject::cast(obj);
   1412     if (gen->is_closed()) continue;
   1413 
   1414     HandleScope scope(isolate);
   1415 
   1416     for (int i = 0; i < len; i++) {
   1417       Handle<JSValue> jsvalue = Handle<JSValue>::cast(
   1418           FixedArray::get(*shared_info_array, i, isolate));
   1419       Handle<SharedFunctionInfo> shared =
   1420           UnwrapSharedFunctionInfoFromJSValue(jsvalue);
   1421 
   1422       if (gen->function()->shared() == *shared) {
   1423         result->set(i, Smi::FromInt(active));
   1424         found_suspended_activations = true;
   1425       }
   1426     }
   1427   }
   1428 
   1429   return found_suspended_activations;
   1430 }
   1431 
   1432 
   1433 class InactiveThreadActivationsChecker : public ThreadVisitor {
   1434  public:
   1435   InactiveThreadActivationsChecker(Handle<JSArray> old_shared_array,
   1436                                    Handle<JSArray> result)
   1437       : old_shared_array_(old_shared_array),
   1438         result_(result),
   1439         has_blocked_functions_(false) {}
   1440   void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
   1441     for (StackFrameIterator it(isolate, top); !it.done(); it.Advance()) {
   1442       has_blocked_functions_ |=
   1443           CheckActivation(old_shared_array_, result_, it.frame(),
   1444                           LiveEdit::FUNCTION_BLOCKED_ON_OTHER_STACK);
   1445     }
   1446   }
   1447   bool HasBlockedFunctions() {
   1448     return has_blocked_functions_;
   1449   }
   1450 
   1451  private:
   1452   Handle<JSArray> old_shared_array_;
   1453   Handle<JSArray> result_;
   1454   bool has_blocked_functions_;
   1455 };
   1456 
   1457 
   1458 Handle<JSArray> LiveEdit::CheckAndDropActivations(
   1459     Handle<JSArray> old_shared_array, Handle<JSArray> new_shared_array,
   1460     bool do_drop) {
   1461   Isolate* isolate = old_shared_array->GetIsolate();
   1462   int len = GetArrayLength(old_shared_array);
   1463 
   1464   DCHECK(old_shared_array->HasFastElements());
   1465   Handle<FixedArray> old_shared_array_elements(
   1466       FixedArray::cast(old_shared_array->elements()));
   1467 
   1468   Handle<JSArray> result = isolate->factory()->NewJSArray(len);
   1469   result->set_length(Smi::FromInt(len));
   1470   JSObject::EnsureWritableFastElements(result);
   1471   Handle<FixedArray> result_elements =
   1472       handle(FixedArray::cast(result->elements()), isolate);
   1473 
   1474   // Fill the default values.
   1475   for (int i = 0; i < len; i++) {
   1476     FunctionPatchabilityStatus status = FUNCTION_AVAILABLE_FOR_PATCH;
   1477     result_elements->set(i, Smi::FromInt(status));
   1478   }
   1479 
   1480   // Scan the heap for active generators -- those that are either currently
   1481   // running (as we wouldn't want to restart them, because we don't know where
   1482   // to restart them from) or suspended.  Fail if any one corresponds to the set
   1483   // of functions being edited.
   1484   if (FindActiveGenerators(old_shared_array_elements, result_elements, len)) {
   1485     return result;
   1486   }
   1487 
   1488   // Check inactive threads. Fail if some functions are blocked there.
   1489   InactiveThreadActivationsChecker inactive_threads_checker(old_shared_array,
   1490                                                             result);
   1491   isolate->thread_manager()->IterateArchivedThreads(
   1492       &inactive_threads_checker);
   1493   if (inactive_threads_checker.HasBlockedFunctions()) {
   1494     return result;
   1495   }
   1496 
   1497   // Try to drop activations from the current stack.
   1498   const char* error_message = DropActivationsInActiveThread(
   1499       old_shared_array, new_shared_array, result, do_drop);
   1500   if (error_message != NULL) {
   1501     // Add error message as an array extra element.
   1502     Handle<String> str =
   1503         isolate->factory()->NewStringFromAsciiChecked(error_message);
   1504     SetElementSloppy(result, len, str);
   1505   }
   1506   return result;
   1507 }
   1508 
   1509 
   1510 // Describes a single callframe a target. Not finding this frame
   1511 // means an error.
   1512 class SingleFrameTarget {
   1513  public:
   1514   explicit SingleFrameTarget(JavaScriptFrame* frame)
   1515       : m_frame(frame),
   1516         m_saved_status(LiveEdit::FUNCTION_AVAILABLE_FOR_PATCH) {}
   1517 
   1518   bool MatchActivation(StackFrame* frame,
   1519       LiveEdit::FunctionPatchabilityStatus status) {
   1520     if (frame->fp() == m_frame->fp()) {
   1521       m_saved_status = status;
   1522       return true;
   1523     }
   1524     return false;
   1525   }
   1526   const char* GetNotFoundMessage() const {
   1527     return "Failed to found requested frame";
   1528   }
   1529   LiveEdit::FunctionPatchabilityStatus saved_status() {
   1530     return m_saved_status;
   1531   }
   1532   void set_status(LiveEdit::FunctionPatchabilityStatus status) {
   1533     m_saved_status = status;
   1534   }
   1535 
   1536   bool FrameUsesNewTarget(StackFrame* frame) {
   1537     if (!frame->is_java_script()) return false;
   1538     JavaScriptFrame* jsframe = JavaScriptFrame::cast(frame);
   1539     Handle<SharedFunctionInfo> shared(jsframe->function()->shared());
   1540     return shared->scope_info()->HasNewTarget();
   1541   }
   1542 
   1543  private:
   1544   JavaScriptFrame* m_frame;
   1545   LiveEdit::FunctionPatchabilityStatus m_saved_status;
   1546 };
   1547 
   1548 
   1549 // Finds a drops required frame and all frames above.
   1550 // Returns error message or NULL.
   1551 const char* LiveEdit::RestartFrame(JavaScriptFrame* frame) {
   1552   SingleFrameTarget target(frame);
   1553 
   1554   const char* result =
   1555       DropActivationsInActiveThreadImpl(frame->isolate(), target, true);
   1556   if (result != NULL) {
   1557     return result;
   1558   }
   1559   if (target.saved_status() == LiveEdit::FUNCTION_BLOCKED_UNDER_NATIVE_CODE) {
   1560     return "Function is blocked under native code";
   1561   }
   1562   if (target.saved_status() == LiveEdit::FUNCTION_BLOCKED_UNDER_GENERATOR) {
   1563     return "Function is blocked under a generator activation";
   1564   }
   1565   return NULL;
   1566 }
   1567 
   1568 Handle<JSArray> LiveEditFunctionTracker::Collect(FunctionLiteral* node,
   1569                                                  Handle<Script> script,
   1570                                                  Zone* zone, Isolate* isolate) {
   1571   LiveEditFunctionTracker visitor(script, zone, isolate);
   1572   visitor.VisitFunctionLiteral(node);
   1573   return visitor.result_;
   1574 }
   1575 
   1576 LiveEditFunctionTracker::LiveEditFunctionTracker(Handle<Script> script,
   1577                                                  Zone* zone, Isolate* isolate)
   1578     : AstTraversalVisitor<LiveEditFunctionTracker>(isolate) {
   1579   current_parent_index_ = -1;
   1580   isolate_ = isolate;
   1581   len_ = 0;
   1582   result_ = isolate->factory()->NewJSArray(10);
   1583   script_ = script;
   1584   zone_ = zone;
   1585 }
   1586 
   1587 void LiveEditFunctionTracker::VisitFunctionLiteral(FunctionLiteral* node) {
   1588   // FunctionStarted is called in pre-order.
   1589   FunctionStarted(node);
   1590   // Recurse using the regular traversal.
   1591   AstTraversalVisitor::VisitFunctionLiteral(node);
   1592   // FunctionDone are called in post-order.
   1593   Handle<SharedFunctionInfo> info =
   1594       script_->FindSharedFunctionInfo(isolate_, node).ToHandleChecked();
   1595   FunctionDone(info, node->scope());
   1596 }
   1597 
   1598 void LiveEditFunctionTracker::FunctionStarted(FunctionLiteral* fun) {
   1599   HandleScope handle_scope(isolate_);
   1600   FunctionInfoWrapper info = FunctionInfoWrapper::Create(isolate_);
   1601   info.SetInitialProperties(fun->name(), fun->start_position(),
   1602                             fun->end_position(), fun->parameter_count(),
   1603                             current_parent_index_, fun->function_literal_id());
   1604   current_parent_index_ = len_;
   1605   SetElementSloppy(result_, len_, info.GetJSArray());
   1606   len_++;
   1607 }
   1608 
   1609 // Saves full information about a function: its code, its scope info
   1610 // and a SharedFunctionInfo object.
   1611 void LiveEditFunctionTracker::FunctionDone(Handle<SharedFunctionInfo> shared,
   1612                                            Scope* scope) {
   1613   HandleScope handle_scope(isolate_);
   1614   FunctionInfoWrapper info = FunctionInfoWrapper::cast(
   1615       *JSReceiver::GetElement(isolate_, result_, current_parent_index_)
   1616            .ToHandleChecked());
   1617   info.SetSharedFunctionInfo(shared);
   1618 
   1619   Handle<Object> scope_info_list = SerializeFunctionScope(scope);
   1620   info.SetFunctionScopeInfo(scope_info_list);
   1621 
   1622   current_parent_index_ = info.GetParentIndex();
   1623 }
   1624 
   1625 Handle<Object> LiveEditFunctionTracker::SerializeFunctionScope(Scope* scope) {
   1626   Handle<JSArray> scope_info_list = isolate_->factory()->NewJSArray(10);
   1627   int scope_info_length = 0;
   1628 
   1629   // Saves some description of scope. It stores name and indexes of
   1630   // variables in the whole scope chain. Null-named slots delimit
   1631   // scopes of this chain.
   1632   Scope* current_scope = scope;
   1633   while (current_scope != NULL) {
   1634     HandleScope handle_scope(isolate_);
   1635     for (Variable* var : *current_scope->locals()) {
   1636       if (!var->IsContextSlot()) continue;
   1637       int context_index = var->index() - Context::MIN_CONTEXT_SLOTS;
   1638       int location = scope_info_length + context_index * 2;
   1639       SetElementSloppy(scope_info_list, location, var->name());
   1640       SetElementSloppy(scope_info_list, location + 1,
   1641                        handle(Smi::FromInt(var->index()), isolate_));
   1642     }
   1643     scope_info_length += current_scope->ContextLocalCount() * 2;
   1644     SetElementSloppy(scope_info_list, scope_info_length,
   1645                      isolate_->factory()->null_value());
   1646     scope_info_length++;
   1647 
   1648     current_scope = current_scope->outer_scope();
   1649   }
   1650 
   1651   return scope_info_list;
   1652 }
   1653 
   1654 }  // namespace internal
   1655 }  // namespace v8
   1656