Home | History | Annotate | Download | only in src
      1 // Copyright 2012 the V8 project authors. All rights reserved.
      2 // Redistribution and use in source and binary forms, with or without
      3 // modification, are permitted provided that the following conditions are
      4 // met:
      5 //
      6 //     * Redistributions of source code must retain the above copyright
      7 //       notice, this list of conditions and the following disclaimer.
      8 //     * Redistributions in binary form must reproduce the above
      9 //       copyright notice, this list of conditions and the following
     10 //       disclaimer in the documentation and/or other materials provided
     11 //       with the distribution.
     12 //     * Neither the name of Google Inc. nor the names of its
     13 //       contributors may be used to endorse or promote products derived
     14 //       from this software without specific prior written permission.
     15 //
     16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27 
     28 
     29 #include "v8.h"
     30 
     31 #include "liveedit.h"
     32 
     33 #include "code-stubs.h"
     34 #include "compilation-cache.h"
     35 #include "compiler.h"
     36 #include "debug.h"
     37 #include "deoptimizer.h"
     38 #include "global-handles.h"
     39 #include "messages.h"
     40 #include "parser.h"
     41 #include "scopeinfo.h"
     42 #include "scopes.h"
     43 #include "v8memory.h"
     44 
     45 namespace v8 {
     46 namespace internal {
     47 
     48 
     49 #ifdef ENABLE_DEBUGGER_SUPPORT
     50 
     51 
     52 void SetElementNonStrict(Handle<JSObject> object,
     53                          uint32_t index,
     54                          Handle<Object> value) {
     55   // Ignore return value from SetElement. It can only be a failure if there
     56   // are element setters causing exceptions and the debugger context has none
     57   // of these.
     58   Handle<Object> no_failure =
     59       JSObject::SetElement(object, index, value, NONE, kNonStrictMode);
     60   ASSERT(!no_failure.is_null());
     61   USE(no_failure);
     62 }
     63 
     64 
     65 // A simple implementation of dynamic programming algorithm. It solves
     66 // the problem of finding the difference of 2 arrays. It uses a table of results
     67 // of subproblems. Each cell contains a number together with 2-bit flag
     68 // that helps building the chunk list.
     69 class Differencer {
     70  public:
     71   explicit Differencer(Comparator::Input* input)
     72       : input_(input), len1_(input->GetLength1()), len2_(input->GetLength2()) {
     73     buffer_ = NewArray<int>(len1_ * len2_);
     74   }
     75   ~Differencer() {
     76     DeleteArray(buffer_);
     77   }
     78 
     79   void Initialize() {
     80     int array_size = len1_ * len2_;
     81     for (int i = 0; i < array_size; i++) {
     82       buffer_[i] = kEmptyCellValue;
     83     }
     84   }
     85 
     86   // Makes sure that result for the full problem is calculated and stored
     87   // in the table together with flags showing a path through subproblems.
     88   void FillTable() {
     89     CompareUpToTail(0, 0);
     90   }
     91 
     92   void SaveResult(Comparator::Output* chunk_writer) {
     93     ResultWriter writer(chunk_writer);
     94 
     95     int pos1 = 0;
     96     int pos2 = 0;
     97     while (true) {
     98       if (pos1 < len1_) {
     99         if (pos2 < len2_) {
    100           Direction dir = get_direction(pos1, pos2);
    101           switch (dir) {
    102             case EQ:
    103               writer.eq();
    104               pos1++;
    105               pos2++;
    106               break;
    107             case SKIP1:
    108               writer.skip1(1);
    109               pos1++;
    110               break;
    111             case SKIP2:
    112             case SKIP_ANY:
    113               writer.skip2(1);
    114               pos2++;
    115               break;
    116             default:
    117               UNREACHABLE();
    118           }
    119         } else {
    120           writer.skip1(len1_ - pos1);
    121           break;
    122         }
    123       } else {
    124         if (len2_ != pos2) {
    125           writer.skip2(len2_ - pos2);
    126         }
    127         break;
    128       }
    129     }
    130     writer.close();
    131   }
    132 
    133  private:
    134   Comparator::Input* input_;
    135   int* buffer_;
    136   int len1_;
    137   int len2_;
    138 
    139   enum Direction {
    140     EQ = 0,
    141     SKIP1,
    142     SKIP2,
    143     SKIP_ANY,
    144 
    145     MAX_DIRECTION_FLAG_VALUE = SKIP_ANY
    146   };
    147 
    148   // Computes result for a subtask and optionally caches it in the buffer table.
    149   // All results values are shifted to make space for flags in the lower bits.
    150   int CompareUpToTail(int pos1, int pos2) {
    151     if (pos1 < len1_) {
    152       if (pos2 < len2_) {
    153         int cached_res = get_value4(pos1, pos2);
    154         if (cached_res == kEmptyCellValue) {
    155           Direction dir;
    156           int res;
    157           if (input_->Equals(pos1, pos2)) {
    158             res = CompareUpToTail(pos1 + 1, pos2 + 1);
    159             dir = EQ;
    160           } else {
    161             int res1 = CompareUpToTail(pos1 + 1, pos2) +
    162                 (1 << kDirectionSizeBits);
    163             int res2 = CompareUpToTail(pos1, pos2 + 1) +
    164                 (1 << kDirectionSizeBits);
    165             if (res1 == res2) {
    166               res = res1;
    167               dir = SKIP_ANY;
    168             } else if (res1 < res2) {
    169               res = res1;
    170               dir = SKIP1;
    171             } else {
    172               res = res2;
    173               dir = SKIP2;
    174             }
    175           }
    176           set_value4_and_dir(pos1, pos2, res, dir);
    177           cached_res = res;
    178         }
    179         return cached_res;
    180       } else {
    181         return (len1_ - pos1) << kDirectionSizeBits;
    182       }
    183     } else {
    184       return (len2_ - pos2) << kDirectionSizeBits;
    185     }
    186   }
    187 
    188   inline int& get_cell(int i1, int i2) {
    189     return buffer_[i1 + i2 * len1_];
    190   }
    191 
    192   // Each cell keeps a value plus direction. Value is multiplied by 4.
    193   void set_value4_and_dir(int i1, int i2, int value4, Direction dir) {
    194     ASSERT((value4 & kDirectionMask) == 0);
    195     get_cell(i1, i2) = value4 | dir;
    196   }
    197 
    198   int get_value4(int i1, int i2) {
    199     return get_cell(i1, i2) & (kMaxUInt32 ^ kDirectionMask);
    200   }
    201   Direction get_direction(int i1, int i2) {
    202     return static_cast<Direction>(get_cell(i1, i2) & kDirectionMask);
    203   }
    204 
    205   static const int kDirectionSizeBits = 2;
    206   static const int kDirectionMask = (1 << kDirectionSizeBits) - 1;
    207   static const int kEmptyCellValue = -1 << kDirectionSizeBits;
    208 
    209   // This method only holds static assert statement (unfortunately you cannot
    210   // place one in class scope).
    211   void StaticAssertHolder() {
    212     STATIC_ASSERT(MAX_DIRECTION_FLAG_VALUE < (1 << kDirectionSizeBits));
    213   }
    214 
    215   class ResultWriter {
    216    public:
    217     explicit ResultWriter(Comparator::Output* chunk_writer)
    218         : chunk_writer_(chunk_writer), pos1_(0), pos2_(0),
    219           pos1_begin_(-1), pos2_begin_(-1), has_open_chunk_(false) {
    220     }
    221     void eq() {
    222       FlushChunk();
    223       pos1_++;
    224       pos2_++;
    225     }
    226     void skip1(int len1) {
    227       StartChunk();
    228       pos1_ += len1;
    229     }
    230     void skip2(int len2) {
    231       StartChunk();
    232       pos2_ += len2;
    233     }
    234     void close() {
    235       FlushChunk();
    236     }
    237 
    238    private:
    239     Comparator::Output* chunk_writer_;
    240     int pos1_;
    241     int pos2_;
    242     int pos1_begin_;
    243     int pos2_begin_;
    244     bool has_open_chunk_;
    245 
    246     void StartChunk() {
    247       if (!has_open_chunk_) {
    248         pos1_begin_ = pos1_;
    249         pos2_begin_ = pos2_;
    250         has_open_chunk_ = true;
    251       }
    252     }
    253 
    254     void FlushChunk() {
    255       if (has_open_chunk_) {
    256         chunk_writer_->AddChunk(pos1_begin_, pos2_begin_,
    257                                 pos1_ - pos1_begin_, pos2_ - pos2_begin_);
    258         has_open_chunk_ = false;
    259       }
    260     }
    261   };
    262 };
    263 
    264 
    265 void Comparator::CalculateDifference(Comparator::Input* input,
    266                                      Comparator::Output* result_writer) {
    267   Differencer differencer(input);
    268   differencer.Initialize();
    269   differencer.FillTable();
    270   differencer.SaveResult(result_writer);
    271 }
    272 
    273 
    274 static bool CompareSubstrings(Handle<String> s1, int pos1,
    275                               Handle<String> s2, int pos2, int len) {
    276   for (int i = 0; i < len; i++) {
    277     if (s1->Get(i + pos1) != s2->Get(i + pos2)) {
    278       return false;
    279     }
    280   }
    281   return true;
    282 }
    283 
    284 
    285 // Additional to Input interface. Lets switch Input range to subrange.
    286 // More elegant way would be to wrap one Input as another Input object
    287 // and translate positions there, but that would cost us additional virtual
    288 // call per comparison.
    289 class SubrangableInput : public Comparator::Input {
    290  public:
    291   virtual void SetSubrange1(int offset, int len) = 0;
    292   virtual void SetSubrange2(int offset, int len) = 0;
    293 };
    294 
    295 
    296 class SubrangableOutput : public Comparator::Output {
    297  public:
    298   virtual void SetSubrange1(int offset, int len) = 0;
    299   virtual void SetSubrange2(int offset, int len) = 0;
    300 };
    301 
    302 
    303 static int min(int a, int b) {
    304   return a < b ? a : b;
    305 }
    306 
    307 
    308 // Finds common prefix and suffix in input. This parts shouldn't take space in
    309 // linear programming table. Enable subranging in input and output.
    310 static void NarrowDownInput(SubrangableInput* input,
    311     SubrangableOutput* output) {
    312   const int len1 = input->GetLength1();
    313   const int len2 = input->GetLength2();
    314 
    315   int common_prefix_len;
    316   int common_suffix_len;
    317 
    318   {
    319     common_prefix_len = 0;
    320     int prefix_limit = min(len1, len2);
    321     while (common_prefix_len < prefix_limit &&
    322         input->Equals(common_prefix_len, common_prefix_len)) {
    323       common_prefix_len++;
    324     }
    325 
    326     common_suffix_len = 0;
    327     int suffix_limit = min(len1 - common_prefix_len, len2 - common_prefix_len);
    328 
    329     while (common_suffix_len < suffix_limit &&
    330         input->Equals(len1 - common_suffix_len - 1,
    331         len2 - common_suffix_len - 1)) {
    332       common_suffix_len++;
    333     }
    334   }
    335 
    336   if (common_prefix_len > 0 || common_suffix_len > 0) {
    337     int new_len1 = len1 - common_suffix_len - common_prefix_len;
    338     int new_len2 = len2 - common_suffix_len - common_prefix_len;
    339 
    340     input->SetSubrange1(common_prefix_len, new_len1);
    341     input->SetSubrange2(common_prefix_len, new_len2);
    342 
    343     output->SetSubrange1(common_prefix_len, new_len1);
    344     output->SetSubrange2(common_prefix_len, new_len2);
    345   }
    346 }
    347 
    348 
    349 // A helper class that writes chunk numbers into JSArray.
    350 // Each chunk is stored as 3 array elements: (pos1_begin, pos1_end, pos2_end).
    351 class CompareOutputArrayWriter {
    352  public:
    353   explicit CompareOutputArrayWriter(Isolate* isolate)
    354       : array_(isolate->factory()->NewJSArray(10)), current_size_(0) {}
    355 
    356   Handle<JSArray> GetResult() {
    357     return array_;
    358   }
    359 
    360   void WriteChunk(int char_pos1, int char_pos2, int char_len1, int char_len2) {
    361     Isolate* isolate = array_->GetIsolate();
    362     SetElementNonStrict(array_,
    363                         current_size_,
    364                         Handle<Object>(Smi::FromInt(char_pos1), isolate));
    365     SetElementNonStrict(array_,
    366                         current_size_ + 1,
    367                         Handle<Object>(Smi::FromInt(char_pos1 + char_len1),
    368                                        isolate));
    369     SetElementNonStrict(array_,
    370                         current_size_ + 2,
    371                         Handle<Object>(Smi::FromInt(char_pos2 + char_len2),
    372                                        isolate));
    373     current_size_ += 3;
    374   }
    375 
    376  private:
    377   Handle<JSArray> array_;
    378   int current_size_;
    379 };
    380 
    381 
    382 // Represents 2 strings as 2 arrays of tokens.
    383 // TODO(LiveEdit): Currently it's actually an array of charactres.
    384 //     Make array of tokens instead.
    385 class TokensCompareInput : public Comparator::Input {
    386  public:
    387   TokensCompareInput(Handle<String> s1, int offset1, int len1,
    388                        Handle<String> s2, int offset2, int len2)
    389       : s1_(s1), offset1_(offset1), len1_(len1),
    390         s2_(s2), offset2_(offset2), len2_(len2) {
    391   }
    392   virtual int GetLength1() {
    393     return len1_;
    394   }
    395   virtual int GetLength2() {
    396     return len2_;
    397   }
    398   bool Equals(int index1, int index2) {
    399     return s1_->Get(offset1_ + index1) == s2_->Get(offset2_ + index2);
    400   }
    401 
    402  private:
    403   Handle<String> s1_;
    404   int offset1_;
    405   int len1_;
    406   Handle<String> s2_;
    407   int offset2_;
    408   int len2_;
    409 };
    410 
    411 
    412 // Stores compare result in JSArray. Converts substring positions
    413 // to absolute positions.
    414 class TokensCompareOutput : public Comparator::Output {
    415  public:
    416   TokensCompareOutput(CompareOutputArrayWriter* array_writer,
    417                       int offset1, int offset2)
    418         : array_writer_(array_writer), offset1_(offset1), offset2_(offset2) {
    419   }
    420 
    421   void AddChunk(int pos1, int pos2, int len1, int len2) {
    422     array_writer_->WriteChunk(pos1 + offset1_, pos2 + offset2_, len1, len2);
    423   }
    424 
    425  private:
    426   CompareOutputArrayWriter* array_writer_;
    427   int offset1_;
    428   int offset2_;
    429 };
    430 
    431 
    432 // Wraps raw n-elements line_ends array as a list of n+1 lines. The last line
    433 // never has terminating new line character.
    434 class LineEndsWrapper {
    435  public:
    436   explicit LineEndsWrapper(Handle<String> string)
    437       : ends_array_(CalculateLineEnds(string, false)),
    438         string_len_(string->length()) {
    439   }
    440   int length() {
    441     return ends_array_->length() + 1;
    442   }
    443   // Returns start for any line including start of the imaginary line after
    444   // the last line.
    445   int GetLineStart(int index) {
    446     if (index == 0) {
    447       return 0;
    448     } else {
    449       return GetLineEnd(index - 1);
    450     }
    451   }
    452   int GetLineEnd(int index) {
    453     if (index == ends_array_->length()) {
    454       // End of the last line is always an end of the whole string.
    455       // If the string ends with a new line character, the last line is an
    456       // empty string after this character.
    457       return string_len_;
    458     } else {
    459       return GetPosAfterNewLine(index);
    460     }
    461   }
    462 
    463  private:
    464   Handle<FixedArray> ends_array_;
    465   int string_len_;
    466 
    467   int GetPosAfterNewLine(int index) {
    468     return Smi::cast(ends_array_->get(index))->value() + 1;
    469   }
    470 };
    471 
    472 
    473 // Represents 2 strings as 2 arrays of lines.
    474 class LineArrayCompareInput : public SubrangableInput {
    475  public:
    476   LineArrayCompareInput(Handle<String> s1, Handle<String> s2,
    477                         LineEndsWrapper line_ends1, LineEndsWrapper line_ends2)
    478       : s1_(s1), s2_(s2), line_ends1_(line_ends1),
    479         line_ends2_(line_ends2),
    480         subrange_offset1_(0), subrange_offset2_(0),
    481         subrange_len1_(line_ends1_.length()),
    482         subrange_len2_(line_ends2_.length()) {
    483   }
    484   int GetLength1() {
    485     return subrange_len1_;
    486   }
    487   int GetLength2() {
    488     return subrange_len2_;
    489   }
    490   bool Equals(int index1, int index2) {
    491     index1 += subrange_offset1_;
    492     index2 += subrange_offset2_;
    493 
    494     int line_start1 = line_ends1_.GetLineStart(index1);
    495     int line_start2 = line_ends2_.GetLineStart(index2);
    496     int line_end1 = line_ends1_.GetLineEnd(index1);
    497     int line_end2 = line_ends2_.GetLineEnd(index2);
    498     int len1 = line_end1 - line_start1;
    499     int len2 = line_end2 - line_start2;
    500     if (len1 != len2) {
    501       return false;
    502     }
    503     return CompareSubstrings(s1_, line_start1, s2_, line_start2,
    504                              len1);
    505   }
    506   void SetSubrange1(int offset, int len) {
    507     subrange_offset1_ = offset;
    508     subrange_len1_ = len;
    509   }
    510   void SetSubrange2(int offset, int len) {
    511     subrange_offset2_ = offset;
    512     subrange_len2_ = len;
    513   }
    514 
    515  private:
    516   Handle<String> s1_;
    517   Handle<String> s2_;
    518   LineEndsWrapper line_ends1_;
    519   LineEndsWrapper line_ends2_;
    520   int subrange_offset1_;
    521   int subrange_offset2_;
    522   int subrange_len1_;
    523   int subrange_len2_;
    524 };
    525 
    526 
    527 // Stores compare result in JSArray. For each chunk tries to conduct
    528 // a fine-grained nested diff token-wise.
    529 class TokenizingLineArrayCompareOutput : public SubrangableOutput {
    530  public:
    531   TokenizingLineArrayCompareOutput(LineEndsWrapper line_ends1,
    532                                    LineEndsWrapper line_ends2,
    533                                    Handle<String> s1, Handle<String> s2)
    534       : array_writer_(s1->GetIsolate()),
    535         line_ends1_(line_ends1), line_ends2_(line_ends2), s1_(s1), s2_(s2),
    536         subrange_offset1_(0), subrange_offset2_(0) {
    537   }
    538 
    539   void AddChunk(int line_pos1, int line_pos2, int line_len1, int line_len2) {
    540     line_pos1 += subrange_offset1_;
    541     line_pos2 += subrange_offset2_;
    542 
    543     int char_pos1 = line_ends1_.GetLineStart(line_pos1);
    544     int char_pos2 = line_ends2_.GetLineStart(line_pos2);
    545     int char_len1 = line_ends1_.GetLineStart(line_pos1 + line_len1) - char_pos1;
    546     int char_len2 = line_ends2_.GetLineStart(line_pos2 + line_len2) - char_pos2;
    547 
    548     if (char_len1 < CHUNK_LEN_LIMIT && char_len2 < CHUNK_LEN_LIMIT) {
    549       // Chunk is small enough to conduct a nested token-level diff.
    550       HandleScope subTaskScope(s1_->GetIsolate());
    551 
    552       TokensCompareInput tokens_input(s1_, char_pos1, char_len1,
    553                                       s2_, char_pos2, char_len2);
    554       TokensCompareOutput tokens_output(&array_writer_, char_pos1,
    555                                           char_pos2);
    556 
    557       Comparator::CalculateDifference(&tokens_input, &tokens_output);
    558     } else {
    559       array_writer_.WriteChunk(char_pos1, char_pos2, char_len1, char_len2);
    560     }
    561   }
    562   void SetSubrange1(int offset, int len) {
    563     subrange_offset1_ = offset;
    564   }
    565   void SetSubrange2(int offset, int len) {
    566     subrange_offset2_ = offset;
    567   }
    568 
    569   Handle<JSArray> GetResult() {
    570     return array_writer_.GetResult();
    571   }
    572 
    573  private:
    574   static const int CHUNK_LEN_LIMIT = 800;
    575 
    576   CompareOutputArrayWriter array_writer_;
    577   LineEndsWrapper line_ends1_;
    578   LineEndsWrapper line_ends2_;
    579   Handle<String> s1_;
    580   Handle<String> s2_;
    581   int subrange_offset1_;
    582   int subrange_offset2_;
    583 };
    584 
    585 
    586 Handle<JSArray> LiveEdit::CompareStrings(Handle<String> s1,
    587                                          Handle<String> s2) {
    588   s1 = FlattenGetString(s1);
    589   s2 = FlattenGetString(s2);
    590 
    591   LineEndsWrapper line_ends1(s1);
    592   LineEndsWrapper line_ends2(s2);
    593 
    594   LineArrayCompareInput input(s1, s2, line_ends1, line_ends2);
    595   TokenizingLineArrayCompareOutput output(line_ends1, line_ends2, s1, s2);
    596 
    597   NarrowDownInput(&input, &output);
    598 
    599   Comparator::CalculateDifference(&input, &output);
    600 
    601   return output.GetResult();
    602 }
    603 
    604 
    605 static void CompileScriptForTracker(Isolate* isolate, Handle<Script> script) {
    606   // TODO(635): support extensions.
    607   PostponeInterruptsScope postpone(isolate);
    608 
    609   // Build AST.
    610   CompilationInfoWithZone info(script);
    611   info.MarkAsGlobal();
    612   // Parse and don't allow skipping lazy functions.
    613   if (Parser::Parse(&info)) {
    614     // Compile the code.
    615     LiveEditFunctionTracker tracker(info.isolate(), info.function());
    616     if (Compiler::MakeCodeForLiveEdit(&info)) {
    617       ASSERT(!info.code().is_null());
    618       tracker.RecordRootFunctionInfo(info.code());
    619     } else {
    620       info.isolate()->StackOverflow();
    621     }
    622   }
    623 }
    624 
    625 
    626 // Unwraps JSValue object, returning its field "value"
    627 static Handle<Object> UnwrapJSValue(Handle<JSValue> jsValue) {
    628   return Handle<Object>(jsValue->value(), jsValue->GetIsolate());
    629 }
    630 
    631 
    632 // Wraps any object into a OpaqueReference, that will hide the object
    633 // from JavaScript.
    634 static Handle<JSValue> WrapInJSValue(Handle<Object> object) {
    635   Isolate* isolate = Isolate::Current();
    636   Handle<JSFunction> constructor = isolate->opaque_reference_function();
    637   Handle<JSValue> result =
    638       Handle<JSValue>::cast(isolate->factory()->NewJSObject(constructor));
    639   result->set_value(*object);
    640   return result;
    641 }
    642 
    643 
    644 static Handle<SharedFunctionInfo> UnwrapSharedFunctionInfoFromJSValue(
    645     Handle<JSValue> jsValue) {
    646   Object* shared = jsValue->value();
    647   CHECK(shared->IsSharedFunctionInfo());
    648   return Handle<SharedFunctionInfo>(SharedFunctionInfo::cast(shared));
    649 }
    650 
    651 
    652 static int GetArrayLength(Handle<JSArray> array) {
    653   Object* length = array->length();
    654   CHECK(length->IsSmi());
    655   return Smi::cast(length)->value();
    656 }
    657 
    658 
    659 // Simple helper class that creates more or less typed structures over
    660 // JSArray object. This is an adhoc method of passing structures from C++
    661 // to JavaScript.
    662 template<typename S>
    663 class JSArrayBasedStruct {
    664  public:
    665   static S Create() {
    666     Factory* factory = Isolate::Current()->factory();
    667     Handle<JSArray> array = factory->NewJSArray(S::kSize_);
    668     return S(array);
    669   }
    670   static S cast(Object* object) {
    671     JSArray* array = JSArray::cast(object);
    672     Handle<JSArray> array_handle(array);
    673     return S(array_handle);
    674   }
    675   explicit JSArrayBasedStruct(Handle<JSArray> array) : array_(array) {
    676   }
    677   Handle<JSArray> GetJSArray() {
    678     return array_;
    679   }
    680   Isolate* isolate() const {
    681     return array_->GetIsolate();
    682   }
    683 
    684  protected:
    685   void SetField(int field_position, Handle<Object> value) {
    686     SetElementNonStrict(array_, field_position, value);
    687   }
    688   void SetSmiValueField(int field_position, int value) {
    689     SetElementNonStrict(array_,
    690                         field_position,
    691                         Handle<Smi>(Smi::FromInt(value), isolate()));
    692   }
    693   Object* GetField(int field_position) {
    694     return array_->GetElementNoExceptionThrown(field_position);
    695   }
    696   int GetSmiValueField(int field_position) {
    697     Object* res = GetField(field_position);
    698     CHECK(res->IsSmi());
    699     return Smi::cast(res)->value();
    700   }
    701 
    702  private:
    703   Handle<JSArray> array_;
    704 };
    705 
    706 
    707 // Represents some function compilation details. This structure will be used
    708 // from JavaScript. It contains Code object, which is kept wrapped
    709 // into a BlindReference for sanitizing reasons.
    710 class FunctionInfoWrapper : public JSArrayBasedStruct<FunctionInfoWrapper> {
    711  public:
    712   explicit FunctionInfoWrapper(Handle<JSArray> array)
    713       : JSArrayBasedStruct<FunctionInfoWrapper>(array) {
    714   }
    715   void SetInitialProperties(Handle<String> name, int start_position,
    716                             int end_position, int param_num,
    717                             int literal_count, int parent_index) {
    718     HandleScope scope(isolate());
    719     this->SetField(kFunctionNameOffset_, name);
    720     this->SetSmiValueField(kStartPositionOffset_, start_position);
    721     this->SetSmiValueField(kEndPositionOffset_, end_position);
    722     this->SetSmiValueField(kParamNumOffset_, param_num);
    723     this->SetSmiValueField(kLiteralNumOffset_, literal_count);
    724     this->SetSmiValueField(kParentIndexOffset_, parent_index);
    725   }
    726   void SetFunctionCode(Handle<Code> function_code,
    727       Handle<Object> code_scope_info) {
    728     Handle<JSValue> code_wrapper = WrapInJSValue(function_code);
    729     this->SetField(kCodeOffset_, code_wrapper);
    730 
    731     Handle<JSValue> scope_wrapper = WrapInJSValue(code_scope_info);
    732     this->SetField(kCodeScopeInfoOffset_, scope_wrapper);
    733   }
    734   void SetOuterScopeInfo(Handle<Object> scope_info_array) {
    735     this->SetField(kOuterScopeInfoOffset_, scope_info_array);
    736   }
    737   void SetSharedFunctionInfo(Handle<SharedFunctionInfo> info) {
    738     Handle<JSValue> info_holder = WrapInJSValue(info);
    739     this->SetField(kSharedFunctionInfoOffset_, info_holder);
    740   }
    741   int GetLiteralCount() {
    742     return this->GetSmiValueField(kLiteralNumOffset_);
    743   }
    744   int GetParentIndex() {
    745     return this->GetSmiValueField(kParentIndexOffset_);
    746   }
    747   Handle<Code> GetFunctionCode() {
    748     Object* element = this->GetField(kCodeOffset_);
    749     CHECK(element->IsJSValue());
    750     Handle<JSValue> value_wrapper(JSValue::cast(element));
    751     Handle<Object> raw_result = UnwrapJSValue(value_wrapper);
    752     CHECK(raw_result->IsCode());
    753     return Handle<Code>::cast(raw_result);
    754   }
    755   Handle<Object> GetCodeScopeInfo() {
    756     Object* element = this->GetField(kCodeScopeInfoOffset_);
    757     CHECK(element->IsJSValue());
    758     return UnwrapJSValue(Handle<JSValue>(JSValue::cast(element)));
    759   }
    760   int GetStartPosition() {
    761     return this->GetSmiValueField(kStartPositionOffset_);
    762   }
    763   int GetEndPosition() {
    764     return this->GetSmiValueField(kEndPositionOffset_);
    765   }
    766 
    767  private:
    768   static const int kFunctionNameOffset_ = 0;
    769   static const int kStartPositionOffset_ = 1;
    770   static const int kEndPositionOffset_ = 2;
    771   static const int kParamNumOffset_ = 3;
    772   static const int kCodeOffset_ = 4;
    773   static const int kCodeScopeInfoOffset_ = 5;
    774   static const int kOuterScopeInfoOffset_ = 6;
    775   static const int kParentIndexOffset_ = 7;
    776   static const int kSharedFunctionInfoOffset_ = 8;
    777   static const int kLiteralNumOffset_ = 9;
    778   static const int kSize_ = 10;
    779 
    780   friend class JSArrayBasedStruct<FunctionInfoWrapper>;
    781 };
    782 
    783 
    784 // Wraps SharedFunctionInfo along with some of its fields for passing it
    785 // back to JavaScript. SharedFunctionInfo object itself is additionally
    786 // wrapped into BlindReference for sanitizing reasons.
    787 class SharedInfoWrapper : public JSArrayBasedStruct<SharedInfoWrapper> {
    788  public:
    789   static bool IsInstance(Handle<JSArray> array) {
    790     return array->length() == Smi::FromInt(kSize_) &&
    791         array->GetElementNoExceptionThrown(kSharedInfoOffset_)->IsJSValue();
    792   }
    793 
    794   explicit SharedInfoWrapper(Handle<JSArray> array)
    795       : JSArrayBasedStruct<SharedInfoWrapper>(array) {
    796   }
    797 
    798   void SetProperties(Handle<String> name, int start_position, int end_position,
    799                      Handle<SharedFunctionInfo> info) {
    800     HandleScope scope(isolate());
    801     this->SetField(kFunctionNameOffset_, name);
    802     Handle<JSValue> info_holder = WrapInJSValue(info);
    803     this->SetField(kSharedInfoOffset_, info_holder);
    804     this->SetSmiValueField(kStartPositionOffset_, start_position);
    805     this->SetSmiValueField(kEndPositionOffset_, end_position);
    806   }
    807   Handle<SharedFunctionInfo> GetInfo() {
    808     Object* element = this->GetField(kSharedInfoOffset_);
    809     CHECK(element->IsJSValue());
    810     Handle<JSValue> value_wrapper(JSValue::cast(element));
    811     return UnwrapSharedFunctionInfoFromJSValue(value_wrapper);
    812   }
    813 
    814  private:
    815   static const int kFunctionNameOffset_ = 0;
    816   static const int kStartPositionOffset_ = 1;
    817   static const int kEndPositionOffset_ = 2;
    818   static const int kSharedInfoOffset_ = 3;
    819   static const int kSize_ = 4;
    820 
    821   friend class JSArrayBasedStruct<SharedInfoWrapper>;
    822 };
    823 
    824 
    825 class FunctionInfoListener {
    826  public:
    827   explicit FunctionInfoListener(Isolate* isolate) {
    828     current_parent_index_ = -1;
    829     len_ = 0;
    830     result_ = isolate->factory()->NewJSArray(10);
    831   }
    832 
    833   void FunctionStarted(FunctionLiteral* fun) {
    834     HandleScope scope(isolate());
    835     FunctionInfoWrapper info = FunctionInfoWrapper::Create();
    836     info.SetInitialProperties(fun->name(), fun->start_position(),
    837                               fun->end_position(), fun->parameter_count(),
    838                               fun->materialized_literal_count(),
    839                               current_parent_index_);
    840     current_parent_index_ = len_;
    841     SetElementNonStrict(result_, len_, info.GetJSArray());
    842     len_++;
    843   }
    844 
    845   void FunctionDone() {
    846     HandleScope scope(isolate());
    847     FunctionInfoWrapper info =
    848         FunctionInfoWrapper::cast(
    849             result_->GetElementNoExceptionThrown(current_parent_index_));
    850     current_parent_index_ = info.GetParentIndex();
    851   }
    852 
    853   // Saves only function code, because for a script function we
    854   // may never create a SharedFunctionInfo object.
    855   void FunctionCode(Handle<Code> function_code) {
    856     FunctionInfoWrapper info =
    857         FunctionInfoWrapper::cast(
    858             result_->GetElementNoExceptionThrown(current_parent_index_));
    859     info.SetFunctionCode(function_code,
    860                          Handle<Object>(isolate()->heap()->null_value(),
    861                                         isolate()));
    862   }
    863 
    864   // Saves full information about a function: its code, its scope info
    865   // and a SharedFunctionInfo object.
    866   void FunctionInfo(Handle<SharedFunctionInfo> shared, Scope* scope,
    867                     Zone* zone) {
    868     if (!shared->IsSharedFunctionInfo()) {
    869       return;
    870     }
    871     FunctionInfoWrapper info =
    872         FunctionInfoWrapper::cast(
    873             result_->GetElementNoExceptionThrown(current_parent_index_));
    874     info.SetFunctionCode(Handle<Code>(shared->code()),
    875                          Handle<Object>(shared->scope_info(), isolate()));
    876     info.SetSharedFunctionInfo(shared);
    877 
    878     Handle<Object> scope_info_list(SerializeFunctionScope(scope, zone),
    879                                    isolate());
    880     info.SetOuterScopeInfo(scope_info_list);
    881   }
    882 
    883   Handle<JSArray> GetResult() { return result_; }
    884 
    885  private:
    886   Isolate* isolate() const { return result_->GetIsolate(); }
    887 
    888   Object* SerializeFunctionScope(Scope* scope, Zone* zone) {
    889     HandleScope handle_scope(isolate());
    890 
    891     Handle<JSArray> scope_info_list = isolate()->factory()->NewJSArray(10);
    892     int scope_info_length = 0;
    893 
    894     // Saves some description of scope. It stores name and indexes of
    895     // variables in the whole scope chain. Null-named slots delimit
    896     // scopes of this chain.
    897     Scope* outer_scope = scope->outer_scope();
    898     if (outer_scope == NULL) {
    899       return isolate()->heap()->undefined_value();
    900     }
    901     do {
    902       ZoneList<Variable*> stack_list(outer_scope->StackLocalCount(), zone);
    903       ZoneList<Variable*> context_list(outer_scope->ContextLocalCount(), zone);
    904       outer_scope->CollectStackAndContextLocals(&stack_list, &context_list);
    905       context_list.Sort(&Variable::CompareIndex);
    906 
    907       for (int i = 0; i < context_list.length(); i++) {
    908         SetElementNonStrict(scope_info_list,
    909                             scope_info_length,
    910                             context_list[i]->name());
    911         scope_info_length++;
    912         SetElementNonStrict(
    913             scope_info_list,
    914             scope_info_length,
    915             Handle<Smi>(Smi::FromInt(context_list[i]->index()), isolate()));
    916         scope_info_length++;
    917       }
    918       SetElementNonStrict(scope_info_list,
    919                           scope_info_length,
    920                           Handle<Object>(isolate()->heap()->null_value(),
    921                                          isolate()));
    922       scope_info_length++;
    923 
    924       outer_scope = outer_scope->outer_scope();
    925     } while (outer_scope != NULL);
    926 
    927     return *scope_info_list;
    928   }
    929 
    930   Handle<JSArray> result_;
    931   int len_;
    932   int current_parent_index_;
    933 };
    934 
    935 
    936 JSArray* LiveEdit::GatherCompileInfo(Handle<Script> script,
    937                                      Handle<String> source) {
    938   Isolate* isolate = Isolate::Current();
    939 
    940   FunctionInfoListener listener(isolate);
    941   Handle<Object> original_source =
    942       Handle<Object>(script->source(), isolate);
    943   script->set_source(*source);
    944   isolate->set_active_function_info_listener(&listener);
    945 
    946   {
    947     // Creating verbose TryCatch from public API is currently the only way to
    948     // force code save location. We do not use this the object directly.
    949     v8::TryCatch try_catch;
    950     try_catch.SetVerbose(true);
    951 
    952     // A logical 'try' section.
    953     CompileScriptForTracker(isolate, script);
    954   }
    955 
    956   // A logical 'catch' section.
    957   Handle<JSObject> rethrow_exception;
    958   if (isolate->has_pending_exception()) {
    959     Handle<Object> exception(isolate->pending_exception()->ToObjectChecked(),
    960                              isolate);
    961     MessageLocation message_location = isolate->GetMessageLocation();
    962 
    963     isolate->clear_pending_message();
    964     isolate->clear_pending_exception();
    965 
    966     // If possible, copy positions from message object to exception object.
    967     if (exception->IsJSObject() && !message_location.script().is_null()) {
    968       rethrow_exception = Handle<JSObject>::cast(exception);
    969 
    970       Factory* factory = isolate->factory();
    971       Handle<String> start_pos_key = factory->InternalizeOneByteString(
    972           STATIC_ASCII_VECTOR("startPosition"));
    973       Handle<String> end_pos_key = factory->InternalizeOneByteString(
    974           STATIC_ASCII_VECTOR("endPosition"));
    975       Handle<String> script_obj_key = factory->InternalizeOneByteString(
    976           STATIC_ASCII_VECTOR("scriptObject"));
    977       Handle<Smi> start_pos(
    978           Smi::FromInt(message_location.start_pos()), isolate);
    979       Handle<Smi> end_pos(Smi::FromInt(message_location.end_pos()), isolate);
    980       Handle<JSValue> script_obj = GetScriptWrapper(message_location.script());
    981       JSReceiver::SetProperty(
    982           rethrow_exception, start_pos_key, start_pos, NONE, kNonStrictMode);
    983       JSReceiver::SetProperty(
    984           rethrow_exception, end_pos_key, end_pos, NONE, kNonStrictMode);
    985       JSReceiver::SetProperty(
    986           rethrow_exception, script_obj_key, script_obj, NONE, kNonStrictMode);
    987     }
    988   }
    989 
    990   // A logical 'finally' section.
    991   isolate->set_active_function_info_listener(NULL);
    992   script->set_source(*original_source);
    993 
    994   if (rethrow_exception.is_null()) {
    995     return *(listener.GetResult());
    996   } else {
    997     isolate->Throw(*rethrow_exception);
    998     return 0;
    999   }
   1000 }
   1001 
   1002 
   1003 void LiveEdit::WrapSharedFunctionInfos(Handle<JSArray> array) {
   1004   HandleScope scope(array->GetIsolate());
   1005   int len = GetArrayLength(array);
   1006   for (int i = 0; i < len; i++) {
   1007     Handle<SharedFunctionInfo> info(
   1008         SharedFunctionInfo::cast(array->GetElementNoExceptionThrown(i)));
   1009     SharedInfoWrapper info_wrapper = SharedInfoWrapper::Create();
   1010     Handle<String> name_handle(String::cast(info->name()));
   1011     info_wrapper.SetProperties(name_handle, info->start_position(),
   1012                                info->end_position(), info);
   1013     SetElementNonStrict(array, i, info_wrapper.GetJSArray());
   1014   }
   1015 }
   1016 
   1017 
   1018 // Visitor that finds all references to a particular code object,
   1019 // including "CODE_TARGET" references in other code objects and replaces
   1020 // them on the fly.
   1021 class ReplacingVisitor : public ObjectVisitor {
   1022  public:
   1023   explicit ReplacingVisitor(Code* original, Code* substitution)
   1024     : original_(original), substitution_(substitution) {
   1025   }
   1026 
   1027   virtual void VisitPointers(Object** start, Object** end) {
   1028     for (Object** p = start; p < end; p++) {
   1029       if (*p == original_) {
   1030         *p = substitution_;
   1031       }
   1032     }
   1033   }
   1034 
   1035   virtual void VisitCodeEntry(Address entry) {
   1036     if (Code::GetObjectFromEntryAddress(entry) == original_) {
   1037       Address substitution_entry = substitution_->instruction_start();
   1038       Memory::Address_at(entry) = substitution_entry;
   1039     }
   1040   }
   1041 
   1042   virtual void VisitCodeTarget(RelocInfo* rinfo) {
   1043     if (RelocInfo::IsCodeTarget(rinfo->rmode()) &&
   1044         Code::GetCodeFromTargetAddress(rinfo->target_address()) == original_) {
   1045       Address substitution_entry = substitution_->instruction_start();
   1046       rinfo->set_target_address(substitution_entry);
   1047     }
   1048   }
   1049 
   1050   virtual void VisitDebugTarget(RelocInfo* rinfo) {
   1051     VisitCodeTarget(rinfo);
   1052   }
   1053 
   1054  private:
   1055   Code* original_;
   1056   Code* substitution_;
   1057 };
   1058 
   1059 
   1060 // Finds all references to original and replaces them with substitution.
   1061 static void ReplaceCodeObject(Handle<Code> original,
   1062                               Handle<Code> substitution) {
   1063   // Perform a full GC in order to ensure that we are not in the middle of an
   1064   // incremental marking phase when we are replacing the code object.
   1065   // Since we are not in an incremental marking phase we can write pointers
   1066   // to code objects (that are never in new space) without worrying about
   1067   // write barriers.
   1068   Heap* heap = original->GetHeap();
   1069   heap->CollectAllGarbage(Heap::kMakeHeapIterableMask,
   1070                           "liveedit.cc ReplaceCodeObject");
   1071 
   1072   ASSERT(!heap->InNewSpace(*substitution));
   1073 
   1074   DisallowHeapAllocation no_allocation;
   1075 
   1076   ReplacingVisitor visitor(*original, *substitution);
   1077 
   1078   // Iterate over all roots. Stack frames may have pointer into original code,
   1079   // so temporary replace the pointers with offset numbers
   1080   // in prologue/epilogue.
   1081   heap->IterateRoots(&visitor, VISIT_ALL);
   1082 
   1083   // Now iterate over all pointers of all objects, including code_target
   1084   // implicit pointers.
   1085   HeapIterator iterator(heap);
   1086   for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
   1087     obj->Iterate(&visitor);
   1088   }
   1089 }
   1090 
   1091 
   1092 // Patch function literals.
   1093 // Name 'literals' is a misnomer. Rather it's a cache for complex object
   1094 // boilerplates and for a native context. We must clean cached values.
   1095 // Additionally we may need to allocate a new array if number of literals
   1096 // changed.
   1097 class LiteralFixer {
   1098  public:
   1099   static void PatchLiterals(FunctionInfoWrapper* compile_info_wrapper,
   1100                             Handle<SharedFunctionInfo> shared_info,
   1101                             Isolate* isolate) {
   1102     int new_literal_count = compile_info_wrapper->GetLiteralCount();
   1103     if (new_literal_count > 0) {
   1104       new_literal_count += JSFunction::kLiteralsPrefixSize;
   1105     }
   1106     int old_literal_count = shared_info->num_literals();
   1107 
   1108     if (old_literal_count == new_literal_count) {
   1109       // If literal count didn't change, simply go over all functions
   1110       // and clear literal arrays.
   1111       ClearValuesVisitor visitor;
   1112       IterateJSFunctions(*shared_info, &visitor);
   1113     } else {
   1114       // When literal count changes, we have to create new array instances.
   1115       // Since we cannot create instances when iterating heap, we should first
   1116       // collect all functions and fix their literal arrays.
   1117       Handle<FixedArray> function_instances =
   1118           CollectJSFunctions(shared_info, isolate);
   1119       for (int i = 0; i < function_instances->length(); i++) {
   1120         Handle<JSFunction> fun(JSFunction::cast(function_instances->get(i)));
   1121         Handle<FixedArray> old_literals(fun->literals());
   1122         Handle<FixedArray> new_literals =
   1123             isolate->factory()->NewFixedArray(new_literal_count);
   1124         if (new_literal_count > 0) {
   1125           Handle<Context> native_context;
   1126           if (old_literals->length() >
   1127               JSFunction::kLiteralNativeContextIndex) {
   1128             native_context = Handle<Context>(
   1129                 JSFunction::NativeContextFromLiterals(fun->literals()));
   1130           } else {
   1131             native_context = Handle<Context>(fun->context()->native_context());
   1132           }
   1133           new_literals->set(JSFunction::kLiteralNativeContextIndex,
   1134               *native_context);
   1135         }
   1136         fun->set_literals(*new_literals);
   1137       }
   1138 
   1139       shared_info->set_num_literals(new_literal_count);
   1140     }
   1141   }
   1142 
   1143  private:
   1144   // Iterates all function instances in the HEAP that refers to the
   1145   // provided shared_info.
   1146   template<typename Visitor>
   1147   static void IterateJSFunctions(SharedFunctionInfo* shared_info,
   1148                                  Visitor* visitor) {
   1149     DisallowHeapAllocation no_allocation;
   1150 
   1151     HeapIterator iterator(shared_info->GetHeap());
   1152     for (HeapObject* obj = iterator.next(); obj != NULL;
   1153         obj = iterator.next()) {
   1154       if (obj->IsJSFunction()) {
   1155         JSFunction* function = JSFunction::cast(obj);
   1156         if (function->shared() == shared_info) {
   1157           visitor->visit(function);
   1158         }
   1159       }
   1160     }
   1161   }
   1162 
   1163   // Finds all instances of JSFunction that refers to the provided shared_info
   1164   // and returns array with them.
   1165   static Handle<FixedArray> CollectJSFunctions(
   1166       Handle<SharedFunctionInfo> shared_info, Isolate* isolate) {
   1167     CountVisitor count_visitor;
   1168     count_visitor.count = 0;
   1169     IterateJSFunctions(*shared_info, &count_visitor);
   1170     int size = count_visitor.count;
   1171 
   1172     Handle<FixedArray> result = isolate->factory()->NewFixedArray(size);
   1173     if (size > 0) {
   1174       CollectVisitor collect_visitor(result);
   1175       IterateJSFunctions(*shared_info, &collect_visitor);
   1176     }
   1177     return result;
   1178   }
   1179 
   1180   class ClearValuesVisitor {
   1181    public:
   1182     void visit(JSFunction* fun) {
   1183       FixedArray* literals = fun->literals();
   1184       int len = literals->length();
   1185       for (int j = JSFunction::kLiteralsPrefixSize; j < len; j++) {
   1186         literals->set_undefined(j);
   1187       }
   1188     }
   1189   };
   1190 
   1191   class CountVisitor {
   1192    public:
   1193     void visit(JSFunction* fun) {
   1194       count++;
   1195     }
   1196     int count;
   1197   };
   1198 
   1199   class CollectVisitor {
   1200    public:
   1201     explicit CollectVisitor(Handle<FixedArray> output)
   1202         : m_output(output), m_pos(0) {}
   1203 
   1204     void visit(JSFunction* fun) {
   1205       m_output->set(m_pos, fun);
   1206       m_pos++;
   1207     }
   1208    private:
   1209     Handle<FixedArray> m_output;
   1210     int m_pos;
   1211   };
   1212 };
   1213 
   1214 
   1215 // Check whether the code is natural function code (not a lazy-compile stub
   1216 // code).
   1217 static bool IsJSFunctionCode(Code* code) {
   1218   return code->kind() == Code::FUNCTION;
   1219 }
   1220 
   1221 
   1222 // Returns true if an instance of candidate were inlined into function's code.
   1223 static bool IsInlined(JSFunction* function, SharedFunctionInfo* candidate) {
   1224   DisallowHeapAllocation no_gc;
   1225 
   1226   if (function->code()->kind() != Code::OPTIMIZED_FUNCTION) return false;
   1227 
   1228   DeoptimizationInputData* data =
   1229       DeoptimizationInputData::cast(function->code()->deoptimization_data());
   1230 
   1231   if (data == HEAP->empty_fixed_array()) return false;
   1232 
   1233   FixedArray* literals = data->LiteralArray();
   1234 
   1235   int inlined_count = data->InlinedFunctionCount()->value();
   1236   for (int i = 0; i < inlined_count; ++i) {
   1237     JSFunction* inlined = JSFunction::cast(literals->get(i));
   1238     if (inlined->shared() == candidate) return true;
   1239   }
   1240 
   1241   return false;
   1242 }
   1243 
   1244 
   1245 class DependentFunctionFilter : public OptimizedFunctionFilter {
   1246  public:
   1247   explicit DependentFunctionFilter(
   1248       SharedFunctionInfo* function_info)
   1249       : function_info_(function_info) {}
   1250 
   1251   virtual bool TakeFunction(JSFunction* function) {
   1252     return (function->shared() == function_info_ ||
   1253             IsInlined(function, function_info_));
   1254   }
   1255 
   1256  private:
   1257   SharedFunctionInfo* function_info_;
   1258 };
   1259 
   1260 
   1261 static void DeoptimizeDependentFunctions(SharedFunctionInfo* function_info) {
   1262   DisallowHeapAllocation no_allocation;
   1263 
   1264   DependentFunctionFilter filter(function_info);
   1265   Deoptimizer::DeoptimizeAllFunctionsWith(function_info->GetIsolate(), &filter);
   1266 }
   1267 
   1268 
   1269 MaybeObject* LiveEdit::ReplaceFunctionCode(
   1270     Handle<JSArray> new_compile_info_array,
   1271     Handle<JSArray> shared_info_array) {
   1272   Isolate* isolate = Isolate::Current();
   1273   HandleScope scope(isolate);
   1274 
   1275   if (!SharedInfoWrapper::IsInstance(shared_info_array)) {
   1276     return isolate->ThrowIllegalOperation();
   1277   }
   1278 
   1279   FunctionInfoWrapper compile_info_wrapper(new_compile_info_array);
   1280   SharedInfoWrapper shared_info_wrapper(shared_info_array);
   1281 
   1282   Handle<SharedFunctionInfo> shared_info = shared_info_wrapper.GetInfo();
   1283 
   1284   isolate->heap()->EnsureHeapIsIterable();
   1285 
   1286   if (IsJSFunctionCode(shared_info->code())) {
   1287     Handle<Code> code = compile_info_wrapper.GetFunctionCode();
   1288     ReplaceCodeObject(Handle<Code>(shared_info->code()), code);
   1289     Handle<Object> code_scope_info = compile_info_wrapper.GetCodeScopeInfo();
   1290     if (code_scope_info->IsFixedArray()) {
   1291       shared_info->set_scope_info(ScopeInfo::cast(*code_scope_info));
   1292     }
   1293     shared_info->DisableOptimization(kLiveEdit);
   1294   }
   1295 
   1296   if (shared_info->debug_info()->IsDebugInfo()) {
   1297     Handle<DebugInfo> debug_info(DebugInfo::cast(shared_info->debug_info()));
   1298     Handle<Code> new_original_code =
   1299         isolate->factory()->CopyCode(compile_info_wrapper.GetFunctionCode());
   1300     debug_info->set_original_code(*new_original_code);
   1301   }
   1302 
   1303   int start_position = compile_info_wrapper.GetStartPosition();
   1304   int end_position = compile_info_wrapper.GetEndPosition();
   1305   shared_info->set_start_position(start_position);
   1306   shared_info->set_end_position(end_position);
   1307 
   1308   LiteralFixer::PatchLiterals(&compile_info_wrapper, shared_info, isolate);
   1309 
   1310   shared_info->set_construct_stub(
   1311       isolate->builtins()->builtin(Builtins::kJSConstructStubGeneric));
   1312 
   1313   DeoptimizeDependentFunctions(*shared_info);
   1314   isolate->compilation_cache()->Remove(shared_info);
   1315 
   1316   return isolate->heap()->undefined_value();
   1317 }
   1318 
   1319 
   1320 MaybeObject* LiveEdit::FunctionSourceUpdated(
   1321     Handle<JSArray> shared_info_array) {
   1322   Isolate* isolate = shared_info_array->GetIsolate();
   1323   HandleScope scope(isolate);
   1324 
   1325   if (!SharedInfoWrapper::IsInstance(shared_info_array)) {
   1326     return isolate->ThrowIllegalOperation();
   1327   }
   1328 
   1329   SharedInfoWrapper shared_info_wrapper(shared_info_array);
   1330   Handle<SharedFunctionInfo> shared_info = shared_info_wrapper.GetInfo();
   1331 
   1332   DeoptimizeDependentFunctions(*shared_info);
   1333   isolate->compilation_cache()->Remove(shared_info);
   1334 
   1335   return isolate->heap()->undefined_value();
   1336 }
   1337 
   1338 
   1339 void LiveEdit::SetFunctionScript(Handle<JSValue> function_wrapper,
   1340                                  Handle<Object> script_handle) {
   1341   Handle<SharedFunctionInfo> shared_info =
   1342       UnwrapSharedFunctionInfoFromJSValue(function_wrapper);
   1343   CHECK(script_handle->IsScript() || script_handle->IsUndefined());
   1344   shared_info->set_script(*script_handle);
   1345 
   1346   Isolate::Current()->compilation_cache()->Remove(shared_info);
   1347 }
   1348 
   1349 
   1350 // For a script text change (defined as position_change_array), translates
   1351 // position in unchanged text to position in changed text.
   1352 // Text change is a set of non-overlapping regions in text, that have changed
   1353 // their contents and length. It is specified as array of groups of 3 numbers:
   1354 // (change_begin, change_end, change_end_new_position).
   1355 // Each group describes a change in text; groups are sorted by change_begin.
   1356 // Only position in text beyond any changes may be successfully translated.
   1357 // If a positions is inside some region that changed, result is currently
   1358 // undefined.
   1359 static int TranslatePosition(int original_position,
   1360                              Handle<JSArray> position_change_array) {
   1361   int position_diff = 0;
   1362   int array_len = GetArrayLength(position_change_array);
   1363   // TODO(635): binary search may be used here
   1364   for (int i = 0; i < array_len; i += 3) {
   1365     Object* element = position_change_array->GetElementNoExceptionThrown(i);
   1366     CHECK(element->IsSmi());
   1367     int chunk_start = Smi::cast(element)->value();
   1368     if (original_position < chunk_start) {
   1369       break;
   1370     }
   1371     element = position_change_array->GetElementNoExceptionThrown(i + 1);
   1372     CHECK(element->IsSmi());
   1373     int chunk_end = Smi::cast(element)->value();
   1374     // Position mustn't be inside a chunk.
   1375     ASSERT(original_position >= chunk_end);
   1376     element = position_change_array->GetElementNoExceptionThrown(i + 2);
   1377     CHECK(element->IsSmi());
   1378     int chunk_changed_end = Smi::cast(element)->value();
   1379     position_diff = chunk_changed_end - chunk_end;
   1380   }
   1381 
   1382   return original_position + position_diff;
   1383 }
   1384 
   1385 
   1386 // Auto-growing buffer for writing relocation info code section. This buffer
   1387 // is a simplified version of buffer from Assembler. Unlike Assembler, this
   1388 // class is platform-independent and it works without dealing with instructions.
   1389 // As specified by RelocInfo format, the buffer is filled in reversed order:
   1390 // from upper to lower addresses.
   1391 // It uses NewArray/DeleteArray for memory management.
   1392 class RelocInfoBuffer {
   1393  public:
   1394   RelocInfoBuffer(int buffer_initial_capicity, byte* pc) {
   1395     buffer_size_ = buffer_initial_capicity + kBufferGap;
   1396     buffer_ = NewArray<byte>(buffer_size_);
   1397 
   1398     reloc_info_writer_.Reposition(buffer_ + buffer_size_, pc);
   1399   }
   1400   ~RelocInfoBuffer() {
   1401     DeleteArray(buffer_);
   1402   }
   1403 
   1404   // As specified by RelocInfo format, the buffer is filled in reversed order:
   1405   // from upper to lower addresses.
   1406   void Write(const RelocInfo* rinfo) {
   1407     if (buffer_ + kBufferGap >= reloc_info_writer_.pos()) {
   1408       Grow();
   1409     }
   1410     reloc_info_writer_.Write(rinfo);
   1411   }
   1412 
   1413   Vector<byte> GetResult() {
   1414     // Return the bytes from pos up to end of buffer.
   1415     int result_size =
   1416         static_cast<int>((buffer_ + buffer_size_) - reloc_info_writer_.pos());
   1417     return Vector<byte>(reloc_info_writer_.pos(), result_size);
   1418   }
   1419 
   1420  private:
   1421   void Grow() {
   1422     // Compute new buffer size.
   1423     int new_buffer_size;
   1424     if (buffer_size_ < 2 * KB) {
   1425       new_buffer_size = 4 * KB;
   1426     } else {
   1427       new_buffer_size = 2 * buffer_size_;
   1428     }
   1429     // Some internal data structures overflow for very large buffers,
   1430     // they must ensure that kMaximalBufferSize is not too large.
   1431     if (new_buffer_size > kMaximalBufferSize) {
   1432       V8::FatalProcessOutOfMemory("RelocInfoBuffer::GrowBuffer");
   1433     }
   1434 
   1435     // Set up new buffer.
   1436     byte* new_buffer = NewArray<byte>(new_buffer_size);
   1437 
   1438     // Copy the data.
   1439     int curently_used_size =
   1440         static_cast<int>(buffer_ + buffer_size_ - reloc_info_writer_.pos());
   1441     OS::MemMove(new_buffer + new_buffer_size - curently_used_size,
   1442                 reloc_info_writer_.pos(), curently_used_size);
   1443 
   1444     reloc_info_writer_.Reposition(
   1445         new_buffer + new_buffer_size - curently_used_size,
   1446         reloc_info_writer_.last_pc());
   1447 
   1448     DeleteArray(buffer_);
   1449     buffer_ = new_buffer;
   1450     buffer_size_ = new_buffer_size;
   1451   }
   1452 
   1453   RelocInfoWriter reloc_info_writer_;
   1454   byte* buffer_;
   1455   int buffer_size_;
   1456 
   1457   static const int kBufferGap = RelocInfoWriter::kMaxSize;
   1458   static const int kMaximalBufferSize = 512*MB;
   1459 };
   1460 
   1461 
   1462 // Patch positions in code (changes relocation info section) and possibly
   1463 // returns new instance of code.
   1464 static Handle<Code> PatchPositionsInCode(
   1465     Handle<Code> code,
   1466     Handle<JSArray> position_change_array) {
   1467   Isolate* isolate = code->GetIsolate();
   1468 
   1469   RelocInfoBuffer buffer_writer(code->relocation_size(),
   1470                                 code->instruction_start());
   1471 
   1472   {
   1473     DisallowHeapAllocation no_allocation;
   1474     for (RelocIterator it(*code); !it.done(); it.next()) {
   1475       RelocInfo* rinfo = it.rinfo();
   1476       if (RelocInfo::IsPosition(rinfo->rmode())) {
   1477         int position = static_cast<int>(rinfo->data());
   1478         int new_position = TranslatePosition(position,
   1479                                              position_change_array);
   1480         if (position != new_position) {
   1481           RelocInfo info_copy(rinfo->pc(), rinfo->rmode(), new_position, NULL);
   1482           buffer_writer.Write(&info_copy);
   1483           continue;
   1484         }
   1485       }
   1486       if (RelocInfo::IsRealRelocMode(rinfo->rmode())) {
   1487         buffer_writer.Write(it.rinfo());
   1488       }
   1489     }
   1490   }
   1491 
   1492   Vector<byte> buffer = buffer_writer.GetResult();
   1493 
   1494   if (buffer.length() == code->relocation_size()) {
   1495     // Simply patch relocation area of code.
   1496     OS::MemCopy(code->relocation_start(), buffer.start(), buffer.length());
   1497     return code;
   1498   } else {
   1499     // Relocation info section now has different size. We cannot simply
   1500     // rewrite it inside code object. Instead we have to create a new
   1501     // code object.
   1502     Handle<Code> result(isolate->factory()->CopyCode(code, buffer));
   1503     return result;
   1504   }
   1505 }
   1506 
   1507 
   1508 MaybeObject* LiveEdit::PatchFunctionPositions(
   1509     Handle<JSArray> shared_info_array, Handle<JSArray> position_change_array) {
   1510   if (!SharedInfoWrapper::IsInstance(shared_info_array)) {
   1511     return Isolate::Current()->ThrowIllegalOperation();
   1512   }
   1513 
   1514   SharedInfoWrapper shared_info_wrapper(shared_info_array);
   1515   Handle<SharedFunctionInfo> info = shared_info_wrapper.GetInfo();
   1516 
   1517   int old_function_start = info->start_position();
   1518   int new_function_start = TranslatePosition(old_function_start,
   1519                                              position_change_array);
   1520   int new_function_end = TranslatePosition(info->end_position(),
   1521                                            position_change_array);
   1522   int new_function_token_pos =
   1523       TranslatePosition(info->function_token_position(), position_change_array);
   1524 
   1525   info->set_start_position(new_function_start);
   1526   info->set_end_position(new_function_end);
   1527   info->set_function_token_position(new_function_token_pos);
   1528 
   1529   HEAP->EnsureHeapIsIterable();
   1530 
   1531   if (IsJSFunctionCode(info->code())) {
   1532     // Patch relocation info section of the code.
   1533     Handle<Code> patched_code = PatchPositionsInCode(Handle<Code>(info->code()),
   1534                                                      position_change_array);
   1535     if (*patched_code != info->code()) {
   1536       // Replace all references to the code across the heap. In particular,
   1537       // some stubs may refer to this code and this code may be being executed
   1538       // on stack (it is safe to substitute the code object on stack, because
   1539       // we only change the structure of rinfo and leave instructions
   1540       // untouched).
   1541       ReplaceCodeObject(Handle<Code>(info->code()), patched_code);
   1542     }
   1543   }
   1544 
   1545   return HEAP->undefined_value();
   1546 }
   1547 
   1548 
   1549 static Handle<Script> CreateScriptCopy(Handle<Script> original) {
   1550   Isolate* isolate = original->GetIsolate();
   1551 
   1552   Handle<String> original_source(String::cast(original->source()));
   1553   Handle<Script> copy = isolate->factory()->NewScript(original_source);
   1554 
   1555   copy->set_name(original->name());
   1556   copy->set_line_offset(original->line_offset());
   1557   copy->set_column_offset(original->column_offset());
   1558   copy->set_data(original->data());
   1559   copy->set_type(original->type());
   1560   copy->set_context_data(original->context_data());
   1561   copy->set_eval_from_shared(original->eval_from_shared());
   1562   copy->set_eval_from_instructions_offset(
   1563       original->eval_from_instructions_offset());
   1564 
   1565   // Copy all the flags, but clear compilation state.
   1566   copy->set_flags(original->flags());
   1567   copy->set_compilation_state(Script::COMPILATION_STATE_INITIAL);
   1568 
   1569   return copy;
   1570 }
   1571 
   1572 
   1573 Object* LiveEdit::ChangeScriptSource(Handle<Script> original_script,
   1574                                      Handle<String> new_source,
   1575                                      Handle<Object> old_script_name) {
   1576   Isolate* isolate = original_script->GetIsolate();
   1577   Handle<Object> old_script_object;
   1578   if (old_script_name->IsString()) {
   1579     Handle<Script> old_script = CreateScriptCopy(original_script);
   1580     old_script->set_name(String::cast(*old_script_name));
   1581     old_script_object = old_script;
   1582     isolate->debugger()->OnAfterCompile(
   1583         old_script, Debugger::SEND_WHEN_DEBUGGING);
   1584   } else {
   1585     old_script_object = isolate->factory()->null_value();
   1586   }
   1587 
   1588   original_script->set_source(*new_source);
   1589 
   1590   // Drop line ends so that they will be recalculated.
   1591   original_script->set_line_ends(HEAP->undefined_value());
   1592 
   1593   return *old_script_object;
   1594 }
   1595 
   1596 
   1597 
   1598 void LiveEdit::ReplaceRefToNestedFunction(
   1599     Handle<JSValue> parent_function_wrapper,
   1600     Handle<JSValue> orig_function_wrapper,
   1601     Handle<JSValue> subst_function_wrapper) {
   1602 
   1603   Handle<SharedFunctionInfo> parent_shared =
   1604       UnwrapSharedFunctionInfoFromJSValue(parent_function_wrapper);
   1605   Handle<SharedFunctionInfo> orig_shared =
   1606       UnwrapSharedFunctionInfoFromJSValue(orig_function_wrapper);
   1607   Handle<SharedFunctionInfo> subst_shared =
   1608       UnwrapSharedFunctionInfoFromJSValue(subst_function_wrapper);
   1609 
   1610   for (RelocIterator it(parent_shared->code()); !it.done(); it.next()) {
   1611     if (it.rinfo()->rmode() == RelocInfo::EMBEDDED_OBJECT) {
   1612       if (it.rinfo()->target_object() == *orig_shared) {
   1613         it.rinfo()->set_target_object(*subst_shared);
   1614       }
   1615     }
   1616   }
   1617 }
   1618 
   1619 
   1620 // Check an activation against list of functions. If there is a function
   1621 // that matches, its status in result array is changed to status argument value.
   1622 static bool CheckActivation(Handle<JSArray> shared_info_array,
   1623                             Handle<JSArray> result,
   1624                             StackFrame* frame,
   1625                             LiveEdit::FunctionPatchabilityStatus status) {
   1626   if (!frame->is_java_script()) return false;
   1627 
   1628   Handle<JSFunction> function(JavaScriptFrame::cast(frame)->function());
   1629 
   1630   Isolate* isolate = shared_info_array->GetIsolate();
   1631   int len = GetArrayLength(shared_info_array);
   1632   for (int i = 0; i < len; i++) {
   1633     Object* element = shared_info_array->GetElementNoExceptionThrown(i);
   1634     CHECK(element->IsJSValue());
   1635     Handle<JSValue> jsvalue(JSValue::cast(element));
   1636     Handle<SharedFunctionInfo> shared =
   1637         UnwrapSharedFunctionInfoFromJSValue(jsvalue);
   1638 
   1639     if (function->shared() == *shared || IsInlined(*function, *shared)) {
   1640       SetElementNonStrict(result, i, Handle<Smi>(Smi::FromInt(status),
   1641                                                  isolate));
   1642       return true;
   1643     }
   1644   }
   1645   return false;
   1646 }
   1647 
   1648 
   1649 // Iterates over handler chain and removes all elements that are inside
   1650 // frames being dropped.
   1651 static bool FixTryCatchHandler(StackFrame* top_frame,
   1652                                StackFrame* bottom_frame) {
   1653   Address* pointer_address =
   1654       &Memory::Address_at(Isolate::Current()->get_address_from_id(
   1655           Isolate::kHandlerAddress));
   1656 
   1657   while (*pointer_address < top_frame->sp()) {
   1658     pointer_address = &Memory::Address_at(*pointer_address);
   1659   }
   1660   Address* above_frame_address = pointer_address;
   1661   while (*pointer_address < bottom_frame->fp()) {
   1662     pointer_address = &Memory::Address_at(*pointer_address);
   1663   }
   1664   bool change = *above_frame_address != *pointer_address;
   1665   *above_frame_address = *pointer_address;
   1666   return change;
   1667 }
   1668 
   1669 
   1670 // Removes specified range of frames from stack. There may be 1 or more
   1671 // frames in range. Anyway the bottom frame is restarted rather than dropped,
   1672 // and therefore has to be a JavaScript frame.
   1673 // Returns error message or NULL.
   1674 static const char* DropFrames(Vector<StackFrame*> frames,
   1675                               int top_frame_index,
   1676                               int bottom_js_frame_index,
   1677                               Debug::FrameDropMode* mode,
   1678                               Object*** restarter_frame_function_pointer) {
   1679   if (!Debug::kFrameDropperSupported) {
   1680     return "Stack manipulations are not supported in this architecture.";
   1681   }
   1682 
   1683   StackFrame* pre_top_frame = frames[top_frame_index - 1];
   1684   StackFrame* top_frame = frames[top_frame_index];
   1685   StackFrame* bottom_js_frame = frames[bottom_js_frame_index];
   1686 
   1687   ASSERT(bottom_js_frame->is_java_script());
   1688 
   1689   // Check the nature of the top frame.
   1690   Isolate* isolate = Isolate::Current();
   1691   Code* pre_top_frame_code = pre_top_frame->LookupCode();
   1692   bool frame_has_padding;
   1693   if (pre_top_frame_code->is_inline_cache_stub() &&
   1694       pre_top_frame_code->is_debug_stub()) {
   1695     // OK, we can drop inline cache calls.
   1696     *mode = Debug::FRAME_DROPPED_IN_IC_CALL;
   1697     frame_has_padding = Debug::FramePaddingLayout::kIsSupported;
   1698   } else if (pre_top_frame_code ==
   1699              isolate->debug()->debug_break_slot()) {
   1700     // OK, we can drop debug break slot.
   1701     *mode = Debug::FRAME_DROPPED_IN_DEBUG_SLOT_CALL;
   1702     frame_has_padding = Debug::FramePaddingLayout::kIsSupported;
   1703   } else if (pre_top_frame_code ==
   1704       isolate->builtins()->builtin(
   1705           Builtins::kFrameDropper_LiveEdit)) {
   1706     // OK, we can drop our own code.
   1707     pre_top_frame = frames[top_frame_index - 2];
   1708     top_frame = frames[top_frame_index - 1];
   1709     *mode = Debug::CURRENTLY_SET_MODE;
   1710     frame_has_padding = false;
   1711   } else if (pre_top_frame_code ==
   1712       isolate->builtins()->builtin(Builtins::kReturn_DebugBreak)) {
   1713     *mode = Debug::FRAME_DROPPED_IN_RETURN_CALL;
   1714     frame_has_padding = Debug::FramePaddingLayout::kIsSupported;
   1715   } else if (pre_top_frame_code->kind() == Code::STUB &&
   1716       pre_top_frame_code->major_key() == CodeStub::CEntry) {
   1717     // Entry from our unit tests on 'debugger' statement.
   1718     // It's fine, we support this case.
   1719     *mode = Debug::FRAME_DROPPED_IN_DIRECT_CALL;
   1720     // We don't have a padding from 'debugger' statement call.
   1721     // Here the stub is CEntry, it's not debug-only and can't be padded.
   1722     // If anyone would complain, a proxy padded stub could be added.
   1723     frame_has_padding = false;
   1724   } else if (pre_top_frame->type() == StackFrame::ARGUMENTS_ADAPTOR) {
   1725     // This must be adaptor that remain from the frame dropping that
   1726     // is still on stack. A frame dropper frame must be above it.
   1727     ASSERT(frames[top_frame_index - 2]->LookupCode() ==
   1728         isolate->builtins()->builtin(Builtins::kFrameDropper_LiveEdit));
   1729     pre_top_frame = frames[top_frame_index - 3];
   1730     top_frame = frames[top_frame_index - 2];
   1731     *mode = Debug::CURRENTLY_SET_MODE;
   1732     frame_has_padding = false;
   1733   } else {
   1734     return "Unknown structure of stack above changing function";
   1735   }
   1736 
   1737   Address unused_stack_top = top_frame->sp();
   1738   Address unused_stack_bottom = bottom_js_frame->fp()
   1739       - Debug::kFrameDropperFrameSize * kPointerSize  // Size of the new frame.
   1740       + kPointerSize;  // Bigger address end is exclusive.
   1741 
   1742   Address* top_frame_pc_address = top_frame->pc_address();
   1743 
   1744   // top_frame may be damaged below this point. Do not used it.
   1745   ASSERT(!(top_frame = NULL));
   1746 
   1747   if (unused_stack_top > unused_stack_bottom) {
   1748     if (frame_has_padding) {
   1749       int shortage_bytes =
   1750           static_cast<int>(unused_stack_top - unused_stack_bottom);
   1751 
   1752       Address padding_start = pre_top_frame->fp() -
   1753           Debug::FramePaddingLayout::kFrameBaseSize * kPointerSize;
   1754 
   1755       Address padding_pointer = padding_start;
   1756       Smi* padding_object =
   1757           Smi::FromInt(Debug::FramePaddingLayout::kPaddingValue);
   1758       while (Memory::Object_at(padding_pointer) == padding_object) {
   1759         padding_pointer -= kPointerSize;
   1760       }
   1761       int padding_counter =
   1762           Smi::cast(Memory::Object_at(padding_pointer))->value();
   1763       if (padding_counter * kPointerSize < shortage_bytes) {
   1764         return "Not enough space for frame dropper frame "
   1765             "(even with padding frame)";
   1766       }
   1767       Memory::Object_at(padding_pointer) =
   1768           Smi::FromInt(padding_counter - shortage_bytes / kPointerSize);
   1769 
   1770       StackFrame* pre_pre_frame = frames[top_frame_index - 2];
   1771 
   1772       OS::MemMove(padding_start + kPointerSize - shortage_bytes,
   1773                   padding_start + kPointerSize,
   1774                   Debug::FramePaddingLayout::kFrameBaseSize * kPointerSize);
   1775 
   1776       pre_top_frame->UpdateFp(pre_top_frame->fp() - shortage_bytes);
   1777       pre_pre_frame->SetCallerFp(pre_top_frame->fp());
   1778       unused_stack_top -= shortage_bytes;
   1779 
   1780       STATIC_ASSERT(sizeof(Address) == kPointerSize);
   1781       top_frame_pc_address -= shortage_bytes / kPointerSize;
   1782     } else {
   1783       return "Not enough space for frame dropper frame";
   1784     }
   1785   }
   1786 
   1787   // Committing now. After this point we should return only NULL value.
   1788 
   1789   FixTryCatchHandler(pre_top_frame, bottom_js_frame);
   1790   // Make sure FixTryCatchHandler is idempotent.
   1791   ASSERT(!FixTryCatchHandler(pre_top_frame, bottom_js_frame));
   1792 
   1793   Handle<Code> code = Isolate::Current()->builtins()->FrameDropper_LiveEdit();
   1794   *top_frame_pc_address = code->entry();
   1795   pre_top_frame->SetCallerFp(bottom_js_frame->fp());
   1796 
   1797   *restarter_frame_function_pointer =
   1798       Debug::SetUpFrameDropperFrame(bottom_js_frame, code);
   1799 
   1800   ASSERT((**restarter_frame_function_pointer)->IsJSFunction());
   1801 
   1802   for (Address a = unused_stack_top;
   1803       a < unused_stack_bottom;
   1804       a += kPointerSize) {
   1805     Memory::Object_at(a) = Smi::FromInt(0);
   1806   }
   1807 
   1808   return NULL;
   1809 }
   1810 
   1811 
   1812 static bool IsDropableFrame(StackFrame* frame) {
   1813   return !frame->is_exit();
   1814 }
   1815 
   1816 
   1817 // Describes a set of call frames that execute any of listed functions.
   1818 // Finding no such frames does not mean error.
   1819 class MultipleFunctionTarget {
   1820  public:
   1821   MultipleFunctionTarget(Handle<JSArray> shared_info_array,
   1822       Handle<JSArray> result)
   1823       : m_shared_info_array(shared_info_array),
   1824         m_result(result) {}
   1825   bool MatchActivation(StackFrame* frame,
   1826       LiveEdit::FunctionPatchabilityStatus status) {
   1827     return CheckActivation(m_shared_info_array, m_result, frame, status);
   1828   }
   1829   const char* GetNotFoundMessage() {
   1830     return NULL;
   1831   }
   1832  private:
   1833   Handle<JSArray> m_shared_info_array;
   1834   Handle<JSArray> m_result;
   1835 };
   1836 
   1837 
   1838 // Drops all call frame matched by target and all frames above them.
   1839 template<typename TARGET>
   1840 static const char* DropActivationsInActiveThreadImpl(
   1841     TARGET& target, bool do_drop) {
   1842   Isolate* isolate = Isolate::Current();
   1843   Debug* debug = isolate->debug();
   1844   Zone zone(isolate);
   1845   Vector<StackFrame*> frames = CreateStackMap(isolate, &zone);
   1846 
   1847 
   1848   int top_frame_index = -1;
   1849   int frame_index = 0;
   1850   for (; frame_index < frames.length(); frame_index++) {
   1851     StackFrame* frame = frames[frame_index];
   1852     if (frame->id() == debug->break_frame_id()) {
   1853       top_frame_index = frame_index;
   1854       break;
   1855     }
   1856     if (target.MatchActivation(
   1857             frame, LiveEdit::FUNCTION_BLOCKED_UNDER_NATIVE_CODE)) {
   1858       // We are still above break_frame. It is not a target frame,
   1859       // it is a problem.
   1860       return "Debugger mark-up on stack is not found";
   1861     }
   1862   }
   1863 
   1864   if (top_frame_index == -1) {
   1865     // We haven't found break frame, but no function is blocking us anyway.
   1866     return target.GetNotFoundMessage();
   1867   }
   1868 
   1869   bool target_frame_found = false;
   1870   int bottom_js_frame_index = top_frame_index;
   1871   bool c_code_found = false;
   1872 
   1873   for (; frame_index < frames.length(); frame_index++) {
   1874     StackFrame* frame = frames[frame_index];
   1875     if (!IsDropableFrame(frame)) {
   1876       c_code_found = true;
   1877       break;
   1878     }
   1879     if (target.MatchActivation(
   1880             frame, LiveEdit::FUNCTION_BLOCKED_ON_ACTIVE_STACK)) {
   1881       target_frame_found = true;
   1882       bottom_js_frame_index = frame_index;
   1883     }
   1884   }
   1885 
   1886   if (c_code_found) {
   1887     // There is a C frames on stack. Check that there are no target frames
   1888     // below them.
   1889     for (; frame_index < frames.length(); frame_index++) {
   1890       StackFrame* frame = frames[frame_index];
   1891       if (frame->is_java_script()) {
   1892         if (target.MatchActivation(
   1893                 frame, LiveEdit::FUNCTION_BLOCKED_UNDER_NATIVE_CODE)) {
   1894           // Cannot drop frame under C frames.
   1895           return NULL;
   1896         }
   1897       }
   1898     }
   1899   }
   1900 
   1901   if (!do_drop) {
   1902     // We are in check-only mode.
   1903     return NULL;
   1904   }
   1905 
   1906   if (!target_frame_found) {
   1907     // Nothing to drop.
   1908     return target.GetNotFoundMessage();
   1909   }
   1910 
   1911   Debug::FrameDropMode drop_mode = Debug::FRAMES_UNTOUCHED;
   1912   Object** restarter_frame_function_pointer = NULL;
   1913   const char* error_message = DropFrames(frames, top_frame_index,
   1914                                          bottom_js_frame_index, &drop_mode,
   1915                                          &restarter_frame_function_pointer);
   1916 
   1917   if (error_message != NULL) {
   1918     return error_message;
   1919   }
   1920 
   1921   // Adjust break_frame after some frames has been dropped.
   1922   StackFrame::Id new_id = StackFrame::NO_ID;
   1923   for (int i = bottom_js_frame_index + 1; i < frames.length(); i++) {
   1924     if (frames[i]->type() == StackFrame::JAVA_SCRIPT) {
   1925       new_id = frames[i]->id();
   1926       break;
   1927     }
   1928   }
   1929   debug->FramesHaveBeenDropped(new_id, drop_mode,
   1930                                restarter_frame_function_pointer);
   1931   return NULL;
   1932 }
   1933 
   1934 
   1935 // Fills result array with statuses of functions. Modifies the stack
   1936 // removing all listed function if possible and if do_drop is true.
   1937 static const char* DropActivationsInActiveThread(
   1938     Handle<JSArray> shared_info_array, Handle<JSArray> result, bool do_drop) {
   1939   MultipleFunctionTarget target(shared_info_array, result);
   1940 
   1941   const char* message =
   1942       DropActivationsInActiveThreadImpl(target, do_drop);
   1943   if (message) {
   1944     return message;
   1945   }
   1946 
   1947   Isolate* isolate = shared_info_array->GetIsolate();
   1948   int array_len = GetArrayLength(shared_info_array);
   1949 
   1950   // Replace "blocked on active" with "replaced on active" status.
   1951   for (int i = 0; i < array_len; i++) {
   1952     if (result->GetElement(i) ==
   1953         Smi::FromInt(LiveEdit::FUNCTION_BLOCKED_ON_ACTIVE_STACK)) {
   1954       Handle<Object> replaced(
   1955           Smi::FromInt(LiveEdit::FUNCTION_REPLACED_ON_ACTIVE_STACK), isolate);
   1956       SetElementNonStrict(result, i, replaced);
   1957     }
   1958   }
   1959   return NULL;
   1960 }
   1961 
   1962 
   1963 class InactiveThreadActivationsChecker : public ThreadVisitor {
   1964  public:
   1965   InactiveThreadActivationsChecker(Handle<JSArray> shared_info_array,
   1966                                    Handle<JSArray> result)
   1967       : shared_info_array_(shared_info_array), result_(result),
   1968         has_blocked_functions_(false) {
   1969   }
   1970   void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
   1971     for (StackFrameIterator it(isolate, top); !it.done(); it.Advance()) {
   1972       has_blocked_functions_ |= CheckActivation(
   1973           shared_info_array_, result_, it.frame(),
   1974           LiveEdit::FUNCTION_BLOCKED_ON_OTHER_STACK);
   1975     }
   1976   }
   1977   bool HasBlockedFunctions() {
   1978     return has_blocked_functions_;
   1979   }
   1980 
   1981  private:
   1982   Handle<JSArray> shared_info_array_;
   1983   Handle<JSArray> result_;
   1984   bool has_blocked_functions_;
   1985 };
   1986 
   1987 
   1988 Handle<JSArray> LiveEdit::CheckAndDropActivations(
   1989     Handle<JSArray> shared_info_array, bool do_drop) {
   1990   Isolate* isolate = shared_info_array->GetIsolate();
   1991   int len = GetArrayLength(shared_info_array);
   1992 
   1993   Handle<JSArray> result = isolate->factory()->NewJSArray(len);
   1994 
   1995   // Fill the default values.
   1996   for (int i = 0; i < len; i++) {
   1997     SetElementNonStrict(
   1998         result,
   1999         i,
   2000         Handle<Smi>(Smi::FromInt(FUNCTION_AVAILABLE_FOR_PATCH), isolate));
   2001   }
   2002 
   2003 
   2004   // First check inactive threads. Fail if some functions are blocked there.
   2005   InactiveThreadActivationsChecker inactive_threads_checker(shared_info_array,
   2006                                                             result);
   2007   Isolate::Current()->thread_manager()->IterateArchivedThreads(
   2008       &inactive_threads_checker);
   2009   if (inactive_threads_checker.HasBlockedFunctions()) {
   2010     return result;
   2011   }
   2012 
   2013   // Try to drop activations from the current stack.
   2014   const char* error_message =
   2015       DropActivationsInActiveThread(shared_info_array, result, do_drop);
   2016   if (error_message != NULL) {
   2017     // Add error message as an array extra element.
   2018     Vector<const char> vector_message(error_message, StrLength(error_message));
   2019     Handle<String> str = isolate->factory()->NewStringFromAscii(vector_message);
   2020     SetElementNonStrict(result, len, str);
   2021   }
   2022   return result;
   2023 }
   2024 
   2025 
   2026 // Describes a single callframe a target. Not finding this frame
   2027 // means an error.
   2028 class SingleFrameTarget {
   2029  public:
   2030   explicit SingleFrameTarget(JavaScriptFrame* frame)
   2031       : m_frame(frame),
   2032         m_saved_status(LiveEdit::FUNCTION_AVAILABLE_FOR_PATCH) {}
   2033 
   2034   bool MatchActivation(StackFrame* frame,
   2035       LiveEdit::FunctionPatchabilityStatus status) {
   2036     if (frame->fp() == m_frame->fp()) {
   2037       m_saved_status = status;
   2038       return true;
   2039     }
   2040     return false;
   2041   }
   2042   const char* GetNotFoundMessage() {
   2043     return "Failed to found requested frame";
   2044   }
   2045   LiveEdit::FunctionPatchabilityStatus saved_status() {
   2046     return m_saved_status;
   2047   }
   2048  private:
   2049   JavaScriptFrame* m_frame;
   2050   LiveEdit::FunctionPatchabilityStatus m_saved_status;
   2051 };
   2052 
   2053 
   2054 // Finds a drops required frame and all frames above.
   2055 // Returns error message or NULL.
   2056 const char* LiveEdit::RestartFrame(JavaScriptFrame* frame) {
   2057   SingleFrameTarget target(frame);
   2058 
   2059   const char* result = DropActivationsInActiveThreadImpl(target, true);
   2060   if (result != NULL) {
   2061     return result;
   2062   }
   2063   if (target.saved_status() == LiveEdit::FUNCTION_BLOCKED_UNDER_NATIVE_CODE) {
   2064     return "Function is blocked under native code";
   2065   }
   2066   return NULL;
   2067 }
   2068 
   2069 
   2070 LiveEditFunctionTracker::LiveEditFunctionTracker(Isolate* isolate,
   2071                                                  FunctionLiteral* fun)
   2072     : isolate_(isolate) {
   2073   if (isolate_->active_function_info_listener() != NULL) {
   2074     isolate_->active_function_info_listener()->FunctionStarted(fun);
   2075   }
   2076 }
   2077 
   2078 
   2079 LiveEditFunctionTracker::~LiveEditFunctionTracker() {
   2080   if (isolate_->active_function_info_listener() != NULL) {
   2081     isolate_->active_function_info_listener()->FunctionDone();
   2082   }
   2083 }
   2084 
   2085 
   2086 void LiveEditFunctionTracker::RecordFunctionInfo(
   2087     Handle<SharedFunctionInfo> info, FunctionLiteral* lit,
   2088     Zone* zone) {
   2089   if (isolate_->active_function_info_listener() != NULL) {
   2090     isolate_->active_function_info_listener()->FunctionInfo(info, lit->scope(),
   2091                                                             zone);
   2092   }
   2093 }
   2094 
   2095 
   2096 void LiveEditFunctionTracker::RecordRootFunctionInfo(Handle<Code> code) {
   2097   isolate_->active_function_info_listener()->FunctionCode(code);
   2098 }
   2099 
   2100 
   2101 bool LiveEditFunctionTracker::IsActive(Isolate* isolate) {
   2102   return isolate->active_function_info_listener() != NULL;
   2103 }
   2104 
   2105 
   2106 #else  // ENABLE_DEBUGGER_SUPPORT
   2107 
   2108 // This ifdef-else-endif section provides working or stub implementation of
   2109 // LiveEditFunctionTracker.
   2110 LiveEditFunctionTracker::LiveEditFunctionTracker(Isolate* isolate,
   2111                                                  FunctionLiteral* fun) {
   2112 }
   2113 
   2114 
   2115 LiveEditFunctionTracker::~LiveEditFunctionTracker() {
   2116 }
   2117 
   2118 
   2119 void LiveEditFunctionTracker::RecordFunctionInfo(
   2120     Handle<SharedFunctionInfo> info, FunctionLiteral* lit,
   2121     Zone* zone) {
   2122 }
   2123 
   2124 
   2125 void LiveEditFunctionTracker::RecordRootFunctionInfo(Handle<Code> code) {
   2126 }
   2127 
   2128 
   2129 bool LiveEditFunctionTracker::IsActive(Isolate* isolate) {
   2130   return false;
   2131 }
   2132 
   2133 #endif  // ENABLE_DEBUGGER_SUPPORT
   2134 
   2135 
   2136 
   2137 } }  // namespace v8::internal
   2138