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