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